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.

Phase 3: a change request can be discussed

7c6e52e75f3a33be57a81663bc840edd6e14f7f9 · Keenan Nemetz · 17d ago · parent 3c5d11fa

Phase 3: a change request can be discussed

Until now the only ways to say something about a request were editing its body or
approving it. A review thread is now a pushed file like everything else:

	requests/<ulid>/comments/<ulid>.md    author + created, then the body

It is the *same file shape* as a comment on an issue and is read and written by the
same code (`issues.ParseComment`, `issues.RenderComment`, with `requests.Comment` as
an alias), so the thread inherited the validation, the markdown boundary and the
ownership rule instead of reimplementing them. That last one is the part worth
having: `pre-receive` compares the author on the old blob to the pushing account, so
a review comment is its author's to edit or delete, an admin may repair a thread
(audited), and rewriting the author line in the same push does not launder it.

`vole request comment <id> -m` prints the comment's id and the page anchor
(`#c-<ulid>`), `edit-comment` and `rm-comment` are the author's own words, and
`request show` prints the thread so the ids are discoverable at all — an id nobody
can see is an id nobody can use. Adding a comment is free, like adding one to an
issue: a new file's author is a claim, and the boundary has never pretended
otherwise.

The request's own file stays outside the ownership rule, for the reason an issue's
does: state, head and base are shared, and updating them is the author's normal edit.

Verified: TestParseReadsTheDiscussion (a thread plus an approval in one tree,
ordered by id), TestCommentNeedsAnAuthorAndATime and
TestUnknownFileInARequestIsRefused (the subtree stays a closed format, with both
expected shapes named), TestCommentPaths (a request comment is not an issue comment
and not an approval); and end to end through the binary,
TestRequestDiscussionIsPushedAndOwned — the empty state prints the command, the CLI
adds a comment, the page renders it with its anchor and `request show` lists it, a
writer is refused rewriting, adopting and deleting somebody else's comment, may join
the thread and may edit his own — with the issue-comment empty state assertion added
to TestIssuePushedThenRendered earlier. scripts/ci.sh green (gofmt, vet, build,
markdown links, go test -race ./...).

internal/web/requests.go +12

@@ -130,6 +130,16 @@ func (w *Web) RequestView(rw http.ResponseWriter, r *http.Request) {
130 130 alreadyMerged = true
131 131 }
132 132 }
133 // The review thread. Comments arrive by push, so they cross the same markdown
134 // boundary every other pushed body does — sanitised, never rendered raw.
135 type renderedComment struct {
136 requests.Comment
137 Body template.HTML
138 }
139 comments := make([]renderedComment, 0, len(req.Comments))
140 for _, cm := range req.Comments {
141 comments = append(comments, renderedComment{Comment: cm, Body: w.renderMarkdown(m.Name, cm.Body)})
142 }
133 143 added, removed := diffSummary(files)
134 144
135 145 // Would it land? A diff says what changed; it cannot say whether the branch
@@ -172,6 +182,7 @@ func (w *Web) RequestView(rw http.ResponseWriter, r *http.Request) {
172 182 Removed int
173 183 Truncated bool
174 184 AlreadyMerged bool
185 Comments []renderedComment
175 186 Conflicts []string
176 187 MergeChecked bool
177 188 Required int
@@ -179,5 +190,6 @@ func (w *Web) RequestView(rw http.ResponseWriter, r *http.Request) {
179 190 }{Page: w.base(m.Name + " · " + req.Title), Name: m.Name, Request: req,
180 191 Description: w.renderMarkdown(m.Name, req.Description), Approvals: approvals, Checks: checks,
181 192 Files: files, Added: added, Removed: removed, Truncated: truncated, AlreadyMerged: alreadyMerged,
193 Comments: comments,
182 194 Conflicts: conflicts, MergeChecked: mergeChecked, Required: required, Current: current}, 0)
183 195 }