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.
Say what each change is waiting for in the list
7cc36ba0f4ba96d3f4938b13758b2cc20c22375a · Keenan Nemetz · 5d ago · parent 946d2fd4
Say what each change is waiting for in the list A change spends most of its life in states "open" cannot describe: held for a maintainer to allow CI, running its checks, failed, waiting for a reviewer, conflicting with its base. The list now says which of those it is, in one column, with a tooltip that explains the label. The answer comes from facts a list can afford: the approvals it already counts, one batched run-queue query for every head on the page, the contributor allowance (one ref listing, not one per row), and — only for a change that would otherwise read as ready — whether it still merges into its base. The full landing plan stays on the detail page. The rest of the row follows the issue list: the author and opening moved under the title, the comment count sits at the end of that line, and the last column is "Updated", the newest commit over the request's directory. The list sorts by it. The separate Author, Approvals and Age columns are gone. Closes #194
forge/index/refresh.go +20−7
| @@ -98,12 +98,17 @@ func (s *Store) IndexRepo(m *repo.Meta) error { | |||
| 98 | 98 | if err != nil { | |
| 99 | 99 | return err | |
| 100 | 100 | } | |
| 101 | // One `git log` dates every issue's last activity. The branch has no updated | ||
| 102 | // field to read, and a process per issue would make a rebuild cost the queue. | ||
| 101 | // One `git log` dates every issue's and request's last activity. The branch has | ||
| 102 | // no updated field to read, and a process per entity would make a rebuild cost | ||
| 103 | // the queue. | ||
| 103 | 104 | touchTimes, err := issueTouchTimes(g, commit) | |
| 104 | 105 | if err != nil { | |
| 105 | 106 | return err | |
| 106 | 107 | } | |
| 108 | requestTimes, err := requestTouchTimes(g, commit) | ||
| 109 | if err != nil { | ||
| 110 | return err | ||
| 111 | } | ||
| 107 | 112 | ||
| 108 | 113 | tx, err := s.db.Begin() | |
| 109 | 114 | if err != nil { | |
| @@ -138,7 +143,7 @@ func (s *Store) IndexRepo(m *repo.Meta) error { | |||
| 138 | 143 | } | |
| 139 | 144 | } | |
| 140 | 145 | for _, req := range requests { | |
| 141 | if err := insertRequest(tx, m.ID, req); err != nil { | ||
| 146 | if err := insertRequest(tx, m.ID, req, requestTimes[req.ID]); err != nil { | ||
| 142 | 147 | return err | |
| 143 | 148 | } | |
| 144 | 149 | if err := replaceComments(tx, m.ID, commentKindRequest, req.ID, req.Title, req.Comments); err != nil { | |
| @@ -220,9 +225,10 @@ func (s *Store) indexFrom(m *repo.Meta, from, to string) error { | |||
| 220 | 225 | } | |
| 221 | 226 | } | |
| 222 | 227 | ||
| 223 | // The commits also date each issue's last activity, which is what the list | ||
| 224 | // sorts by. They name every issue the range touched, including one edited and | ||
| 225 | // then edited back: the tree diff cannot see those, but the issue still moved. | ||
| 228 | // The commits also date each entity's last activity, which is what the lists | ||
| 229 | // sort by. They name every issue and request the range touched, including one | ||
| 230 | // edited and then edited back: the tree diff cannot see those, but the entity | ||
| 231 | // still moved. | ||
| 226 | 232 | touchTimes, err := issueTouchTimes(g, from+".."+to) | |
| 227 | 233 | if err != nil { | |
| 228 | 234 | return err | |
| @@ -230,6 +236,13 @@ func (s *Store) indexFrom(m *repo.Meta, from, to string) error { | |||
| 230 | 236 | for id := range touchTimes { | |
| 231 | 237 | issueIDs[id] = true | |
| 232 | 238 | } | |
| 239 | requestTimes, err := requestTouchTimes(g, from+".."+to) | ||
| 240 | if err != nil { | ||
| 241 | return err | ||
| 242 | } | ||
| 243 | for id := range requestTimes { | ||
| 244 | requestIDs[id] = true | ||
| 245 | } | ||
| 233 | 246 | ||
| 234 | 247 | // Read every changed entity before opening the write transaction. `to` is a | |
| 235 | 248 | // commit, so a concurrent push cannot make the rows describe two tree states. | |
| @@ -324,7 +337,7 @@ func (s *Store) indexFrom(m *repo.Meta, from, to string) error { | |||
| 324 | 337 | if err := deleteRequest(tx, m.ID, req.ID); err != nil { | |
| 325 | 338 | return err | |
| 326 | 339 | } | |
| 327 | if err := insertRequest(tx, m.ID, req); err != nil { | ||
| 340 | if err := insertRequest(tx, m.ID, req, requestTimes[req.ID]); err != nil { | ||
| 328 | 341 | return err | |
| 329 | 342 | } | |
| 330 | 343 | if err := replaceComments(tx, m.ID, commentKindRequest, req.ID, req.Title, req.Comments); err != nil { | |