Skip to content

Commit 713b95d

Browse files
committed
chore: Add linting rule to help catch InTx misuse
This isn't perfect, as if you nest your misuse in another code block like an if statement, it won't catch it :/. It is better than nothing
1 parent dcf03d8 commit 713b95d

File tree

1 file changed

+35
-0
lines changed

1 file changed

+35
-0
lines changed

scripts/rules.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,38 @@ func doNotCallTFailNowInsideGoroutine(m dsl.Matcher) {
6969
Where(m["t"].Type.Implements("testing.TB") && m["fail"].Text.Matches("^(FailNow|Fatal|Fatalf)$")).
7070
Report("Do not call functions that may call t.FailNow in a goroutine, as this can cause data races (see testing.go:834)")
7171
}
72+
73+
// InTx checks to ensure the database used inside the transaction closure is the transaction
74+
// database, and not the original database that creates the tx.
75+
func InTx(m dsl.Matcher) {
76+
m.Import("github.com/coder/coder/coderd/database")
77+
78+
m.Match(`
79+
$x.InTx(func($y database.Store) error {
80+
$*_
81+
$*_ = $x.$f($*_)
82+
$*_
83+
})
84+
`).Where(m["x"].Text != m["y"].Text && m["x"].Type.Implements("database.Store")).
85+
At(m["f"]).
86+
Report("Do not use the database directly within the InTx closure. Use '$y' instead of '$x'.")
87+
88+
// When using a tx closure, ensure that if you pass the db to another
89+
// function inside the closure, it is the tx.
90+
// This will miss more complex cases such as passing the db as apart
91+
// of another struct.
92+
m.Match(`
93+
$x.InTx(func($y database.Store) error {
94+
$*_
95+
$*_ = $f($*_, $x, $*_)
96+
$*_
97+
})
98+
`, `
99+
$x.InTx(func($y database.Store) error {
100+
$*_
101+
$f($*_, $x, $*_)
102+
$*_
103+
})
104+
`).Where(m["x"].Text != m["y"].Text && m["x"].Type.Implements("database.Store")).
105+
At(m["f"]).Report("Pass the tx database into the '$f' function inside the closure. Use '$y' over $x'")
106+
}

0 commit comments

Comments
 (0)