╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─────────────╮ │src/event/PatchRev.zig│ ╰──────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────╮ │149 var bytes: [hash.byteLen(hash_kind)]u8 = undefined; │ │150 _ = try std.fmt.hexToBytes(&bytes, oid); │ │151 if (!std.mem.eql(u8, oid, &std.fmt.bytesToHex(bytes, .lower))) return error.InvalidOid;│ │155 -} │ │156 - │ │157 -pub fn validateTarget(target_ref: []const u8) !void { │ │158 - if (!std.mem.startsWith(u8, target_ref, "refs/heads/") or │ │159 - !xit.ref.validateName(target_ref["refs/".len..])) return error.InvalidTarget; │ │152 } │ │153 │ │154 pub fn readById( │ ╰────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───╮ │src/fork.zig│ ╰────────────╯ ╭──────────────────────────────────────────────────────╮ │15 pub const Route = struct { │ │16 identity: []const u8, │ │17 id: [evt.event_id_size * 2]u8, │ │18 - target: []const u8, │ │18 }; │ │19 │ │20 pub fn parseRoute(route_path: []const u8) ?Route {│ ╰──────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │21 const patch_segment = "/patch:"; │ │23 - const branch_segment = "/branch:"; │ │22 const patch_start = std.mem.indexOf(u8, route_path, patch_segment) orelse return null; │ │25 - const branch_start = std.mem.indexOfPos(u8, route_path, patch_start + patch_segment.len, branch_segment) orelse return null;│ │23 const identity = route_path[0..patch_start]; │ │27 - const id_text = route_path[patch_start + patch_segment.len .. branch_start]; │ │28 - const target = route_path[branch_start + branch_segment.len ..]; │ │29 - if (identity.len == 0 or target.len == 0 or id_text.len != evt.event_id_size * 2) return null; │ │24 + const id_text = route_path[patch_start + patch_segment.len ..]; │ │25 + if (identity.len == 0 or id_text.len != evt.event_id_size * 2) return null; │ │26 const id_bytes = evt.parseEventId(id_text) catch return null; │ │31 - return .{ .identity = identity, .id = std.fmt.bytesToHex(id_bytes, .lower), .target = target }; │ │27 + return .{ .identity = identity, .id = std.fmt.bytesToHex(id_bytes, .lower) }; │ │28 } │ │29 │ │30 pub fn forkPath(allocator: std.mem.Allocator, repo_root_path: []const u8, id: []const u8) ![]u8 { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────╮ │39 title: []const u8, │ │40 description: []const u8, │ │41 tags: []const u8, │ │42 + target_branch: []const u8,│ │43 author: evt.CommitAuthor, │ │44 timestamp: u64, │ │45 }; │ ╰──────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │76 defer allocator.free(target_path); │ │77 var target_repo = try rp.Repo(.xit, repo_opts).open(io, allocator, .{ .path = target_path, .require_repo_root = true });│ │78 defer target_repo.deinit(io, allocator); │ │79 + if (!rf.validateName(input.target_branch)) return error.InvalidTarget; │ │80 + if ((try target_repo.readRef(io, .{ .kind = .head, .name = input.target_branch })) == null) return error.TargetNotFound;│ │81 │ │82 // create the fork repo dir │ │83 const forks_path = std.fs.path.dirname(fork_path) orelse return error.InvalidPatchDraft; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────╮ │174 .title = input.title, │ │175 .description = input.description, │ │176 .tags = input.tags, │ │177 + .target_branch = input.target_branch,│ │178 } }, │ │179 }}); │ │180 │ ╰──────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────╮ │199 fork_repo: *rp.Repo(.xit, repo_opts), │ │200 target_repo: *rp.Repo(.xit, repo_opts),│ │201 id: *const [evt.event_id_size * 2]u8, │ │202 - target_branch: []const u8, │ │202 author: evt.CommitAuthor, │ │203 timestamp: u64, │ │204 reader: *std.Io.Reader, │ ╰────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────╮ │205 writer: *std.Io.Writer, │ │206 error_writer: *std.Io.Writer, │ │207 ) !void { │ │209 - if (!rf.validateName(target_branch)) return error.InvalidTarget;│ │208 const patch_id = try evt.parseEventId(id); │ │209 var arena = std.heap.ArenaAllocator.init(allocator); │ │210 defer arena.deinit(); │ ╰─────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │226 if (patch.event.status.kind() == .merged) return error.PatchAlreadyMerged; │ │227 } │ │228 const published = target_patch != null; │ │231 - const title = if (target_patch) |patch| patch.event.title else fork_patch.event.title; │ │229 + const active_patch = target_patch orelse fork_patch; │ │230 + const title = active_patch.event.title; │ │231 │ │232 // resolve the target and the newest fork revision │ │233 + const target_branch = active_patch.event.target_branch; │ │234 const target_oid = (try target_repo.readRef(io, .{ .kind = .head, .name = target_branch })) orelse return error.TargetNotFound;│ │235 const newest = try evt.PatchRev.readNewest(evt.EventDB(repo_opts.hash), repo_opts.hash, fork_moment, &arena); │ │236 - const target_ref = try std.fmt.allocPrint(arena.allocator(), "refs/heads/{s}", .{target_branch}); │ │236 var revision_id_maybe: ?[evt.event_id_size]u8 = null; │ │237 │ │238 // execute a transaction that receives the push and materializes its revision │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────╮ │250 patch: evt.Patch.Record, │ │251 published: bool, │ │252 target_oid: [hash.hexLen(repo_opts.hash)]u8,│ │254 - target_ref: []const u8, │ │253 title: []const u8, │ │254 author: evt.CommitAuthor, │ │255 timestamp: u64, │ ╰─────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯