Share commit preparation and checkout updates across merge paths
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
package agents
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"g.fc.run/ai/byre/internal/api"
|
||||
"g.fc.run/ai/byre/internal/git"
|
||||
)
|
||||
|
||||
func (m *Manager) prepareMainCommit(ctx context.Context, task api.Task, project api.Project, user api.User) (string, string, error) {
|
||||
coAuthors, err := m.CoAuthors(ctx, task.Id, user.Login)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
env := git.IdentityEnv(user.GitName, user.GitEmail)
|
||||
commit, err := git.SquashCommit(project.RepoPath, task.WorktreePath, project.DefaultBranch, squashMessage(task.MergeTitle, coAuthors), env, m.signer(ctx, user))
|
||||
if err != nil || commit == "" {
|
||||
return "", "", err
|
||||
}
|
||||
note, err := m.mergeNote(ctx, task, user.Login)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
notes, err := git.NoteCommit(project.RepoPath, commit, note, env)
|
||||
return commit, notes, err
|
||||
}
|
||||
|
||||
func advanceMainCheckout(project api.Project, commit, notes string) error {
|
||||
pushed := git.Remote + "/" + project.DefaultBranch
|
||||
err := git.AdvanceNotes(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)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) CoAuthors(ctx context.Context, taskID, login string) ([]api.Participant, error) {
|
||||
participants, err := m.store.Participants(ctx, taskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
coAuthors := []api.Participant{}
|
||||
for _, p := range participants {
|
||||
if p.Login != login {
|
||||
coAuthors = append(coAuthors, p)
|
||||
}
|
||||
}
|
||||
return coAuthors, nil
|
||||
}
|
||||
|
||||
func squashMessage(title string, coAuthors []api.Participant) string {
|
||||
trailers := []string{}
|
||||
for _, p := range coAuthors {
|
||||
if p.GitName == "" || p.GitEmail == "" {
|
||||
continue
|
||||
}
|
||||
trailers = append(trailers, fmt.Sprintf("Co-authored-by: %s <%s>", p.GitName, p.GitEmail))
|
||||
}
|
||||
if len(trailers) == 0 {
|
||||
return title
|
||||
}
|
||||
return title + "\n\n" + strings.Join(trailers, "\n")
|
||||
}
|
||||
@@ -330,12 +330,7 @@ func (m *Manager) landMerge(ctx context.Context, f store.FinalizingMerge) error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
coAuthors, err := m.CoAuthors(ctx, task.Id, f.By)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
env := git.IdentityEnv(user.GitName, user.GitEmail)
|
||||
commit, err = git.SquashCommit(project.RepoPath, task.WorktreePath, project.DefaultBranch, squashMessage(task.MergeTitle, coAuthors), env, m.signer(ctx, user))
|
||||
commit, notes, err = m.prepareMainCommit(ctx, task, project, user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -346,15 +341,6 @@ func (m *Manager) landMerge(ctx context.Context, f store.FinalizingMerge) error
|
||||
}
|
||||
return m.closeUnchanged(ctx, task, project, f.By)
|
||||
}
|
||||
|
||||
note, err := m.mergeNote(ctx, task, f.By)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notes, err = git.NoteCommit(project.RepoPath, commit, note, env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = m.store.SetFinalizingCommit(ctx, task.Id, commit, notes)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -391,13 +377,9 @@ func (m *Manager) closeUnchanged(ctx context.Context, task api.Task, project api
|
||||
|
||||
func (m *Manager) closePushed(ctx context.Context, task api.Task, project api.Project, commit, notes, login string) error {
|
||||
pushed := git.Remote + "/" + project.DefaultBranch
|
||||
err := git.AdvanceNotes(project.RepoPath, notes)
|
||||
err := advanceMainCheckout(project, commit, notes)
|
||||
if err != nil {
|
||||
return &unfinishedMergeError{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 &unfinishedMergeError{fmt.Errorf("pushed %s to %s, but fast-forwarding the project checkout failed: %w", commit, pushed, err)}
|
||||
return &unfinishedMergeError{err}
|
||||
}
|
||||
err = m.RemoveTask(ctx, task, project, login)
|
||||
if err != nil {
|
||||
@@ -410,35 +392,6 @@ func (m *Manager) closePushed(ctx context.Context, task api.Task, project api.Pr
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) CoAuthors(ctx context.Context, taskID, login string) ([]api.Participant, error) {
|
||||
participants, err := m.store.Participants(ctx, taskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
coAuthors := []api.Participant{}
|
||||
for _, p := range participants {
|
||||
if p.Login != login {
|
||||
coAuthors = append(coAuthors, p)
|
||||
}
|
||||
}
|
||||
return coAuthors, nil
|
||||
}
|
||||
|
||||
func squashMessage(title string, coAuthors []api.Participant) string {
|
||||
trailers := []string{}
|
||||
for _, p := range coAuthors {
|
||||
if p.GitName == "" || p.GitEmail == "" {
|
||||
continue
|
||||
}
|
||||
trailers = append(trailers, fmt.Sprintf("Co-authored-by: %s <%s>", p.GitName, p.GitEmail))
|
||||
}
|
||||
if len(trailers) == 0 {
|
||||
return title
|
||||
}
|
||||
return title + "\n\n" + strings.Join(trailers, "\n")
|
||||
}
|
||||
|
||||
func (m *Manager) RemoveTask(ctx context.Context, task api.Task, project api.Project, actor string) error {
|
||||
err := m.StopTask(ctx, task.Id, actor)
|
||||
if err != nil {
|
||||
|
||||
@@ -116,12 +116,8 @@ func (m *Manager) pushToMain(ctx context.Context, l *live, task api.Task, projec
|
||||
return "", err
|
||||
}
|
||||
|
||||
coAuthors, err := m.CoAuthors(ctx, task.Id, user.Login)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
env := git.IdentityEnv(user.GitName, user.GitEmail)
|
||||
commit, err := git.SquashCommit(project.RepoPath, l.dir, project.DefaultBranch, squashMessage(title, coAuthors), env, m.signer(ctx, user))
|
||||
task.MergeTitle = title
|
||||
commit, notes, err := m.prepareMainCommit(ctx, task, project, user)
|
||||
conflict := &git.ConflictError{}
|
||||
if errors.As(err, &conflict) {
|
||||
return "", fmt.Errorf("%w; run `git merge --no-ff --no-commit %s`, resolve them, and call merge_to_main again", err, project.DefaultBranch)
|
||||
@@ -134,15 +130,6 @@ func (m *Manager) pushToMain(ctx context.Context, l *live, task api.Task, projec
|
||||
return "", err
|
||||
}
|
||||
|
||||
task.MergeTitle = title
|
||||
note, err := m.mergeNote(ctx, task, user.Login)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
notes, err := git.NoteCommit(project.RepoPath, commit, note, env)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = git.Push(ctx, project.RepoPath, commit, project.DefaultBranch, notes)
|
||||
if errors.Is(err, git.ErrRemoteMoved) {
|
||||
return "", fmt.Errorf("%w; call merge_to_main again", err)
|
||||
@@ -152,13 +139,9 @@ func (m *Manager) pushToMain(ctx context.Context, l *live, task api.Task, projec
|
||||
}
|
||||
|
||||
pushed := git.Remote + "/" + project.DefaultBranch
|
||||
err = git.AdvanceNotes(project.RepoPath, notes)
|
||||
err = advanceMainCheckout(project, commit, 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)
|
||||
return "", err
|
||||
}
|
||||
err = git.Merge(l.dir, commit, fmt.Sprintf("Merge %s from %s", commit[:7], project.DefaultBranch), l.gitName, l.gitEmail)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user