Skip to content

allow mark PR as manually merged by push option #21951

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
3f428b6
allow mark PR as manually merged by push option
a1012112796 Nov 27, 2022
c661bdf
Update models/migrations/migrations.go
a1012112796 Nov 27, 2022
834e62e
Merge branch 'main' into zzc/dev/merge-pull-manually-quick
a1012112796 Nov 27, 2022
eee691f
Apply suggestions from code review
a1012112796 Nov 27, 2022
6cf8203
fix build
a1012112796 Nov 28, 2022
b0898fc
Merge branch 'main' into zzc/dev/merge-pull-manually-quick
a1012112796 Nov 29, 2022
61f0924
Merge branch 'main' into zzc/dev/merge-pull-manually-quick
a1012112796 Dec 2, 2022
f83fca2
fix lint
a1012112796 Dec 2, 2022
286d031
Merge branch 'main' into zzc/dev/merge-pull-manually-quick
a1012112796 Dec 5, 2022
b485854
Merge branch 'main' into zzc/dev/merge-pull-manually-quick
a1012112796 Dec 13, 2022
335a2e6
Merge branch 'main' into zzc/dev/merge-pull-manually-quick
a1012112796 Dec 16, 2022
0b3ef59
limit base_branch
a1012112796 Dec 16, 2022
4b7f007
Merge branch 'main' into zzc/dev/merge-pull-manually-quick
a1012112796 Dec 20, 2022
b8ffb32
add ManuallyMergeConfirmedVersion to sync ManuallyMergeConfirmed
a1012112796 Dec 20, 2022
1997f8c
fix lint
a1012112796 Dec 20, 2022
7e0aa22
Merge branch 'main' into zzc/dev/merge-pull-manually-quick
a1012112796 Feb 4, 2023
ffd62b6
Merge branch 'main' into zzc/dev/merge-pull-manually-quick
a1012112796 Feb 4, 2023
e4c3fb9
rename push option
a1012112796 Feb 5, 2023
3b682a8
update document
a1012112796 Feb 5, 2023
7bc20a7
Update docs/content/doc/usage/push-options.en-us.md
a1012112796 Feb 5, 2023
61f2dd4
Merge branch 'main' into zzc/dev/merge-pull-manually-quick
a1012112796 Feb 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/content/doc/usage/push-options.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,15 @@ Example of changing a repository's visibility to public:
```shell
git push -o repo.private=false -u origin master
```

- `pulls.merged` (pull index0 [, pull index1]*) - manually merge comfirmed pulls

notify service that these pull requst has been manually merged by this push
event. then service will mark these pulls as manually merged if manually merge check pass.
if push manually merged pulls without this push option, they maybe will become to empty pulls.

Example:

```shell
git push -o pulls.merged=1,2,3 -u origin master
```
29 changes: 29 additions & 0 deletions models/issues/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ type PullRequest struct {
isHeadRepoLoaded bool `xorm:"-"`

Flow PullRequestFlow `xorm:"NOT NULL DEFAULT 0"`

ManuallyMergeConfirmed bool `xorm:"NOT NULL DEFAULT false"`
ManuallyMergeConfirmedVersion int64 `xorm:"NOT NULL DEFAULT 0"`
}

func init() {
Expand Down Expand Up @@ -872,3 +875,29 @@ func MergeBlockedByOfficialReviewRequests(ctx context.Context, protectBranch *gi
func MergeBlockedByOutdatedBranch(protectBranch *git_model.ProtectedBranch, pr *PullRequest) bool {
return protectBranch.BlockOnOutdatedBranch && pr.CommitsBehind > 0
}

// ManuallyMergePullConfirm confirm manually merge pulls by repo id and indexes
func ManuallyMergePullConfirmByIndexes(ctx context.Context, repoID int64, baseBranchs []string, indexes []int64) error {
_, err := db.GetEngine(ctx).Where(builder.And(
builder.Eq{"base_repo_id": repoID},
builder.Eq{"has_merged": false},
builder.In("`index`", indexes),
builder.In("`base_branch`", baseBranchs),
)).
Incr("manually_merge_confirmed_version").
SetExpr("manually_merge_confirmed", true).Update(new(PullRequest))

return err
}

// ResetManuallyMergePullConfirm reset manually merge confirmed flag
func (pr *PullRequest) ResetManuallyMergePullConfirm(ctx context.Context) error {
_, err := db.GetEngine(ctx).
Where(builder.And(
builder.Eq{"`id`": pr.ID},
builder.Eq{"manually_merge_confirmed_version": pr.ManuallyMergeConfirmedVersion},
)).
Incr("manually_merge_confirmed_version").
SetExpr("manually_merge_confirmed", false).Update(new(PullRequest))
return err
}
2 changes: 2 additions & 0 deletions models/migrations/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,8 @@ var migrations = []Migration{
NewMigration("Add scope for access_token", v1_19.AddScopeForAccessTokens),
// v240 -> v241
NewMigration("Add actions tables", v1_19.AddActionsTables),
// v241 -> v242
NewMigration("Add manually_merge_pull_confirmed to pull_request table", v1_19.AddManuallyMergePullConfirmedToPullRequest),
}

// GetCurrentDBVersion returns the current db version
Expand Down
19 changes: 19 additions & 0 deletions models/migrations/v1_19/v241.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package v1_19 //nolint

import (
"xorm.io/xorm"
)

func AddManuallyMergePullConfirmedToPullRequest(x *xorm.Engine) error {
type PullRequest struct {
ID int64 `xorm:"pk autoincr"`

ManuallyMergeConfirmed bool `xorm:"NOT NULL DEFAULT false"`
ManuallyMergeConfirmedVersion int64 `xorm:"NOT NULL DEFAULT 0"`
}

return x.Sync(new(PullRequest))
}
22 changes: 22 additions & 0 deletions modules/private/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"net/http"
"net/url"
"strconv"
"strings"
"time"

"code.gitea.io/gitea/modules/json"
Expand All @@ -31,6 +32,7 @@ type GitPushOptions map[string]string
const (
GitPushOptionRepoPrivate = "repo.private"
GitPushOptionRepoTemplate = "repo.template"
GitPushOptionMergePulls = "pulls.merged"
)

// Bool checks for a key in the map and parses as a boolean
Expand All @@ -43,6 +45,26 @@ func (g GitPushOptions) Bool(key string, def bool) bool {
return def
}

// Int64Array checks for a key in the map and parses as a int64 array
func (g GitPushOptions) Int64Array(key string) []int64 {
if val, ok := g[key]; ok {
parts := strings.SplitN(val, ",", 10)
result := make([]int64, 0, len(parts))
for _, part := range parts {
v, err := strconv.ParseInt(part, 10, 64)
if err != nil {
break
}

result = append(result, v)
}

return result
}

return []int64{}
}

// HookOptions represents the options for the Hook calls
type HookOptions struct {
OldCommitIDs []string
Expand Down
23 changes: 23 additions & 0 deletions routers/private/hook_post_receive.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,29 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
Err: fmt.Sprintf("Failed to Update: %s/%s Error: %v", ownerName, repoName, err),
})
return
}

// handle manually merge pulls confirm
mergePullIndexes := opts.GitPushOptions.Int64Array(private.GitPushOptionMergePulls)
if len(mergePullIndexes) > 0 {
baseBranchs := make([]string, 0, len(opts.OldCommitIDs))
for i := range opts.OldCommitIDs {
refFullName := opts.RefFullNames[i]
newCommitID := opts.NewCommitIDs[i]

if newCommitID != git.EmptySHA && strings.HasPrefix(refFullName, git.BranchPrefix) {
baseBranchs = append(baseBranchs, strings.TrimPrefix(refFullName, git.BranchPrefix))
}
}

if err := issues_model.ManuallyMergePullConfirmByIndexes(ctx, repo.ID, baseBranchs, mergePullIndexes); err != nil {
log.Error("Failed to manually merge pull confirm: %s/%s Error: %v", ownerName, repoName, err)
ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
Err: fmt.Sprintf("Failed to manually merge pull confirm: %s/%s Error: %v", ownerName, repoName, err),
})
return
}
}
}

Expand Down
25 changes: 19 additions & 6 deletions services/pull/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,15 @@ func getMergeCommit(ctx context.Context, pr *issues_model.PullRequest) (*git.Com
return commit, nil
}

func resetManuallyMergePullConfirm(ctx context.Context, pr *issues_model.PullRequest) {
if pr.ManuallyMergeConfirmed {
pr.ManuallyMergeConfirmed = false
if err := pr.ResetManuallyMergePullConfirm(ctx); err != nil {
log.Error("PullRequest[%d]: reset manually_merge_pull_confirmed failed: %v", pr.ID, err)
}
}
}

// manuallyMerged checks if a pull request got manually merged
// When a pull request got manually merged mark the pull request as merged
func manuallyMerged(ctx context.Context, pr *issues_model.PullRequest) bool {
Expand All @@ -232,14 +241,16 @@ func manuallyMerged(ctx context.Context, pr *issues_model.PullRequest) bool {
return false
}

if unit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests); err == nil {
config := unit.PullRequestsConfig()
if !config.AutodetectManualMerge {
if !pr.ManuallyMergeConfirmed {
if unit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests); err == nil {
config := unit.PullRequestsConfig()
if !config.AutodetectManualMerge {
return false
}
} else {
log.Error("%-v BaseRepo.GetUnit(unit.TypePullRequests): %v", pr, err)
return false
}
} else {
log.Error("%-v BaseRepo.GetUnit(unit.TypePullRequests): %v", pr, err)
return false
}

commit, err := getMergeCommit(ctx, pr)
Expand All @@ -250,6 +261,7 @@ func manuallyMerged(ctx context.Context, pr *issues_model.PullRequest) bool {

if commit == nil {
// no merge commit found
resetManuallyMergePullConfirm(ctx, pr)
return false
}

Expand All @@ -275,6 +287,7 @@ func manuallyMerged(ctx context.Context, pr *issues_model.PullRequest) bool {
log.Error("%-v setMerged : %v", pr, err)
return false
} else if !merged {
resetManuallyMergePullConfirm(ctx, pr)
return false
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
<div class="ui secondary segment">
<div>git checkout {{$.Issue.PullRequest.BaseBranch}}</div>
<div>git merge --no-ff {{if ne $.Issue.PullRequest.HeadRepo.ID $.Issue.PullRequest.BaseRepo.ID}}{{$.Issue.PullRequest.HeadRepo.OwnerName}}-{{end}}{{$.Issue.PullRequest.HeadBranch}}</div>
<div>git push origin {{$.Issue.PullRequest.BaseBranch}}</div>
<div>git push origin {{$.Issue.PullRequest.BaseBranch}} -o pulls.merged={{$.Issue.PullRequest.Index}}</div>
</div>
</div>