Skip to content

Commit 9d8178b

Browse files
adelowolafriks
authored andcommitted
Add option to close issues via commit on a non master branch (#5992)
* fixes #5957 * add tests to make sure config option is respected * use already defined struct * - use migration to make the flag repo wide not for the entire gitea instance Also note that the config value can still be set so as to be able to control the value for new repositories that are to be created - fix copy/paste error in copyright header year and rearrange import - use repo config instead of server config value to determine if a commit should close an issue - update testsuite * use global config only when creating a new repository * allow repo admin toggle feature via UI * fix typo and improve testcase * fix fixtures * add DEFAULT prefix to config value * fix test
1 parent c0adb5e commit 9d8178b

File tree

15 files changed

+141
-44
lines changed

15 files changed

+141
-44
lines changed

custom/conf/app.ini.sample

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ DISABLE_HTTP_GIT = false
3636
ACCESS_CONTROL_ALLOW_ORIGIN =
3737
; Force ssh:// clone url instead of scp-style uri when default SSH port is used
3838
USE_COMPAT_SSH_URI = false
39+
; Close issues as long as a commit on any branch marks it as fixed
40+
DEFAULT_CLOSE_ISSUES_VIA_COMMITS_IN_ANY_BRANCH = false
3941

4042
[repository.editor]
4143
; List of file extensions for which lines should be wrapped in the CodeMirror editor

docs/content/doc/advanced/config-cheat-sheet.en-us.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
6565
- `ACCESS_CONTROL_ALLOW_ORIGIN`: **\<empty\>**: Value for Access-Control-Allow-Origin header,
6666
default is not to present. **WARNING**: This maybe harmful to you website if you do not
6767
give it a right value.
68+
- `DEFAULT_CLOSE_ISSUES_VIA_COMMITS_IN_ANY_BRANCH`: **false**: Close an issue if a commit on a non default branch marks it as closed.
6869

6970
### Repository - Pull Request (`repository.pull-request`)
7071
- `WORK_IN_PROGRESS_PREFIXES`: **WIP:,\[WIP\]**: List of prefixes used in Pull Request

models/action.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,8 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit, bra
539539
}
540540

541541
// Change issue status only if the commit has been pushed to the default branch.
542-
if repo.DefaultBranch != branchName {
542+
// and if the repo is configured to allow only that
543+
if repo.DefaultBranch != branchName && !repo.CloseIssuesViaCommitInAnyBranch {
543544
continue
544545
}
545546

models/action_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,40 @@ func TestUpdateIssuesCommit(t *testing.T) {
260260
CheckConsistencyFor(t, &Action{})
261261
}
262262

263+
func TestUpdateIssuesCommit_Issue5957(t *testing.T) {
264+
assert.NoError(t, PrepareTestDatabase())
265+
user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
266+
267+
// Test that push to a non-default branch closes an issue.
268+
pushCommits := []*PushCommit{
269+
{
270+
Sha1: "abcdef1",
271+
CommitterEmail: "[email protected]",
272+
CommitterName: "User Two",
273+
AuthorEmail: "[email protected]",
274+
AuthorName: "User Four",
275+
Message: "close #2",
276+
},
277+
}
278+
279+
repo := AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository)
280+
commentBean := &Comment{
281+
Type: CommentTypeCommitRef,
282+
CommitSHA: "abcdef1",
283+
PosterID: user.ID,
284+
IssueID: 7,
285+
}
286+
287+
issueBean := &Issue{RepoID: repo.ID, Index: 2, ID: 7}
288+
289+
AssertNotExistsBean(t, commentBean)
290+
AssertNotExistsBean(t, issueBean, "is_closed=1")
291+
assert.NoError(t, UpdateIssuesCommit(user, repo, pushCommits, "non-existing-branch"))
292+
AssertExistsAndLoadBean(t, commentBean)
293+
AssertExistsAndLoadBean(t, issueBean, "is_closed=1")
294+
CheckConsistencyFor(t, &Action{})
295+
}
296+
263297
func testCorrectRepoAction(t *testing.T, opts CommitRepoActionOptions, actionBean *Action) {
264298
AssertNotExistsBean(t, actionBean)
265299
assert.NoError(t, CommitRepoAction(opts))

models/fixtures/issue.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,16 @@
7373
num_comments: 0
7474
created_unix: 946684850
7575
updated_unix: 978307200
76+
77+
-
78+
id: 7
79+
repo_id: 2
80+
index: 2
81+
poster_id: 2
82+
name: issue7
83+
content: content for the seventh issue
84+
is_closed: false
85+
is_pull: false
86+
created_unix: 946684830
87+
updated_unix: 978307200
88+

models/fixtures/repository.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@
1717
lower_name: repo2
1818
name: repo2
1919
is_private: true
20-
num_issues: 1
20+
num_issues: 2
2121
num_closed_issues: 1
2222
num_pulls: 0
2323
num_closed_pulls: 0
2424
num_stars: 1
25+
close_issues_via_commit_in_any_branch: true
2526

2627
-
2728
id: 3

models/issue_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ func TestGetUserIssueStats(t *testing.T) {
275275
YourRepositoriesCount: 2,
276276
AssignCount: 0,
277277
CreateCount: 2,
278-
OpenCount: 1,
278+
OpenCount: 2,
279279
ClosedCount: 2,
280280
},
281281
},

models/migrations/migrations.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ var migrations = []Migration{
210210
NewMigration("add theme to users", addUserDefaultTheme),
211211
// v78 -> v79
212212
NewMigration("rename repo is_bare to repo is_empty", renameRepoIsBareToIsEmpty),
213+
// v79 -> v80
214+
NewMigration("add can close issues via commit in any branch", addCanCloseIssuesViaCommitInAnyBranch),
213215
}
214216

215217
// Migrate database to current version

models/migrations/v79.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2019 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+
"code.gitea.io/gitea/modules/setting"
9+
10+
"github.com/go-xorm/xorm"
11+
)
12+
13+
func addCanCloseIssuesViaCommitInAnyBranch(x *xorm.Engine) error {
14+
15+
type Repository struct {
16+
ID int64 `xorm:"pk autoincr"`
17+
CloseIssuesViaCommitInAnyBranch bool `xorm:"NOT NULL DEFAULT false"`
18+
}
19+
20+
if err := x.Sync2(new(Repository)); err != nil {
21+
return err
22+
}
23+
24+
_, err := x.Exec("UPDATE repository SET close_issues_via_commit_in_any_branch = ?",
25+
setting.Repository.DefaultCloseIssuesViaCommitsInAnyBranch)
26+
return err
27+
}

models/repo.go

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -197,13 +197,14 @@ type Repository struct {
197197
ExternalMetas map[string]string `xorm:"-"`
198198
Units []*RepoUnit `xorm:"-"`
199199

200-
IsFork bool `xorm:"INDEX NOT NULL DEFAULT false"`
201-
ForkID int64 `xorm:"INDEX"`
202-
BaseRepo *Repository `xorm:"-"`
203-
Size int64 `xorm:"NOT NULL DEFAULT 0"`
204-
IndexerStatus *RepoIndexerStatus `xorm:"-"`
205-
IsFsckEnabled bool `xorm:"NOT NULL DEFAULT true"`
206-
Topics []string `xorm:"TEXT JSON"`
200+
IsFork bool `xorm:"INDEX NOT NULL DEFAULT false"`
201+
ForkID int64 `xorm:"INDEX"`
202+
BaseRepo *Repository `xorm:"-"`
203+
Size int64 `xorm:"NOT NULL DEFAULT 0"`
204+
IndexerStatus *RepoIndexerStatus `xorm:"-"`
205+
IsFsckEnabled bool `xorm:"NOT NULL DEFAULT true"`
206+
CloseIssuesViaCommitInAnyBranch bool `xorm:"NOT NULL DEFAULT false"`
207+
Topics []string `xorm:"TEXT JSON"`
207208

208209
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
209210
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
@@ -1373,13 +1374,14 @@ func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err
13731374
}
13741375

13751376
repo := &Repository{
1376-
OwnerID: u.ID,
1377-
Owner: u,
1378-
Name: opts.Name,
1379-
LowerName: strings.ToLower(opts.Name),
1380-
Description: opts.Description,
1381-
IsPrivate: opts.IsPrivate,
1382-
IsFsckEnabled: !opts.IsMirror,
1377+
OwnerID: u.ID,
1378+
Owner: u,
1379+
Name: opts.Name,
1380+
LowerName: strings.ToLower(opts.Name),
1381+
Description: opts.Description,
1382+
IsPrivate: opts.IsPrivate,
1383+
IsFsckEnabled: !opts.IsMirror,
1384+
CloseIssuesViaCommitInAnyBranch: setting.Repository.DefaultCloseIssuesViaCommitsInAnyBranch,
13831385
}
13841386

13851387
sess := x.NewSession()

modules/auth/repo_form.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414

1515
"github.com/Unknwon/com"
1616
"github.com/go-macaron/binding"
17-
"gopkg.in/macaron.v1"
17+
macaron "gopkg.in/macaron.v1"
1818
)
1919

2020
// _______________________________________ _________.______________________ _______________.___.
@@ -120,7 +120,8 @@ type RepoSettingForm struct {
120120
IsArchived bool
121121

122122
// Admin settings
123-
EnableHealthCheck bool
123+
EnableHealthCheck bool
124+
EnableCloseIssuesViaCommitInAnyBranch bool
124125
}
125126

126127
// Validate validates the fields

modules/setting/setting.go

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -190,16 +190,17 @@ var (
190190

191191
// Repository settings
192192
Repository = struct {
193-
AnsiCharset string
194-
ForcePrivate bool
195-
DefaultPrivate string
196-
MaxCreationLimit int
197-
MirrorQueueLength int
198-
PullRequestQueueLength int
199-
PreferredLicenses []string
200-
DisableHTTPGit bool
201-
AccessControlAllowOrigin string
202-
UseCompatSSHURI bool
193+
AnsiCharset string
194+
ForcePrivate bool
195+
DefaultPrivate string
196+
MaxCreationLimit int
197+
MirrorQueueLength int
198+
PullRequestQueueLength int
199+
PreferredLicenses []string
200+
DisableHTTPGit bool
201+
AccessControlAllowOrigin string
202+
UseCompatSSHURI bool
203+
DefaultCloseIssuesViaCommitsInAnyBranch bool
203204

204205
// Repository editor settings
205206
Editor struct {
@@ -227,16 +228,17 @@ var (
227228
WorkInProgressPrefixes []string
228229
} `ini:"repository.pull-request"`
229230
}{
230-
AnsiCharset: "",
231-
ForcePrivate: false,
232-
DefaultPrivate: RepoCreatingLastUserVisibility,
233-
MaxCreationLimit: -1,
234-
MirrorQueueLength: 1000,
235-
PullRequestQueueLength: 1000,
236-
PreferredLicenses: []string{"Apache License 2.0,MIT License"},
237-
DisableHTTPGit: false,
238-
AccessControlAllowOrigin: "",
239-
UseCompatSSHURI: false,
231+
AnsiCharset: "",
232+
ForcePrivate: false,
233+
DefaultPrivate: RepoCreatingLastUserVisibility,
234+
MaxCreationLimit: -1,
235+
MirrorQueueLength: 1000,
236+
PullRequestQueueLength: 1000,
237+
PreferredLicenses: []string{"Apache License 2.0,MIT License"},
238+
DisableHTTPGit: false,
239+
AccessControlAllowOrigin: "",
240+
UseCompatSSHURI: false,
241+
DefaultCloseIssuesViaCommitsInAnyBranch: false,
240242

241243
// Repository editor settings
242244
Editor: struct {

options/locale/locale_en-US.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,7 @@ settings.pulls.allow_rebase_merge_commit = Enable Rebasing with explicit merge c
10351035
settings.pulls.allow_squash_commits = Enable Squashing to Merge Commits
10361036
settings.admin_settings = Administrator Settings
10371037
settings.admin_enable_health_check = Enable Repository Health Checks (git fsck)
1038+
settings.admin_enable_close_issues_via_commit_in_any_branch = Close an issue via a commit made in a non default branch
10381039
settings.danger_zone = Danger Zone
10391040
settings.new_owner_has_same_repo = The new owner already has a repository with same name. Please choose another name.
10401041
settings.convert = Convert to Regular Repository

routers/repo/setting.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,13 +250,19 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
250250

251251
if repo.IsFsckEnabled != form.EnableHealthCheck {
252252
repo.IsFsckEnabled = form.EnableHealthCheck
253-
if err := models.UpdateRepository(repo, false); err != nil {
254-
ctx.ServerError("UpdateRepository", err)
255-
return
256-
}
257-
log.Trace("Repository admin settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
258253
}
259254

255+
if repo.CloseIssuesViaCommitInAnyBranch != form.EnableCloseIssuesViaCommitInAnyBranch {
256+
repo.CloseIssuesViaCommitInAnyBranch = form.EnableCloseIssuesViaCommitInAnyBranch
257+
}
258+
259+
if err := models.UpdateRepository(repo, false); err != nil {
260+
ctx.ServerError("UpdateRepository", err)
261+
return
262+
}
263+
264+
log.Trace("Repository admin settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
265+
260266
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
261267
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
262268

templates/repo/settings/options.tmpl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,10 @@
263263
<label>{{.i18n.Tr "repo.settings.admin_enable_health_check"}}</label>
264264
</div>
265265
</div>
266+
<div class="ui checkbox">
267+
<input name="enable_close_issues_via_commit_in_any_branch" type="checkbox" {{ if .Repository.CloseIssuesViaCommitInAnyBranch }}checked{{end}}>
268+
<label>{{.i18n.Tr "repo.settings.admin_enable_close_issues_via_commit_in_any_branch"}}</label>
269+
</div>
266270

267271
<div class="ui divider"></div>
268272
<div class="field">

0 commit comments

Comments
 (0)