Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Show which branch a change request came from

8e1005eb2c104934adef950c5afc090d4025ce06 · Keenan Nemetz · 13d ago · parent b7ac1a00

Show which branch a change request came from

A request records the exact commit under review, and the page showed only
that: `main ← 43f98bcd`. The branch the work is on is how people talk about
a change, fetch it, and find it after it lands, and it was being thrown
away when the request was opened — the web form resolved the chosen branch
to a commit and kept only the commit.

`request.md` now records `head_ref:` beside `head:`. It is a display hint
and nothing else: approvals, checks, the diff and the landing gate still
name the commit, and a test pins that a branch name cannot authorise a
different tip. The request page, the request list and `vole change show`
show it, and the page marks the branch as moved or deleted when it no
longer points at the reviewed commit, so the name reads as provenance
rather than as a claim about what is being reviewed.

It is optional on read: records written before it existed still load, and
a request opened from a bare commit id records no branch.

server/web_test.go +103

@@ -196,6 +196,109 @@ func TestMergedRequestStillShowsWhatLanded(t *testing.T) {
196 196 }
197 197 }
198 198
199 // TestRequestRecordsTheBranchItCameFrom: a request names the exact commit under
200 // review, and the page shows the commit. The branch it was opened from is worth
201 // showing too — it is how people find and fetch the change — as long as the page
202 // says so when the branch has moved past that commit. A request opened from a bare
203 // commit records no branch, and one written before the field existed still loads.
204 func TestRequestRecordsTheBranchItCameFrom(t *testing.T) {
205 t.Parallel()
206 f := newFixture(t)
207 f.publish(f.repo)
208
209 base := workRepo(t, map[string]string{"readme.md": "v1\n"})
210 if _, errs, err := f.git(base, "push", f.sshURL(f.repo), "main:refs/heads/main"); err != nil {
211 t.Fatalf("main push: %s", errs)
212 }
213 feature, head := f.cloneWithChange(t, map[string]string{"readme.md": "v1\nfeature line\n"}, "feature")
214 // The clone works on the default branch; name the pushed branch locally too, so
215 // --head can name a branch the way a contributor would.
216 if _, errs, err := runGit(t, feature, "branch", "feature"); err != nil {
217 t.Fatalf("branch: %s", errs)
218 }
219 if _, errs, err := f.git(feature, "push", f.sshURL(f.repo), "HEAD:refs/heads/feature"); err != nil {
220 t.Fatalf("feature push: %s", errs)
221 }
222
223 out, errs, err := f.cli(feature, "change", "new", "--title", "Land the feature",
224 "--base", "main", "--head", "feature", "-m", "why this change")
225 if err != nil {
226 t.Fatalf("change new: %v\n%s", err, errs)
227 }
228 id := strings.Fields(out)[0]
229 recordPath := "refs/heads/vole:requests/" + id + "/request.md"
230 record, _, err := runGit(t, filepath.Join(f.cfg.ReposDir(), f.repo+".git"), "show", recordPath)
231 if err != nil {
232 t.Fatalf("read the request: %v", err)
233 }
234 for _, want := range []string{"head: " + head, "head_ref: feature"} {
235 if !strings.Contains(record, want) {
236 t.Fatalf("the request is missing %q:\n%s", want, record)
237 }
238 }
239
240 code, body := f.get("/r/" + f.repo + "/requests/" + id)
241 if code != 200 {
242 t.Fatalf("request page = %d", code)
243 }
244 if !strings.Contains(body, ">feature</code>") {
245 t.Fatalf("the request page does not name the branch it came from:\n%s", body)
246 }
247 _, body = f.get("/r/" + f.repo + "/requests")
248 if !strings.Contains(body, ">feature</code>") {
249 t.Fatalf("the request list does not name the branch it came from:\n%s", body)
250 }
251 out, _, err = f.cli(feature, "change", "show", id)
252 if err != nil {
253 t.Fatalf("change show: %v", err)
254 }
255 if !strings.Contains(out, "branch: feature") {
256 t.Fatalf("change show does not name the branch:\n%s", out)
257 }
258
259 // A branch that moves past the reviewed commit is still the branch the request
260 // came from, but the page must not present it as what is being reviewed.
261 if err := os.WriteFile(filepath.Join(feature, "readme.md"), []byte("v1\nfeature line\nand more\n"), 0o644); err != nil {
262 t.Fatal(err)
263 }
264 if _, errs, err := runGit(t, feature, "commit", "-qam", "fixup"); err != nil {
265 t.Fatalf("commit: %s", errs)
266 }
267 if _, errs, err := f.git(feature, "push", f.sshURL(f.repo), "HEAD:refs/heads/feature"); err != nil {
268 t.Fatalf("fixup push: %s", errs)
269 }
270 _, body = f.get("/r/" + f.repo + "/requests/" + id)
271 if !strings.Contains(body, "branch moved") || !strings.Contains(body, "/commit/"+head) {
272 t.Fatalf("a moved branch is not labelled, or the reviewed commit is gone:\n%s", body)
273 }
274
275 // A branch that is gone is still the branch the request came from, and the page
276 // says so instead of dropping the name or pretending it can check it.
277 if _, errs, err := f.git(feature, "push", f.sshURL(f.repo), ":refs/heads/feature"); err != nil {
278 t.Fatalf("delete branch: %s", errs)
279 }
280 _, body = f.get("/r/" + f.repo + "/requests/" + id)
281 if !strings.Contains(body, "branch deleted") || !strings.Contains(body, ">feature</code>") {
282 t.Fatalf("a deleted branch is not labelled, or its name is gone:\n%s", body)
283 }
284
285 // A raw commit is a head with no branch behind it.
286 out, errs, err = f.cli(feature, "change", "new", "--title", "From a commit",
287 "--base", "main", "--head", head, "-m", "why this change")
288 if err != nil {
289 t.Fatalf("change new from a commit: %v\n%s", err, errs)
290 }
291 commitID := strings.Fields(out)[0]
292 record, _, err = runGit(t, filepath.Join(f.cfg.ReposDir(), f.repo+".git"),
293 "show", "refs/heads/vole:requests/"+commitID+"/request.md")
294 if err != nil {
295 t.Fatalf("read the commit request: %v", err)
296 }
297 if strings.Contains(record, "head_ref:") {
298 t.Fatalf("a request opened from a bare commit recorded a branch:\n%s", record)
299 }
300 }
301
199 302 // TestCommitPageEscapesFileContent matters because the web renders other people's
200 303 // commits: a diff that executes a tag is an XSS, not a syntax error.
201 304 func TestCommitPageEscapesFileContent(t *testing.T) {