aboutsummaryrefslogtreecommitdiffstats
path: root/routers/private
diff options
context:
space:
mode:
Diffstat (limited to 'routers/private')
-rw-r--r--routers/private/hook_post_receive.go64
-rw-r--r--routers/private/hook_post_receive_test.go49
2 files changed, 112 insertions, 1 deletions
diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go
index adc435b42c..0c2c1836ed 100644
--- a/routers/private/hook_post_receive.go
+++ b/routers/private/hook_post_receive.go
@@ -4,20 +4,25 @@
package private
import (
+ "context"
"fmt"
"net/http"
+ "code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
issues_model "code.gitea.io/gitea/models/issues"
access_model "code.gitea.io/gitea/models/perm/access"
+ pull_model "code.gitea.io/gitea/models/pull"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/private"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
+ timeutil "code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
gitea_context "code.gitea.io/gitea/services/context"
@@ -158,6 +163,14 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
}
}
+ // handle pull request merging, a pull request action should push at least 1 commit
+ if opts.PushTrigger == repo_module.PushTriggerPRMergeToBase {
+ handlePullRequestMerging(ctx, opts, ownerName, repoName, updates)
+ if ctx.Written() {
+ return
+ }
+ }
+
isPrivate := opts.GitPushOptions.Bool(private.GitPushOptionRepoPrivate)
isTemplate := opts.GitPushOptions.Bool(private.GitPushOptionRepoTemplate)
// Handle Push Options
@@ -172,7 +185,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
wasEmpty = repo.IsEmpty
}
- pusher, err := user_model.GetUserByID(ctx, opts.UserID)
+ pusher, err := loadContextCacheUser(ctx, opts.UserID)
if err != nil {
log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err)
ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
@@ -307,3 +320,52 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
RepoWasEmpty: wasEmpty,
})
}
+
+func loadContextCacheUser(ctx context.Context, id int64) (*user_model.User, error) {
+ return cache.GetWithContextCache(ctx, "hook_post_receive_user", id, func() (*user_model.User, error) {
+ return user_model.GetUserByID(ctx, id)
+ })
+}
+
+// handlePullRequestMerging handle pull request merging, a pull request action should push at least 1 commit
+func handlePullRequestMerging(ctx *gitea_context.PrivateContext, opts *private.HookOptions, ownerName, repoName string, updates []*repo_module.PushUpdateOptions) {
+ if len(updates) == 0 {
+ ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
+ Err: fmt.Sprintf("Pushing a merged PR (pr:%d) no commits pushed ", opts.PullRequestID),
+ })
+ return
+ }
+
+ pr, err := issues_model.GetPullRequestByID(ctx, opts.PullRequestID)
+ if err != nil {
+ log.Error("GetPullRequestByID[%d]: %v", opts.PullRequestID, err)
+ ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{Err: "GetPullRequestByID failed"})
+ return
+ }
+
+ pusher, err := loadContextCacheUser(ctx, opts.UserID)
+ if err != nil {
+ log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err)
+ ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{Err: "Load pusher user failed"})
+ return
+ }
+
+ pr.MergedCommitID = updates[len(updates)-1].NewCommitID
+ pr.MergedUnix = timeutil.TimeStampNow()
+ pr.Merger = pusher
+ pr.MergerID = pusher.ID
+ err = db.WithTx(ctx, func(ctx context.Context) error {
+ // Removing an auto merge pull and ignore if not exist
+ if err := pull_model.DeleteScheduledAutoMerge(ctx, pr.ID); err != nil && !db.IsErrNotExist(err) {
+ return fmt.Errorf("DeleteScheduledAutoMerge[%d]: %v", opts.PullRequestID, err)
+ }
+ if _, err := pr.SetMerged(ctx); err != nil {
+ return fmt.Errorf("SetMerged failed: %s/%s Error: %v", ownerName, repoName, err)
+ }
+ return nil
+ })
+ if err != nil {
+ log.Error("Failed to update PR to merged: %v", err)
+ ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{Err: "Failed to update PR to merged"})
+ }
+}
diff --git a/routers/private/hook_post_receive_test.go b/routers/private/hook_post_receive_test.go
new file mode 100644
index 0000000000..658557d3cf
--- /dev/null
+++ b/routers/private/hook_post_receive_test.go
@@ -0,0 +1,49 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package private
+
+import (
+ "testing"
+
+ "code.gitea.io/gitea/models/db"
+ issues_model "code.gitea.io/gitea/models/issues"
+ pull_model "code.gitea.io/gitea/models/pull"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/private"
+ repo_module "code.gitea.io/gitea/modules/repository"
+ "code.gitea.io/gitea/services/contexttest"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestHandlePullRequestMerging(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+ pr, err := issues_model.GetUnmergedPullRequest(db.DefaultContext, 1, 1, "branch2", "master", issues_model.PullRequestFlowGithub)
+ assert.NoError(t, err)
+ assert.NoError(t, pr.LoadBaseRepo(db.DefaultContext))
+
+ user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
+
+ err = pull_model.ScheduleAutoMerge(db.DefaultContext, user1, pr.ID, repo_model.MergeStyleSquash, "squash merge a pr")
+ assert.NoError(t, err)
+
+ autoMerge := unittest.AssertExistsAndLoadBean(t, &pull_model.AutoMerge{PullID: pr.ID})
+
+ ctx, resp := contexttest.MockPrivateContext(t, "/")
+ handlePullRequestMerging(ctx, &private.HookOptions{
+ PullRequestID: pr.ID,
+ UserID: 2,
+ }, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, []*repo_module.PushUpdateOptions{
+ {NewCommitID: "01234567"},
+ })
+ assert.Equal(t, 0, len(resp.Body.String()))
+ pr, err = issues_model.GetPullRequestByID(db.DefaultContext, pr.ID)
+ assert.NoError(t, err)
+ assert.True(t, pr.HasMerged)
+ assert.EqualValues(t, "01234567", pr.MergedCommitID)
+
+ unittest.AssertNotExistsBean(t, &pull_model.AutoMerge{ID: autoMerge.ID})
+}