╭ changed ───────────────╮ │src/test/event/patch.zig│ ╰────────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────╮ │178 try testBranchMerge(.squash); │ │179 } │ │180 │ │181 -fn testBranchMerge(selection: pch.MergeRevision) !void { │ │181 +fn testBranchMerge(selection: evt.Patch.MergeRevision) !void { │ │182 const io = std.testing.io; │ │183 const allocator = std.testing.allocator; │ │184 const opts: rp.RepoOpts(.xit) = .{ .is_test = true, .ProgressCtx = *push.PushProgress };│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │238 var moment = try repo.core.latestMoment(); │ │239 const result = try pch.readMergeability(opts, .{ .core = &repo.core, .extra = .{ .moment = &moment } }, io, &arena, &id, before.event);│ │240 try std.testing.expectEqualDeep(pch.Mergeability{ .source = .clean, .squash = .clean }, result); │ │241 + } │ │242 + │ │243 + // a diverged target produces a merge commit in both merge styles │ │244 + { │ │245 + const file = try repo.core.work_dir.createFile(io, "target.txt", .{}); │ │246 + defer file.close(io); │ │247 + try file.writeStreamingAll(io, "target only\n"); │ │248 } │ │249 + try repo.add(io, allocator, &.{"target.txt"}); │ │250 + const target_oid = try repo.commit(io, allocator, .{ .message = "advance target" }); │ │251 + pch.refreshMergeability(opts, io, allocator, &repo, id); │ │252 │ │253 // both merge styles use the stored revision, without fork data │ │254 try pch.merge(opts, io, allocator, path, &repo, .{ .id = id_hex, .revision = selection, .author = author, .timestamp = 100 }); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │255 const merged = (try evt.Patch.readFromRepo(.xit, opts, io, allocator, &arena, &repo, &id)) orelse return error.NotFound;│ │246 - const oid = switch (merged.event.status) { │ │256 + const range = switch (merged.event.status) { │ │257 .merged => |value| value, │ │258 else => return error.NotMerged, │ │259 }; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │250 - try std.testing.expectEqualStrings(if (selection == .source) revision.source_oid else revision.squash_oid, oid); │ │260 + const result_oid = (try repo.readRef(io, .{ .kind = .head, .name = "master" })) orelse return error.NotFound; │ │261 + try std.testing.expectEqual(selection, range.revision); │ │262 + try std.testing.expectEqualStrings(&target_oid, range.before_oid); │ │263 + try std.testing.expectEqualStrings(&result_oid, range.after_oid); │ │264 + { │ │265 + var commits = try repo.log(io, allocator, .{ .start_oids = &.{result_oid} }); │ │266 + defer commits.deinit(); │ │267 + const commit = (try commits.next(allocator)) orelse return error.NotFound; │ │268 + defer commit.deinit(); │ │269 + const parents = commit.content.commit.metadata.parent_oids orelse return error.ParentOidsNotFound; │ │270 + try std.testing.expectEqual(2, parents.len); │ │271 + try std.testing.expectEqualStrings(&target_oid, &parents[0]); │ │272 + try std.testing.expectEqualStrings(if (selection == .source) revision.source_oid else revision.squash_oid, &parents[1]);│ │273 + } │ │274 │ │275 // the source survives, and merged patches no longer follow it │ │276 _ = try repo.commitAtRef(io, allocator, .{ .message = "later" }, null, .{ .kind = .head, .name = "feature" }); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │591 .{ .tree = .{ .name = "head", .oid = &source_b_tree } }, │ │592 }; │ │593 var parent_patch = updated_patch; │ │571 - parent_patch.status = .{ .merged = &source_b_oid }; │ │594 + parent_patch.status = .{ .merged = .{ .revision = .source, .before_oid = &base_oid, .after_oid = &source_b_oid } };│ │595 { │ │596 try consumePatchWithRevision(.repo, io, allocator, &target, side_events_ref, patchrev_b_id, .{ │ │597 .base_oid = &base_oid, │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │705 .event = .{ .patch = closed_child }, │ │706 }}); │ │707 var merged_child = child.event; │ │685 - merged_child.status = .{ .merged = (child.event.revision orelse return error.NotFound).source_oid }; │ │708 + merged_child.status = .{ .merged = .{ .revision = .source, .before_oid = &base_oid, .after_oid = (child.event.revision orelse return error.NotFound).source_oid } };│ │709 try evt.consume(.local, .repo, .xit, repo_opts, io, allocator, &target, status_side_ref, &.{.{ │ │710 .id = std.fmt.bytesToHex(child_id, .lower), │ │711 .timestamp = 15, │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │747 .description = "has no revision", │ │748 .tags = "enhancement", │ │749 .target_branch = "master", │ │727 - .status = .{ .merged = &base_oid }, │ │750 + .status = .{ .merged = .{ .revision = .source, .before_oid = &base_oid, .after_oid = &base_oid } },│ │751 } }, │ │752 }})); │ │753 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────╮ │773 try patchLifecycle(.source); │ │774 } │ │775 │ │753 -fn patchLifecycle(merge_revision: pch.MergeRevision) !void { │ │776 +fn patchLifecycle(merge_revision: evt.Patch.MergeRevision) !void {│ │777 const io = std.testing.io; │ │778 const allocator = std.testing.allocator; │ │779 │ ╰───────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1068 const merged_moment = try evt.currentMoment(repo_opts, &target); │ │1069 const merged = (try evt.Patch.readById(Repo.DB, repo_opts.hash, merged_moment, &arena, &patch_id)) orelse return error.NotFound;│ │1070 try std.testing.expectEqual(.merged, merged.event.status.kind()); │ │1048 - const merged_oid = switch (merged.event.status) { │ │1049 - .merged => |oid| oid, │ │1071 + const merged_range = switch (merged.event.status) { │ │1072 + .merged => |range| range, │ │1073 else => return error.InvalidPatch, │ │1074 }; │ │1052 - try std.testing.expectEqualStrings(&selected_oid, merged_oid); │ │1075 + try std.testing.expectEqual(merge_revision, merged_range.revision); │ │1076 + try std.testing.expectEqualStrings(&base_oid, merged_range.before_oid); │ │1077 + try std.testing.expectEqualStrings(&selected_oid, merged_range.after_oid); │ │1078 try std.testing.expect(null != try evt.PatchRev.readById(Repo.DB, repo_opts.hash, merged_moment, &arena, &first_patchrev_id)); │ │1079 │ │1080 _ = arena.reset(.retain_capacity); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯