╭ changed ──╮ │src/try.zig│ ╰───────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │381 } │ │382 } │ │383 │ │384 + // the timestamps issue's description, in paragraphs, so the │ │385 + // seeded conflict below can insert and delete among them │ │386 + const tz_p1 = "All timestamps in the activity feed render in UTC regardless of the system timezone."; │ │387 + const tz_p2 = "The tooltip on each entry repeats the same UTC value, so there is no way to see the local time without converting by hand.";│ │388 + const tz_p3 = "A quick survey of other clients shows every one of them rendering local time by default."; │ │389 + const tz_p4 = "Convert to local time and include the offset in tooltips."; │ │390 + │ │391 // seed issues so every repo's issue tracker has content │ │392 const issue_data = [_]struct { │ │393 title: []const u8, │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │515 }, │ │516 .{ │ │517 .title = "Timestamps display in UTC instead of local time", │ │511 - .description = "All timestamps in the activity feed render in UTC regardless of the system timezone. Convert to local time and include the offset in tooltips.",│ │518 + .description = tz_p1 ++ "\n\n" ++ tz_p2 ++ "\n\n" ++ tz_p3 ++ "\n\n" ++ tz_p4, │ │519 .tags = "bug i18n time", │ │520 }, │ │521 .{ │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │556 }; │ │557 } │ │558 try evt.consume(.xit, .{}, io, allocator, &template_repo, evt.events_ref, &issue_events); │ │559 + // the tip is the branch point for the conflicting edits below │ │560 + const seed_tip = (try template_repo.readRef(io, evt.events_ref)) orelse unreachable; │ │561 + │ │562 + // two divergent edits per conflicted issue: ours on the events │ │563 + // branch, theirs on a temp branch rooted at the seed tip, then a │ │564 + // merge. the 4th-newest issue conflicts on title and tags; the │ │565 + // 2nd-newest on its description, with a deletion conflict (ours │ │566 + // removes a paragraph theirs rewords) and an insertion conflict │ │567 + // (each side appends a different closing paragraph). │ │568 + { │ │569 + const other_ref: xit.ref.Ref = .{ .kind = .head, .name = "haxy/other" }; │ │570 + const title_issue = issue_data[issue_data.len - 4]; │ │571 + const desc_issue = issue_data[issue_data.len - 2]; │ │572 + │ │573 + const ours = [_]evt.EventWithId{ .{ │ │574 + .id = issue_events[issue_data.len - 4].id, │ │575 + .timestamp = 100, │ │576 + .author_email = user_data[1].email, │ │577 + .event = .{ .issue = .{ │ │578 + .title = "Crash when resizing the window during the splash animation", │ │579 + .description = title_issue.description, │ │580 + .tags = "bug crash ui priority-high", │ │581 + } }, │ │582 + }, .{ │ │583 + .id = issue_events[issue_data.len - 2].id, │ │584 + .timestamp = 101, │ │585 + .author_email = user_data[1].email, │ │586 + .event = .{ .issue = .{ │ │587 + .title = desc_issue.title, │ │588 + .description = tz_p1 ++ "\n\n" ++ tz_p2 ++ "\n\n" ++ tz_p4 ++ "\n\n" ++ │ │589 + "The confusion is worst for teams spread across timezones, who each read a different wall-clock time from the same feed.", │ │590 + .tags = desc_issue.tags, │ │591 + } }, │ │592 + } }; │ │593 + const theirs = [_]evt.EventWithId{ .{ │ │594 + .id = issue_events[issue_data.len - 4].id, │ │595 + .timestamp = 102, │ │596 + .author_email = user_data[2].email, │ │597 + .event = .{ .issue = .{ │ │598 + .title = "Segfault on early window resize", │ │599 + .description = title_issue.description, │ │600 + .tags = "bug crash rendering", │ │601 + } }, │ │602 + }, .{ │ │603 + .id = issue_events[issue_data.len - 2].id, │ │604 + .timestamp = 103, │ │605 + .author_email = user_data[2].email, │ │606 + .event = .{ .issue = .{ │ │607 + .title = desc_issue.title, │ │608 + .description = tz_p1 ++ "\n\n" ++ tz_p2 ++ "\n\n" ++ │ │609 + "Most other clients already render local time by default, which makes our UTC output stand out as a bug." ++ "\n\n" ++ tz_p4 ++ "\n\n" ++│ │610 + "Log exports inherit the same UTC rendering, so downstream tooling has to guess the source timezone.", │ │611 + .tags = desc_issue.tags, │ │612 + } }, │ │613 + } }; │ │614 + │ │615 + try evt.consume(.xit, .{}, io, allocator, &template_repo, evt.events_ref, &ours); │ │616 + │ │617 + // consume can't root a new branch, so theirs commits by hand │ │618 + var json: std.Io.Writer.Allocating = .init(allocator); │ │619 + defer json.deinit(); │ │620 + for (theirs, 0..) |event, i| { │ │621 + json.clearRetainingCapacity(); │ │622 + try std.json.Stringify.value(event, .{}, &json.writer); │ │623 + const author = try std.fmt.allocPrint(allocator, "haxy <{s}>", .{event.author_email}); │ │624 + defer allocator.free(author); │ │625 + _ = try template_repo.commitAtRef(io, allocator, .{ │ │626 + .author = author, │ │627 + .message = json.written(), │ │628 + .timestamp = event.timestamp, │ │629 + // root the branch at the shared seed tip │ │630 + .parent_oids = if (i == 0) &.{seed_tip} else null, │ │631 + }, null, other_ref); │ │632 + } │ │633 + │ │634 + { │ │635 + var to_events = try template_repo.switchDir(io, allocator, .{ .target = .{ .ref = evt.events_ref } }); │ │636 + defer to_events.deinit(); │ │637 + } │ │638 + { │ │639 + var merge = try template_repo.merge(io, allocator, .{ .kind = .full, .action = .{ .new = .{ .source = &.{.{ .ref = other_ref }} } } }, null); │ │640 + defer merge.deinit(); │ │641 + if (merge.result != .success) return error.MergeFailed; │ │642 + } │ │643 + { │ │644 + var to_master = try template_repo.switchDir(io, allocator, .{ .target = .{ .ref = .{ .kind = .head, .name = "master" } } }); │ │645 + defer to_master.deinit(); │ │646 + } │ │647 + try template_repo.removeBranch(io, .{ .name = other_ref.name }); │ │648 + } │ │649 + │ │650 + try evt.consume(.xit, .{}, io, allocator, &template_repo, evt.events_ref, &.{}); │ │651 } │ │652 │ │653 // copy the template to each repo's on-disk location, named by its │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯