From 0f99f61b42492b8990d9cf954b79f2d3b215eace Mon Sep 17 00:00:00 2001 From: Bob Glickstein Date: Wed, 5 Apr 2023 07:19:21 -0400 Subject: [PATCH 1/4] Add golangci-lint GitHub Action. Add test coverage. --- .github/workflows/go.yml | 2 +- .github/workflows/golangci-lint.yml | 53 +++++++++++++++++++++++++++++ _testdata/foo.go | 27 +++++++++++++++ decouple.go | 32 ++++++++++------- decouple_test.go | 2 +- 5 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/golangci-lint.yml diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 3f0e45e..26242e6 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -16,7 +16,7 @@ jobs: fetch-depth: 0 - name: Set up Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v4 with: go-version: 1.19 diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml new file mode 100644 index 0000000..249c511 --- /dev/null +++ b/.github/workflows/golangci-lint.yml @@ -0,0 +1,53 @@ +name: golangci-lint +on: + push: + tags: + - v* + branches: + - master + - main + pull_request: + +permissions: + contents: read + # Optional: allow read access to pull request. Use with `only-new-issues` option. + # pull-requests: read + +jobs: + golangci: + name: lint + runs-on: ubuntu-latest + steps: + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.19' + cache: false + + - name: Checkout + uses: actions/checkout@v3 + + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version + version: v3.4.0 + + # Optional: working directory, useful for monorepos + # working-directory: somedir + + # Optional: golangci-lint command line arguments. + # args: --issues-exit-code=0 + + # Optional: show only new issues if it's a pull request. The default value is `false`. + # only-new-issues: true + + # Optional: if set to true then the all caching functionality will be complete disabled, + # takes precedence over all other caching options. + # skip-cache: true + + # Optional: if set to true then the action don't cache or restore ~/go/pkg. + # skip-pkg-cache: true + + # Optional: if set to true then the action don't cache or restore ~/.cache/go-build. + # skip-build-cache: true diff --git a/_testdata/foo.go b/_testdata/foo.go index 92e5fb9..e549b66 100644 --- a/_testdata/foo.go +++ b/_testdata/foo.go @@ -200,3 +200,30 @@ func F27(r *os.File) (data []byte, err error) { func F28(r *os.File) map[int]io.Reader { return map[int]io.Reader{7: r} } + +func F29(r *os.File) ([]byte, error) { + s := struct { + rd io.Reader + }{rd: r} + return io.ReadAll(s.rd) +} + +func F30(f *os.File) ([]byte, error) { + s := struct { + file *os.File + }{file: f} + return io.ReadAll(s.file) +} + +func F31(r *os.File) ([]byte, error) { + fn := func(readers ...io.Reader) ([]byte, error) { + for _, reader := range readers { + if reader != nil { + return io.ReadAll(reader) + } + } + return nil, nil + } + + return fn(nil, r) +} diff --git a/decouple.go b/decouple.go index 5a49090..de9abfe 100644 --- a/decouple.go +++ b/decouple.go @@ -349,21 +349,27 @@ func (a *analyzer) stmt(stmt ast.Stmt) (ok bool) { } for i, rhs := range stmt.Rhs { // xxx do a recursive analysis of how this var is used! - if a.isObj(rhs) && stmt.Tok != token.DEFINE { - if stmt.Tok != token.ASSIGN { - // Reject OP= - return false - } - tv, ok := a.pkg.TypesInfo.Types[stmt.Lhs[i]] - if !ok { - panic(errf("no type info for lvalue %d in assignment at %s", i, a.pos(stmt))) - } - intf := getInterface(tv.Type) - if intf == nil { + if a.isObj(rhs) { + switch stmt.Tok { + case token.DEFINE: + continue + + case token.ASSIGN: + tv, ok := a.pkg.TypesInfo.Types[stmt.Lhs[i]] + if !ok { + panic(errf("no type info for lvalue %d in assignment at %s", i, a.pos(stmt))) + } + intf := getInterface(tv.Type) + if intf == nil { + return false + } + a.addMethods(intf) + continue + + default: + // Reject OP= (e.g., foo += obj) return false } - a.addMethods(intf) - continue } if !a.expr(rhs) { return false diff --git a/decouple_test.go b/decouple_test.go index fbc8164..53591e4 100644 --- a/decouple_test.go +++ b/decouple_test.go @@ -13,7 +13,7 @@ import ( // "github.com/davecgh/go-spew/spew" ) -func TestAnalyze(t *testing.T) { +func TestCheckParam(t *testing.T) { ctx := context.Background() conf := &packages.Config{ From c8bbece9d41cbf6bae74b7b0b5103403b2227cec Mon Sep 17 00:00:00 2001 From: Bob Glickstein Date: Wed, 5 Apr 2023 07:22:01 -0400 Subject: [PATCH 2/4] Oops, had the wrong version for golangci-lint. --- .github/workflows/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 249c511..dd6f4a7 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -31,7 +31,7 @@ jobs: uses: golangci/golangci-lint-action@v3 with: # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version - version: v3.4.0 + version: v1.52.2 # Optional: working directory, useful for monorepos # working-directory: somedir From 931d89a12cb44b2b52cfad9f2ee90a5151434e59 Mon Sep 17 00:00:00 2001 From: Bob Glickstein Date: Wed, 5 Apr 2023 07:26:47 -0400 Subject: [PATCH 3/4] golangci-lint already paying for itself --- debug.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debug.go b/debug.go index 9841b57..f3d48da 100644 --- a/debug.go +++ b/debug.go @@ -11,9 +11,9 @@ func (a *analyzer) debugf(format string, args ...any) { return } s := fmt.Sprintf(format, args...) - strings.TrimRight(s, "\r\n") + s = strings.TrimRight(s, "\r\n") if a.level > 0 { - fmt.Fprintf(os.Stderr, strings.Repeat(" ", a.level)) + fmt.Fprint(os.Stderr, strings.Repeat(" ", a.level)) } fmt.Fprintln(os.Stderr, s) } From 6dfc63cc6eec75447dc633503656fa04fc204c7a Mon Sep 17 00:00:00 2001 From: Bob Glickstein Date: Fri, 7 Apr 2023 10:33:36 -0400 Subject: [PATCH 4/4] Add fab.d. --- fab.d/fab.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 fab.d/fab.go diff --git a/fab.d/fab.go b/fab.d/fab.go new file mode 100644 index 0000000..68c4640 --- /dev/null +++ b/fab.d/fab.go @@ -0,0 +1,30 @@ +package fab + +import ( + "context" + "os" + + "github.com/bobg/fab" + "github.com/bobg/fab/deps" + "github.com/pkg/errors" +) + +var ( + Cover = fab.Deps(showCoverage, computeCoverage) + Clean = fab.Clean("cover.out") + + showCoverage = fab.Command("go tool cover -html cover.out") +) + +var computeCoverage = fab.Register("computeCoverage", "compute coverage profile", fab.F(func(ctx context.Context) error { + in, err := deps.Go(".", true) + if err != nil { + return errors.Wrap(err, "in deps.Go") + } + filesTarget := fab.Files{ + Target: fab.Command("go test -coverprofile cover.out ./...", fab.CmdStdout(os.Stdout)), + In: in, + Out: []string{"cover.out"}, + } + return filesTarget.Run(ctx) +}))