aboutsummaryrefslogtreecommitdiffstats
path: root/services/agit/agit.go
diff options
context:
space:
mode:
Diffstat (limited to 'services/agit/agit.go')
-rw-r--r--services/agit/agit.go64
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,