feat(basin): merge confirmation with editable commit message
3 files changed, +28 −2
- pull.go modified +17 −1
- static/style.css modified +4 −0
- templates/pull.html modified +7 −1
pull.go modified
| @@ -417,7 +417,15 @@ func (s *Server) pull(w http.ResponseWriter, r *http.Request, repo Repo, rest st | ||
| 417 | 417 | s.fail(w, r, 403, "Only the repository owner can merge") |
| 418 | 418 | return |
| 419 | 419 | } |
| 420 | - hash, err := g.Merge(pull.TargetBranch, pull.Ref(), fmt.Sprintf("Merge pull request #%d from %s\n\n%s", pull.Number, pull.SourceRepo.Path()+":"+pull.SourceBranch, pull.Title), user.Name, user.Name+"@"+s.host) | |
| 420 | + title := strings.TrimSpace(r.FormValue("title")) | |
| 421 | + if title == "" { | |
| 422 | + title = mergeTitle(pull) | |
| 423 | + } | |
| 424 | + message := title | |
| 425 | + if body := strings.TrimSpace(r.FormValue("body")); body != "" { | |
| 426 | + message += "\n\n" + body | |
| 427 | + } | |
| 428 | + hash, err := g.Merge(pull.TargetBranch, pull.Ref(), message, user.Name, user.Name+"@"+s.host) | |
| 421 | 429 | if err != nil { |
| 422 | 430 | http.Redirect(w, r, back+"?error="+template.URLQueryEscaper(err.Error()), http.StatusSeeOther) |
| 423 | 431 | return |
| @@ -458,6 +466,10 @@ func (s *Server) pull(w http.ResponseWriter, r *http.Request, repo Repo, rest st | ||
| 458 | 466 | if cur, err := g.Resolve("refs/heads/" + pull.TargetBranch); err == nil && cur == head { |
| 459 | 467 | data["Mergeable"] = false |
| 460 | 468 | } |
| 469 | + if isOwner && data["Mergeable"] == true && r.URL.Query().Get("merge") == "1" { | |
| 470 | + data["Confirm"] = true | |
| 471 | + data["MergeTitle"] = mergeTitle(pull) | |
| 472 | + } | |
| 461 | 473 | } |
| 462 | 474 | } else { |
| 463 | 475 | data["Unrelated"] = true |
| @@ -471,6 +483,10 @@ func (s *Server) pull(w http.ResponseWriter, r *http.Request, repo Repo, rest st | ||
| 471 | 483 | s.render(w, r, "pull", page{Title: fmt.Sprintf("#%d %s", pull.Number, pull.Title), Error: r.URL.Query().Get("error"), Math: hasMath(data["Body"]), Data: data}) |
| 472 | 484 | } |
| 473 | 485 | |
| 486 | +func mergeTitle(pull Pull) string { | |
| 487 | + return fmt.Sprintf("Merge pull request #%d from %s", pull.Number, pull.SourceRepo.Path()+":"+pull.SourceBranch) | |
| 488 | +} | |
| 489 | + | |
| 474 | 490 | func (s *Server) fork(w http.ResponseWriter, r *http.Request, repo Repo) { |
| 475 | 491 | user := s.require(w, r) |
| 476 | 492 | if user == nil { |
static/style.css modified
| @@ -204,3 +204,7 @@ nav.filters a.active{color:var(--fg);font-weight:600} | ||
| 204 | 204 | .btn.block+form{margin-top:.4rem} |
| 205 | 205 | .btn:disabled{opacity:.5;cursor:default} |
| 206 | 206 | select{font:inherit;padding:.35rem .5rem;border:1px solid #ced4da;background:#fff} |
| 207 | +.mergeform{max-width:none;margin:.4rem 0 .8rem} | |
| 208 | +.mergeform input,.mergeform textarea{width:100%} | |
| 209 | +.mergeform .actions{gap:.4rem} | |
| 210 | +.panel a.btn.block{margin-top:.4rem} | |
templates/pull.html modified
| @@ -19,7 +19,13 @@ | ||
| 19 | 19 | {{if eq $pr.State "open"}} |
| 20 | 20 | {{if .Data.Unrelated}}<p>The branches have no common history.</p> |
| 21 | 21 | {{else if .Data.Mergeable}}<p>This branch can be merged automatically.</p>{{else}}<p>This branch has conflicts or nothing new to merge. Resolve locally, push, then update.</p>{{end}} |
| 22 | -{{if .Data.Owner}}<form method="post" action="/{{$p.Repo.Path}}/pulls/{{$pr.Number}}/merge"><button class="btn primary block"{{if not .Data.Mergeable}} disabled{{end}}>Merge pull request ▸</button></form>{{end}} | |
| 22 | +{{if .Data.Owner}}{{if .Data.Confirm}} | |
| 23 | +<form method="post" action="/{{$p.Repo.Path}}/pulls/{{$pr.Number}}/merge" class="stack mergeform"> | |
| 24 | +<label>Commit message <input name="title" value="{{.Data.MergeTitle}}" maxlength="200" required></label> | |
| 25 | +<label>Extended description <textarea name="body" rows="4">{{$pr.Title}}</textarea></label> | |
| 26 | +<div class="actions left"><button class="btn primary">Confirm merge ▸</button><a class="btn" href="/{{$p.Repo.Path}}/pulls/{{$pr.Number}}">Cancel</a></div> | |
| 27 | +</form> | |
| 28 | +{{else}}{{if .Data.Mergeable}}<a class="btn primary block" href="?merge=1">Merge pull request ▸</a>{{else}}<button class="btn primary block" disabled>Merge pull request ▸</button>{{end}}{{end}}{{end}} | |
| 23 | 29 | {{if or .Data.Owner .Data.Author}}<form method="post" action="/{{$p.Repo.Path}}/pulls/{{$pr.Number}}/update"><button class="btn block">Update from source ▸</button></form> |
| 24 | 30 | <form method="post" action="/{{$p.Repo.Path}}/pulls/{{$pr.Number}}/close"><button class="btn danger block">Close ▸</button></form>{{end}} |
| 25 | 31 | {{else if eq $pr.State "closed"}}<p>Closed without merging.</p>{{if or .Data.Owner .Data.Author}}<form method="post" action="/{{$p.Repo.Path}}/pulls/{{$pr.Number}}/reopen"><button class="btn block">Reopen ▸</button></form>{{end}} |