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.
Record the default branch summary when a push lands
8dc56e4e258dd56e2c20776f80d61dbed4993f31 · Keenan Nemetz · 10d ago · parent 20442b59
Record the default branch summary when a push lands The landing card showed the default branch tip and the language it is mostly made of by running `symbolic-ref`, `rev-parse`, `log -1` and `ls-tree -r` per repository on every home page read. Those facts change only when a push moves the branch, so the push now records them. - `repos` carries head_sha, head_subject, head_author, head_when, language and lang_class, and `Index.Entry` returns them with the rest of the row. - `Store.RefreshHead` recomputes the summary and skips the tree walk when the recorded tip is still the branch tip, so a metadata or tag push costs one rev-parse. It runs from post-receive, from the rebuild, and after the default branch changes in settings. - The language mapping moved to `internal/lang`, shared by the web pages and the summary; `fileClass` and `languageFor` are now one table. - The home cards read the head, language, counts, ACL and newest event time from the index. The home page starts no git process at all; the all-git card builder stays as the fallback for a Web without an index. Load harness at concurrency 4 with three repositories: home goes from 243 to 749 req/s, p50 from 16 ms to 5 ms, and the server runs no git child process for those requests.
server/web/file_icons_test.go +6−2
| @@ -1,6 +1,10 @@ | |||
| 1 | 1 | package web | |
| 2 | 2 | ||
| 3 | import "testing" | ||
| 3 | import ( | ||
| 4 | "testing" | ||
| 5 | |||
| 6 | "github.com/rodent-software/vole/internal/lang" | ||
| 7 | ) | ||
| 4 | 8 | ||
| 5 | 9 | func TestFileIconsChooseByExtension(t *testing.T) { | |
| 6 | 10 | t.Parallel() | |
| @@ -20,7 +24,7 @@ func TestFileIconsChooseByExtension(t *testing.T) { | |||
| 20 | 24 | if got := fileIcon(c.name); got != c.icon { | |
| 21 | 25 | t.Errorf("%s icon = %q, want %q", c.name, got, c.icon) | |
| 22 | 26 | } | |
| 23 | if got := fileClass(c.name); got != c.class { | ||
| 27 | if got := lang.Class(c.name); got != c.class { | ||
| 24 | 28 | t.Errorf("%s class = %q, want %q", c.name, got, c.class) | |
| 25 | 29 | } | |
| 26 | 30 | if _, ok := iconPaths[c.icon]; !ok { | |