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.
Turn the code tab into an editor-style file browser
a464f8927bfb3edcf170694f120dc9b3f68320da · Keenan Nemetz · 15d ago · parent f09ef39e
Turn the code tab into an editor-style file browser - Add a persistent nested file tree with HTMX file and folder swaps, active rows, expanded ancestors, and deep-link support. - Share one page header across every repository tab: title and summary on the left, tab actions grouped on the right. - Make the repository name the first tab and show visibility with a lock or globe icon derived from the ACL. - Open markdown as syntax-highlighted source by default, with an explicit full-width preview toggle. - Point the branch breadcrumb at the Code overview instead of a second root directory listing. - Move contributor-branch CI approval from the code browser to the Runs tab. - Extend UI tests for the file tree, fragments, repo visibility, markdown source/preview, shared headers, and the moved CI control.
server/auth_test.go +6−2
| @@ -433,7 +433,7 @@ jobs: | |||
| 433 | 433 | } | |
| 434 | 434 | ||
| 435 | 435 | contribSess, contribCookie := f.browserSession(t, contrib.ID) | |
| 436 | resp, body := f.browserGet(t, "/r/"+f.repo+"/code", contribCookie) | ||
| 436 | resp, body := f.browserGet(t, "/r/"+f.repo+"/runs", contribCookie) | ||
| 437 | 437 | if resp.StatusCode != http.StatusOK || !strings.Contains(body, "waiting for a maintainer") { | |
| 438 | 438 | t.Fatalf("contributor branch status: status=%d body=%s", resp.StatusCode, body) | |
| 439 | 439 | } | |
| @@ -445,10 +445,14 @@ jobs: | |||
| 445 | 445 | } | |
| 446 | 446 | ||
| 447 | 447 | ownerSess, ownerCookie := f.browserSession(t, f.ownerID) | |
| 448 | resp, body = f.browserGet(t, "/r/"+f.repo+"/code", ownerCookie) | ||
| 448 | resp, body = f.browserGet(t, "/r/"+f.repo+"/runs", ownerCookie) | ||
| 449 | 449 | if resp.StatusCode != http.StatusOK || !strings.Contains(body, "Allow CI for this tip") { | |
| 450 | 450 | t.Fatalf("maintainer CI control missing: status=%d body=%s", resp.StatusCode, body) | |
| 451 | 451 | } | |
| 452 | resp, codePage := f.browserGet(t, "/r/"+f.repo+"/code", ownerCookie) | ||
| 453 | if resp.StatusCode != http.StatusOK || strings.Contains(codePage, "Allow CI for this tip") { | ||
| 454 | t.Fatalf("contributor CI control should not be in the code browser: status=%d body=%s", resp.StatusCode, codePage) | ||
| 455 | } | ||
| 452 | 456 | resp, body = f.browserPost(t, "/r/"+f.repo+"/ci/allow", ownerCookie, url.Values{ | |
| 453 | 457 | "csrf": {ownerSess.CSRF}, "ref": {"refs/heads/" + ref}, | |
| 454 | 458 | }) | |