From ff2ed9b257bdd195182068199bca4209f3bf7340 Mon Sep 17 00:00:00 2001 From: hiifong Date: Sat, 28 Dec 2024 15:14:35 +0800 Subject: [PATCH 1/2] Fix duplicate co-author in squashed merge commit messages --- services/pull/merge_squash.go | 53 ++++++----------------------------- 1 file changed, 8 insertions(+), 45 deletions(-) diff --git a/services/pull/merge_squash.go b/services/pull/merge_squash.go index 8f8a5d82e7d66..8a52ac2610fbb 100644 --- a/services/pull/merge_squash.go +++ b/services/pull/merge_squash.go @@ -5,57 +5,17 @@ package pull import ( "fmt" + "strings" repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" ) -// doMergeStyleSquash gets a commit author signature for squash commits -func getAuthorSignatureSquash(ctx *mergeContext) (*git.Signature, error) { - if err := ctx.pr.Issue.LoadPoster(ctx); err != nil { - log.Error("%-v Issue[%d].LoadPoster: %v", ctx.pr, ctx.pr.Issue.ID, err) - return nil, err - } - - // Try to get an signature from the same user in one of the commits, as the - // poster email might be private or commits might have a different signature - // than the primary email address of the poster. - gitRepo, err := git.OpenRepository(ctx, ctx.tmpBasePath) - if err != nil { - log.Error("%-v Unable to open base repository: %v", ctx.pr, err) - return nil, err - } - defer gitRepo.Close() - - commits, err := gitRepo.CommitsBetweenIDs(trackingBranch, "HEAD") - if err != nil { - log.Error("%-v Unable to get commits between: %s %s: %v", ctx.pr, "HEAD", trackingBranch, err) - return nil, err - } - - uniqueEmails := make(container.Set[string]) - for _, commit := range commits { - if commit.Author != nil && uniqueEmails.Add(commit.Author.Email) { - commitUser, _ := user_model.GetUserByEmail(ctx, commit.Author.Email) - if commitUser != nil && commitUser.ID == ctx.pr.Issue.Poster.ID { - return commit.Author, nil - } - } - } - - return ctx.pr.Issue.Poster.NewGitSig(), nil -} - // doMergeStyleSquash squashes the tracking branch on the current HEAD (=base) func doMergeStyleSquash(ctx *mergeContext, message string) error { - sig, err := getAuthorSignatureSquash(ctx) - if err != nil { - return fmt.Errorf("getAuthorSignatureSquash: %w", err) - } + poster := ctx.pr.Issue.Poster.NewGitSig() cmdMerge := git.NewCommand(ctx, "merge", "--squash").AddDynamicArguments(trackingBranch) if err := runMergeCommand(ctx, repo_model.MergeStyleSquash, cmdMerge); err != nil { @@ -63,12 +23,15 @@ func doMergeStyleSquash(ctx *mergeContext, message string) error { return err } - if setting.Repository.PullRequest.AddCoCommitterTrailers && ctx.committer.String() != sig.String() { + if setting.Repository.PullRequest.AddCoCommitterTrailers && ctx.committer.String() != poster.String() { // add trailer - message += fmt.Sprintf("\nCo-authored-by: %s\nCo-committed-by: %s\n", sig.String(), sig.String()) + if !strings.Contains(message, fmt.Sprintf("Co-authored-by: %s", ctx.committer.String())) { + message += fmt.Sprintf("\nCo-authored-by: %s", ctx.committer.String()) + } + message += fmt.Sprintf("\nCo-committed-by: %s\n", ctx.committer.String()) } cmdCommit := git.NewCommand(ctx, "commit"). - AddOptionFormat("--author='%s <%s>'", sig.Name, sig.Email). + AddOptionFormat("--author='%s <%s>'", poster.Name, poster.Email). AddOptionFormat("--message=%s", message) if ctx.signKeyID == "" { cmdCommit.AddArguments("--no-gpg-sign") From ac4e2dbce12b0bb9684efce9b60a48ee6acfc85f Mon Sep 17 00:00:00 2001 From: hiifong Date: Sat, 28 Dec 2024 22:13:19 +0800 Subject: [PATCH 2/2] Update --- services/pull/merge_squash.go | 53 +++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/services/pull/merge_squash.go b/services/pull/merge_squash.go index 8a52ac2610fbb..7258671888c6d 100644 --- a/services/pull/merge_squash.go +++ b/services/pull/merge_squash.go @@ -8,14 +8,55 @@ import ( "strings" repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" ) +// doMergeStyleSquash gets a commit author signature for squash commits +func getAuthorSignatureSquash(ctx *mergeContext) (*git.Signature, error) { + if err := ctx.pr.Issue.LoadPoster(ctx); err != nil { + log.Error("%-v Issue[%d].LoadPoster: %v", ctx.pr, ctx.pr.Issue.ID, err) + return nil, err + } + + // Try to get an signature from the same user in one of the commits, as the + // poster email might be private or commits might have a different signature + // than the primary email address of the poster. + gitRepo, err := git.OpenRepository(ctx, ctx.tmpBasePath) + if err != nil { + log.Error("%-v Unable to open base repository: %v", ctx.pr, err) + return nil, err + } + defer gitRepo.Close() + + commits, err := gitRepo.CommitsBetweenIDs(trackingBranch, "HEAD") + if err != nil { + log.Error("%-v Unable to get commits between: %s %s: %v", ctx.pr, "HEAD", trackingBranch, err) + return nil, err + } + + uniqueEmails := make(container.Set[string]) + for _, commit := range commits { + if commit.Author != nil && uniqueEmails.Add(commit.Author.Email) { + commitUser, _ := user_model.GetUserByEmail(ctx, commit.Author.Email) + if commitUser != nil && commitUser.ID == ctx.pr.Issue.Poster.ID { + return commit.Author, nil + } + } + } + + return ctx.pr.Issue.Poster.NewGitSig(), nil +} + // doMergeStyleSquash squashes the tracking branch on the current HEAD (=base) func doMergeStyleSquash(ctx *mergeContext, message string) error { - poster := ctx.pr.Issue.Poster.NewGitSig() + sig, err := getAuthorSignatureSquash(ctx) + if err != nil { + return fmt.Errorf("getAuthorSignatureSquash: %w", err) + } cmdMerge := git.NewCommand(ctx, "merge", "--squash").AddDynamicArguments(trackingBranch) if err := runMergeCommand(ctx, repo_model.MergeStyleSquash, cmdMerge); err != nil { @@ -23,15 +64,15 @@ func doMergeStyleSquash(ctx *mergeContext, message string) error { return err } - if setting.Repository.PullRequest.AddCoCommitterTrailers && ctx.committer.String() != poster.String() { + if setting.Repository.PullRequest.AddCoCommitterTrailers && ctx.committer.String() != sig.String() { // add trailer - if !strings.Contains(message, fmt.Sprintf("Co-authored-by: %s", ctx.committer.String())) { - message += fmt.Sprintf("\nCo-authored-by: %s", ctx.committer.String()) + if !strings.Contains(message, fmt.Sprintf("Co-authored-by: %s", sig.String())) { + message += fmt.Sprintf("\nCo-authored-by: %s", sig.String()) } - message += fmt.Sprintf("\nCo-committed-by: %s\n", ctx.committer.String()) + message += fmt.Sprintf("\nCo-committed-by: %s\n", sig.String()) } cmdCommit := git.NewCommand(ctx, "commit"). - AddOptionFormat("--author='%s <%s>'", poster.Name, poster.Email). + AddOptionFormat("--author='%s <%s>'", sig.Name, sig.Email). AddOptionFormat("--message=%s", message) if ctx.signKeyID == "" { cmdCommit.AddArguments("--no-gpg-sign")