diff --git a/.golangci.yml b/.golangci.yml index 4460be7..c32e59b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -39,12 +39,15 @@ linters: - gosimple - govet - ineffassign + # - mirror # requires golangci-lint 1.53 - misspell - staticcheck - structcheck + - thelper - typecheck - unparam - unused + - usestdlibvars - varcheck linters-settings: diff --git a/main.go b/main.go index f94ac0c..1cda1c1 100644 --- a/main.go +++ b/main.go @@ -102,6 +102,7 @@ func main() { // TODO(bwplotka): Move to customized better setup function. return runner(ctx, logger) }, func(err error) { + level.Error(logger).Log("err", fmt.Errorf("%s runner failed: %w", cmd, err)) cancel() }) diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go index 3d329b8..d643d12 100644 --- a/pkg/cache/cache.go +++ b/pkg/cache/cache.go @@ -134,7 +134,7 @@ func (s *SQLite3Storage) IsCached(URL string) (bool, error) { row := statement.QueryRow(URL) if err = row.Scan(×tamp); err != nil { // If ErrNoRows then it means URL is new, so need to call Visited. - if err == sql.ErrNoRows { + if errors.Is(err, sql.ErrNoRows) { return false, nil } return false, err diff --git a/pkg/cache/config.go b/pkg/cache/config.go index f901969..921b51c 100644 --- a/pkg/cache/config.go +++ b/pkg/cache/config.go @@ -50,10 +50,7 @@ func (c *Config) UnmarshalYAML(value *yaml.Node) error { if err := value.Decode(c.cacheParser); err != nil { return err } - if err := c.load(); err != nil { - return err - } - return nil + return c.load() } // load validates the cache configuration from the parser and copy it diff --git a/pkg/clilog/clilog.go b/pkg/clilog/clilog.go index 3c3016b..fdf3868 100644 --- a/pkg/clilog/clilog.go +++ b/pkg/clilog/clilog.go @@ -57,7 +57,10 @@ func New(w io.Writer) log.Logger { } func (l logger) Log(keyvals ...interface{}) error { - buf := bufPool.Get().(*buf) + buf, ok := bufPool.Get().(*buf) + if !ok { + return errors.New("invalid buffer") + } buf.Reset() defer bufPool.Put(buf) @@ -152,14 +155,17 @@ func (enc *Encoder) EncodeKeyvals(keyvals ...interface{}) error { for i := 0; i < len(keyvals); i += 2 { k, v := keyvals[i], keyvals[i+1] err := enc.EncodeKeyval(k, v) - if err == ErrUnsupportedKeyType { + + var marshalError *MarshalerError + switch { + case errors.Is(err, ErrUnsupportedKeyType): continue - } - if _, ok := err.(*MarshalerError); ok || err == ErrUnsupportedValueType { + case + errors.As(err, &marshalError), + errors.Is(err, ErrUnsupportedValueType): v = err - err = enc.EncodeKeyval(k, v) - } - if err != nil { + return enc.EncodeKeyval(k, v) + case err != nil: return err } } diff --git a/pkg/mdformatter/linktransformer/config.go b/pkg/mdformatter/linktransformer/config.go index 8760583..423705f 100644 --- a/pkg/mdformatter/linktransformer/config.go +++ b/pkg/mdformatter/linktransformer/config.go @@ -148,14 +148,14 @@ func getGitHubRegex(pullsIssuesRe string, repoToken string) (*regexp.Regexp, int client := &http.Client{} // Check latest pull request number. - reqPull, err := http.NewRequest("GET", fmt.Sprintf(gitHubAPIURL, reponame, "pulls"), nil) + reqPull, err := http.NewRequest(http.MethodGet, fmt.Sprintf(gitHubAPIURL, reponame, "pulls"), nil) if err != nil { return nil, math.MaxInt64, err } reqPull.Header.Set("User-Agent", "mdox") // Check latest issue number and return whichever is greater. - reqIssue, err := http.NewRequest("GET", fmt.Sprintf(gitHubAPIURL, reponame, "issues"), nil) + reqIssue, err := http.NewRequest(http.MethodGet, fmt.Sprintf(gitHubAPIURL, reponame, "issues"), nil) if err != nil { return nil, math.MaxInt64, err } @@ -170,7 +170,7 @@ func getGitHubRegex(pullsIssuesRe string, repoToken string) (*regexp.Regexp, int if err != nil { return nil, math.MaxInt64, err } - if respPull.StatusCode != 200 { + if respPull.StatusCode != http.StatusOK { return nil, math.MaxInt64, fmt.Errorf("pulls API request failed. status code: %d", respPull.StatusCode) } defer respPull.Body.Close() @@ -182,7 +182,7 @@ func getGitHubRegex(pullsIssuesRe string, repoToken string) (*regexp.Regexp, int if err != nil { return nil, math.MaxInt64, err } - if respIssue.StatusCode != 200 { + if respIssue.StatusCode != http.StatusOK { return nil, math.MaxInt64, fmt.Errorf("issues API request failed. status code: %d", respIssue.StatusCode) } defer respIssue.Body.Close() diff --git a/pkg/mdformatter/linktransformer/link.go b/pkg/mdformatter/linktransformer/link.go index a2b842d..34a82a0 100644 --- a/pkg/mdformatter/linktransformer/link.go +++ b/pkg/mdformatter/linktransformer/link.go @@ -173,7 +173,7 @@ func (l *localizer) TransformDestination(ctx mdformatter.SourceContext, destinat return absLinkToRelLink(newDest, ctx.Filepath) } -func (l *localizer) Close(mdformatter.SourceContext) error { return nil } +func (*localizer) Close(mdformatter.SourceContext) error { return nil } type validator struct { logger log.Logger @@ -532,12 +532,12 @@ func (l localLinksCache) addRelLinks(localLink string) error { reader := bufio.NewReader(file) for { b, err = reader.ReadBytes('\n') - if err != nil { - if err != io.EOF { - return fmt.Errorf("failed to read file %v: %w", localLink, err) - } + if errors.Is(err, io.EOF) { break } + if err != nil { + return fmt.Errorf("failed to read file %v: %w", localLink, err) + } if bytes.HasPrefix(b, []byte(`#`)) { ids = append(ids, toHeaderID(b)) diff --git a/pkg/mdformatter/linktransformer/link_bench_test.go b/pkg/mdformatter/linktransformer/link_bench_test.go index 1fd26ad..8a02eca 100644 --- a/pkg/mdformatter/linktransformer/link_bench_test.go +++ b/pkg/mdformatter/linktransformer/link_bench_test.go @@ -34,6 +34,8 @@ This is a test section [link](./doc.md#this-is-a-section)` ) func benchLinktransformer(b *testing.B) { + b.Helper() + tmpDir, err := os.MkdirTemp("", "bench-test") testutil.Ok(b, err) b.Cleanup(func() { testutil.Ok(b, os.RemoveAll(tmpDir)) }) diff --git a/pkg/mdformatter/linktransformer/validator.go b/pkg/mdformatter/linktransformer/validator.go index 9787575..137c1b6 100644 --- a/pkg/mdformatter/linktransformer/validator.go +++ b/pkg/mdformatter/linktransformer/validator.go @@ -32,7 +32,7 @@ func (v GitHubPullsIssuesValidator) IsValid(k futureKey, r *validator) (bool, er } // RoundTripValidator.IsValid returns true if URL is checked by colly or it is a valid local link. -func (v RoundTripValidator) IsValid(k futureKey, r *validator) (bool, error) { +func (RoundTripValidator) IsValid(k futureKey, r *validator) (bool, error) { matches := remoteLinkPrefixRe.FindAllStringIndex(k.dest, 1) if matches == nil && r.validateConfig.ExplicitLocalValidators { r.l.localLinksChecked.Inc() @@ -73,7 +73,7 @@ func (v RoundTripValidator) IsValid(k futureKey, r *validator) (bool, error) { } // IgnoreValidator.IsValid returns true if matched so that link in not checked. -func (v IgnoreValidator) IsValid(k futureKey, r *validator) (bool, error) { +func (IgnoreValidator) IsValid(_ futureKey, r *validator) (bool, error) { r.l.ignoreSkippedLinks.Inc() return true, nil diff --git a/pkg/mdformatter/mdformatter.go b/pkg/mdformatter/mdformatter.go index ceabbbc..eb951fc 100644 --- a/pkg/mdformatter/mdformatter.go +++ b/pkg/mdformatter/mdformatter.go @@ -182,13 +182,13 @@ func FormatFrontMatter(m map[string]interface{}) ([]byte, error) { keys: keys, } - b := bytes.NewBuffer([]byte("---\n")) + b := bytes.NewBufferString("---\n") o, err := yaml.Marshal(f) if err != nil { return nil, fmt.Errorf("marshall front matter: %w", err) } _, _ = b.Write(o) - _, _ = b.Write([]byte("---\n\n")) + _, _ = b.WriteString("---\n\n") return b.Bytes(), nil } diff --git a/pkg/mdformatter/mdformatter_bench_test.go b/pkg/mdformatter/mdformatter_bench_test.go index bd99bb1..1b0c021 100644 --- a/pkg/mdformatter/mdformatter_bench_test.go +++ b/pkg/mdformatter/mdformatter_bench_test.go @@ -14,7 +14,9 @@ import ( var testBuf bytes.Buffer -func benchMdformatter(filename string, b *testing.B) { +func benchMdformatter(b *testing.B, filename string) { + b.Helper() + file, err := os.OpenFile(filename, os.O_RDONLY, 0) testutil.Ok(b, err) defer file.Close() @@ -28,4 +30,4 @@ func benchMdformatter(filename string, b *testing.B) { }) } -func Benchmark_Mdformatter(b *testing.B) { benchMdformatter("testdata/not_formatted.md", b) } +func Benchmark_Mdformatter(b *testing.B) { benchMdformatter(b, "testdata/not_formatted.md") } diff --git a/pkg/mdformatter/mdgen/mdgen.go b/pkg/mdformatter/mdgen/mdgen.go index 8baa3d0..245e45f 100644 --- a/pkg/mdformatter/mdgen/mdgen.go +++ b/pkg/mdformatter/mdgen/mdgen.go @@ -5,6 +5,7 @@ package mdgen import ( "bytes" + "errors" "fmt" "os/exec" "strconv" @@ -19,9 +20,7 @@ const ( infoStringKeyExitCode = "mdox-expect-exit-code" ) -var ( - newLineChar = []byte("\n") -) +var newLineChar = []byte("\n") type genCodeBlockTransformer struct{} @@ -29,7 +28,7 @@ func NewCodeBlockTransformer() *genCodeBlockTransformer { return &genCodeBlockTransformer{} } -func (t *genCodeBlockTransformer) TransformCodeBlock(ctx mdformatter.SourceContext, infoString []byte, code []byte) ([]byte, error) { +func (*genCodeBlockTransformer) TransformCodeBlock(ctx mdformatter.SourceContext, infoString []byte, code []byte) ([]byte, error) { if len(infoString) == 0 { return code, nil } @@ -82,13 +81,13 @@ func (t *genCodeBlockTransformer) TransformCodeBlock(ctx mdformatter.SourceConte cmd.Stdout = &b if err := cmd.Run(); err != nil { expectedCode, _ := strconv.Atoi(infoStringAttr[infoStringKeyExitCode]) - if exitErr, ok := err.(*exec.ExitError); ok { - if exitErr.ExitCode() != expectedCode { - return nil, fmt.Errorf("run %v, expected exit code %v, got %v, out: %v, error: %w", execCmd, expectedCode, exitErr.ExitCode(), b.String(), err) - } - } else { + var exitErr *exec.ExitError + if !errors.As(err, &exitErr) { return nil, fmt.Errorf("run %v, out: %v, error: %w", execCmd, b.String(), err) } + if exitErr.ExitCode() != expectedCode { + return nil, fmt.Errorf("run %v, expected exit code %v, got %v, out: %v, error: %w", execCmd, expectedCode, exitErr.ExitCode(), b.String(), err) + } } output := b.Bytes() // Add newline to output if not present. @@ -101,4 +100,4 @@ func (t *genCodeBlockTransformer) TransformCodeBlock(ctx mdformatter.SourceConte panic("should never get here") } -func (t *genCodeBlockTransformer) Close(ctx mdformatter.SourceContext) error { return nil } +func (*genCodeBlockTransformer) Close(_ mdformatter.SourceContext) error { return nil } diff --git a/pkg/mdformatter/mdgen/mdgen_bench_test.go b/pkg/mdformatter/mdgen/mdgen_bench_test.go index 5668539..611bd6d 100644 --- a/pkg/mdformatter/mdgen/mdgen_bench_test.go +++ b/pkg/mdformatter/mdgen/mdgen_bench_test.go @@ -15,7 +15,9 @@ import ( var testBuf bytes.Buffer -func benchMdgen(filename string, b *testing.B) { +func benchMdgen(b *testing.B, filename string) { + b.Helper() + file, err := os.OpenFile(filename, os.O_RDONLY, 0) testutil.Ok(b, err) defer file.Close() @@ -30,8 +32,8 @@ func benchMdgen(filename string, b *testing.B) { }) } -func Benchmark_Mdgen_Sleep2(b *testing.B) { benchMdgen("benchdata/sleep2.md", b) } +func Benchmark_Mdgen_Sleep2(b *testing.B) { benchMdgen(b, "benchdata/sleep2.md") } -func Benchmark_Mdgen_Sleep5(b *testing.B) { benchMdgen("benchdata/sleep5.md", b) } +func Benchmark_Mdgen_Sleep5(b *testing.B) { benchMdgen(b, "benchdata/sleep5.md") } -func Benchmark_Mdgen_GoHelp(b *testing.B) { benchMdgen("benchdata/gohelp.md", b) } +func Benchmark_Mdgen_GoHelp(b *testing.B) { benchMdgen(b, "benchdata/gohelp.md") } diff --git a/pkg/mdformatter/transformer.go b/pkg/mdformatter/transformer.go index 43ada32..e4bfb7e 100644 --- a/pkg/mdformatter/transformer.go +++ b/pkg/mdformatter/transformer.go @@ -5,6 +5,7 @@ package mdformatter import ( "bytes" + "errors" "io" "regexp" "strconv" @@ -102,7 +103,8 @@ func (t *transformer) Render(w io.Writer, source []byte, node ast.Node) error { } out += token.String() } - if err := z.Err(); err != nil && err != io.EOF { + + if err := z.Err(); err != nil && !errors.Is(err, io.EOF) { return ast.WalkStop, err } diff --git a/pkg/transform/transform.go b/pkg/transform/transform.go index 725f84a..20018d3 100644 --- a/pkg/transform/transform.go +++ b/pkg/transform/transform.go @@ -361,7 +361,7 @@ func (r *relLinkTransformer) TransformDestination(ctx mdformatter.SourceContext, return []byte(newDest), nil } -func (r *relLinkTransformer) Close(mdformatter.SourceContext) error { return nil } +func (*relLinkTransformer) Close(mdformatter.SourceContext) error { return nil } type frontMatterTransformer struct { localLinksStyle LocalLinksStyle @@ -419,9 +419,9 @@ func (f *frontMatterTransformer) TransformFrontMatter(ctx mdformatter.SourceCont return mdformatter.FormatFrontMatter(m) } -func (f *frontMatterTransformer) Close(mdformatter.SourceContext) error { return nil } +func (*frontMatterTransformer) Close(mdformatter.SourceContext) error { return nil } -func (f *backMatterTransformer) TransformBackMatter(ctx mdformatter.SourceContext) ([]byte, error) { +func (f *backMatterTransformer) TransformBackMatter(_ mdformatter.SourceContext) ([]byte, error) { b := bytes.Buffer{} if err := f.b._template.Execute(&b, struct { Origin MatterOrigin @@ -442,7 +442,7 @@ func (f *backMatterTransformer) TransformBackMatter(ctx mdformatter.SourceContex return m, nil } -func (f *backMatterTransformer) Close(mdformatter.SourceContext) error { return nil } +func (*backMatterTransformer) Close(mdformatter.SourceContext) error { return nil } func firstMatch(absRelPath string, trs []*TransformationConfig) (*TransformationConfig, bool) { for _, tr := range trs { diff --git a/pkg/transform/transform_e2e_test.go b/pkg/transform/transform_e2e_test.go index b7046ef..d5f400c 100644 --- a/pkg/transform/transform_e2e_test.go +++ b/pkg/transform/transform_e2e_test.go @@ -37,18 +37,18 @@ func TestTransform(t *testing.T) { testutil.Ok(t, err) testutil.Ok(t, transform.Dir(context.Background(), logger, mdox2)) assertDirContent(t, filepath.Join(testData, "expected", "test2"), filepath.Join(tmpDir, "test2")) - }) t.Run("mdox3.yaml", func(t *testing.T) { mdox2, err := os.ReadFile(filepath.Join(testData, "mdox3.yaml")) testutil.Ok(t, err) testutil.Ok(t, transform.Dir(context.Background(), logger, mdox2)) assertDirContent(t, filepath.Join(testData, "expected", "test3"), filepath.Join(tmpDir, "test3")) - }) } func assertDirContent(t *testing.T, expectedDir string, gotDir string) { + t.Helper() + // TODO(bwplotka): Check if some garbage was not generated too! testutil.Ok(t, filepath.Walk(expectedDir, func(path string, info os.FileInfo, err error) error { if err != nil { diff --git a/scripts/copyright/copyright.go b/scripts/copyright/copyright.go index e7c0781..9cd0013 100644 --- a/scripts/copyright/copyright.go +++ b/scripts/copyright/copyright.go @@ -46,7 +46,7 @@ func applyLicenseToProtoAndGo() error { return err } - if !strings.HasPrefix(string(b), string(license)) { + if !bytes.HasPrefix(b, license) { log.Println("file", path, "is missing Copyright header. Adding.") var bb bytes.Buffer