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/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.

Show real accounts as repository contributors

a32a859a08276681497be390d6f7195098a97ab4 · Keenan Nemetz · 5d ago · parent 802e0e52

Show real accounts as repository contributors

Count contributors from the change and issue records instead of the author text in commits: changes merged, issues those changes fixed, issues the reporter opened that were fixed, and reviews that named the merged head. The overview lists accounts by that work with compact icon counts and full labels in tooltips. The shortlog-derived contributor table and its refresh path are gone.

server/ui_test.go +54

@@ -538,6 +538,60 @@ func TestOverviewShowsRecentOpenIssuesAndChanges(t *testing.T) {
538 538 }
539 539 }
540 540
541 func TestOverviewContributorsAreAccountsNotCommitAuthors(t *testing.T) {
542 t.Parallel()
543 f := newFixture(t)
544 f.publish(f.repo)
545 f.addWriter(t) // wilbur
546
547 const (
548 keenanIssue = "01M5JR2JK29KKMAA1T9MDNTP11"
549 wilburIssue = "01M5JR2JK29KKMAA1T9MDNTP12"
550 changeID = "01M5JR2JK29KKMAA1T9MDNTR11"
551 )
552 head := strings.Repeat("a", 40)
553 issues := f.issuesRepo(t, map[string]string{
554 "issues/" + keenanIssue + "/issue.md": issueFile(
555 "Reported by keenan", "keenan", "open", "2026-10-22T21:00:00Z", nil, ""),
556 "issues/" + wilburIssue + "/issue.md": issueFile(
557 "Reported by wilbur", "wilbur", "open", "2026-10-22T21:01:00Z", nil, ""),
558 })
559 if _, errs, err := f.git(issues, "push", f.sshURL(f.repo), "HEAD:refs/heads/vole"); err != nil {
560 t.Fatalf("push issues: %v\n%s", err, errs)
561 }
562
563 // Wilbur's change closes both reports and carries keenan's approval of the
564 // exact head that merged.
565 meta := f.newMetaRepo(t)
566 if err := meta.apply(map[string]string{
567 "issues/" + keenanIssue + "/issue.md": issueFile(
568 "Reported by keenan", "keenan", "closed", "2026-10-22T21:00:00Z", nil, ""),
569 "issues/" + wilburIssue + "/issue.md": issueFile(
570 "Reported by wilbur", "wilbur", "closed", "2026-10-22T21:01:00Z", nil, ""),
571 "requests/" + changeID + "/request.md": requestFileMerged(
572 "Fix both reports", "main", head, "wilbur", "keenan",
573 []string{keenanIssue, wilburIssue}),
574 "requests/" + changeID + "/approvals/keenan.md": approvalFile("main", head),
575 }, "merge wilbur's change"); err != nil {
576 t.Fatalf("push merged change: %v", err)
577 }
578
579 code, body := f.get("/r/" + f.repo)
580 if code != 200 {
581 t.Fatalf("overview = %d", code)
582 }
583 for _, want := range []string{
584 "Contributors",
585 `href="/u/wilbur"`,
586 `data-tip="1 change merged"`, `data-tip="2 issues fixed"`, `data-tip="1 issue reported"`,
587 `href="/u/keenan"`, `data-tip="1 review"`,
588 } {
589 if !strings.Contains(body, want) {
590 t.Fatalf("overview does not show %q:\n%s", want, body)
591 }
592 }
593 }
594
541 595 func TestCodeBrowserTreeAndFragments(t *testing.T) {
542 596 t.Parallel()
543 597 f := newFixture(t)