Skip to content

Commit a0bc0b3

Browse files
authored
all: follow golangci-lint rules for linters (#2)
1 parent 6cf6a20 commit a0bc0b3

File tree

7 files changed

+84
-31
lines changed

7 files changed

+84
-31
lines changed

.github/workflows/go.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,4 @@ jobs:
103103
check-latest: true
104104

105105
- name: "Run golangci-lint"
106-
uses: golangci/golangci-lint-action@4696ba8babb6127d732c3c6dde519db15edab9ea # v6.5.1
106+
uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7.0.0

.golangci.yml

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1+
version: "2"
2+
run:
3+
go: "1.23"
4+
15
linters:
26
enable:
37
- "bodyclose"
48
- "copyloopvar"
59
- "errcheck"
6-
- "gci"
7-
- "gofumpt"
810
- "goheader"
911
- "gosec"
10-
- "gosimple"
1112
- "govet"
1213
- "ineffassign"
1314
- "nilerr"
15+
- "nolintlint"
1416
- "predeclared"
1517
- "revive"
1618
- "staticcheck"
@@ -20,11 +22,15 @@ linters:
2022
- "unparam"
2123
- "whitespace"
2224

23-
linters-settings:
24-
# Enforces import order in Go source files
25-
gci:
26-
sections:
27-
- "standard"
28-
- "default"
29-
- "localmodule"
30-
custom-order: true
25+
formatters:
26+
enable:
27+
- "gci"
28+
- "gofumpt"
29+
settings:
30+
# Enforces import order in Go source files
31+
gci:
32+
sections:
33+
- "standard"
34+
- "default"
35+
- "localmodule"
36+
custom-order: true

analysis.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1919
// SOFTWARE.
2020

21+
// Package golicenser implements a go/analysis for linting license headers.
2122
package golicenser
2223

2324
import (
@@ -35,16 +36,23 @@ import (
3536
const (
3637
analyzerName = "golicenser"
3738

39+
// DefaultMatchHeaderRegexp is the default regexp used to detect license
40+
// headers. This will match any header containing "copyright".
3841
DefaultMatchHeaderRegexp = "(?i)copyright"
3942
)
4043

4144
var (
45+
// DefaultMaxConcurrent is the default maximum concurrency to use when
46+
// analyzing files.
4247
DefaultMaxConcurrent = runtime.GOMAXPROCS(0) * 2
43-
DefaultExcludes = []string{
48+
49+
// DefaultExcludes are the default files to exclude when analyzing.
50+
DefaultExcludes = []string{
4451
"**/testdata/**", // Exclude testdata directories
4552
}
4653
)
4754

55+
// Config is the golicenser configuration.
4856
type Config struct {
4957
Header HeaderOpts
5058

@@ -53,6 +61,7 @@ type Config struct {
5361
MatchHeaderRegexp string
5462
}
5563

64+
// NewAnalyzer creates a golicenser analyzer.
5665
func NewAnalyzer(cfg Config) (*analysis.Analyzer, error) {
5766
a, err := newAnalyzer(cfg)
5867
if err != nil {
@@ -68,6 +77,7 @@ func NewAnalyzer(cfg Config) (*analysis.Analyzer, error) {
6877
}, nil
6978
}
7079

80+
// ExcludeMatcherFunc is a function for determining whether to exclude a file.
7181
type ExcludeMatcherFunc func(filename string) bool
7282

7383
type analyzer struct {
@@ -173,7 +183,10 @@ func (a *analyzer) checkFile(pass *analysis.Pass, file *ast.File) error {
173183

174184
if header == "" || !a.headerMatcher.MatchString(header) {
175185
// License header is missing, generate a new one.
176-
header = a.header.Create(filename) + "\n"
186+
newHeader, err := a.header.Create(filename)
187+
if err != nil {
188+
return fmt.Errorf("create %s header: %w", filename, err)
189+
}
177190
pass.Report(analysis.Diagnostic{
178191
Pos: file.FileStart,
179192
Category: analyzerName,
@@ -182,14 +195,18 @@ func (a *analyzer) checkFile(pass *analysis.Pass, file *ast.File) error {
182195
Message: "add license header",
183196
TextEdits: []analysis.TextEdit{{
184197
Pos: file.FileStart,
185-
NewText: []byte(header),
198+
NewText: []byte(newHeader + "\n"),
186199
}},
187200
}},
188201
})
189202
return nil
190203
}
191204

192-
if newHeader, modified := a.header.Update(filename, header); modified {
205+
newHeader, modified, err := a.header.Update(filename, header)
206+
if err != nil {
207+
return fmt.Errorf("update %s header: %w", filename, err)
208+
}
209+
if modified {
193210
pass.Report(analysis.Diagnostic{
194211
Pos: headerPos,
195212
End: headerEnd,

cmd/golicenser/golicenser.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1919
// SOFTWARE.
2020

21+
// Package main provides a CLI for running golicenser.
2122
package main
2223

2324
import (
2425
"flag"
2526
"log"
2627
"os"
2728
"strings"
29+
"sync"
2830

2931
"golang.org/x/tools/go/analysis"
3032
"golang.org/x/tools/go/analysis/singlechecker"
@@ -50,7 +52,9 @@ var (
5052
matchHeaderRegexp string
5153
)
5254

53-
func init() {
55+
var setupFlagsOnce = sync.OnceFunc(setupFlags)
56+
57+
func setupFlags() {
5458
flag.StringVar(&template, "tmpl", "", "License header template")
5559
flag.StringVar(&templateFile, "tmpl-file", "license_header.txt",
5660
"License header template file")
@@ -84,8 +88,11 @@ var analyzer = &analysis.Analyzer{
8488
URL: "https://github.com/joshuasing/golicenser",
8589
Flags: flagSet,
8690
Run: func(pass *analysis.Pass) (any, error) {
91+
setupFlagsOnce()
92+
8793
var err error
8894
if template == "" {
95+
//nolint:gosec // Reading user-defined file.
8996
b, err := os.ReadFile(templateFile)
9097
if err != nil {
9198
log.Fatal("read template file: ", err)
@@ -97,6 +104,7 @@ var analyzer = &analysis.Analyzer{
97104
}
98105
}
99106
if matchTemplate == "" && matchTemplateFile != "" {
107+
//nolint:gosec // Reading user-defined file.
100108
b, err := os.ReadFile(matchTemplateFile)
101109
if err != nil {
102110
log.Fatal("read match template file: ", err)

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
module github.com/joshuasing/golicenser
22

3-
go 1.24.1
3+
go 1.23.0
4+
5+
toolchain go1.24.2
46

57
require (
68
github.com/bmatcuk/doublestar/v4 v4.8.1

header.go

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,12 @@ func (cs CommentStyle) Render(s string) string {
186186
case CommentStyleBlock:
187187
return "/*\n" + s + "\n*/\n"
188188
default:
189-
panic(fmt.Errorf("golicenser: missing comment style render for %q", cs))
189+
// Cannot render as a comment.
190+
return s
190191
}
191192
}
192193

194+
// Parse parses the comment and returns the uncommented string.
193195
func (cs CommentStyle) Parse(s string) string {
194196
switch cs {
195197
case CommentStyleLine:
@@ -208,10 +210,12 @@ func (cs CommentStyle) Parse(s string) string {
208210
case CommentStyleBlock:
209211
return strings.TrimSuffix(strings.TrimPrefix(s, "/*\n"), "\n*/\n")
210212
default:
211-
panic(fmt.Errorf("golicenser: missing comment style parse for %q", cs))
213+
// Cannot parse as a comment.
214+
return s
212215
}
213216
}
214217

218+
// Header is a helper for generating and updating license headers.
215219
type Header struct {
216220
tmpl *template.Template
217221
matcher *regexp.Regexp
@@ -226,6 +230,7 @@ var tmplFuncMap = template.FuncMap{
226230
"basename": filepath.Base,
227231
}
228232

233+
// HeaderOpts are the options for creating a license header.
229234
type HeaderOpts struct {
230235
Template string
231236
MatchTemplate string
@@ -237,6 +242,7 @@ type HeaderOpts struct {
237242
CommentStyle CommentStyle
238243
}
239244

245+
// NewHeader creates a new header with the given options.
240246
func NewHeader(opts HeaderOpts) (*Header, error) {
241247
if opts.Author == "" {
242248
return nil, fmt.Errorf("invalid author: %q", opts.Author)
@@ -304,18 +310,22 @@ func NewHeader(opts HeaderOpts) (*Header, error) {
304310
}
305311

306312
// Create creates a new license header for the file.
307-
func (h *Header) Create(filename string) string {
308-
return h.commentStyle.Render(h.render(filename, timeNow().Format("2006")))
313+
func (h *Header) Create(filename string) (string, error) {
314+
header, err := h.render(filename, timeNow().Format("2006"))
315+
if err != nil {
316+
return "", fmt.Errorf("render header: %w", err)
317+
}
318+
return h.commentStyle.Render(header), nil
309319
}
310320

311321
// Update updates an existing license header if it matches the
312-
func (h *Header) Update(filename, header string) (string, bool) {
322+
func (h *Header) Update(filename, header string) (string, bool, error) {
313323
if cs, err := detectCommentStyle(header); err == nil {
314324
header = cs.Parse(header)
315325
}
316326
match := h.matcher.FindStringSubmatch(header)
317327
if match == nil {
318-
return header, false
328+
return header, false, nil
319329
}
320330

321331
var year string
@@ -374,12 +384,15 @@ func (h *Header) Update(filename, header string) (string, bool) {
374384
if year == "" {
375385
year = timeNow().Format("2006")
376386
}
377-
newHeader := h.render(filename, year)
378387

379-
return h.commentStyle.Render(newHeader), newHeader != header
388+
newHeader, err := h.render(filename, year)
389+
if err != nil {
390+
return "", false, fmt.Errorf("render header: %w", err)
391+
}
392+
return h.commentStyle.Render(newHeader), newHeader != header, nil
380393
}
381394

382-
func (h *Header) render(filename, year string) string {
395+
func (h *Header) render(filename, year string) (string, error) {
383396
// Built-in variables.
384397
m := map[string]any{
385398
"author": h.author,
@@ -390,9 +403,9 @@ func (h *Header) render(filename, year string) string {
390403

391404
var b bytes.Buffer
392405
if err := h.tmpl.Execute(&b, m); err != nil {
393-
panic(fmt.Errorf("golicenser: execute header template: %w", err))
406+
return "", fmt.Errorf("execute template: %w", err)
394407
}
395-
return b.String()
408+
return b.String(), nil
396409
}
397410

398411
func headerMatcher(tmpl *template.Template, escapeTmpl bool, authorRegexp *regexp.Regexp, variables map[string]any) (*regexp.Regexp, error) {

header_test.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,11 @@ func TestHeaderCreate(t *testing.T) {
215215
if (err != nil) != tt.wantErr {
216216
t.Errorf("NewHeader err = %v, want err %v", err, tt.wantErr)
217217
}
218-
if got := h.Create(tt.filename); got != tt.want {
218+
header, err := h.Create(tt.filename)
219+
if err != nil {
220+
t.Errorf("h.Create(%q) err = %v, want nil", header, err)
221+
}
222+
if got := header; got != tt.want {
219223
t.Errorf("h.Create(%q) = %q, want %q", tt.filename, got, tt.want)
220224
}
221225
})
@@ -324,7 +328,10 @@ func TestHeaderUpdate(t *testing.T) {
324328
if (err != nil) != tt.wantErr {
325329
t.Errorf("NewHeader err = %v, want err %v", err, tt.wantErr)
326330
}
327-
got, modified := h.Update(tt.filename, tt.existing)
331+
got, modified, err := h.Update(tt.filename, tt.existing)
332+
if err != nil {
333+
t.Errorf("h.Update() err = %v, want nil", err)
334+
}
328335
if modified != tt.wantModified {
329336
t.Errorf("h.Update() modified = %v, want %v",
330337
modified, tt.wantModified)

0 commit comments

Comments
 (0)