Skip to content

Commit 2b60c55

Browse files
committed
feat: add TestNoTODOComments audit check
Catches actionable TODO:, FIXME:, HACK:, XXX: markers in non-test Go source comments. Deferred work must be tracked in TASKS.md, not hidden in code. Prose mentions of the words are not flagged (only conventional marker forms with : ( / - suffixes). Zero violations. Signed-off-by: Jose Alekhinne <jose@ctx.ist>
1 parent 8580b99 commit 2b60c55

File tree

1 file changed

+95
-0
lines changed

1 file changed

+95
-0
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// / ctx: https://ctx.ist
2+
// ,'`./ do you remember?
3+
// `.,'\
4+
// \ Copyright 2026-present Context contributors.
5+
// SPDX-License-Identifier: Apache-2.0
6+
7+
package audit
8+
9+
import (
10+
"bufio"
11+
"os"
12+
"path/filepath"
13+
"regexp"
14+
"strings"
15+
"testing"
16+
"unicode/utf8"
17+
)
18+
19+
// todoPattern matches actionable TODO, FIXME, HACK,
20+
// and XXX markers in comments. Requires the marker
21+
// to be followed by a colon, parenthesis, or dash
22+
// (conventional action-item forms), not just prose
23+
// mentions of the word.
24+
var todoPattern = regexp.MustCompile(
25+
`//.*\b(TODO|FIXME|HACK|XXX)\s*[:(/-]` +
26+
`|/\*.*\b(TODO|FIXME|HACK|XXX)\s*[:(/-]`,
27+
)
28+
29+
// TestNoTODOComments ensures no TODO, FIXME, HACK, or
30+
// XXX comments exist in non-test Go source files.
31+
//
32+
// Deferred work must be tracked in TASKS.md, not
33+
// hidden in source comments. Test files are exempt.
34+
func TestNoTODOComments(t *testing.T) {
35+
var violations []string
36+
37+
walkErr := filepath.WalkDir(
38+
"../",
39+
func(path string, d os.DirEntry, err error) error {
40+
if err != nil {
41+
return err
42+
}
43+
if d.IsDir() {
44+
return nil
45+
}
46+
if !strings.HasSuffix(d.Name(), ".go") {
47+
return nil
48+
}
49+
if isTestFile(d.Name()) {
50+
return nil
51+
}
52+
53+
abs, absErr := filepath.Abs(path)
54+
if absErr != nil {
55+
return absErr
56+
}
57+
58+
data, readErr := os.ReadFile(path) //nolint:gosec
59+
if readErr != nil {
60+
return readErr
61+
}
62+
63+
scanner := bufio.NewScanner(
64+
strings.NewReader(string(data)),
65+
)
66+
lineNum := 0
67+
for scanner.Scan() {
68+
lineNum++
69+
line := scanner.Text()
70+
if todoPattern.MatchString(line) {
71+
// Trim for display.
72+
display := line
73+
if utf8.RuneCountInString(display) > 60 {
74+
display = display[:60] + "..."
75+
}
76+
violations = append(violations,
77+
abs+":"+
78+
itoa(lineNum)+
79+
": "+
80+
strings.TrimSpace(display),
81+
)
82+
}
83+
}
84+
85+
return scanner.Err()
86+
},
87+
)
88+
if walkErr != nil {
89+
t.Fatalf("filepath.WalkDir: %v", walkErr)
90+
}
91+
92+
for _, v := range violations {
93+
t.Error(v)
94+
}
95+
}

0 commit comments

Comments
 (0)