Attach a refs/notes/byre note to each squash merge and push it

This commit is contained in:
Ian Gulliver
2026-10-15 19:44:53 -07:00
parent c5e3a680d8
commit 6741177f53
8 changed files with 275 additions and 11 deletions
+16 -3
View File
@@ -269,23 +269,36 @@ func (m *Manager) squashAndClose(ctx context.Context, taskID, login string) erro
return err
}
commit, err := git.SquashCommit(project.RepoPath, task.WorktreePath, project.DefaultBranch, squashMessage(task.MergeTitle, coAuthors), []string{
env := []string{
"GIT_AUTHOR_NAME=" + user.GitName,
"GIT_AUTHOR_EMAIL=" + user.GitEmail,
"GIT_COMMITTER_NAME=" + user.GitName,
"GIT_COMMITTER_EMAIL=" + user.GitEmail,
})
}
commit, err := git.SquashCommit(project.RepoPath, task.WorktreePath, project.DefaultBranch, squashMessage(task.MergeTitle, coAuthors), env)
if err != nil {
return err
}
pushed := ""
if commit != "" {
err = git.Push(project.RepoPath, commit, project.DefaultBranch)
note, err := m.mergeNote(ctx, task, login)
if err != nil {
return err
}
notes, err := git.NoteCommit(project.RepoPath, commit, note, env)
if err != nil {
return err
}
err = git.Push(project.RepoPath, commit, project.DefaultBranch, notes)
if err != nil {
return err
}
pushed = git.Remote + "/" + project.DefaultBranch
err = git.SetNotes(project.RepoPath, notes)
if err != nil {
return fmt.Errorf("pushed %s to %s, but updating %s in the project checkout failed: %w", commit, pushed, git.NotesRef, err)
}
err = git.FastForward(project.RepoPath, commit)
if err != nil {
return fmt.Errorf("pushed %s to %s, but fast-forwarding the project checkout failed: %w", commit, pushed, err)
+107
View File
@@ -0,0 +1,107 @@
package agents
import (
"context"
"fmt"
"strings"
"time"
"g.fc.run/misc/byre/internal/api"
"g.fc.run/misc/byre/internal/store"
)
func (m *Manager) mergeNote(ctx context.Context, task api.Task, login string) (string, error) {
handoffs, err := m.store.TaskHandoffs(ctx, task.Id)
if err != nil {
return "", err
}
reviews, err := m.store.ListReviews(ctx, task.Id)
if err != nil {
return "", err
}
answered, err := m.store.ListInbox(ctx, store.InboxFilter{TaskID: task.Id, State: api.Answered})
if err != nil {
return "", err
}
b := &strings.Builder{}
fmt.Fprintf(b, "# %s\n\n", task.MergeTitle)
fmt.Fprintf(b, "byre task %s, %q, created by %s, merged by %s.\n", task.Id, task.Title, task.CreatedBy, login)
if task.TodoItem != nil {
fmt.Fprintf(b, "Started from the TODO item %q.\n", *task.TodoItem)
}
if task.ForkedFrom != nil && task.ForkedAt != nil {
fmt.Fprintf(b, "Forked from task %s at snapshot %d.\n", *task.ForkedFrom, *task.ForkedAt)
}
fmt.Fprintf(b, "Full transcripts: the events of task %s in byre (GET /api/events?task_id=%s).\n", task.Id, task.Id)
if len(handoffs) > 0 {
b.WriteString("\n## Handoffs\n")
for _, h := range handoffs {
fmt.Fprintf(b, "\n### Session %s, %s\n\n%s\n", h.SessionID, h.At.Format(time.RFC3339), strings.TrimSpace(h.Text))
}
}
if len(reviews) > 0 {
b.WriteString("\n## Reviews\n")
for _, r := range reviews {
fmt.Fprintf(b, "\n### Snapshot %d, %s %s: %s\n", r.SnapshotN, r.Vendor, r.Model, r.State)
if r.Error != "" {
fmt.Fprintf(b, "\n%s\n", r.Error)
}
if r.Result == nil {
continue
}
for _, key := range []string{"change", "summary"} {
text, _ := (*r.Result)[key].(string)
if strings.TrimSpace(text) != "" {
fmt.Fprintf(b, "\n%s\n", strings.TrimSpace(text))
}
}
}
}
decisions := []api.InboxItem{}
for _, item := range answered {
if item.Kind == api.Question {
decisions = append(decisions, item)
}
}
if len(decisions) > 0 {
b.WriteString("\n## Decisions\n")
for _, item := range decisions {
fmt.Fprintf(b, "\n### %s\n", item.Payload["question"])
background, _ := item.Payload["context"].(string)
if strings.TrimSpace(background) != "" {
fmt.Fprintf(b, "\n%s\n", strings.TrimSpace(background))
}
b.WriteString("\n")
for _, r := range item.Responses {
b.WriteString(decisionLine(item, r))
}
}
}
return b.String(), nil
}
func decisionLine(item api.InboxItem, r api.InboxResponse) string {
text := ""
if r.Text != nil {
text = strings.TrimSpace(*r.Text)
}
switch r.Type {
case api.Option:
line := fmt.Sprintf("%s chose: %s\n", r.User, strings.Join(*r.Options, "; "))
if item.Payload["multiple"] == true {
line = fmt.Sprintf("%s checked: %s\n", r.User, strings.Join(*r.Options, "; "))
}
if text != "" {
line += fmt.Sprintf("%s added: %s\n", r.User, text)
}
return line
case api.Other:
return fmt.Sprintf("%s answered: %s\n", r.User, text)
}
return ""
}