╭ changed ───╮ │src/fork.zig│ ╰────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────╮ │← previous│ ╰──────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │383 - const published_patch = (evt.Patch.readById(evt.EventDB(repo_opts.hash), repo_opts.hash, update_moment, &update_arena, &patch_id) catch return) orelse return; │ │384 - if (published_patch.removed) return; │ │385 - const revision_hex = std.fmt.bytesToHex(revision_id, .lower); │ │386 - if (published_patch.event.patchrev_id) |*published_revision| { │ │387 - if (std.mem.eql(u8, published_revision, &revision_hex)) return; │ │403 + const posted_patch = (evt.Patch.readById(evt.EventDB(repo_opts.hash), repo_opts.hash, update_moment, &update_arena, &patch_id) catch return) orelse return; │ │404 + if (posted_patch.removed) return; │ │405 + const fork_update_moment = evt.currentMoment(repo_opts, fork_repo) catch return; │ │406 + const revision = (evt.PatchRev.readById(evt.EventDB(repo_opts.hash), repo_opts.hash, fork_update_moment, &update_arena, &revision_id) catch return) orelse return;│ │407 + if (revision.removed) return; │ │408 + const selected = evt.Patch.Revision.fromRecord(revision_id, revision); │ │409 + if (posted_patch.event.revision) |current| { │ │410 + if (evt.fieldEqual(evt.Patch.Revision, current, selected)) return; │ │411 } │ │389 - var patch = published_patch.event; │ │390 - patch.patchrev_id = revision_hex; │ │412 + var patch = posted_patch.event; │ │413 + patch.revision = selected; │ │414 evt.consume(.repo, .xit, repo_opts, io, allocator, target_repo, evt.events_ref, &.{.{ │ │415 .id = id.*, │ │416 .timestamp = timestamp, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │417 .author = author, │ │418 .event = .{ .patch = patch }, │ │419 }}) catch {}; │ │397 -} │ │398 - │ │399 -pub const PublishInput = struct { │ │400 - id: [evt.event_id_size * 2]u8, │ │401 - user_id: [evt.event_id_size]u8, │ │402 - repo_id: [evt.event_id_size]u8, │ │403 - author: evt.CommitAuthor, │ │404 - timestamp: u64, │ │405 -}; │ │406 - │ │407 -pub fn publish( │ │408 - comptime repo_opts: rp.RepoOpts(.xit), │ │409 - io: std.Io, │ │410 - allocator: std.mem.Allocator, │ │411 - admin_repo: *rp.Repo(.xit, evt.admin_repo_opts), │ │412 - target_repo: *rp.Repo(.xit, repo_opts), │ │413 - path: []const u8, │ │414 - input: PublishInput, │ │415 -) !void { │ │416 - const patch_id = try evt.parseEventId(&input.id); │ │417 - var arena = std.heap.ArenaAllocator.init(allocator); │ │418 - defer arena.deinit(); │ │419 - │ │420 - const admin_moment = try evt.currentMoment(evt.admin_repo_opts, admin_repo); │ │421 - const fork_record = (try evt.Fork.readById(evt.AdminDB, evt.admin_repo_opts.hash, admin_moment, &arena, &patch_id)) orelse return error.InvalidPatchDraft; │ │422 - if (fork_record.removed or │ │423 - !std.mem.eql(u8, fork_record.event.user_id, &input.user_id) or │ │424 - !std.mem.eql(u8, fork_record.event.repo_id, &input.repo_id)) return error.InvalidPatchDraft; │ │425 - const user = (try evt.User.readById(evt.AdminDB, evt.admin_repo_opts.hash, admin_moment, &arena, &input.user_id)) orelse return error.InvalidPatchDraft; │ │426 - if (user.removed or │ │427 - !std.mem.eql(u8, user.event.name, input.author.name) or │ │428 - !std.mem.eql(u8, user.event.email, input.author.email)) return error.InvalidPatchDraft; │ │429 - │ │430 - var fork_repo = rp.Repo(.xit, repo_opts).open(io, allocator, .{ .path = path }) catch return error.PatchDataUnavailable; │ │431 - defer fork_repo.deinit(io, allocator); │ │432 - const fork_moment = evt.currentMoment(repo_opts, &fork_repo) catch return error.PatchDataUnavailable; │ │433 - const local_patch = (try evt.Patch.readById(evt.EventDB(repo_opts.hash), repo_opts.hash, fork_moment, &arena, &patch_id)) orelse return error.PatchDataUnavailable; │ │434 - │ │435 - const target_moment = evt.currentMoment(repo_opts, target_repo) catch |err| switch (err) { │ │436 - error.NotFound => null, │ │437 - else => |other| return other, │ │438 - }; │ │439 - const existing = if (target_moment) |moment| │ │440 - try evt.Patch.readById(evt.EventDB(repo_opts.hash), repo_opts.hash, moment, &arena, &patch_id) │ │441 - else │ │442 - null; │ │443 - if (existing) |record| { │ │444 - if (record.removed or !std.mem.eql(u8, record.author_email orelse "", input.author.email)) return error.InvalidPatch; │ │445 - } │ │446 - if (local_patch.removed) { │ │447 - if (existing == null) return error.PatchDataUnavailable; │ │448 - } else { │ │449 - const revision_hex = local_patch.event.patchrev_id orelse return error.PatchNotPushed; │ │450 - const revision_id = try evt.parseEventId(&revision_hex); │ │451 - const revision = (try evt.PatchRev.readById(evt.EventDB(repo_opts.hash), repo_opts.hash, fork_moment, &arena, &revision_id)) orelse return error.PatchNotPushed;│ │452 - if (revision.removed) return error.PatchNotPushed; │ │453 - var patch = (existing orelse local_patch).event; │ │454 - patch.patchrev_id = revision_hex; │ │455 - if (existing == null) patch.status = .open; │ │456 - │ │457 - try evt.consume(.repo, .xit, repo_opts, io, allocator, target_repo, evt.events_ref, &.{.{ │ │458 - .id = input.id, │ │459 - .timestamp = input.timestamp, │ │460 - .author = input.author, │ │461 - .event = .{ .patch = patch }, │ │462 - }}); │ │463 - │ │464 - try evt.consume(.fork, .xit, repo_opts, io, allocator, &fork_repo, evt.events_ref, &.{.{ │ │465 - .id = input.id, │ │466 - .timestamp = input.timestamp, │ │467 - .author = input.author, │ │468 - .event = .{ .patch = null }, │ │469 - }}); │ │470 - } │ │471 - │ │472 - if (fork_record.event.stage == .draft) { │ │473 - var posted = fork_record.event; │ │474 - posted.stage = .posted; │ │475 - try evt.consume(.admin, .xit, evt.admin_repo_opts, io, allocator, admin_repo, evt.events_ref, &.{.{ │ │476 - .id = input.id, │ │477 - .timestamp = input.timestamp, │ │478 - .author = input.author, │ │479 - .event = .{ .fork = posted }, │ │480 - }}); │ │481 - } │ │420 } │ │421 │ │422 // delete first so a failed tombstone can be retried safely │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯