Skip to content

Commit 71467f9

Browse files
committed
Fix #6946 by checking PullRequest ID on pushing
1 parent 7dd9837 commit 71467f9

File tree

8 files changed

+83
-9
lines changed

8 files changed

+83
-9
lines changed

cmd/hook.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ func runHookPreReceive(c *cli.Context) error {
6868
reponame := os.Getenv(models.EnvRepoName)
6969
userIDStr := os.Getenv(models.EnvPusherID)
7070
repoPath := models.RepoPath(username, reponame)
71+
prID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchPRID), 10, 64)
7172

7273
buf := bytes.NewBuffer(nil)
7374
scanner := bufio.NewScanner(os.Stdin)
@@ -115,6 +116,9 @@ func runHookPreReceive(c *cli.Context) error {
115116

116117
userID, _ := strconv.ParseInt(userIDStr, 10, 64)
117118
canPush, err := private.CanUserPush(protectBranch.ID, userID)
119+
if err == nil && !canPush {
120+
canPush, err = private.HasEnoughApprovals(protectBranch.ID, prID)
121+
}
118122
if err != nil {
119123
fail("Internal error", "Fail to detect user can push: %v", err)
120124
} else if !canPush {

cmd/serv.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ func runServ(c *cli.Context) error {
336336
}
337337

338338
os.Setenv(models.ProtectedBranchRepoID, fmt.Sprintf("%d", repo.ID))
339+
os.Setenv(models.ProtectedBranchPRID, fmt.Sprintf("%d", 0))
339340

340341
gitcmd.Dir = setting.RepoRootPath
341342
gitcmd.Stdout = os.Stdout

models/branches.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import (
1919
const (
2020
// ProtectedBranchRepoID protected Repo ID
2121
ProtectedBranchRepoID = "GITEA_REPO_ID"
22+
// ProtectedBranchPRID protected Repo PR ID
23+
ProtectedBranchPRID = "GITEA_PR_ID"
2224
)
2325

2426
// ProtectedBranch struct

models/helper_environment.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,31 @@ import (
1212

1313
// PushingEnvironment returns an os environment to allow hooks to work on push
1414
func PushingEnvironment(doer *User, repo *Repository) []string {
15+
return FullPushingEnvironment(doer, doer, repo, 0)
16+
}
17+
18+
// FullPushingEnvironment returns an os environment to allow hooks to work on push
19+
func FullPushingEnvironment(author, committer *User, repo *Repository, prID int64) []string {
1520
isUncyclo := "false"
1621
if strings.HasSuffix(repo.Name, ".wiki") {
1722
isUncyclo = "true"
1823
}
1924

20-
sig := doer.NewGitSig()
25+
authorSig := author.NewGitSig()
26+
committerSig := committer.NewGitSig()
2127

2228
return append(os.Environ(),
23-
"GIT_AUTHOR_NAME="+sig.Name,
24-
"GIT_AUTHOR_EMAIL="+sig.Email,
25-
"GIT_COMMITTER_NAME="+sig.Name,
26-
"GIT_COMMITTER_EMAIL="+sig.Email,
29+
"GIT_AUTHOR_NAME="+authorSig.Name,
30+
"GIT_AUTHOR_EMAIL="+authorSig.Email,
31+
"GIT_COMMITTER_NAME="+committerSig.Name,
32+
"GIT_COMMITTER_EMAIL="+committerSig.Email,
2733
EnvRepoName+"="+repo.Name,
2834
EnvRepoUsername+"="+repo.OwnerName,
2935
EnvRepoIsUncyclo+"="+isUncyclo,
30-
EnvPusherName+"="+doer.Name,
31-
EnvPusherID+"="+fmt.Sprintf("%d", doer.ID),
36+
EnvPusherName+"="+committer.Name,
37+
EnvPusherID+"="+fmt.Sprintf("%d", committer.ID),
3238
ProtectedBranchRepoID+"="+fmt.Sprintf("%d", repo.ID),
39+
ProtectedBranchPRID+"="+fmt.Sprintf("%d", prID),
3340
"SSH_ORIGINAL_COMMAND=gitea-internal",
3441
)
3542

models/pull.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
555555
return ErrInvalidMergeStyle{pr.BaseRepo.ID, mergeStyle}
556556
}
557557

558-
env := PushingEnvironment(doer, pr.BaseRepo)
558+
env := FullPushingEnvironment(doer, doer, pr.BaseRepo, pr.ID)
559559

560560
// Push back to upstream.
561561
if err := git.NewCommand("push", baseGitRepo.Path, pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil {
@@ -1123,7 +1123,7 @@ func (pr *PullRequest) UpdatePatch() (err error) {
11231123
if err = pr.GetHeadRepo(); err != nil {
11241124
return fmt.Errorf("GetHeadRepo: %v", err)
11251125
} else if pr.HeadRepo == nil {
1126-
log.Trace("PullRequest[%d].UpdatePatch: ignored cruppted data", pr.ID)
1126+
log.Trace("PullRequest[%d].UpdatePatch: ignored corrupted data", pr.ID)
11271127
return nil
11281128
}
11291129

modules/private/branch.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,33 @@ func CanUserPush(protectedBranchID, userID int64) (bool, error) {
6565

6666
return canPush["can_push"].(bool), nil
6767
}
68+
69+
// HasEnoughApprovals returns if true if pr has enough granted approvals.
70+
func HasEnoughApprovals(protectedBranchID, prID int64) (bool, error) {
71+
if prID <= 0 {
72+
return false, nil
73+
}
74+
75+
// Ask for running deliver hook and test pull request tasks.
76+
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/protectedbranchpr/%d/%d", protectedBranchID, prID)
77+
log.GitLogger.Trace("CanUserPush: %s", reqURL)
78+
79+
resp, err := newInternalRequest(reqURL, "GET").Response()
80+
if err != nil {
81+
return false, err
82+
}
83+
84+
var canPush = make(map[string]interface{})
85+
if err := json.NewDecoder(resp.Body).Decode(&canPush); err != nil {
86+
return false, err
87+
}
88+
89+
defer resp.Body.Close()
90+
91+
// All 2XX status codes are accepted and others will return an error
92+
if resp.StatusCode/100 != 2 {
93+
return false, fmt.Errorf("Failed to retrieve push user: %s", decodeJSONError(resp).Err)
94+
}
95+
96+
return canPush["can_push"].(bool), nil
97+
}

routers/private/branch.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,32 @@ func CanUserPush(ctx *macaron.Context) {
5050
})
5151
}
5252
}
53+
54+
// HasEnoughApprovals return if PR has enough approvals
55+
func HasEnoughApprovals(ctx *macaron.Context) {
56+
pbID := ctx.ParamsInt64(":pbid")
57+
prID := ctx.ParamsInt64(":prid")
58+
59+
protectBranch, err := models.GetProtectedBranchByID(pbID)
60+
if err != nil {
61+
ctx.JSON(500, map[string]interface{}{
62+
"err": err.Error(),
63+
})
64+
return
65+
} else if prID > 0 && protectBranch != nil {
66+
pr, err := models.GetPullRequestByID(prID)
67+
if err != nil {
68+
ctx.JSON(500, map[string]interface{}{
69+
"err": err.Error(),
70+
})
71+
return
72+
}
73+
ctx.JSON(200, map[string]interface{}{
74+
"can_push": protectBranch.HasEnoughApprovals(pr),
75+
})
76+
} else {
77+
ctx.JSON(200, map[string]interface{}{
78+
"can_push": false,
79+
})
80+
}
81+
}

routers/private/internal.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ func RegisterRoutes(m *macaron.Macaron) {
8686
m.Get("/repositories/:repoid/wiki/init", InitUncyclo)
8787
m.Post("/push/update", PushUpdate)
8888
m.Get("/protectedbranch/:pbid/:userid", CanUserPush)
89+
m.Get("/protectedbranchpr/:pbid/:prid", HasEnoughApprovals)
8990
m.Get("/repo/:owner/:repo", GetRepositoryByOwnerAndName)
9091
m.Get("/branch/:id/*", GetProtectedBranchBy)
9192
m.Get("/repository/:rid", GetRepository)

0 commit comments

Comments
 (0)