Skip to content

Commit 8ac1501

Browse files
authored
Add Pull Request merge options - Ignore white-space for conflict checking, Rebase, Squash merge (#3188)
* Pull request options migration and UI in settings * Add ignore whitespace functionality * Fix settings if pull requests are disabled * Fix migration transaction * Merge with Rebase functionality * UI changes and related functionality for pull request merging button * Implement squash functionality * Fix rebase merging * Fix pull request merge tests * Add squash and rebase tests * Fix API method to reuse default message functions * Some refactoring and small fixes * Remove more hardcoded values from tests * Remove unneeded check from API method * Fix variable name and comment typo * Fix reset commit count after PR merge
1 parent a192f30 commit 8ac1501

File tree

20 files changed

+529
-44
lines changed

20 files changed

+529
-44
lines changed

integrations/pull_merge_test.go

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,23 @@ import (
1111
"strings"
1212
"testing"
1313

14+
"code.gitea.io/gitea/models"
1415
"code.gitea.io/gitea/modules/test"
1516

1617
"github.com/stretchr/testify/assert"
1718
)
1819

19-
func testPullMerge(t *testing.T, session *TestSession, user, repo, pullnum string) *httptest.ResponseRecorder {
20+
func testPullMerge(t *testing.T, session *TestSession, user, repo, pullnum string, mergeStyle models.MergeStyle) *httptest.ResponseRecorder {
2021
req := NewRequest(t, "GET", path.Join(user, repo, "pulls", pullnum))
2122
resp := session.MakeRequest(t, req, http.StatusOK)
2223

2324
// Click the little green button to create a pull
2425
htmlDoc := NewHTMLParser(t, resp.Body)
25-
link, exists := htmlDoc.doc.Find("form.ui.form>button.ui.green.button").Parent().Attr("action")
26+
link, exists := htmlDoc.doc.Find(".ui.form." + string(mergeStyle) + "-fields > form").Attr("action")
2627
assert.True(t, exists, "The template has changed")
2728
req = NewRequestWithValues(t, "POST", link, map[string]string{
2829
"_csrf": htmlDoc.GetCSRF(),
30+
"do": string(mergeStyle),
2931
})
3032
resp = session.MakeRequest(t, req, http.StatusFound)
3133

@@ -58,7 +60,34 @@ func TestPullMerge(t *testing.T) {
5860

5961
elem := strings.Split(test.RedirectURL(resp), "/")
6062
assert.EqualValues(t, "pulls", elem[3])
61-
testPullMerge(t, session, elem[1], elem[2], elem[4])
63+
testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge)
64+
}
65+
66+
func TestPullRebase(t *testing.T) {
67+
prepareTestEnv(t)
68+
session := loginUser(t, "user1")
69+
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
70+
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
71+
72+
resp := testPullCreate(t, session, "user1", "repo1", "master")
73+
74+
elem := strings.Split(test.RedirectURL(resp), "/")
75+
assert.EqualValues(t, "pulls", elem[3])
76+
testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebase)
77+
}
78+
79+
func TestPullSquash(t *testing.T) {
80+
prepareTestEnv(t)
81+
session := loginUser(t, "user1")
82+
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
83+
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
84+
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited!)\n")
85+
86+
resp := testPullCreate(t, session, "user1", "repo1", "master")
87+
88+
elem := strings.Split(test.RedirectURL(resp), "/")
89+
assert.EqualValues(t, "pulls", elem[3])
90+
testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleSquash)
6291
}
6392

6493
func TestPullCleanUpAfterMerge(t *testing.T) {
@@ -71,7 +100,7 @@ func TestPullCleanUpAfterMerge(t *testing.T) {
71100

72101
elem := strings.Split(test.RedirectURL(resp), "/")
73102
assert.EqualValues(t, "pulls", elem[3])
74-
testPullMerge(t, session, elem[1], elem[2], elem[4])
103+
testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge)
75104

76105
// Check PR branch deletion
77106
resp = testPullCleanUp(t, session, elem[1], elem[2], elem[4])

integrations/repo_activity_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"strings"
1010
"testing"
1111

12+
"code.gitea.io/gitea/models"
1213
"code.gitea.io/gitea/modules/test"
1314

1415
"github.com/stretchr/testify/assert"
@@ -24,7 +25,7 @@ func TestRepoActivity(t *testing.T) {
2425
resp := testPullCreate(t, session, "user1", "repo1", "master")
2526
elem := strings.Split(test.RedirectURL(resp), "/")
2627
assert.EqualValues(t, "pulls", elem[3])
27-
testPullMerge(t, session, elem[1], elem[2], elem[4])
28+
testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge)
2829

2930
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feat/better_readme", "README.md", "Hello, World (Edited Again)\n")
3031
testPullCreate(t, session, "user1", "repo1", "feat/better_readme")

models/error.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,23 @@ func (err ErrPullRequestAlreadyExists) Error() string {
878878
err.ID, err.IssueID, err.HeadRepoID, err.BaseRepoID, err.HeadBranch, err.BaseBranch)
879879
}
880880

881+
// ErrInvalidMergeStyle represents an error if merging with disabled merge strategy
882+
type ErrInvalidMergeStyle struct {
883+
ID int64
884+
Style MergeStyle
885+
}
886+
887+
// IsErrInvalidMergeStyle checks if an error is a ErrInvalidMergeStyle.
888+
func IsErrInvalidMergeStyle(err error) bool {
889+
_, ok := err.(ErrInvalidMergeStyle)
890+
return ok
891+
}
892+
893+
func (err ErrInvalidMergeStyle) Error() string {
894+
return fmt.Sprintf("merge strategy is not allowed or is invalid [repo_id: %d, strategy: %s]",
895+
err.ID, err.Style)
896+
}
897+
881898
// _________ __
882899
// \_ ___ \ ____ _____ _____ ____ _____/ |_
883900
// / \ \/ / _ \ / \ / \_/ __ \ / \ __\

models/fixtures/repo_unit.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
id: 5
3131
repo_id: 1
3232
type: 3
33-
config: "{}"
33+
config: "{\"IgnoreWhitespaceConflicts\":false,\"AllowMerge\":true,\"AllowRebase\":true,\"AllowSquash\":true}"
3434
created_unix: 946684810
3535

3636
-
@@ -51,7 +51,7 @@
5151
id: 8
5252
repo_id: 3
5353
type: 3
54-
config: "{}"
54+
config: "{\"IgnoreWhitespaceConflicts\":true,\"AllowMerge\":true,\"AllowRebase\":false,\"AllowSquash\":false}"
5555
created_unix: 946684810
5656

5757
-

models/migrations/migrations.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ var migrations = []Migration{
160160
NewMigration("add lfs lock table", addLFSLock),
161161
// v53 -> v54
162162
NewMigration("add reactions", addReactions),
163+
// v54 -> v55
164+
NewMigration("add pull request options", addPullRequestOptions),
163165
}
164166

165167
// Migrate database to current version

models/migrations/v54.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2017 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package migrations
6+
7+
import (
8+
"fmt"
9+
10+
"code.gitea.io/gitea/modules/util"
11+
12+
"github.com/go-xorm/xorm"
13+
)
14+
15+
func addPullRequestOptions(x *xorm.Engine) error {
16+
// RepoUnit describes all units of a repository
17+
type RepoUnit struct {
18+
ID int64
19+
RepoID int64 `xorm:"INDEX(s)"`
20+
Type int `xorm:"INDEX(s)"`
21+
Config map[string]interface{} `xorm:"JSON"`
22+
CreatedUnix util.TimeStamp `xorm:"INDEX CREATED"`
23+
}
24+
25+
sess := x.NewSession()
26+
defer sess.Close()
27+
if err := sess.Begin(); err != nil {
28+
return err
29+
}
30+
31+
//Updating existing issue units
32+
units := make([]*RepoUnit, 0, 100)
33+
if err := sess.Where("`type` = ?", V16UnitTypePRs).Find(&units); err != nil {
34+
return fmt.Errorf("Query repo units: %v", err)
35+
}
36+
for _, unit := range units {
37+
if unit.Config == nil {
38+
unit.Config = make(map[string]interface{})
39+
}
40+
if _, ok := unit.Config["IgnoreWhitespaceConflicts"]; !ok {
41+
unit.Config["IgnoreWhitespaceConflicts"] = false
42+
}
43+
if _, ok := unit.Config["AllowMerge"]; !ok {
44+
unit.Config["AllowMerge"] = true
45+
}
46+
if _, ok := unit.Config["AllowRebase"]; !ok {
47+
unit.Config["AllowRebase"] = true
48+
}
49+
if _, ok := unit.Config["AllowSquash"]; !ok {
50+
unit.Config["AllowSquash"] = true
51+
}
52+
if _, err := sess.ID(unit.ID).Cols("config").Update(unit); err != nil {
53+
return err
54+
}
55+
}
56+
return sess.Commit()
57+
}

0 commit comments

Comments
 (0)