╭ changed ────╮ │src/patch.zig│ ╰─────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │325 } │ │326 if (existing == null) patch.status = .open; │ │327 │ │328 - try evt.consume(.repo, .xit, repo_opts, io, allocator, target_repo, evt.events_ref, &.{.{ │ │328 + try evt.consume(.server, .repo, .xit, repo_opts, io, allocator, target_repo, evt.events_ref, &.{.{│ │329 .id = input.id, │ │330 .timestamp = input.timestamp, │ │331 .author = input.author, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │332 .event = .{ .patch = patch }, │ │333 }}); │ │334 │ │335 - try evt.consume(.fork, .xit, repo_opts, io, allocator, &fork_repo, evt.events_ref, &.{.{ │ │335 + try evt.consume(.server, .fork, .xit, repo_opts, io, allocator, &fork_repo, evt.events_ref, &.{.{│ │336 .id = input.id, │ │337 .timestamp = input.timestamp, │ │338 .author = input.author, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │343 if (fork_record.event.stage == .draft) { │ │344 var published = fork_record.event; │ │345 published.stage = .publish; │ │346 - try evt.consume(.admin, .xit, evt.admin_repo_opts, io, allocator, admin_repo, evt.events_ref, &.{.{ │ │346 + try evt.consume(.server, .admin, .xit, evt.admin_repo_opts, io, allocator, admin_repo, evt.events_ref, &.{.{│ │347 .id = input.id, │ │348 .timestamp = input.timestamp, │ │349 .author = input.author, │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────╮ │350 .event = .{ .fork = published }, │ │351 }}); │ │352 } │ │353 - refreshMergeability(repo_opts, io, allocator, target_repo, patch_id);│ │353 } │ │354 │ │355 pub fn editDraft( │ ╰──────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │388 patch.description = input.description; │ │389 if (!std.mem.eql(u8, patch.target_branch, input.target_branch)) patch.revision = null; │ │390 patch.target_branch = input.target_branch; │ │392 - try evt.consume(.fork, .xit, repo_opts, io, allocator, &fork_repo, evt.events_ref, &.{.{ │ │391 + try evt.consume(.server, .fork, .xit, repo_opts, io, allocator, &fork_repo, evt.events_ref, &.{.{│ │392 .id = input.id, │ │393 .timestamp = input.timestamp, │ │394 .author = input.author, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │407 input: MergeInput, │ │408 ) !void { │ │409 const patch_id = try evt.parseEventId(&input.id); │ │410 + errdefer |err| { │ │411 + if (err == error.PatchDataUnavailable or err == error.PatchOutOfDate) { │ │412 + refreshMergeability(repo_opts, io, allocator, target_repo, patch_id);│ │413 + } │ │414 + } │ │415 var arena = std.heap.ArenaAllocator.init(allocator); │ │416 defer arena.deinit(); │ │417 │ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │425 .merged => return error.PatchAlreadyMerged, │ │426 } │ │427 const selected = patch_record.event.revision orelse return error.PatchNotPushed; │ │424 - const revision_id = try evt.parseEventId(&selected.id); │ │428 const target_ref = rf.Ref{ .kind = .head, .name = patch_record.event.target_branch }; │ │429 │ │427 - // open and lock the fork │ │430 + // open the fork │ │431 const fork_path = try fork.forkPath(arena.allocator(), repo_root_path, &input.id); │ │432 var fork_repo = rp.Repo(.xit, repo_opts).open(io, allocator, .{ .path = fork_path, .require_repo_root = true }) catch return error.PatchDataUnavailable;│ │433 defer fork_repo.deinit(io, allocator); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │431 - try fork_repo.core.db_file.lock(io, .shared); │ │432 - defer fork_repo.core.db_file.unlock(io); │ │433 - │ │434 - // require the fork's newest revision │ │435 - { │ │436 - const fork_moment = try evt.currentMoment(repo_opts, &fork_repo); │ │437 - const newest = (try evt.PatchRev.readNewest(evt.EventDB(repo_opts.hash), repo_opts.hash, fork_moment, &arena)) orelse return error.PatchDataUnavailable;│ │438 - if (!std.mem.eql(u8, &newest.id, &revision_id) or │ │439 - !selected.matches(newest.record)) return error.PatchOutOfDate; │ │440 - } │ │441 - │ │434 // select the commit and merge identity │ │435 const merge_oid = oidArray(repo_opts.hash, switch (input.revision) { │ │436 .squash => selected.squash_oid, │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │462 │ │463 var check_arena = std.heap.ArenaAllocator.init(ctx.allocator); │ │464 defer check_arena.deinit(); │ │465 + │ │466 + // require the fork's newest revision while both repos are locked │ │467 + const selected_revision = ctx.expected_patch.revision.?; │ │468 + const revision_id = try evt.parseEventId(&selected_revision.id); │ │469 + const fork_moment = try evt.currentMoment(repo_opts, ctx.fork_repo); │ │470 + const newest = (try evt.PatchRev.readNewest(evt.EventDB(repo_opts.hash), repo_opts.hash, fork_moment, &check_arena)) orelse return error.PatchDataUnavailable;│ │471 + if (!std.mem.eql(u8, &newest.id, &revision_id) or │ │472 + !selected_revision.matches(newest.record)) return error.PatchOutOfDate; │ │473 + │ │474 const availability = try readMergeability(repo_opts, state.readOnly(), ctx.io, &check_arena, &ctx.patch_id, ctx.expected_patch); │ │475 switch (availability.get(ctx.revision)) { │ │476 .clean => {}, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────╮ │515 } │ │516 }; │ │517 │ │518 + try fork_repo.core.db_file.lock(io, .shared); │ │519 + defer fork_repo.core.db_file.unlock(io); │ │520 try target_repo.core.db_file.lock(io, .exclusive);│ │521 defer target_repo.core.db_file.unlock(io); │ │522 │ ╰───────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯