╭ changed ──╮ │src/try.zig│ ╰───────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭───────────────────────────────────────────────────────────────────────────────╮ │19 const fork = hx.fork; │ │20 const pch = hx.pch; │ │21 const push = hx.push; │ │22 +const notify = hx.notify; │ │23 │ │24 // cook the terminal before a panic/segfault trace is printed, so the trace│ │25 // isn't mangled by raw mode and the alternate buffer │ ╰───────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │292 // template repo and copy that to each repo's location below rather than │ │293 // redoing the expensive commit work for every repo. │ │294 const template_path = try std.Io.Dir.path.join(arena.allocator(), &.{ cwd_path, temp_dir_name, "template" });│ │295 + // the threads admin takes part in: its discussion, its assigned issue and its newest patch │ │296 + var admin_thread_ids: [3][evt.event_id_size]u8 = undefined; │ │297 { │ │298 var template_repo = try rp.Repo(.xit, .{}).init(io, allocator, .{ .path = template_path }); │ │299 defer template_repo.deinit(io, allocator); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │815 } │ │816 try evt.consume(.local, .repo, .xit, .{}, io, allocator, &template_repo, evt.events_ref, &assignment_events); │ │817 │ │818 + // a comment on admin's assigned issue, which notifies admin as its assignee │ │819 + { │ │820 + const thread_id = issue_events[issue_data.len - 5].id; │ │821 + admin_thread_ids[1] = try evt.parseEventId(&thread_id); │ │822 + try evt.consume(.local, .repo, .xit, .{}, io, allocator, &template_repo, evt.events_ref, &.{.{ │ │823 + .id = std.fmt.bytesToHex(evt.EventWithId.randomId(prng.random()), .lower), │ │824 + .timestamp = now - 15 * std.time.s_per_min, │ │825 + .author = .{ .name = user_data[3].name, .email = user_data[3].email }, │ │826 + .event = .{ .comment = .{ .thread_id = thread_id, .parent_id = thread_id, .body = "Is this still on your list? I can pick it up if you're busy." } },│ │827 + }}); │ │828 + } │ │829 + │ │830 const discussion_data = [_]struct { │ │831 title: []const u8, │ │832 description: []const u8, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │873 }; │ │874 } │ │875 try evt.consume(.local, .repo, .xit, .{}, io, allocator, &template_repo, evt.events_ref, &discussion_events);│ │876 + admin_thread_ids[0] = try evt.parseEventId(&discussion_events[0].id); │ │877 │ │878 var discussion_comment_ids: [discussion_data.len][3][evt.event_id_size]u8 = undefined; │ │879 for (&discussion_comment_ids) |*ids| { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │937 if (repo_index + 1 == repo_data.len) { │ │938 var target_repo = try rp.Repo(.xit, .{}).open(io, allocator, .{ .path = repo_path, .require_repo_root = true }); │ │939 defer target_repo.deinit(io, allocator); │ │924 - try seedPatches(io, allocator, server_path, &repo, &target_repo, &repo_event_ids[repo_index], &user_ids[repo_data[repo_index].user_index], &admin_user_id, prng.random(), now); │ │940 + admin_thread_ids[2] = try seedPatches(io, allocator, server_path, &repo, &target_repo, &repo_event_ids[repo_index], &user_ids[repo_data[repo_index].user_index], &admin_user_id, prng.random(), now);│ │941 } │ │942 } │ │943 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │944 │ │945 + // seeding consumed locally, which subscribes nobody, so subscribe admin as the server │ │946 + // would have, then deliver the notifications of its own repos the way the worker does │ │947 + for (repo_data, repo_event_ids, 0..) |r, id_bytes, repo_index| { │ │948 + if (r.user_index != 0) continue; │ │949 + const location: evt.RepoLocation = .{ .owner_id = user_ids[r.user_index], .repo_id = id_bytes }; │ │950 + // only the last repo has patches │ │951 + const thread_ids: []const [evt.event_id_size]u8 = if (repo_index + 1 == repo_data.len) &admin_thread_ids else admin_thread_ids[0..2]; │ │952 + for (thread_ids) |*thread_id| try notify.subscribe(io, allocator, users_dir, &admin_user_id, location, thread_id, .{ .name = user_data[0].name, .email = user_data[0].email });│ │953 + try notify.notifyRepo(io, allocator, users_dir, work_path, location); │ │954 + } │ │955 + │ │956 break :blk try ui.Session.init(&session_arena, &repo, .{ .user_id = &admin_user_id }); │ │957 }; │ │958 session.is_terminal = true; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────╮ │1226 }}); │ │1227 } │ │1228 │ │1229 +// returns the newest patch, the one the seeded comments are on│ │1230 fn seedPatches( │ │1231 io: std.Io, │ │1232 allocator: std.mem.Allocator, │ ╰─────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────╮ │1238 user_id: *const [evt.event_id_size]u8,│ │1239 random: std.Random, │ │1240 now: u64, │ │1213 -) !void { │ │1241 +) ![evt.event_id_size]u8 { │ │1242 const patch_data = [_]struct { │ │1243 title: []const u8, │ │1244 description: []const u8, │ ╰────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1349 try seedPatchRevision(io, allocator, users_dir, user_id, &patch_ids[i], patch.title, patch_author, timestamp + 1, random, base_oid, file_path, contents[0..count], patch.removed_path);│ │1350 } │ │1351 const status = patch.status orelse continue; │ │1324 - try pch.publish(.{}, io, allocator, users_dir, admin_repo, target_repo, .{ │ │1352 + try pch.publish(.{}, io, allocator, .{ .users_dir = users_dir }, admin_repo, target_repo, .{ │ │1353 .id = patch_hex, │ │1354 .user_id = user_id.*, │ │1355 .repo_id = repo_id.*, │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1358 }); │ │1359 │ │1360 if (status == .merged) { │ │1333 - try pch.mergeAndRemoveFork(.{}, io, allocator, users_dir, target_repo, .{ │ │1361 + try pch.mergeAndRemoveFork(.{}, io, allocator, .{ .users_dir = users_dir }, target_repo, .{│ │1362 .id = patch_hex, │ │1363 .revision = .source, │ │1364 .author = patch_author, │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯