Skip to content

Commit 8427f90

Browse files
committed
feat: clean up and use more standard library
1 parent 3d6d305 commit 8427f90

File tree

18 files changed

+626
-801
lines changed

18 files changed

+626
-801
lines changed

cmd/app.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cmd
22

33
import (
44
"context"
5+
"github.com/somebadcode/commit-tool/internal/replaceattr"
56
"log/slog"
67
"os"
78
"os/signal"
@@ -12,7 +13,6 @@ import (
1213
"github.com/urfave/cli/v2"
1314

1415
"github.com/somebadcode/commit-tool/cmd/lint"
15-
"github.com/somebadcode/commit-tool/internal/replaceattr"
1616
)
1717

1818
type StatusCode = int
@@ -93,7 +93,7 @@ func Execute() StatusCode {
9393
Commands: []*cli.Command{
9494
{
9595
Name: "lint",
96-
Aliases: []string{"linter"},
96+
Aliases: []string{"commitlinter"},
9797
UsageText: "lint [command options]",
9898
Description: "lint git repository",
9999
Action: func(c *cli.Context) error {

cmd/lint/lint.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@ package lint
33
import (
44
"context"
55
"fmt"
6-
"github.com/somebadcode/commit-tool/slognop"
76
"log/slog"
87
"os"
98

109
"github.com/go-git/go-git/v5"
1110
"github.com/go-git/go-git/v5/plumbing"
1211
"github.com/urfave/cli/v2"
1312

13+
"github.com/somebadcode/commit-tool/commitlinter"
1414
"github.com/somebadcode/commit-tool/linter"
15-
"github.com/somebadcode/commit-tool/traverser"
1615
)
1716

1817
type Command struct {
@@ -24,7 +23,7 @@ type Command struct {
2423

2524
func (cmd *Command) Validate() error {
2625
if cmd.Logger == nil {
27-
cmd.Logger = slognop.New()
26+
cmd.Logger = slog.New(slog.DiscardHandler)
2827
}
2928

3029
if cmd.RepositoryPath == "" {
@@ -44,15 +43,15 @@ func (cmd *Command) Execute(ctx context.Context) error {
4443
return err
4544
}
4645

47-
trav := traverser.Traverser{
46+
trav := linter.Linter{
4847
Rev: cmd.Revision,
4948
OtherRev: cmd.OtherRevision,
50-
ReportFunc: traverser.SlogReporter(cmd.Logger),
51-
VisitFunc: linter.Linter{
52-
Rules: linter.Rules{
53-
linter.RuleConventionalCommit,
49+
ReportFunc: linter.SlogReporter(cmd.Logger),
50+
CommitLinter: &commitlinter.Linter{
51+
Rules: commitlinter.Rules{
52+
commitlinter.RuleConventionalCommit,
5453
},
55-
}.Lint,
54+
},
5655
Logger: cmd.Logger,
5756
}
5857

linter/filter.go renamed to commitlinter/filter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package linter
1+
package commitlinter
22

33
import (
44
"fmt"

commitlinter/linter.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package commitlinter
2+
3+
import (
4+
"errors"
5+
6+
"github.com/go-git/go-git/v5/plumbing/object"
7+
8+
"github.com/somebadcode/commit-tool/commitparser"
9+
"github.com/somebadcode/commit-tool/linter"
10+
)
11+
12+
type Linter struct {
13+
Filters Filters
14+
Rules Rules
15+
}
16+
17+
// Lint commit to ensures that it adheres to Conventional Commits 1.0.0.
18+
func (l Linter) Lint(commit *object.Commit) error {
19+
msg, err := commitparser.Parse(commit.Message)
20+
if err != nil {
21+
if l.Filters.Filter(msg, commit, err) == nil {
22+
return nil
23+
}
24+
25+
var parseError commitparser.ParseError
26+
if errors.As(err, &parseError) {
27+
return linter.LintError{
28+
Err: parseError,
29+
Hash: commit.Hash,
30+
Pos: parseError.Pos,
31+
}
32+
}
33+
34+
return err
35+
}
36+
37+
// TODO: Add support for linting revert and merge commits.
38+
if msg.Revert || msg.Merge {
39+
return nil
40+
}
41+
42+
if err = l.Rules.Validate(msg, commit); err != nil {
43+
return linter.LintError{
44+
Err: err,
45+
Hash: commit.Hash,
46+
}
47+
}
48+
49+
return nil
50+
}

commitlinter/linter_test.go

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
package commitlinter_test
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/go-git/go-git/v5"
8+
"github.com/go-git/go-git/v5/plumbing"
9+
"github.com/go-git/go-git/v5/plumbing/object"
10+
11+
"github.com/somebadcode/commit-tool/commitlinter"
12+
"github.com/somebadcode/commit-tool/internal/repobuilder"
13+
"github.com/somebadcode/commit-tool/linter"
14+
)
15+
16+
func TestLinter_Lint(t *testing.T) {
17+
type fields struct {
18+
Rev plumbing.Revision
19+
ReportFunc linter.ReportFunc
20+
StopFunc linter.StopFunc
21+
Linter linter.CommitLinter
22+
}
23+
24+
commitOpts := git.CommitOptions{
25+
AllowEmptyCommits: true,
26+
Author: &object.Signature{
27+
Name: "Gopher",
28+
Email: "gopher@example.com",
29+
When: time.Date(2023, 2, 4, 23, 22, 0, 0, time.UTC),
30+
},
31+
}
32+
33+
tests := []struct {
34+
name string
35+
repoOps []repobuilder.OperationFunc
36+
fields fields
37+
wantErr bool
38+
}{
39+
{
40+
repoOps: []repobuilder.OperationFunc{
41+
repobuilder.Commit("Initial commit", commitOpts),
42+
repobuilder.Commit("feat: add foo", commitOpts),
43+
repobuilder.CheckoutBranch("fix-foo"),
44+
repobuilder.Commit("fix(foo): avoid panic", commitOpts),
45+
repobuilder.Commit("chore(foo): tweaked comments", commitOpts),
46+
repobuilder.Commit("chore(foo): fixed formatting", commitOpts),
47+
},
48+
fields: fields{
49+
Rev: "HEAD",
50+
Linter: &commitlinter.Linter{
51+
Filters: commitlinter.Filters{
52+
commitlinter.FilterInitialCommit,
53+
},
54+
},
55+
StopFunc: func(commit *object.Commit) bool {
56+
return false
57+
},
58+
},
59+
},
60+
{
61+
repoOps: []repobuilder.OperationFunc{
62+
repobuilder.Commit("Initial commit", commitOpts),
63+
repobuilder.Commit("feat: add foo", commitOpts),
64+
repobuilder.CheckoutBranch("fix-foo"),
65+
repobuilder.Commit("fix(foo): avoid panic", commitOpts),
66+
repobuilder.Commit("chore(foo): tweaked comments", commitOpts),
67+
repobuilder.Commit("chore(foo): fixed formatting", commitOpts),
68+
},
69+
fields: fields{
70+
Rev: "HEAD",
71+
Linter: &commitlinter.Linter{
72+
Filters: commitlinter.Filters{
73+
commitlinter.FilterInitialCommit,
74+
},
75+
},
76+
},
77+
},
78+
{
79+
repoOps: []repobuilder.OperationFunc{
80+
repobuilder.Commit("Initial commit", commitOpts),
81+
repobuilder.Commit("add foo", commitOpts),
82+
repobuilder.CheckoutBranch("fix-foo"),
83+
repobuilder.Commit("fix(foo): avoid panic", commitOpts),
84+
repobuilder.Commit("tweaked comments", commitOpts),
85+
repobuilder.Commit("chore(foo): fixed formatting", commitOpts),
86+
},
87+
fields: fields{
88+
Rev: "HEAD",
89+
Linter: &commitlinter.Linter{
90+
Filters: commitlinter.Filters{
91+
commitlinter.FilterInitialCommit,
92+
},
93+
},
94+
},
95+
wantErr: true,
96+
},
97+
{
98+
repoOps: []repobuilder.OperationFunc{
99+
repobuilder.Commit("Initial commit", commitOpts),
100+
repobuilder.Commit("add foo", commitOpts),
101+
},
102+
fields: fields{
103+
Rev: "HEAD",
104+
Linter: &commitlinter.Linter{},
105+
},
106+
wantErr: true,
107+
},
108+
{
109+
repoOps: []repobuilder.OperationFunc{
110+
repobuilder.Commit("Initial commit", commitOpts),
111+
repobuilder.Commit("woop: add foo", commitOpts),
112+
},
113+
fields: fields{
114+
Rev: "HEAD",
115+
Linter: &commitlinter.Linter{
116+
Filters: commitlinter.Filters{
117+
commitlinter.FilterInitialCommit,
118+
},
119+
},
120+
},
121+
},
122+
{
123+
repoOps: []repobuilder.OperationFunc{
124+
repobuilder.Commit("Revert \"feat: add foo\"", commitOpts),
125+
repobuilder.Commit("chore(foo): fixed formatting", commitOpts),
126+
},
127+
fields: fields{
128+
Rev: "HEAD",
129+
Linter: &commitlinter.Linter{},
130+
},
131+
},
132+
{
133+
repoOps: []repobuilder.OperationFunc{
134+
repobuilder.Commit("Merge 'foo' into 'bar'", commitOpts),
135+
repobuilder.Commit("chore(foo): fixed formatting", commitOpts),
136+
},
137+
fields: fields{
138+
Rev: "HEAD",
139+
Linter: &commitlinter.Linter{},
140+
},
141+
},
142+
{
143+
repoOps: []repobuilder.OperationFunc{
144+
repobuilder.Commit("improvement(bah): ", commitOpts),
145+
repobuilder.Commit("chore(foo): fixed formatting", commitOpts),
146+
},
147+
fields: fields{
148+
Rev: "HEAD",
149+
Linter: &commitlinter.Linter{
150+
Rules: commitlinter.Rules{
151+
commitlinter.RuleConventionalCommit,
152+
},
153+
},
154+
},
155+
wantErr: true,
156+
},
157+
{
158+
repoOps: []repobuilder.OperationFunc{
159+
repobuilder.Commit("improvement(bah): Apple", commitOpts),
160+
repobuilder.Commit("chore(foo): fixed formatting", commitOpts),
161+
},
162+
fields: fields{
163+
Rev: "HEAD",
164+
Linter: &commitlinter.Linter{
165+
Rules: commitlinter.Rules{
166+
commitlinter.RuleConventionalCommit,
167+
},
168+
},
169+
},
170+
wantErr: true,
171+
},
172+
}
173+
174+
t.Parallel()
175+
176+
for _, tc := range tests {
177+
tt := tc
178+
179+
t.Run(tt.name, func(t *testing.T) {
180+
t.Parallel()
181+
182+
repo, err := repobuilder.Build(tt.repoOps...)
183+
if err != nil {
184+
t.Errorf("failed to build repo: %v", err)
185+
return
186+
}
187+
188+
l := &linter.Linter{
189+
Repo: repo,
190+
Rev: tt.fields.Rev,
191+
ReportFunc: tt.fields.ReportFunc,
192+
StopFunc: tt.fields.StopFunc,
193+
CommitLinter: tt.fields.Linter,
194+
}
195+
196+
if err = l.Run(t.Context()); (err != nil) != tt.wantErr {
197+
t.Errorf("Run() error = %v, wantErr %v", err, tt.wantErr)
198+
}
199+
})
200+
}
201+
}

linter/rules.go renamed to commitlinter/rules.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package linter
1+
package commitlinter
22

33
import (
44
"errors"

commitparser/parser_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ func TestParse(t *testing.T) {
361361
func BenchmarkParse(b *testing.B) {
362362
for _, tt := range tests {
363363
b.Run(tt.name, func(b *testing.B) {
364-
for i := 0; i < b.N; i++ {
364+
for b.Loop() {
365365
_, _ = Parse(tt.args.message)
366366
}
367367
})

0 commit comments

Comments
 (0)