]> source.dussan.org Git - gitea.git/commitdiff
Change/remove a branch of an open issue (#9080)
authorVedran <vedran.mikov@protonmail.com>
Tue, 8 Sep 2020 16:29:51 +0000 (18:29 +0200)
committerGitHub <noreply@github.com>
Tue, 8 Sep 2020 16:29:51 +0000 (12:29 -0400)
* 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 <art27@cantab.net>
Co-authored-by: Gitea <gitea@fake.local>
Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
models/issue.go
modules/notification/base/notifier.go
modules/notification/base/null.go
modules/notification/indexer/indexer.go
modules/notification/notification.go
options/locale/locale_en-US.ini
routers/repo/issue.go
routers/routes/routes.go
services/issue/issue.go
templates/repo/issue/branch_selector_field.tmpl
web_src/js/index.js

index 81652771baf2e04f0f9aabf8674d5af5140a47d0..228316fc3c3cef523f462f8181d2367cfe8377d2 100644 (file)
@@ -709,6 +709,22 @@ func (issue *Issue) ChangeTitle(doer *User, oldTitle string) (err error) {
        return sess.Commit()
 }
 
+// ChangeRef changes the branch of this issue, as the given user.
+func (issue *Issue) ChangeRef(doer *User, oldRef string) (err error) {
+       sess := x.NewSession()
+       defer sess.Close()
+
+       if err = sess.Begin(); err != nil {
+               return err
+       }
+
+       if err = updateIssueCols(sess, issue, "ref"); err != nil {
+               return fmt.Errorf("updateIssueCols: %v", err)
+       }
+
+       return sess.Commit()
+}
+
 // AddDeletePRBranchComment adds delete branch comment for pull request issue
 func AddDeletePRBranchComment(doer *User, repo *Repository, issueID int64, branchName string) error {
        issue, err := getIssueByID(x, issueID)
index 428f9a9544f3c7e291e82dba0775c956cbd7e8aa..5cd2b4c0605958e6d72051e0491dfe5605581895 100644 (file)
@@ -28,6 +28,7 @@ type Notifier interface {
        NotifyIssueChangeContent(doer *models.User, issue *models.Issue, oldContent string)
        NotifyIssueClearLabels(doer *models.User, issue *models.Issue)
        NotifyIssueChangeTitle(doer *models.User, issue *models.Issue, oldTitle string)
+       NotifyIssueChangeRef(doer *models.User, issue *models.Issue, oldRef string)
        NotifyIssueChangeLabels(doer *models.User, issue *models.Issue,
                addedLabels []*models.Label, removedLabels []*models.Label)
 
index b2ce0742b6c16ba6a49063e52a673e93276e7192..15d06ec856305d1f0d4c7276e9ba7e8ff829517f 100644 (file)
@@ -102,6 +102,10 @@ func (*NullNotifier) NotifyIssueClearLabels(doer *models.User, issue *models.Iss
 func (*NullNotifier) NotifyIssueChangeTitle(doer *models.User, issue *models.Issue, oldTitle string) {
 }
 
+// NotifyIssueChangeRef places a place holder function
+func (*NullNotifier) NotifyIssueChangeRef(doer *models.User, issue *models.Issue, oldTitle string) {
+}
+
 // NotifyIssueChangeLabels places a place holder function
 func (*NullNotifier) NotifyIssueChangeLabels(doer *models.User, issue *models.Issue,
        addedLabels []*models.Label, removedLabels []*models.Label) {
index f292d7339b20c692b334190aacfa9a2b37dbfce6..6e848e6318ad55da9767710dbca080134e6db6e7 100644 (file)
@@ -148,3 +148,7 @@ func (r *indexerNotifier) NotifyIssueChangeContent(doer *models.User, issue *mod
 func (r *indexerNotifier) NotifyIssueChangeTitle(doer *models.User, issue *models.Issue, oldTitle string) {
        issue_indexer.UpdateIssueIndexer(issue)
 }
+
+func (r *indexerNotifier) NotifyIssueChangeRef(doer *models.User, issue *models.Issue, oldRef string) {
+       issue_indexer.UpdateIssueIndexer(issue)
+}
index d17b13b9e53f3779db0c11fb68c8a21eb807296d..57f1e7c16df811498c2db4d075081f30c3ff556f 100644 (file)
@@ -178,6 +178,13 @@ func NotifyIssueChangeTitle(doer *models.User, issue *models.Issue, oldTitle str
        }
 }
 
+// NotifyIssueChangeRef notifies change reference to notifiers
+func NotifyIssueChangeRef(doer *models.User, issue *models.Issue, oldRef string) {
+       for _, notifier := range notifiers {
+               notifier.NotifyIssueChangeRef(doer, issue, oldRef)
+       }
+}
+
 // NotifyIssueChangeLabels notifies change labels to notifiers
 func NotifyIssueChangeLabels(doer *models.User, issue *models.Issue,
        addedLabels []*models.Label, removedLabels []*models.Label) {
index 9dd49b06c8e87d301021acf7119ce11c3b3b87da..a7b917ae1e6e7434fdf4ed7dc4e13b335c43b0c5 100644 (file)
@@ -760,6 +760,7 @@ code = Code
 code.desc = Access source code, files, commits and branches.
 branch = Branch
 tree = Tree
+clear_ref = `Clear current reference`
 filter_branch_and_tag = Filter branch or tag
 branches = Branches
 tags = Tags
index 4c745ed5d734956f763b7d2f182f79608806ac30..4fc83719fd0d8bcd92d701349b76f0bfb6ef7815 100644 (file)
@@ -1244,7 +1244,7 @@ func ViewIssue(ctx *context.Context) {
        ctx.Data["Participants"] = participants
        ctx.Data["NumParticipants"] = len(participants)
        ctx.Data["Issue"] = issue
-       ctx.Data["ReadOnly"] = true
+       ctx.Data["ReadOnly"] = false
        ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login?redirect_to=" + ctx.Data["Link"].(string)
        ctx.Data["IsIssuePoster"] = ctx.IsSigned && issue.IsPoster(ctx.User.ID)
        ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)
@@ -1344,6 +1344,30 @@ func UpdateIssueTitle(ctx *context.Context) {
        })
 }
 
+// UpdateIssueRef change issue's ref (branch)
+func UpdateIssueRef(ctx *context.Context) {
+       issue := GetActionIssue(ctx)
+       if ctx.Written() {
+               return
+       }
+
+       if !ctx.IsSigned || (!issue.IsPoster(ctx.User.ID) && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)) || issue.IsPull {
+               ctx.Error(403)
+               return
+       }
+
+       ref := ctx.QueryTrim("ref")
+
+       if err := issue_service.ChangeIssueRef(issue, ctx.User, ref); err != nil {
+               ctx.ServerError("ChangeRef", err)
+               return
+       }
+
+       ctx.JSON(200, map[string]interface{}{
+               "ref": ref,
+       })
+}
+
 // UpdateIssueContent change issue's content
 func UpdateIssueContent(ctx *context.Context) {
        issue := GetActionIssue(ctx)
index bdb82db6f5042a8a8bff8008611e1f8918403f22..779e8614b3b1c03424f4a2077cebdb6bb4bc8811 100644 (file)
@@ -733,6 +733,7 @@ func RegisterRoutes(m *macaron.Macaron) {
                                m.Post("/title", repo.UpdateIssueTitle)
                                m.Post("/content", repo.UpdateIssueContent)
                                m.Post("/watch", repo.IssueWatch)
+                               m.Post("/ref", repo.UpdateIssueRef)
                                m.Group("/dependency", func() {
                                        m.Post("/add", repo.AddDependency)
                                        m.Post("/delete", repo.RemoveDependency)
index 64d69119b76221ce31d7e3d21398862fb9a9a806..0f90a2bcd05ab5e5838668e4cfd00c8b6c5fe899 100644 (file)
@@ -42,6 +42,20 @@ func ChangeTitle(issue *models.Issue, doer *models.User, title string) (err erro
        return nil
 }
 
+// ChangeIssueRef changes the branch of this issue, as the given user.
+func ChangeIssueRef(issue *models.Issue, doer *models.User, ref string) error {
+       oldRef := issue.Ref
+       issue.Ref = ref
+
+       if err := issue.ChangeRef(doer, oldRef); err != nil {
+               return err
+       }
+
+       notification.NotifyIssueChangeRef(doer, issue, oldRef)
+
+       return nil
+}
+
 // UpdateAssignees is a helper function to add or delete one or multiple issue assignee(s)
 // Deleting is done the GitHub way (quote from their api documentation):
 // https://developer.github.com/v3/issues/#edit-an-issue
index 4f80c13e52df138ce2ff46dfffea2ec5cfcb22ce..69d99b3441b2df00172d4a26995acf53c4b48337 100644 (file)
@@ -1,5 +1,10 @@
 {{if and (not .Issue.IsPull) (not .PageIsComparePull)}}
 <input id="ref_selector" name="ref" type="hidden" value="{{.Issue.Ref}}">
+<input id="editing_mode" name="edit_mode" type="hidden" value="{{(or .IsIssueWriter .HasIssuesOrPullsWritePermission)}}">
+<form method="POST" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/ref" id="update_issueref_form">
+       {{$.CsrfTokenHtml}}
+</form>
+
 <div class="ui {{if .ReadOnly}}disabled{{end}} floating filter select-branch dropdown" data-no-results="{{.i18n.Tr "repo.pulls.no_results"}}">
        <div class="ui basic small button">
                <span class="text branch-name">{{if .Issue.Ref}}{{$.RefEndName}}{{else}}{{.i18n.Tr "repo.issues.no_ref"}}{{end}}</span>
                        </div>
                </div>
                <div id="branch-list" class="scrolling menu reference-list-menu">
-               {{range .Branches}}
-                       <div class="item" data-id="refs/heads/{{.}}" data-name="{{.}}" data-id-selector="#ref_selector">{{.}}</div>
-               {{end}}
+                       {{if .Issue.Ref}}
+                               <div class="item text small" data-id="" data-id-selector="#ref_selector"><strong><a href="#">{{$.i18n.Tr "repo.clear_ref"}}</a></strong></div>
+                       {{end}} 
+                       {{range .Branches}}
+                               <div class="item" data-id="refs/heads/{{.}}" data-name="{{.}}" data-id-selector="#ref_selector">{{.}}</div>
+                       {{end}}
                </div>
                <div id="tag-list" class="scrolling menu reference-list-menu" style="display: none">
-               {{range .Tags}}
-                       <div class="item" data-id="refs/tags/{{.}}" data-name="tags/{{.}}" data-id-selector="#ref_selector">{{.}}</div>
-               {{end}}
+                       {{if .Issue.Ref}}
+                               <div class="item text small" data-id="" data-id-selector="#ref_selector"><strong><a href="#">{{.i18n.Tr "repo.clear_ref"}}</a></strong></div>
+                       {{end}} 
+                       {{range .Tags}}
+                               <div class="item" data-id="refs/tags/{{.}}" data-name="tags/{{.}}" data-id-selector="#ref_selector">{{.}}</div>
+                       {{end}}
                </div>
        </div>
 </div>
index 1c23d0f735974907271a5f2a87237e2387744be4..73f040ac75a24cbf6e0afb682263035870c7d290 100644 (file)
@@ -112,8 +112,23 @@ function initBranchSelector() {
   const $selectBranch = $('.ui.select-branch');
   const $branchMenu = $selectBranch.find('.reference-list-menu');
   $branchMenu.find('.item:not(.no-select)').click(function () {
-    $($(this).data('id-selector')).val($(this).data('id'));
-    $selectBranch.find('.ui .branch-name').text($(this).data('name'));
+    const selectedValue = $(this).data('id');
+    const editMode = $('#editing_mode').val();
+    $($(this).data('id-selector')).val(selectedValue);
+
+    if (editMode === 'true') {
+      const form = $('#update_issueref_form');
+
+      $.post(form.attr('action'), {
+        _csrf: csrf,
+        ref: selectedValue
+      },
+      () => {
+        window.location.reload();
+      });
+    } else if (editMode === '') {
+      $selectBranch.find('.ui .branch-name').text(selectedValue);
+    }
   });
   $selectBranch.find('.reference.column').on('click', function () {
     $selectBranch.find('.scrolling.reference-list-menu').css('display', 'none');