Skip to content

Improve squash merge commit author and co-author with private emails #22977

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 10, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 38 additions & 5 deletions services/pull/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,38 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U
return nil
}

// Get commit author signature for squash commits
func getSquashAuthorSignature(ctx context.Context, pr *issues_model.PullRequest, repoBasePath, newCommit, oldCommit string) (*git.Signature, error) {
if err := pr.Issue.LoadPoster(ctx); err != nil {
return nil, fmt.Errorf("LoadPoster: %w", err)
}

// Try to get an signature from the same user in one of the commits, as the
// poster email might be private or commits with a different signature than
// the primary email address in their account.
gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repoBasePath)
if err != nil {
return nil, fmt.Errorf("Unable to open repository: Error %v", err)
}
defer closer.Close()

commits, err := gitRepo.CommitsBetweenIDs(newCommit, oldCommit)
if err != nil {
return nil, fmt.Errorf("Unable to get commits between: %s %s Error %v", oldCommit, newCommit, err)
}

for _, commit := range commits {
if commit.Author != nil {
commitUser, _ := user_model.GetUserByEmail(ctx, commit.Author.Email)
if commitUser != nil && commitUser.ID == pr.Issue.Poster.ID {
return commit.Author, nil
}
}
}

return pr.Issue.Poster.NewGitSig(), nil
}

// rawMerge perform the merge operation without changing any pull information in database
func rawMerge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string) (string, error) {
// Clone base repo.
Expand Down Expand Up @@ -514,18 +546,19 @@ func rawMerge(ctx context.Context, pr *issues_model.PullRequest, doer *user_mode
}
}
case repo_model.MergeStyleSquash:
sig, err := getSquashAuthorSignature(ctx, pr, tmpBasePath, trackingBranch, "HEAD")
if err != nil {
log.Error("getSquashAuthorSignature: %v", err)
return "", err
}

// Merge with squash
cmd := git.NewCommand(ctx, "merge", "--squash").AddDynamicArguments(trackingBranch)
if err := runMergeCommand(pr, mergeStyle, cmd, tmpBasePath); err != nil {
log.Error("Unable to merge --squash tracking into base: %v", err)
return "", err
}

if err = pr.Issue.LoadPoster(ctx); err != nil {
log.Error("LoadPoster: %v", err)
return "", fmt.Errorf("LoadPoster: %w", err)
}
sig := pr.Issue.Poster.NewGitSig()
if setting.Repository.PullRequest.AddCoCommitterTrailers && committer.String() != sig.String() {
// add trailer
message += fmt.Sprintf("\nCo-authored-by: %s\nCo-committed-by: %s\n", sig.String(), sig.String())
Expand Down
12 changes: 10 additions & 2 deletions services/pull/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,12 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ

authorString := commit.Author.String()
if uniqueAuthors.Add(authorString) && authorString != posterSig {
authors = append(authors, authorString)
// Compare use account as well to avoid adding the same author multiple times
// times when email addresses are private or multiple emails are used.
commitUser, _ := user_model.GetUserByEmail(ctx, commit.Author.Email)
if commitUser == nil || commitUser.ID != pr.Issue.Poster.ID {
authors = append(authors, authorString)
}
}
}

Expand All @@ -694,7 +699,10 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ
for _, commit := range commits {
authorString := commit.Author.String()
if uniqueAuthors.Add(authorString) && authorString != posterSig {
authors = append(authors, authorString)
commitUser, _ := user_model.GetUserByEmail(ctx, commit.Author.Email)
if commitUser == nil || commitUser.ID != pr.Issue.Poster.ID {
authors = append(authors, authorString)
}
}
}
skip += limit
Expand Down