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 an issue's linked changes and commits in the sidebar

fd9aa8ed41eb04a21fe73fbc0c6bd14762abd735 · Keenan Nemetz · 1d ago · parent c980fe53

server/web/issues.go +50−3

@@ -7,6 +7,7 @@ import (
7 7 "sort"
8 8 "strconv"
9 9 "strings"
10 "time"
10 11
11 12 "github.com/rodent-software/vole/core/git"
12 13 voleid "github.com/rodent-software/vole/core/id"
@@ -164,12 +165,25 @@ type issueSidebarView struct {
164 165 Error string
165 166 }
166 167
168 // issueChange is one change request linked to an issue. It carries what the
169 // sidebar row shows: the number that names it, the title that identifies it, and
170 // the state so a merged or closed change is not read as pending work.
171 type issueChange struct {
172 ID string
173 Number int
174 Title string
175 State string
176 Author string
177 Created time.Time
178 }
179
167 180 // issuePageView is the full issue page: the sidebar plus the conversation.
168 181 type issuePageView struct {
169 182 issueSidebarView
170 Description template.HTML
171 Thread threadView
172 Backlinks []git.Commit
183 Description template.HTML
184 Thread threadView
185 Backlinks []git.Commit
186 LinkedChanges []issueChange
173 187 }
174 188
175 189 // issueSidebar is the data the issue page and its HTMX fragments share. The
@@ -237,9 +251,42 @@ func (w *Web) IssueView(rw http.ResponseWriter, r *http.Request) {
237 251 Description: w.renderMarkdown(m.Name, iss.Description),
238 252 Thread: w.issueThread(r, m, iss, ""),
239 253 Backlinks: w.backlinks(m, iss.ID),
254 LinkedChanges: w.issueLinkedChanges(memoOf(r), m, iss.ID),
240 255 }, 0)
241 256 }
242 257
258 // issueLinkedChanges finds the change requests whose closes list names the
259 // issue. The index stores the link in both directions, so this is one lookup
260 // rather than a read of every request on the metadata branch.
261 func (w *Web) issueLinkedChanges(memo *requestMemo, m *repo.Meta, id string) []issueChange {
262 if w.Index == nil {
263 return nil
264 }
265 if err := w.ensureIndex(memo, m); err != nil {
266 return nil
267 }
268 ids, err := w.Index.Closes(m.ID, id)
269 if err != nil || len(ids) == 0 {
270 return nil
271 }
272 rows, err := w.Index.RequestsByID(m.ID, ids)
273 if err != nil {
274 return nil
275 }
276 out := make([]issueChange, 0, len(ids))
277 for _, id := range ids {
278 row, ok := rows[id]
279 if !ok {
280 continue
281 }
282 out = append(out, issueChange{
283 ID: row.ID, Number: row.Number, Title: row.Title,
284 State: row.State, Author: row.Author, Created: row.Created,
285 })
286 }
287 return out
288 }
289
243 290 // backlinks finds commits whose message mentions the issue. git does the search,
244 291 // so there is no second index to keep in sync.
245 292 func (w *Web) backlinks(m *repo.Meta, id string) []git.Commit {