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.

Code

395 commit(s) on main

update readme Keenan Nemetz · 28m ago 32290114
history blame raw 3.0 KiB
1package git
2
3// TouchTimes answers "when was this file last changed?" for a whole subtree in
4// one `git log`. These tests pin the two properties the issue list depends on:
5// the newest commit wins, and a commit range only names the paths it touched.
6
7import (
8 "os"
9 "os/exec"
10 "path/filepath"
11 "strings"
12 "testing"
13 "time"
14)
15
16func touchRepo(t *testing.T) *Repo {
17 t.Helper()
18 dir := t.TempDir()
19 run := func(at time.Time, args ...string) {
20 t.Helper()
21 cmd := exec.Command("git", args...)
22 cmd.Dir = dir
23 date := at.Format(time.RFC3339)
24 cmd.Env = append(os.Environ(),
25 "GIT_CONFIG_GLOBAL=/dev/null", "GIT_CONFIG_SYSTEM=/dev/null",
26 "GIT_AUTHOR_NAME=t", "GIT_AUTHOR_EMAIL=t@example.com",
27 "GIT_COMMITTER_NAME=t", "GIT_COMMITTER_EMAIL=t@example.com",
28 "GIT_AUTHOR_DATE="+date, "GIT_COMMITTER_DATE="+date)
29 if out, err := cmd.CombinedOutput(); err != nil {
30 t.Fatalf("git %s: %v: %s", strings.Join(args, " "), err, out)
31 }
32 }
33 write := func(name, content string) {
34 t.Helper()
35 p := filepath.Join(dir, name)
36 if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil {
37 t.Fatal(err)
38 }
39 if err := os.WriteFile(p, []byte(content), 0o644); err != nil {
40 t.Fatal(err)
41 }
42 }
43 first := time.Date(2026, 1, 1, 12, 0, 0, 0, time.UTC)
44 second := first.Add(24 * time.Hour)
45 third := second.Add(24 * time.Hour)
46
47 run(first, "init", "-q", "-b", "main")
48 write("issues/a/issue.md", "a\n")
49 write("issues/b/issue.md", "b\n")
50 run(first, "add", "-A")
51 run(first, "commit", "-qm", "open both")
52
53 write("issues/b/issue.md", "b, edited\n")
54 run(second, "add", "-A")
55 run(second, "commit", "-qm", "edit b")
56
57 write("issues/b/comments/c.md", "a comment\n")
58 run(third, "add", "-A")
59 run(third, "commit", "-qm", "comment on b")
60 return open(t, dir)
61}
62
63func TestTouchTimesKeepsTheNewestCommitPerPath(t *testing.T) {
64 t.Parallel()
65 r := touchRepo(t)
66 first := time.Date(2026, 1, 1, 12, 0, 0, 0, time.UTC)
67 second := first.Add(24 * time.Hour)
68 third := second.Add(24 * time.Hour)
69
70 times, err := r.TouchTimes("HEAD", "issues")
71 if err != nil {
72 t.Fatalf("TouchTimes: %v", err)
73 }
74 want := map[string]int64{
75 "issues/a/issue.md": first.Unix(),
76 "issues/b/issue.md": second.Unix(),
77 "issues/b/comments/c.md": third.Unix(),
78 }
79 if len(times) != len(want) {
80 t.Fatalf("TouchTimes = %v, want %v", times, want)
81 }
82 for path, when := range want {
83 if got, ok := times[path]; !ok || got != when {
84 t.Fatalf("%s = %d (present %v), want %d", path, got, ok, when)
85 }
86 }
87}
88
89func TestTouchTimesReadsOnlyTheRangeItIsGiven(t *testing.T) {
90 t.Parallel()
91 r := touchRepo(t)
92 third := time.Date(2026, 1, 3, 12, 0, 0, 0, time.UTC)
93
94 times, err := r.TouchTimes("HEAD~1..HEAD", "issues")
95 if err != nil {
96 t.Fatalf("TouchTimes: %v", err)
97 }
98 if len(times) != 1 || times["issues/b/comments/c.md"] != third.Unix() {
99 t.Fatalf("range TouchTimes = %v, want only the comment at %d", times, third.Unix())
100 }
101
102 empty, err := r.TouchTimes("", "issues")
103 if err != nil || empty != nil {
104 t.Fatalf("TouchTimes with no rev = %v, %v; want no rows and no error", empty, err)
105 }
106}
107