Add Co-authored-by trailers to Merge's squash commit

This commit is contained in:
Ian Gulliver
2026-10-15 07:15:51 -07:00
parent c778741a4a
commit 60a1d221f4
15 changed files with 478 additions and 123 deletions
+24 -3
View File
@@ -1,4 +1,4 @@
import { get, post, type ByreEvent, type Snapshot } from "./api.js";
import { get, post, type ByreEvent, type Participant, type Snapshot } from "./api.js";
import { ago, errorText, h, replace, showAlert, showConfirm } from "./dom.js";
import { markdown } from "./markdown.js";
import { openChanges } from "./panes.js";
@@ -161,10 +161,18 @@ export function mountTranscript(root: HTMLElement): () => void {
{ disabled: busy || unmerged?.taskId !== task.id || !unmerged.has, title: `The agent merges ${target} in, then byre squashes into one commit on ${target} and pushes it to origin` },
"Merge",
);
merge.onclick = () =>
confirmThen(`Merge "${task.title}" into ${target}?`, "Merge", false, async () => {
merge.onclick = async () => {
let coAuthors;
try {
coAuthors = await get("/api/tasks/{taskId}/co-authors", { path: { taskId: task.id } });
} catch (err) {
void showAlert(errorText(err));
return;
}
await confirmThen(mergeQuestion(task.merge_title, target, coAuthors), "Merge", false, async () => {
await post("/api/tasks/{taskId}/merge", { path: { taskId: task.id } });
});
};
const mergeIn = h("button", { disabled: busy, title: `Ask the agent to bring ${target} into this branch and resolve any conflicts` }, `Sync from ${target}`);
mergeIn.onclick = async () => {
mergeIn.disabled = true;
@@ -881,6 +889,19 @@ function messageImages(ids: unknown): HTMLElement | null {
);
}
function mergeQuestion(title: string, target: string, coAuthors: Participant[]): string {
const lines = [`Merge "${title}" into ${target}?`];
const credited = coAuthors.filter((p) => p.git_name && p.git_email);
const missing = coAuthors.filter((p) => !p.git_name || !p.git_email);
if (credited.length > 0) {
lines.push("", "Co-authored-by:", ...credited.map((p) => ` ${p.git_name} <${p.git_email}>`));
}
if (missing.length > 0) {
lines.push("", "No git identity, so no trailer:", ...missing.map((p) => ` ${p.display_name} (${p.login})`));
}
return lines.join("\n");
}
async function confirmThen(question: string, action: string, danger: boolean, act: () => Promise<void>) {
if (!(await showConfirm(question, action, danger))) {
return;