diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index bde132f..a97f7e7 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -12,27 +12,43 @@ on: description: 'New Ref' required: true +# Cancel the workflow in progress in newer build is about to start. +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + env: GO111MODULE: "on" CACHE_BENCHMARK: "off" # Enables benchmark result reuse between runs, may skew latency results. RUN_BASE_BENCHMARK: "on" # Runs benchmark for PR base in case benchmark result is missing. + GO_VERSION: 1.23.x jobs: bench: - strategy: - matrix: - go-version: [ 1.16.x ] runs-on: ubuntu-latest steps: - - name: Install Go - uses: actions/setup-go@v2 + - name: Install Go stable + if: env.GO_VERSION != 'tip' + uses: actions/setup-go@v4 with: - go-version: ${{ matrix.go-version }} + go-version: ${{ env.GO_VERSION }} + + - name: Install Go tip + if: env.GO_VERSION == 'tip' + run: | + curl -sL https://storage.googleapis.com/go-build-snap/go/linux-amd64/$(git ls-remote https://github.com/golang/go.git HEAD | awk '{print $1;}').tar.gz -o gotip.tar.gz + ls -lah gotip.tar.gz + mkdir -p ~/sdk/gotip + tar -C ~/sdk/gotip -xzf gotip.tar.gz + ~/sdk/gotip/bin/go version + echo "PATH=$HOME/go/bin:$HOME/sdk/gotip/bin/:$PATH" >> $GITHUB_ENV + - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: ref: ${{ (github.event.inputs.new != '') && github.event.inputs.new || github.event.ref }} + - name: Go cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: # In order: # * Module download cache @@ -43,44 +59,58 @@ jobs: key: ${{ runner.os }}-go-cache-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go-cache + - name: Restore benchstat - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/go/bin/benchstat - key: ${{ runner.os }}-benchstat + key: ${{ runner.os }}-benchstat-legacy + - name: Restore base benchmark result + id: base-benchmark if: env.CACHE_BENCHMARK == 'on' - id: benchmark-base - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | bench-master.txt bench-main.txt # Use base sha for PR or new commit hash for master/main push in benchmark result key. key: ${{ runner.os }}-bench-${{ (github.event.pull_request.base.sha != github.event.after) && github.event.pull_request.base.sha || github.event.after }} - - name: Checkout base code - if: env.RUN_BASE_BENCHMARK == 'on' && steps.benchmark-base.outputs.cache-hit != 'true' && (github.event.pull_request.base.sha != '' || github.event.inputs.old != '') - uses: actions/checkout@v2 - with: - ref: ${{ (github.event.pull_request.base.sha != '' ) && github.event.pull_request.base.sha || github.event.inputs.old }} - path: __base - - name: Run base benchmark - if: env.RUN_BASE_BENCHMARK == 'on' && steps.benchmark-base.outputs.cache-hit != 'true' && (github.event.pull_request.base.sha != '' || github.event.inputs.old != '') + + - name: Run benchmark + run: | + export REF_NAME=new + make bench + OUTPUT=$(make bench-stat-diff) + echo "${OUTPUT}" + echo "diff<> $GITHUB_OUTPUT && echo "$OUTPUT" >> $GITHUB_OUTPUT && echo "EOF" >> $GITHUB_OUTPUT + OUTPUT=$(make bench-stat) + echo "${OUTPUT}" + echo "result<> $GITHUB_OUTPUT && echo "$OUTPUT" >> $GITHUB_OUTPUT && echo "EOF" >> $GITHUB_OUTPUT + + - name: Run benchmark for base code + if: env.RUN_BASE_BENCHMARK == 'on' && steps.base-benchmark.outputs.cache-hit != 'true' && (github.event.pull_request.base.sha != '' || github.event.inputs.old != '') run: | + git fetch origin master ${{ github.event.pull_request.base.sha }} + HEAD=$(git rev-parse HEAD) + git reset --hard ${{ github.event.pull_request.base.sha }} export REF_NAME=master - cd __base - make | grep bench-run && (BENCH_COUNT=5 make bench-run bench-stat && cp bench-master.txt ../bench-master.txt) || echo "No benchmarks in base" - - name: Benchmark + make bench-run bench-stat + git reset --hard $HEAD + + - name: Benchmark stats id: bench run: | export REF_NAME=new - BENCH_COUNT=5 make bench-run bench-stat + OUTPUT=$(make bench-stat-diff) + echo "${OUTPUT}" + echo "diff<> $GITHUB_OUTPUT && echo "$OUTPUT" >> $GITHUB_OUTPUT && echo "EOF" >> $GITHUB_OUTPUT OUTPUT=$(make bench-stat) - OUTPUT="${OUTPUT//'%'/'%25'}" - OUTPUT="${OUTPUT//$'\n'/'%0A'}" - OUTPUT="${OUTPUT//$'\r'/'%0D'}" - echo "::set-output name=result::$OUTPUT" - - name: Comment Benchmark Result + echo "${OUTPUT}" + echo "result<> $GITHUB_OUTPUT && echo "$OUTPUT" >> $GITHUB_OUTPUT && echo "EOF" >> $GITHUB_OUTPUT + + - name: Comment benchmark result + continue-on-error: true uses: marocchino/sticky-pull-request-comment@v2 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -89,6 +119,13 @@ jobs: ### Benchmark Result
Benchmark diff with base branch + ``` + ${{ steps.bench.outputs.diff }} + ``` +
+ +
Benchmark result + ``` ${{ steps.bench.outputs.result }} ``` diff --git a/.github/workflows/cloc.yml b/.github/workflows/cloc.yml index ed1ddb9..3f1fc19 100644 --- a/.github/workflows/cloc.yml +++ b/.github/workflows/cloc.yml @@ -2,30 +2,37 @@ name: cloc on: pull_request: + +# Cancel the workflow in progress in newer build is about to start. +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: cloc: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: path: pr - name: Checkout base code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.base.sha }} path: base - - name: Count Lines Of Code + - name: Count lines of code id: loc run: | - curl -OL https://github.com/vearutop/sccdiff/releases/download/v1.0.1/linux_amd64.tar.gz && tar xf linux_amd64.tar.gz + curl -sLO https://github.com/vearutop/sccdiff/releases/download/v1.0.3/linux_amd64.tar.gz && tar xf linux_amd64.tar.gz + sccdiff_hash=$(git hash-object ./sccdiff) + [ "$sccdiff_hash" == "ae8a07b687bd3dba60861584efe724351aa7ff63" ] || (echo "::error::unexpected hash for sccdiff, possible tampering: $sccdiff_hash" && exit 1) OUTPUT=$(cd pr && ../sccdiff -basedir ../base) - OUTPUT="${OUTPUT//'%'/'%25'}" - OUTPUT="${OUTPUT//$'\n'/'%0A'}" - OUTPUT="${OUTPUT//$'\r'/'%0D'}" - echo "::set-output name=diff::$OUTPUT" + echo "${OUTPUT}" + echo "diff<> $GITHUB_OUTPUT && echo "$OUTPUT" >> $GITHUB_OUTPUT && echo "EOF" >> $GITHUB_OUTPUT - - name: Comment Code Lines + - name: Comment lines of code + continue-on-error: true uses: marocchino/sticky-pull-request-comment@v2 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index a7977d6..9acf314 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -8,17 +8,26 @@ on: - master - main pull_request: + +# Cancel the workflow in progress in newer build is about to start. +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: golangci: name: golangci-lint runs-on: ubuntu-latest steps: + - uses: actions/setup-go@v3 + with: + go-version: 1.23.x - uses: actions/checkout@v2 - name: golangci-lint - uses: golangci/golangci-lint-action@v2.5.2 + uses: golangci/golangci-lint-action@v6.1.0 with: # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.40.1 + version: v1.61.0 # Optional: working directory, useful for monorepos # working-directory: somedir diff --git a/.github/workflows/gorelease.yml b/.github/workflows/gorelease.yml new file mode 100644 index 0000000..c031db4 --- /dev/null +++ b/.github/workflows/gorelease.yml @@ -0,0 +1,56 @@ +# This script is provided by github.com/bool64/dev. +name: gorelease +on: + pull_request: + +# Cancel the workflow in progress in newer build is about to start. +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +env: + GO_VERSION: 1.23.x +jobs: + gorelease: + runs-on: ubuntu-latest + steps: + - name: Install Go stable + if: env.GO_VERSION != 'tip' + uses: actions/setup-go@v4 + with: + go-version: ${{ env.GO_VERSION }} + - name: Install Go tip + if: env.GO_VERSION == 'tip' + run: | + curl -sL https://storage.googleapis.com/go-build-snap/go/linux-amd64/$(git ls-remote https://github.com/golang/go.git HEAD | awk '{print $1;}').tar.gz -o gotip.tar.gz + ls -lah gotip.tar.gz + mkdir -p ~/sdk/gotip + tar -C ~/sdk/gotip -xzf gotip.tar.gz + ~/sdk/gotip/bin/go version + echo "PATH=$HOME/go/bin:$HOME/sdk/gotip/bin/:$PATH" >> $GITHUB_ENV + - name: Checkout code + uses: actions/checkout@v3 + - name: Gorelease cache + uses: actions/cache@v3 + with: + path: | + ~/go/bin/gorelease + key: ${{ runner.os }}-gorelease-generic + - name: Gorelease + id: gorelease + run: | + test -e ~/go/bin/gorelease || go install golang.org/x/exp/cmd/gorelease@latest + OUTPUT=$(gorelease 2>&1 || exit 0) + echo "${OUTPUT}" + echo "report<> $GITHUB_OUTPUT && echo "$OUTPUT" >> $GITHUB_OUTPUT && echo "EOF" >> $GITHUB_OUTPUT + - name: Comment report + continue-on-error: true + uses: marocchino/sticky-pull-request-comment@v2 + with: + header: gorelease + message: | + ### Go API Changes + +
+            ${{ steps.gorelease.outputs.report }}
+            
\ No newline at end of file diff --git a/.github/workflows/test-unit.yml b/.github/workflows/test-unit.yml index a7f892a..42a4780 100644 --- a/.github/workflows/test-unit.yml +++ b/.github/workflows/test-unit.yml @@ -6,24 +6,45 @@ on: - master - main pull_request: + +# Cancel the workflow in progress in newer build is about to start. +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + env: GO111MODULE: "on" RUN_BASE_COVERAGE: "on" # Runs test for PR base in case base test coverage is missing. + COV_GO_VERSION: 1.23.x # Version of Go to collect coverage + TARGET_DELTA_COV: 90 # Target coverage of changed lines, in percents jobs: test: strategy: matrix: - go-version: [ 1.11.x, 1.12.x, 1.13.x, 1.14.x, 1.15.x, 1.16.x ] + go-version: [ 1.11.x, 1.22.x, 1.23.x ] runs-on: ubuntu-latest steps: - - name: Install Go - uses: actions/setup-go@v2 + - name: Install Go stable + if: matrix.go-version != 'tip' + uses: actions/setup-go@v4 with: go-version: ${{ matrix.go-version }} + + - name: Install Go tip + if: matrix.go-version == 'tip' + run: | + curl -sL https://storage.googleapis.com/go-build-snap/go/linux-amd64/$(git ls-remote https://github.com/golang/go.git HEAD | awk '{print $1;}').tar.gz -o gotip.tar.gz + ls -lah gotip.tar.gz + mkdir -p ~/sdk/gotip + tar -C ~/sdk/gotip -xzf gotip.tar.gz + ~/sdk/gotip/bin/go version + echo "PATH=$HOME/go/bin:$HOME/sdk/gotip/bin/:$PATH" >> $GITHUB_ENV + - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 + - name: Go cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: # In order: # * Module download cache @@ -34,42 +55,55 @@ jobs: key: ${{ runner.os }}-go-cache-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go-cache + - name: Restore base test coverage - if: matrix.go-version == '1.16.x' + id: base-coverage + if: matrix.go-version == env.COV_GO_VERSION && github.event.pull_request.base.sha != '' uses: actions/cache@v2 with: path: | unit-base.txt # Use base sha for PR or new commit hash for master/main push in test result key. key: ${{ runner.os }}-unit-test-coverage-${{ (github.event.pull_request.base.sha != github.event.after) && github.event.pull_request.base.sha || github.event.after }} - - name: Checkout base code - if: matrix.go-version == '1.16.x' && env.RUN_BASE_COVERAGE == 'on' && steps.benchmark-base.outputs.cache-hit != 'true' && github.event.pull_request.base.sha != '' - uses: actions/checkout@v2 - with: - ref: ${{ github.event.pull_request.base.sha }} - path: __base + - name: Run test for base code - if: matrix.go-version == '1.16.x' && env.RUN_BASE_COVERAGE == 'on' && steps.benchmark-base.outputs.cache-hit != 'true' && github.event.pull_request.base.sha != '' + if: matrix.go-version == env.COV_GO_VERSION && env.RUN_BASE_COVERAGE == 'on' && steps.base-coverage.outputs.cache-hit != 'true' && github.event.pull_request.base.sha != '' run: | - cd __base - make | grep test-unit && (make test-unit && go tool cover -func=./unit.coverprofile | sed -e 's/.go:[0-9]*:\t/.go\t/g' | sed -e 's/\t\t*/\t/g' > ../unit-base.txt) || echo "No test-unit in base" + git fetch origin master ${{ github.event.pull_request.base.sha }} + HEAD=$(git rev-parse HEAD) + git reset --hard ${{ github.event.pull_request.base.sha }} + (make test-unit && go tool cover -func=./unit.coverprofile > unit-base.txt) || echo "No test-unit in base" + git reset --hard $HEAD + - name: Test id: test run: | make test-unit - go tool cover -func=./unit.coverprofile | sed -e 's/.go:[0-9]*:\t/.go\t/g' | sed -e 's/\t\t*/\t/g' > unit.txt - OUTPUT=$(test -e unit-base.txt && (diff unit-base.txt unit.txt || exit 0) || cat unit.txt) - OUTPUT="${OUTPUT//'%'/'%25'}" - OUTPUT="${OUTPUT//$'\n'/'%0A'}" - OUTPUT="${OUTPUT//$'\r'/'%0D'}" + go tool cover -func=./unit.coverprofile > unit.txt TOTAL=$(grep 'total:' unit.txt) - echo "::set-output name=diff::$OUTPUT" - echo "::set-output name=total::$TOTAL" - - name: Store base coverage - if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' }} - run: cp unit.txt unit-base.txt - - name: Comment Test Coverage - if: matrix.go-version == '1.16.x' + echo "${TOTAL}" + echo "total=$TOTAL" >> $GITHUB_OUTPUT + + - name: Annotate missing test coverage + id: annotate + if: matrix.go-version == env.COV_GO_VERSION && github.event.pull_request.base.sha != '' + run: | + curl -sLO https://github.com/vearutop/gocovdiff/releases/download/v1.4.2/linux_amd64.tar.gz && tar xf linux_amd64.tar.gz && rm linux_amd64.tar.gz + gocovdiff_hash=$(git hash-object ./gocovdiff) + [ "$gocovdiff_hash" == "c37862c73a677e5a9c069470287823ab5bbf0244" ] || (echo "::error::unexpected hash for gocovdiff, possible tampering: $gocovdiff_hash" && exit 1) + git fetch origin master ${{ github.event.pull_request.base.sha }} + REP=$(./gocovdiff -mod github.com/$GITHUB_REPOSITORY -cov unit.coverprofile -gha-annotations gha-unit.txt -delta-cov-file delta-cov-unit.txt -target-delta-cov ${TARGET_DELTA_COV}) + echo "${REP}" + cat gha-unit.txt + DIFF=$(test -e unit-base.txt && ./gocovdiff -mod github.com/$GITHUB_REPOSITORY -func-cov unit.txt -func-base-cov unit-base.txt || echo "Missing base coverage file") + TOTAL=$(cat delta-cov-unit.txt) + echo "rep<> $GITHUB_OUTPUT && echo "$REP" >> $GITHUB_OUTPUT && echo "EOF" >> $GITHUB_OUTPUT + echo "diff<> $GITHUB_OUTPUT && echo "$DIFF" >> $GITHUB_OUTPUT && echo "EOF" >> $GITHUB_OUTPUT + echo "total<> $GITHUB_OUTPUT && echo "$TOTAL" >> $GITHUB_OUTPUT && echo "EOF" >> $GITHUB_OUTPUT + + - name: Comment test coverage + continue-on-error: true + if: matrix.go-version == env.COV_GO_VERSION && github.event.pull_request.base.sha != '' uses: marocchino/sticky-pull-request-comment@v2 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -77,15 +111,25 @@ jobs: message: | ### Unit Test Coverage ${{ steps.test.outputs.total }} + ${{ steps.annotate.outputs.total }} +
Coverage of changed lines + + ${{ steps.annotate.outputs.rep }} + +
+
Coverage diff with base branch - ```diff - ${{ steps.test.outputs.diff }} - ``` + ${{ steps.annotate.outputs.diff }} +
+ - name: Store base coverage + if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' }} + run: cp unit.txt unit-base.txt + - name: Upload code coverage - if: matrix.go-version == '1.16.x' + if: matrix.go-version == env.COV_GO_VERSION uses: codecov/codecov-action@v1 with: file: ./unit.coverprofile diff --git a/.golangci.yml b/.golangci.yml index a01f296..d657f20 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -20,35 +20,55 @@ linters-settings: linters: enable-all: true disable: + - containedctx + - fatcontext + - contextcheck - errorlint - cyclop - - goerr113 + - err113 - testpackage - lll - - maligned - gochecknoglobals - gomnd - wrapcheck - paralleltest - forbidigo - - exhaustivestruct - - interfacer # deprecated - forcetypeassert - - scopelint # deprecated - - ifshort # too many false positives - - golint # deprecated + - varnamelen + - tagliatelle + - errname + - ireturn + - exhaustruct + - nonamedreturns + - testableexamples + - dupword + - depguard + - tagalign + - execinquery + - mnd + - testifylint issues: exclude-use-default: false exclude-rules: - linters: - gomnd + - mnd - goconst - - goerr113 - noctx - funlen - dupl + - structcheck + - unused + - unparam - sqlclosecheck - rowserrcheck path: "_test.go" + - linters: + - errcheck # Error checking omitted for brevity. + - gosec + path: "example_" + - linters: + - revive + text: "unused-parameter: parameter" diff --git a/Makefile b/Makefile index e772ab6..d1ea9ce 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -#GOLANGCI_LINT_VERSION := "v1.40.1" # Optional configuration to pinpoint golangci-lint version. +#GOLANGCI_LINT_VERSION := "v1.61.0" # Optional configuration to pinpoint golangci-lint version. # The head of Makefile determines location of dev-go to include standard targets. GO ?= go @@ -23,7 +23,7 @@ ifeq ($(DEVGO_PATH),) DEVGO_PATH := $(shell GO111MODULE=on $(GO) list ${modVendor} -f '{{.Dir}}' -m github.com/bool64/dev) ifeq ($(DEVGO_PATH),) $(info Module github.com/bool64/dev not found, downloading.) - DEVGO_PATH := $(shell export GO111MODULE=on && $(GO) mod tidy && $(GO) list -f '{{.Dir}}' -m github.com/bool64/dev) + DEVGO_PATH := $(shell export GO111MODULE=on && $(GO) get github.com/bool64/dev && $(GO) list -f '{{.Dir}}' -m github.com/bool64/dev) endif endif diff --git a/driver.go b/driver.go index c573298..6012c24 100644 --- a/driver.go +++ b/driver.go @@ -49,9 +49,9 @@ var defaultOperations = map[Operation]bool{ type conn interface { driver.Pinger - driver.Execer // nolint:staticcheck // Deprecated usage for backwards compatibility. + driver.Execer //nolint:staticcheck // Deprecated usage for backwards compatibility. driver.ExecerContext - driver.Queryer // nolint:staticcheck // Deprecated usage for backwards compatibility. + driver.Queryer //nolint:staticcheck // Deprecated usage for backwards compatibility. driver.QueryerContext driver.Conn driver.ConnPrepareContext @@ -241,7 +241,7 @@ func (c wConn) Ping(ctx context.Context) (err error) { func (c wConn) Exec(query string, args []driver.Value) (res driver.Result, err error) { ctx := context.Background() - // nolint:staticcheck // Deprecated usage for backwards compatibility. + //nolint:staticcheck // Deprecated usage for backwards compatibility. exec, ok := c.parent.(driver.Execer) if !ok { @@ -303,7 +303,7 @@ func (c wConn) ExecContext(ctx context.Context, query string, args []driver.Name } func (c wConn) Query(query string, args []driver.Value) (rows driver.Rows, err error) { - // nolint:staticcheck // Deprecated usage for backwards compatibility. + //nolint:staticcheck // Deprecated usage for backwards compatibility. queryer, ok := c.parent.(driver.Queryer) if !ok { @@ -448,7 +448,7 @@ func (c *wConn) BeginTx(ctx context.Context, opts driver.TxOptions) (tx driver.T return wTx{parent: tx, ctx: ctx, options: c.options}, nil } - tx, err = c.parent.Begin() // nolint:staticcheck // Deprecated usage for backwards compatibility. + tx, err = c.parent.Begin() //nolint:staticcheck // Deprecated usage for backwards compatibility. if err != nil { return nil, err } @@ -530,7 +530,7 @@ func (s wStmt) Exec(args []driver.Value) (res driver.Result, err error) { }() } - res, err = s.parent.Exec(args) // nolint:staticcheck // Deprecated usage for backwards compatibility. + res, err = s.parent.Exec(args) //nolint:staticcheck // Deprecated usage for backwards compatibility. if err != nil { return nil, err } @@ -581,7 +581,7 @@ func (s wStmt) Query(args []driver.Value) (rows driver.Rows, err error) { }() } - rows, err = s.parent.Query(args) // nolint:staticcheck // Deprecated usage for backwards compatibility. + rows, err = s.parent.Query(args) //nolint:staticcheck // Deprecated usage for backwards compatibility. if err != nil { return nil, err } diff --git a/driver_ext_test.go b/driver_ext_test.go index b4f9927..e3e87cd 100644 --- a/driver_ext_test.go +++ b/driver_ext_test.go @@ -30,6 +30,7 @@ func TestRegister(t *testing.T) { dbwrap.WithMiddleware( func(ctx context.Context, operation dbwrap.Operation, statement string, args []driver.NamedValue) (nCtx context.Context, onFinish func(error)) { assert.Equal(t, "bool64/dbwrap_test.TestRegister", dbwrap.Caller()) + l = append(l, "mw1 triggered: "+string(operation)+": "+statement) return ctx, func(err error) { diff --git a/driver_go1.10.go b/driver_go1.10.go index 0888c8b..084768c 100644 --- a/driver_go1.10.go +++ b/driver_go1.10.go @@ -1,3 +1,4 @@ +//go:build go1.10 // +build go1.10 package dbwrap @@ -74,12 +75,12 @@ func wrapConn(parent driver.Conn, options Options) driver.Conn { panic("unreachable") } -// nolint:funlen,gocyclo // Large switch is necessary to combine a variety of traits. +//nolint:funlen,gocyclo // Large switch is necessary to combine a variety of traits. func wrapStmt(ctx context.Context, stmt driver.Stmt, query string, options Options) driver.Stmt { var ( _, hasExeCtx = stmt.(driver.StmtExecContext) _, hasQryCtx = stmt.(driver.StmtQueryContext) - c, hasColConv = stmt.(driver.ColumnConverter) // nolint:staticcheck // Deprecated usage for backwards compatibility. + c, hasColConv = stmt.(driver.ColumnConverter) //nolint:staticcheck // Deprecated usage for backwards compatibility. n, hasNamValChk = stmt.(driver.NamedValueChecker) ) diff --git a/driver_go1.8.go b/driver_go1.8.go index 44b44e3..816a3e8 100644 --- a/driver_go1.8.go +++ b/driver_go1.8.go @@ -1,3 +1,4 @@ +//go:build !go1.9 // +build !go1.9 package dbwrap diff --git a/driver_go1.9.go b/driver_go1.9.go index 3a6590f..43af8af 100644 --- a/driver_go1.9.go +++ b/driver_go1.9.go @@ -1,3 +1,4 @@ +//go:build go1.9 && !go1.10 // +build go1.9,!go1.10 package dbwrap diff --git a/driver_test.go b/driver_test.go index d201738..ed9cf5d 100644 --- a/driver_test.go +++ b/driver_test.go @@ -99,11 +99,13 @@ func TestWrappingFallback(t *testing.T) { oRows = struct{ driver.Rows }{&stubRows{}} options, _ = prepareOptions([]Option{ WithInterceptor(func(ctx context.Context, operation Operation, statement string, - args []driver.NamedValue) (context.Context, string, []driver.NamedValue) { + args []driver.NamedValue, + ) (context.Context, string, []driver.NamedValue) { return ctx, statement, args }), WithMiddleware(func(ctx context.Context, operation Operation, statement string, - args []driver.NamedValue) (nCtx context.Context, onFinish func(error)) { + args []driver.NamedValue, + ) (nCtx context.Context, onFinish func(error)) { return ctx, nil }), }) diff --git a/example_test.go b/example_test.go index 98e8f93..46aed4f 100644 --- a/example_test.go +++ b/example_test.go @@ -23,7 +23,7 @@ func ExampleWrapConnector() { dbwrap.WithInterceptor(func(ctx context.Context, operation dbwrap.Operation, statement string, args []driver.NamedValue) (context.Context, string, []driver.NamedValue) { // Closest caller in the stack with package not equal to listed and to "database/sql". // Put your database helper packages here, so that caller bubbles up to app level. - caller := dbwrap.Caller( + caller := dbwrap.CallerCtx(ctx, "github.com/Masterminds/squirrel", "github.com/jmoiron/sqlx", ) @@ -46,7 +46,7 @@ func ExampleWrapConnector() { args []driver.NamedValue, ) (nCtx context.Context, onFinish func(error)) { // Closest caller in the stack with package not equal to listed and to "database/sql". - caller := dbwrap.Caller( + caller := dbwrap.CallerCtx(ctx, "github.com/Masterminds/squirrel", "github.com/jmoiron/sqlx", ) diff --git a/go.mod b/go.mod index c5fee4d..3a25253 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,6 @@ go 1.11 require ( github.com/DATA-DOG/go-sqlmock v1.5.0 - github.com/bool64/dev v0.1.35 + github.com/bool64/dev v0.2.36 github.com/stretchr/testify v1.4.0 ) diff --git a/go.sum b/go.sum index 74299dc..507bd10 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/bool64/dev v0.1.35 h1:uouBAq2kAJ+k9UypYRs118bAYttNQWDyK4IzjfLb5fc= -github.com/bool64/dev v0.1.35/go.mod h1:cTHiTDNc8EewrQPy3p1obNilpMpdmlUesDkFTF2zRWU= +github.com/bool64/dev v0.2.36 h1:yU3bbOTujoxhWnt8ig8t94PVmZXIkCaRj9C57OtqJBY= +github.com/bool64/dev v0.2.36/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/options.go b/options.go index 2ab5a3b..ac6a2dc 100644 --- a/options.go +++ b/options.go @@ -64,7 +64,8 @@ func WithInterceptor(i func( operation Operation, statement string, args []driver.NamedValue, -) (context.Context, string, []driver.NamedValue)) Option { +) (context.Context, string, []driver.NamedValue), +) Option { return func(o *Options) { o.Intercept = i } diff --git a/runtime.go b/runtime.go index f48e329..507c3a8 100644 --- a/runtime.go +++ b/runtime.go @@ -1,6 +1,7 @@ package dbwrap import ( + "context" "path" "runtime" "strings" @@ -11,11 +12,28 @@ const ( stackSize = 30 ) +type callerCtxKey struct{} + +// WithCaller overrides context with pre-defined caller value. +func WithCaller(ctx context.Context, caller string) context.Context { + return context.WithValue(ctx, callerCtxKey{}, caller) +} + +// CallerCtx checks context for a pre-defined caller value or returns caller from runtime stack. +func CallerCtx(ctx context.Context, skipPackages ...string) string { + if caller, ok := ctx.Value(callerCtxKey{}).(string); ok { + return caller + } + + return Caller(skipPackages...) +} + // Caller returns name and package of closest parent function // that does not belong to skipped packages. // // For example the result could be -// pressly/goose.MySQLDialect.dbVersionQuery +// +// pressly/goose.MySQLDialect.dbVersionQuery func Caller(skipPackages ...string) string { p := "" pc := make([]uintptr, stackSize) diff --git a/runtime_test.go b/runtime_test.go index e71549b..ac9ab2b 100644 --- a/runtime_test.go +++ b/runtime_test.go @@ -1,9 +1,11 @@ package dbwrap_test import ( + "context" "testing" "github.com/bool64/dbwrap" + "github.com/stretchr/testify/assert" ) func BenchmarkCaller(b *testing.B) { @@ -13,3 +15,9 @@ func BenchmarkCaller(b *testing.B) { _ = dbwrap.Caller("database/sql", "abc", "def") } } + +func TestCallerCtx(t *testing.T) { + ctx := dbwrap.WithCaller(context.Background(), "test") + + assert.Equal(t, "test", dbwrap.CallerCtx(ctx, "abc")) +}