vole
Clone
Read only, no credentials:
https://rodent.software/vole.git
Write over SSH with a registered key:
git clone ssh://git@rodent.software:2222/vole.git
A free and open-source forge that lives in your Git repo.
Phase 7 slice 1: review on the web, so approving does not start with a clone
78912785b00227cffe3f8fb26b057cd60159a6b4 · Keenan Nemetz · 18d ago · parent 9bea7f11
Phase 7 slice 1: review on the web, so approving does not start with a clone Phase 7 is re-scoped: signing is deferred (the SSH handshake already establishes who pushed, and there is no third-party verifier here), and the phase is now about the experience of using the forge. - GET /r/<repo>/commit/<sha>: a commit's metadata and the patch it introduced, per-file hunks with line numbers; the commit list links to it - change requests show the same diff, computed three-dot: a review is what the branch adds since it diverged, not every commit main gained meanwhile - diffs are capped at 512 KiB and labelled when cut, binary files are named rather than faked, and every line is escaped (a <script> line is a test) - the repository README renders on its home page and markdown blobs render as markdown, through the sanitiser issues already use
internal/web/requests.go +15−6
| @@ -114,18 +114,23 @@ func (w *Web) RequestView(rw http.ResponseWriter, r *http.Request) { | |||
| 114 | 114 | } | |
| 115 | 115 | ||
| 116 | 116 | // The diff is computed from git on every view: it is cheap for one branch and | |
| 117 | // always matches what the approver is being asked to approve. | ||
| 118 | var changed []string | ||
| 117 | // always matches what the approver is being asked to approve. Three-dot range: | ||
| 118 | // a review is about what the branch adds since it diverged, not about every | ||
| 119 | // commit main gained meanwhile. | ||
| 120 | var files []diffFile | ||
| 121 | truncated := false | ||
| 119 | 122 | alreadyMerged := false | |
| 120 | 123 | if req.Head != "" { | |
| 121 | if files, err := m.Git().DiffNameStatus(req.Base, req.Head); err == nil { | ||
| 122 | changed = files | ||
| 124 | if patch, cut, err := m.Git().Diff(req.Base+"..."+req.Head, "", diffCap); err == nil { | ||
| 125 | files = parseDiff(patch) | ||
| 126 | truncated = cut | ||
| 123 | 127 | } | |
| 124 | 128 | // An empty diff means one of two very different things, so say which. | |
| 125 | 129 | if in, err := m.Git().IsAncestor(req.Head, req.Base); err == nil && in { | |
| 126 | 130 | alreadyMerged = true | |
| 127 | 131 | } | |
| 128 | 132 | } | |
| 133 | added, removed := diffSummary(files) | ||
| 129 | 134 | w.render(rw, "request", struct { | |
| 130 | 135 | Page | |
| 131 | 136 | Name string | |
| @@ -133,8 +138,12 @@ func (w *Web) RequestView(rw http.ResponseWriter, r *http.Request) { | |||
| 133 | 138 | Description template.HTML | |
| 134 | 139 | Approvals []requestApproval | |
| 135 | 140 | Checks []checkRow | |
| 136 | Changed []string | ||
| 141 | Files []diffFile | ||
| 142 | Added int | ||
| 143 | Removed int | ||
| 144 | Truncated bool | ||
| 137 | 145 | AlreadyMerged bool | |
| 138 | 146 | }{Page: w.base(m.Name + " · " + req.Title), Name: m.Name, Request: req, | |
| 139 | Description: w.renderMarkdown(m.Name, req.Description), Approvals: approvals, Checks: checks, Changed: changed, AlreadyMerged: alreadyMerged}, 0) | ||
| 147 | Description: w.renderMarkdown(m.Name, req.Description), Approvals: approvals, Checks: checks, | ||
| 148 | Files: files, Added: added, Removed: removed, Truncated: truncated, AlreadyMerged: alreadyMerged}, 0) | ||
| 140 | 149 | } | |