Skip to content

Commit e204398

Browse files
VedranGiteazeripathlunnytechknowlogick
authored
Change/remove a branch of an open issue (#9080)
* Add field with isIssueWriter to front end * Make branch field editable * Switch frontend to form and POST from javascript * Add /issue/id/ref endpoint to routes * Use UpdateIssueTitle model to change ref in backend * Removed crossreference check and adding comments on branch change * Use ref returned from POST to update the field * Prevent calling loadRepo from models/ * Branch/tag refreshed without page reload * Remove filter for empty branch name * Add clear option to tag list as well * Delete button translation and coloring * Fix for not showing selected branch name in new issue * Check that branch is not being changed on a PR * Change logic * Notification when changing issue ref * Fix for renamed permission parameter * Fix for failing build * Apply suggestions from code review Co-authored-by: zeripath <[email protected]> Co-authored-by: Gitea <[email protected]> Co-authored-by: zeripath <[email protected]> Co-authored-by: Lunny Xiao <[email protected]> Co-authored-by: techknowlogick <[email protected]>
1 parent 0ed8d26 commit e204398

File tree

11 files changed

+107
-9
lines changed

11 files changed

+107
-9
lines changed

models/issue.go

+16
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,22 @@ func (issue *Issue) ChangeTitle(doer *User, oldTitle string) (err error) {
709709
return sess.Commit()
710710
}
711711

712+
// ChangeRef changes the branch of this issue, as the given user.
713+
func (issue *Issue) ChangeRef(doer *User, oldRef string) (err error) {
714+
sess := x.NewSession()
715+
defer sess.Close()
716+
717+
if err = sess.Begin(); err != nil {
718+
return err
719+
}
720+
721+
if err = updateIssueCols(sess, issue, "ref"); err != nil {
722+
return fmt.Errorf("updateIssueCols: %v", err)
723+
}
724+
725+
return sess.Commit()
726+
}
727+
712728
// AddDeletePRBranchComment adds delete branch comment for pull request issue
713729
func AddDeletePRBranchComment(doer *User, repo *Repository, issueID int64, branchName string) error {
714730
issue, err := getIssueByID(x, issueID)

modules/notification/base/notifier.go

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ type Notifier interface {
2828
NotifyIssueChangeContent(doer *models.User, issue *models.Issue, oldContent string)
2929
NotifyIssueClearLabels(doer *models.User, issue *models.Issue)
3030
NotifyIssueChangeTitle(doer *models.User, issue *models.Issue, oldTitle string)
31+
NotifyIssueChangeRef(doer *models.User, issue *models.Issue, oldRef string)
3132
NotifyIssueChangeLabels(doer *models.User, issue *models.Issue,
3233
addedLabels []*models.Label, removedLabels []*models.Label)
3334

modules/notification/base/null.go

+4
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ func (*NullNotifier) NotifyIssueClearLabels(doer *models.User, issue *models.Iss
102102
func (*NullNotifier) NotifyIssueChangeTitle(doer *models.User, issue *models.Issue, oldTitle string) {
103103
}
104104

105+
// NotifyIssueChangeRef places a place holder function
106+
func (*NullNotifier) NotifyIssueChangeRef(doer *models.User, issue *models.Issue, oldTitle string) {
107+
}
108+
105109
// NotifyIssueChangeLabels places a place holder function
106110
func (*NullNotifier) NotifyIssueChangeLabels(doer *models.User, issue *models.Issue,
107111
addedLabels []*models.Label, removedLabels []*models.Label) {

modules/notification/indexer/indexer.go

+4
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,7 @@ func (r *indexerNotifier) NotifyIssueChangeContent(doer *models.User, issue *mod
148148
func (r *indexerNotifier) NotifyIssueChangeTitle(doer *models.User, issue *models.Issue, oldTitle string) {
149149
issue_indexer.UpdateIssueIndexer(issue)
150150
}
151+
152+
func (r *indexerNotifier) NotifyIssueChangeRef(doer *models.User, issue *models.Issue, oldRef string) {
153+
issue_indexer.UpdateIssueIndexer(issue)
154+
}

modules/notification/notification.go

+7
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,13 @@ func NotifyIssueChangeTitle(doer *models.User, issue *models.Issue, oldTitle str
178178
}
179179
}
180180

181+
// NotifyIssueChangeRef notifies change reference to notifiers
182+
func NotifyIssueChangeRef(doer *models.User, issue *models.Issue, oldRef string) {
183+
for _, notifier := range notifiers {
184+
notifier.NotifyIssueChangeRef(doer, issue, oldRef)
185+
}
186+
}
187+
181188
// NotifyIssueChangeLabels notifies change labels to notifiers
182189
func NotifyIssueChangeLabels(doer *models.User, issue *models.Issue,
183190
addedLabels []*models.Label, removedLabels []*models.Label) {

options/locale/locale_en-US.ini

+1
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,7 @@ code = Code
760760
code.desc = Access source code, files, commits and branches.
761761
branch = Branch
762762
tree = Tree
763+
clear_ref = `Clear current reference`
763764
filter_branch_and_tag = Filter branch or tag
764765
branches = Branches
765766
tags = Tags

routers/repo/issue.go

+25-1
Original file line numberDiff line numberDiff line change
@@ -1244,7 +1244,7 @@ func ViewIssue(ctx *context.Context) {
12441244
ctx.Data["Participants"] = participants
12451245
ctx.Data["NumParticipants"] = len(participants)
12461246
ctx.Data["Issue"] = issue
1247-
ctx.Data["ReadOnly"] = true
1247+
ctx.Data["ReadOnly"] = false
12481248
ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login?redirect_to=" + ctx.Data["Link"].(string)
12491249
ctx.Data["IsIssuePoster"] = ctx.IsSigned && issue.IsPoster(ctx.User.ID)
12501250
ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)
@@ -1344,6 +1344,30 @@ func UpdateIssueTitle(ctx *context.Context) {
13441344
})
13451345
}
13461346

1347+
// UpdateIssueRef change issue's ref (branch)
1348+
func UpdateIssueRef(ctx *context.Context) {
1349+
issue := GetActionIssue(ctx)
1350+
if ctx.Written() {
1351+
return
1352+
}
1353+
1354+
if !ctx.IsSigned || (!issue.IsPoster(ctx.User.ID) && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)) || issue.IsPull {
1355+
ctx.Error(403)
1356+
return
1357+
}
1358+
1359+
ref := ctx.QueryTrim("ref")
1360+
1361+
if err := issue_service.ChangeIssueRef(issue, ctx.User, ref); err != nil {
1362+
ctx.ServerError("ChangeRef", err)
1363+
return
1364+
}
1365+
1366+
ctx.JSON(200, map[string]interface{}{
1367+
"ref": ref,
1368+
})
1369+
}
1370+
13471371
// UpdateIssueContent change issue's content
13481372
func UpdateIssueContent(ctx *context.Context) {
13491373
issue := GetActionIssue(ctx)

routers/routes/routes.go

+1
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,7 @@ func RegisterRoutes(m *macaron.Macaron) {
733733
m.Post("/title", repo.UpdateIssueTitle)
734734
m.Post("/content", repo.UpdateIssueContent)
735735
m.Post("/watch", repo.IssueWatch)
736+
m.Post("/ref", repo.UpdateIssueRef)
736737
m.Group("/dependency", func() {
737738
m.Post("/add", repo.AddDependency)
738739
m.Post("/delete", repo.RemoveDependency)

services/issue/issue.go

+14
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ func ChangeTitle(issue *models.Issue, doer *models.User, title string) (err erro
4242
return nil
4343
}
4444

45+
// ChangeIssueRef changes the branch of this issue, as the given user.
46+
func ChangeIssueRef(issue *models.Issue, doer *models.User, ref string) error {
47+
oldRef := issue.Ref
48+
issue.Ref = ref
49+
50+
if err := issue.ChangeRef(doer, oldRef); err != nil {
51+
return err
52+
}
53+
54+
notification.NotifyIssueChangeRef(doer, issue, oldRef)
55+
56+
return nil
57+
}
58+
4559
// UpdateAssignees is a helper function to add or delete one or multiple issue assignee(s)
4660
// Deleting is done the GitHub way (quote from their api documentation):
4761
// https://developer.github.com/v3/issues/#edit-an-issue

templates/repo/issue/branch_selector_field.tmpl

+17-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
{{if and (not .Issue.IsPull) (not .PageIsComparePull)}}
22
<input id="ref_selector" name="ref" type="hidden" value="{{.Issue.Ref}}">
3+
<input id="editing_mode" name="edit_mode" type="hidden" value="{{(or .IsIssueWriter .HasIssuesOrPullsWritePermission)}}">
4+
<form method="POST" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/ref" id="update_issueref_form">
5+
{{$.CsrfTokenHtml}}
6+
</form>
7+
38
<div class="ui {{if .ReadOnly}}disabled{{end}} floating filter select-branch dropdown" data-no-results="{{.i18n.Tr "repo.pulls.no_results"}}">
49
<div class="ui basic small button">
510
<span class="text branch-name">{{if .Issue.Ref}}{{$.RefEndName}}{{else}}{{.i18n.Tr "repo.issues.no_ref"}}{{end}}</span>
@@ -27,14 +32,20 @@
2732
</div>
2833
</div>
2934
<div id="branch-list" class="scrolling menu reference-list-menu">
30-
{{range .Branches}}
31-
<div class="item" data-id="refs/heads/{{.}}" data-name="{{.}}" data-id-selector="#ref_selector">{{.}}</div>
32-
{{end}}
35+
{{if .Issue.Ref}}
36+
<div class="item text small" data-id="" data-id-selector="#ref_selector"><strong><a href="#">{{$.i18n.Tr "repo.clear_ref"}}</a></strong></div>
37+
{{end}}
38+
{{range .Branches}}
39+
<div class="item" data-id="refs/heads/{{.}}" data-name="{{.}}" data-id-selector="#ref_selector">{{.}}</div>
40+
{{end}}
3341
</div>
3442
<div id="tag-list" class="scrolling menu reference-list-menu" style="display: none">
35-
{{range .Tags}}
36-
<div class="item" data-id="refs/tags/{{.}}" data-name="tags/{{.}}" data-id-selector="#ref_selector">{{.}}</div>
37-
{{end}}
43+
{{if .Issue.Ref}}
44+
<div class="item text small" data-id="" data-id-selector="#ref_selector"><strong><a href="#">{{.i18n.Tr "repo.clear_ref"}}</a></strong></div>
45+
{{end}}
46+
{{range .Tags}}
47+
<div class="item" data-id="refs/tags/{{.}}" data-name="tags/{{.}}" data-id-selector="#ref_selector">{{.}}</div>
48+
{{end}}
3849
</div>
3950
</div>
4051
</div>

web_src/js/index.js

+17-2
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,23 @@ function initBranchSelector() {
112112
const $selectBranch = $('.ui.select-branch');
113113
const $branchMenu = $selectBranch.find('.reference-list-menu');
114114
$branchMenu.find('.item:not(.no-select)').click(function () {
115-
$($(this).data('id-selector')).val($(this).data('id'));
116-
$selectBranch.find('.ui .branch-name').text($(this).data('name'));
115+
const selectedValue = $(this).data('id');
116+
const editMode = $('#editing_mode').val();
117+
$($(this).data('id-selector')).val(selectedValue);
118+
119+
if (editMode === 'true') {
120+
const form = $('#update_issueref_form');
121+
122+
$.post(form.attr('action'), {
123+
_csrf: csrf,
124+
ref: selectedValue
125+
},
126+
() => {
127+
window.location.reload();
128+
});
129+
} else if (editMode === '') {
130+
$selectBranch.find('.ui .branch-name').text(selectedValue);
131+
}
117132
});
118133
$selectBranch.find('.reference.column').on('click', function () {
119134
$selectBranch.find('.scrolling.reference-list-menu').css('display', 'none');

0 commit comments

Comments
 (0)