gitea源码

merge_squash.go 3.3KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. // Copyright 2023 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package pull
  4. import (
  5. "fmt"
  6. repo_model "code.gitea.io/gitea/models/repo"
  7. user_model "code.gitea.io/gitea/models/user"
  8. "code.gitea.io/gitea/modules/container"
  9. "code.gitea.io/gitea/modules/git"
  10. "code.gitea.io/gitea/modules/git/gitcmd"
  11. "code.gitea.io/gitea/modules/log"
  12. "code.gitea.io/gitea/modules/setting"
  13. )
  14. // doMergeStyleSquash gets a commit author signature for squash commits
  15. func getAuthorSignatureSquash(ctx *mergeContext) (*git.Signature, error) {
  16. if err := ctx.pr.Issue.LoadPoster(ctx); err != nil {
  17. log.Error("%-v Issue[%d].LoadPoster: %v", ctx.pr, ctx.pr.Issue.ID, err)
  18. return nil, err
  19. }
  20. // Try to get an signature from the same user in one of the commits, as the
  21. // poster email might be private or commits might have a different signature
  22. // than the primary email address of the poster.
  23. gitRepo, err := git.OpenRepository(ctx, ctx.tmpBasePath)
  24. if err != nil {
  25. log.Error("%-v Unable to open base repository: %v", ctx.pr, err)
  26. return nil, err
  27. }
  28. defer gitRepo.Close()
  29. commits, err := gitRepo.CommitsBetweenIDs(trackingBranch, "HEAD")
  30. if err != nil {
  31. log.Error("%-v Unable to get commits between: %s %s: %v", ctx.pr, "HEAD", trackingBranch, err)
  32. return nil, err
  33. }
  34. uniqueEmails := make(container.Set[string])
  35. for _, commit := range commits {
  36. if commit.Author != nil && uniqueEmails.Add(commit.Author.Email) {
  37. commitUser, _ := user_model.GetUserByEmail(ctx, commit.Author.Email)
  38. if commitUser != nil && commitUser.ID == ctx.pr.Issue.Poster.ID {
  39. return commit.Author, nil
  40. }
  41. }
  42. }
  43. return ctx.pr.Issue.Poster.NewGitSig(), nil
  44. }
  45. // doMergeStyleSquash squashes the tracking branch on the current HEAD (=base)
  46. func doMergeStyleSquash(ctx *mergeContext, message string) error {
  47. sig, err := getAuthorSignatureSquash(ctx)
  48. if err != nil {
  49. return fmt.Errorf("getAuthorSignatureSquash: %w", err)
  50. }
  51. cmdMerge := gitcmd.NewCommand("merge", "--squash").AddDynamicArguments(trackingBranch)
  52. if err := runMergeCommand(ctx, repo_model.MergeStyleSquash, cmdMerge); err != nil {
  53. log.Error("%-v Unable to merge --squash tracking into base: %v", ctx.pr, err)
  54. return err
  55. }
  56. if setting.Repository.PullRequest.AddCoCommitterTrailers && ctx.committer.String() != sig.String() {
  57. // add trailer
  58. message = AddCommitMessageTailer(message, "Co-authored-by", sig.String())
  59. message = AddCommitMessageTailer(message, "Co-committed-by", sig.String()) // FIXME: this one should be removed, it is not really used or widely used
  60. }
  61. cmdCommit := gitcmd.NewCommand("commit").
  62. AddOptionFormat("--author='%s <%s>'", sig.Name, sig.Email).
  63. AddOptionFormat("--message=%s", message)
  64. if ctx.signKey == nil {
  65. cmdCommit.AddArguments("--no-gpg-sign")
  66. } else {
  67. if ctx.signKey.Format != "" {
  68. cmdCommit.AddConfig("gpg.format", ctx.signKey.Format)
  69. }
  70. cmdCommit.AddOptionFormat("-S%s", ctx.signKey.KeyID)
  71. }
  72. if err := cmdCommit.Run(ctx, ctx.RunOpts()); err != nil {
  73. log.Error("git commit %-v: %v\n%s\n%s", ctx.pr, err, ctx.outbuf.String(), ctx.errbuf.String())
  74. return fmt.Errorf("git commit [%s:%s -> %s:%s]: %w\n%s\n%s", ctx.pr.HeadRepo.FullName(), ctx.pr.HeadBranch, ctx.pr.BaseRepo.FullName(), ctx.pr.BaseBranch, err, ctx.outbuf.String(), ctx.errbuf.String())
  75. }
  76. ctx.outbuf.Reset()
  77. ctx.errbuf.Reset()
  78. return nil
  79. }