diff options
Diffstat (limited to 'services/agit/agit.go')
-rw-r--r-- | services/agit/agit.go | 64 |
1 files changed, 53 insertions, 11 deletions
diff --git a/services/agit/agit.go b/services/agit/agit.go index 83b12dfcdb..63b3eab4f2 100644 --- a/services/agit/agit.go +++ b/services/agit/agit.go @@ -5,28 +5,44 @@ package agit import ( "context" + "encoding/base64" "fmt" "os" "strings" + git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" notify_service "code.gitea.io/gitea/services/notify" pull_service "code.gitea.io/gitea/services/pull" ) +func parseAgitPushOptionValue(s string) string { + if base64Value, ok := strings.CutPrefix(s, "{base64}"); ok { + decoded, err := base64.StdEncoding.DecodeString(base64Value) + return util.Iif(err == nil, string(decoded), s) + } + return s +} + // ProcReceive handle proc receive work func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, opts *private.HookOptions) ([]private.HookProcReceiveRefResult, error) { results := make([]private.HookProcReceiveRefResult, 0, len(opts.OldCommitIDs)) forcePush := opts.GitPushOptions.Bool(private.GitPushOptionForcePush) topicBranch := opts.GitPushOptions["topic"] - title := strings.TrimSpace(opts.GitPushOptions["title"]) - description := strings.TrimSpace(opts.GitPushOptions["description"]) + + // some options are base64-encoded with "{base64}" prefix if they contain new lines + // other agit push options like "issue", "reviewer" and "cc" are not supported + title := parseAgitPushOptionValue(opts.GitPushOptions["title"]) + description := parseAgitPushOptionValue(opts.GitPushOptions["description"]) + objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName) userName := strings.ToLower(opts.UserName) @@ -56,10 +72,10 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. baseBranchName := opts.RefFullNames[i].ForBranchName() currentTopicBranch := "" - if !gitRepo.IsBranchExist(baseBranchName) { + if !gitrepo.IsBranchExist(ctx, repo, baseBranchName) { // try match refs/for/<target-branch>/<topic-branch> for p, v := range baseBranchName { - if v == '/' && gitRepo.IsBranchExist(baseBranchName[:p]) && p != len(baseBranchName)-1 { + if v == '/' && gitrepo.IsBranchExist(ctx, repo, baseBranchName[:p]) && p != len(baseBranchName)-1 { currentTopicBranch = baseBranchName[p+1:] baseBranchName = baseBranchName[:p] break @@ -149,11 +165,11 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. log.Trace("Pull request created: %d/%d", repo.ID, prIssue.ID) results = append(results, private.HookProcReceiveRefResult{ - Ref: pr.GetGitRefName(), + Ref: pr.GetGitHeadRefName(), OriginalRef: opts.RefFullNames[i], OldOID: objectFormat.EmptyObjectID().String(), NewOID: opts.NewCommitIDs[i], - IsCreatePR: true, + IsCreatePR: false, // AGit always creates a pull request so there is no point in prompting user to create one URL: fmt.Sprintf("%s/pulls/%d", repo.HTMLURL(), pr.Index), ShouldShowMessage: setting.Git.PullRequestPushMessage && repo.AllowsPulls(ctx), HeadBranch: headBranch, @@ -166,7 +182,7 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. return nil, fmt.Errorf("unable to load base repository for PR[%d] Error: %w", pr.ID, err) } - oldCommitID, err := gitRepo.GetRefCommitID(pr.GetGitRefName()) + oldCommitID, err := gitRepo.GetRefCommitID(pr.GetGitHeadRefName()) if err != nil { return nil, fmt.Errorf("unable to get ref commit id in base repository for PR[%d] Error: %w", pr.ID, err) } @@ -182,9 +198,9 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. } if !forcePush.Value() { - output, _, err := git.NewCommand(ctx, "rev-list", "--max-count=1"). + output, _, err := git.NewCommand("rev-list", "--max-count=1"). AddDynamicArguments(oldCommitID, "^"+opts.NewCommitIDs[i]). - RunStdString(&git.RunOpts{Dir: repo.RepoPath(), Env: os.Environ()}) + RunStdString(ctx, &git.RunOpts{Dir: repo.RepoPath(), Env: os.Environ()}) if err != nil { return nil, fmt.Errorf("failed to detect force push: %w", err) } else if len(output) > 0 { @@ -198,12 +214,38 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. } } + // Store old commit ID for review staleness checking + oldHeadCommitID := pr.HeadCommitID + pr.HeadCommitID = opts.NewCommitIDs[i] if err = pull_service.UpdateRef(ctx, pr); err != nil { return nil, fmt.Errorf("failed to update pull ref. Error: %w", err) } - pull_service.AddToTaskQueue(ctx, pr) + // Mark existing reviews as stale when PR content changes (same as regular GitHub flow) + if oldHeadCommitID != opts.NewCommitIDs[i] { + if err := issues_model.MarkReviewsAsStale(ctx, pr.IssueID); err != nil { + log.Error("MarkReviewsAsStale: %v", err) + } + + // Dismiss all approval reviews if protected branch rule item enabled + pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch) + if err != nil { + log.Error("GetFirstMatchProtectedBranchRule: %v", err) + } + if pb != nil && pb.DismissStaleApprovals { + if err := pull_service.DismissApprovalReviews(ctx, pusher, pr); err != nil { + log.Error("DismissApprovalReviews: %v", err) + } + } + + // Mark reviews for the new commit as not stale + if err := issues_model.MarkReviewsAsNotStale(ctx, pr.IssueID, opts.NewCommitIDs[i]); err != nil { + log.Error("MarkReviewsAsNotStale: %v", err) + } + } + + pull_service.StartPullRequestCheckImmediately(ctx, pr) err = pr.LoadIssue(ctx) if err != nil { return nil, fmt.Errorf("failed to load pull issue. Error: %w", err) @@ -218,7 +260,7 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. results = append(results, private.HookProcReceiveRefResult{ OldOID: oldCommitID, NewOID: opts.NewCommitIDs[i], - Ref: pr.GetGitRefName(), + Ref: pr.GetGitHeadRefName(), OriginalRef: opts.RefFullNames[i], IsForcePush: isForcePush, IsCreatePR: false, |