From 802e1bb47f72b8cc9daba9b5e643fa4f51735018 Mon Sep 17 00:00:00 2001 From: Darien Hernandez Date: Fri, 22 Nov 2024 18:25:32 +0100 Subject: [PATCH] patch: Github Actions and Makefile functionalities --- .github/actions/check-branch/README.md | 45 ++++++ .github/actions/check-branch/action.yml | 16 +++ .github/actions/check-branch/check-branch.sh | 49 +++++++ .github/dependabot.yml | 14 ++ .github/workflows/check.yml | 19 +++ .github/workflows/cloc.yml | 40 ++++++ .github/workflows/golangci-lint.yml | 46 +++++++ .github/workflows/gorelease.yml | 56 ++++++++ .github/workflows/release.yml | 69 ++++++++++ .github/workflows/test-unit.yml | 136 +++++++++++++++++++ .golangci.yml | 19 ++- Makefile | 37 +++++ dev.go | 8 ++ doc.go | 5 + errors.go | 1 - errors_test.go | 136 +++++++++---------- go.mod | 5 +- go.sum | 4 + 18 files changed, 618 insertions(+), 87 deletions(-) create mode 100644 .github/actions/check-branch/README.md create mode 100644 .github/actions/check-branch/action.yml create mode 100755 .github/actions/check-branch/check-branch.sh create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/check.yml create mode 100644 .github/workflows/cloc.yml create mode 100644 .github/workflows/golangci-lint.yml create mode 100644 .github/workflows/gorelease.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/test-unit.yml create mode 100644 Makefile create mode 100644 dev.go create mode 100755 doc.go diff --git a/.github/actions/check-branch/README.md b/.github/actions/check-branch/README.md new file mode 100644 index 0000000..1af8b27 --- /dev/null +++ b/.github/actions/check-branch/README.md @@ -0,0 +1,45 @@ +# Check Branch + +This action gets the head ref or source branch of the pull request in a workflow to run a checks on the branch name. The check verify that the branch name starts with a placeholder `types` and followed by another placeholder `separators`. + +The input `types` default values are: + +- major +- release +- minor +- feature +- feat +- patch +- issue +- hotfix +- dependabot +- whitesource/ + +The input `separators` default value are `-` and `\`. + +## Usage + +See [action.yml](action.yml). + +## Examples + +```yaml +--- +name: check branch name + +on: + pull_request: + +jobs: + bump: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Check branch + uses: ./.github/actions/check-branch/ +``` + +## How does it work + +This simple action runs a [check-branch script](check-branch.sh) diff --git a/.github/actions/check-branch/action.yml b/.github/actions/check-branch/action.yml new file mode 100644 index 0000000..b5e4e22 --- /dev/null +++ b/.github/actions/check-branch/action.yml @@ -0,0 +1,16 @@ +name: 'Check Branch' +description: 'Check branch name' + +inputs: + types: + description: "Provide custom types if you don't want the default ones from major|release|minor|feature|patch|issue|hotfix|dependabot|whitesource/" + required: false + separators: + description: "Provide custom separators if you don't want the default ones from -|/" + required: false + +runs: + using: "composite" + steps: + - run: ${{ github.action_path }}/check-branch.sh "${{ inputs.types }}" "${{ inputs.separators }}" + shell: bash diff --git a/.github/actions/check-branch/check-branch.sh b/.github/actions/check-branch/check-branch.sh new file mode 100755 index 0000000..6281d83 --- /dev/null +++ b/.github/actions/check-branch/check-branch.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env sh + +# This code is provided by github.com/dohernandez/dev. + +FLAT_TYPES_DEFAULT="major release minor feature feat patch issue hotfix dependabot whitesource/" +FLAT_SEPARATORS_DEFAULT="- /" + +types="${1}" + +FLAT_TYPES="" + +for target in $types +do + FLAT_TYPES="$FLAT_TYPES $target" +done + +# removing the first space added when FLAT_TYPES is empty +FLAT_TYPES=$(echo "${FLAT_TYPES}" | sed 's/^ //g') + +# If FLAT_TYPES is empty, use the value of FLAT_TYPES_DEFAULT instead +FLAT_TYPES=${FLAT_TYPES:-$FLAT_TYPES_DEFAULT} + +REGEX_FLAT_TYPES=$(echo "${FLAT_TYPES}" | sed 's/ /|/g') + + +separators="${2}" + +FLAT_SEPARATORS="" + +for target in $separators +do + FLAT_SEPARATORS="$FLAT_SEPARATORS $target" +done + +# If FLAT_SEPARATORS is empty, use the value of FLAT_TYPES_DEFAULT instead +FLAT_SEPARATORS=${FLAT_SEPARATORS:-$FLAT_SEPARATORS_DEFAULT} + +REGEX_FLAT_SEPARATORS=$(echo "${FLAT_SEPARATORS}" | sed 's/ /|/g') + + + +# ^minor([-\/]+.+)?$ +if ! (echo "${GITHUB_HEAD_REF}" | grep -i -E "^($REGEX_FLAT_TYPES)([$REGEX_FLAT_SEPARATORS]+.+)?$"); then + VALID_FLAT_TYPES=$(echo "${FLAT_TYPES}" | sed 's/ /, /g') + VALID_FLAT_SEPARATORS=$(echo "${FLAT_SEPARATORS}" | sed 's/ /, /g') + echo "Invalid branch name \"${GITHUB_HEAD_REF}\". Valid branch prefixes: ${VALID_FLAT_TYPES} and separators: ${VALID_FLAT_SEPARATORS}" + exit 1 +fi +echo "Valid branch name" \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..87284b1 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,14 @@ +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" # Location go.mod + schedule: + interval: "daily" + open-pull-requests-limit: 1 + groups: + dependencies: + patterns: + - "*" # Update all dependencies + update-types: + - "minor" + - "patch" \ No newline at end of file diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 0000000..89d2611 --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,19 @@ +name: check + +on: + pull_request: + branches: + - main + types: [opened, edited, synchronize, reopened] + +jobs: + branch-name: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Check branch name + uses: ./.github/actions/check-branch/ + with: + types: ${{env.types}} + separators: ${{env.separators}} diff --git a/.github/workflows/cloc.yml b/.github/workflows/cloc.yml new file mode 100644 index 0000000..244a80d --- /dev/null +++ b/.github/workflows/cloc.yml @@ -0,0 +1,40 @@ +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@v3 + with: + path: pr + - name: Checkout base code + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.base.sha }} + path: base + - 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 + OUTPUT=$(cd pr && ../sccdiff -basedir ../base) + { + echo "diff<> $GITHUB_OUTPUT + - name: Comment Code Lines + uses: marocchino/sticky-pull-request-comment@v2 + with: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + header: LOC + message: | + ### Lines Of Code + ${{ steps.loc.outputs.diff }} \ No newline at end of file diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml new file mode 100644 index 0000000..5b030b0 --- /dev/null +++ b/.github/workflows/golangci-lint.yml @@ -0,0 +1,46 @@ +name: lint +on: + push: + tags: + - v* + branches: + - 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@v3 + - name: golangci-lint + 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.61.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 action will use pre-installed Go. + # skip-go-installation: 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 \ No newline at end of file diff --git a/.github/workflows/gorelease.yml b/.github/workflows/gorelease.yml new file mode 100644 index 0000000..6651c31 --- /dev/null +++ b/.github/workflows/gorelease.yml @@ -0,0 +1,56 @@ +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: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + header: gorelease + message: | + ### Go API Changes + +
+            ${{ steps.gorelease.outputs.report }}
+            
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..9dc222a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,69 @@ +name: release + +on: + pull_request: + types: + - closed + branches: + - main + +jobs: + create-release: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.23.x + + - name: Get Merged PR Branch + id: get-branch + run: | + PR_BRANCH=$(jq -r '.pull_request.head.ref' "$GITHUB_EVENT_PATH") + echo "Merged PR Branch: $PR_BRANCH" + echo "PR_BRANCH=$PR_BRANCH" >> $GITHUB_ENV + + - name: Determine level + id: determine-level + run: | + case "${{ env.PR_BRANCH }}" in + patch* | issue* | hotfix* | dependabot* | whitesource/*) + LEVEL="patch";; + minor* | feature* | feat*) + LEVEL="minor";; + major* | release*) + LEVEL="major";; + *) + LEVEL="unknown";; + esac + echo "Determined level: $LEVEL" + echo "LEVEL=$LEVEL" >> $GITHUB_ENV + + - name: Get latest tag + id: latest_tag + uses: actions-ecosystem/action-get-latest-tag@v1 + + - name: Bump release version + id: bump_version + uses: actions-ecosystem/action-bump-semver@v1 + with: + current_version: ${{ steps.latest_tag.outputs.tag }} + level: ${{ env.LEVEL }} + + - name: Get Merge Commit Message + id: get_merge_commit_message + run: | + MERGE_COMMIT_MESSAGE=$(git log --merges --format=%B -n 1) + echo "Merge Commit Message: $MERGE_COMMIT_MESSAGE" + echo "$MERGE_COMMIT_MESSAGE" > ${{ github.workspace }}-CHANGELOG.txt + + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + body_path: ${{ github.workspace }}-CHANGELOG.txt + tag_name: ${{ steps.bump_version.outputs.new_version }} + token: ${{ secrets.GH_TOKEN }} diff --git a/.github/workflows/test-unit.yml b/.github/workflows/test-unit.yml new file mode 100644 index 0000000..a0aa98d --- /dev/null +++ b/.github/workflows/test-unit.yml @@ -0,0 +1,136 @@ +name: test-unit +on: + push: + branches: + - 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.23.x ] + runs-on: ubuntu-latest + steps: + - 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@v3 + + - name: Go cache + uses: actions/cache@v3 + with: + # In order: + # * Module download cache + # * Build cache (Linux) + path: | + ~/go/pkg/mod + ~/.cache/go-build + key: ${{ runner.os }}-go-cache-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go-cache + + - name: Restore base test coverage + id: base-coverage + if: matrix.go-version == env.COV_GO_VERSION && github.event.pull_request.base.sha != '' + uses: actions/cache@v3 + with: + path: | + unit-base.txt + # Use base sha for PR or new commit hash for 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: Run test for base code + 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: | + git fetch origin main ${{ github.event.pull_request.base.sha }} + HEAD=$(git rev-parse HEAD) + git reset --hard ${{ github.event.pull_request.base.sha }} + (make test-unit && grep -v "/mocks/" ./unit.coverprofile | grep -v "/cmd/" > ./unit.coverprofile.sanitize && mv ./unit.coverprofile.sanitize ./unit.coverprofile && 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 + grep -v "/mocks/" ./unit.coverprofile | grep -v "/cmd/" > ./unit.coverprofile.sanitize + mv ./unit.coverprofile.sanitize ./unit.coverprofile + go tool cover -func=./unit.coverprofile > unit.txt + TOTAL=$(grep 'total:' unit.txt) + 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 main ${{ 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.GH_TOKEN }} + header: unit-test + 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 + + ${{ steps.annotate.outputs.diff }} + +
+ + - name: Store base coverage + if: ${{ github.ref == 'refs/heads/main' }} + run: cp unit.txt unit-base.txt + + - name: Upload code coverage + if: matrix.go-version == env.COV_GO_VERSION + uses: codecov/codecov-action@v1 + with: + file: ./unit.coverprofile + flags: unittests diff --git a/.golangci.yml b/.golangci.yml index f84cc97..7fd3c86 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,6 +1,6 @@ # See https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml run: - go: 1.19 + go: 1.23.3 tests: true linters-settings: @@ -31,31 +31,28 @@ linters: disable: - contextcheck - lll - - maligned # deprecated - gochecknoglobals - gomnd - wrapcheck - paralleltest - forbidigo - - exhaustivestruct - - interfacer # deprecated - forcetypeassert - - scopelint # deprecated - - ifshort # too many false positives - - golint # deprecated - varnamelen - tagliatelle - errname - ireturn - testpackage - - structcheck # deprecated - - nosnakecase # deprecated - - deadcode # deprecated - - varcheck # deprecated - exhaustruct - rowserrcheck # disabled because of generics. You can track the evolution of the generics support by following the https://github.com/golangci/golangci-lint/issues/2649. - sqlclosecheck # disabled because of generics. You can track the evolution of the generics support by following the https://github.com/golangci/golangci-lint/issues/2649. - wastedassign # disabled because of generics. You can track the evolution of the generics support by following the https://github.com/golangci/golangci-lint/issues/2649. + - tagalign + - depguard + - perfsprint + - mnd + - err113 + - exportloopref # deprecated https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle + - execinquery # deprecated https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle issues: exclude-use-default: false diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..34d2a2c --- /dev/null +++ b/Makefile @@ -0,0 +1,37 @@ +#GOLANGCI_LINT_VERSION := "v1.43.0" # Optional configuration to pinpoint golangci-lint version. + +# The head of Makefile determines location of dev-go to include standard targets. +GO ?= go +export GO111MODULE = on + +ifneq "$(GOFLAGS)" "" + $(info GOFLAGS: ${GOFLAGS}) +endif + +ifneq "$(wildcard ./vendor )" "" + $(info Using vendor) + modVendor = -mod=vendor + ifeq (,$(findstring -mod,$(GOFLAGS))) + export GOFLAGS := ${GOFLAGS} ${modVendor} + endif + ifneq "$(wildcard ./vendor/github.com/bool64/dev)" "" + DEVGO_PATH := ./vendor/github.com/bool64/dev + endif +endif + +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) get github.com/bool64/dev && $(GO) list -f '{{.Dir}}' -m github.com/bool64/dev) + endif +endif + +-include $(DEVGO_PATH)/makefiles/main.mk +-include $(DEVGO_PATH)/makefiles/lint.mk +-include $(DEVGO_PATH)/makefiles/test-unit.mk + +# Add your custom targets here. + +## Run tests +test: test-unit diff --git a/dev.go b/dev.go new file mode 100644 index 0000000..9beae28 --- /dev/null +++ b/dev.go @@ -0,0 +1,8 @@ +//go:build never +// +build never + +package noprune + +import ( + _ "github.com/bool64/dev" // Include CI/Dev scripts to project. +) diff --git a/doc.go b/doc.go new file mode 100755 index 0000000..abcb811 --- /dev/null +++ b/doc.go @@ -0,0 +1,5 @@ +// Package errors provides enriched errors, with error chain. +// +// Provides functions that create enriched grpc status.Status with error details, +// that can be use in the client to recreate the error chain. +package errors diff --git a/errors.go b/errors.go index 896f053..d442b61 100644 --- a/errors.go +++ b/errors.go @@ -159,7 +159,6 @@ func Cause(err error) error { Cause() error } - //nolint:errorlint cause, ok := err.(causer) if !ok { return nil diff --git a/errors_test.go b/errors_test.go index a182553..d41f904 100644 --- a/errors_test.go +++ b/errors_test.go @@ -102,9 +102,9 @@ func TestWrapError(t *testing.T) { require.Error(t, errWrap, "it is not an error") expected := "oops" - assert.EqualError(t, errWrap, expected, "error message mismatch, got %s want %s", errWrap, expected) + require.EqualError(t, errWrap, expected, "error message mismatch, got %s want %s", errWrap, expected) - assert.Equal(t, sErr, errWrap) + require.Equal(t, sErr, errWrap) }) t.Run("WrapWithError with supplied nil", func(t *testing.T) { @@ -116,9 +116,9 @@ func TestWrapError(t *testing.T) { require.Error(t, errWrap, "it is not an error") expected := "oops" - assert.EqualError(t, errWrap, expected, "error message mismatch, got %s want %s", errWrap, expected) + require.EqualError(t, errWrap, expected, "error message mismatch, got %s want %s", errWrap, expected) - assert.Equal(t, err, errWrap) + require.Equal(t, err, errWrap) }) } @@ -139,12 +139,11 @@ func TestEnriched(t *testing.T) { require.Error(t, errEnriched, "it is not an error") expected := "failed" - assert.EqualError(t, errEnriched, expected, "error message mismatch, got %s want %s", errEnriched, expected) + require.EqualError(t, errEnriched, expected, "error message mismatch, got %s want %s", errEnriched, expected) - //nolint:errorlint errKV, ok := errEnriched.(enrichedError) - assert.True(t, ok, "error does not implement enrichedError interface") - assert.Equal(t, []interface{}{"id", 5}, errKV.Tuples()) + require.True(t, ok, "error does not implement enrichedError interface") + require.Equal(t, []interface{}{"id", 5}, errKV.Tuples()) }) t.Run("Enrich error and wrap", func(t *testing.T) { @@ -158,12 +157,11 @@ func TestEnriched(t *testing.T) { sErr := errors.WrapError(errors.New("oops"), errEnriched) expected := "failed: oops" - assert.EqualError(t, sErr, expected, "error message mismatch, got %s want %s", sErr, expected) + require.EqualError(t, sErr, expected, "error message mismatch, got %s want %s", sErr, expected) - //nolint:errorlint errKV, ok := errEnriched.(enrichedError) - assert.True(t, ok, "error does not implement enrichedError interface") - assert.Equal(t, []interface{}{"id", 5}, errKV.Tuples()) + require.True(t, ok, "error does not implement enrichedError interface") + require.Equal(t, []interface{}{"id", 5}, errKV.Tuples()) }) t.Run("Enrich error, malformed", func(t *testing.T) { @@ -175,11 +173,10 @@ func TestEnriched(t *testing.T) { require.Error(t, errEnriched, "it is not an error") expected := "failed" - assert.EqualError(t, errEnriched, expected, "error message mismatch, got %s want %s", errEnriched, expected) + require.EqualError(t, errEnriched, expected, "error message mismatch, got %s want %s", errEnriched, expected) - //nolint:errorlint _, ok := errEnriched.(enrichedError) - assert.False(t, ok, "error does implement enrichedError interface") + require.False(t, ok, "error does implement enrichedError interface") }) t.Run("EnrichWrapWithError error", func(t *testing.T) { @@ -195,12 +192,11 @@ func TestEnriched(t *testing.T) { require.ErrorIs(t, errEnrichedWrap, err) expected := "oops: failed" - assert.EqualError(t, errEnrichedWrap, expected, "error message mismatch, got %s want %s", errEnrichedWrap, expected) + require.EqualError(t, errEnrichedWrap, expected, "error message mismatch, got %s want %s", errEnrichedWrap, expected) - //nolint:errorlint errKV, ok := errEnrichedWrap.(enrichedError) - assert.True(t, ok, "error does not implement enrichedError interface") - assert.Equal(t, []interface{}{"id", 5}, errKV.Tuples()) + require.True(t, ok, "error does not implement enrichedError interface") + require.Equal(t, []interface{}{"id", 5}, errKV.Tuples()) }) t.Run("Enrich enriched error", func(t *testing.T) { @@ -215,20 +211,18 @@ func TestEnriched(t *testing.T) { require.Error(t, errEnriched2, "it is not an error") expected := "failed" - assert.EqualError(t, errEnriched, expected, "error message mismatch, got %s want %s", errEnriched, expected) + require.EqualError(t, errEnriched, expected, "error message mismatch, got %s want %s", errEnriched, expected) - //nolint:errorlint errKV, ok := errEnriched.(enrichedError) - assert.True(t, ok, "error does not implement enrichedError interface") - assert.Equal(t, []interface{}{"id", 5}, errKV.Tuples()) + require.True(t, ok, "error does not implement enrichedError interface") + require.Equal(t, []interface{}{"id", 5}, errKV.Tuples()) expected2 := "failed" - assert.EqualError(t, errEnriched2, expected2, "error message mismatch, got %s want %s", errEnriched, expected) + require.EqualError(t, errEnriched2, expected2, "error message mismatch, got %s want %s", errEnriched, expected) - //nolint:errorlint errKV, ok = errEnriched2.(enrichedError) - assert.True(t, ok, "error does not implement enrichedError interface") - assert.Equal(t, []interface{}{"number", 6, "hash", "0X0", "id", 5}, errKV.Tuples()) + require.True(t, ok, "error does not implement enrichedError interface") + require.Equal(t, []interface{}{"number", 6, "hash", "0X0", "id", 5}, errKV.Tuples()) }) t.Run("Enrich enriched cause error", func(t *testing.T) { @@ -243,20 +237,18 @@ func TestEnriched(t *testing.T) { require.Error(t, errEnriched2) expected := "stream blocks: failed" - assert.EqualError(t, errEnriched, expected, "error message mismatch, got %s want %s", errEnriched, expected) + require.EqualError(t, errEnriched, expected, "error message mismatch, got %s want %s", errEnriched, expected) - //nolint:errorlint errKV, ok := errEnriched.(enrichedError) - assert.True(t, ok, "error does not implement enrichedError interface") - assert.Equal(t, []interface{}{"block_hash", "0X0"}, errKV.Tuples()) + require.True(t, ok, "error does not implement enrichedError interface") + require.Equal(t, []interface{}{"block_hash", "0X0"}, errKV.Tuples()) expected2 := "stream blocks: failed: oops" - assert.EqualError(t, errEnriched2, expected2, "error message mismatch, got %s want %s", errEnriched, expected) + require.EqualError(t, errEnriched2, expected2, "error message mismatch, got %s want %s", errEnriched, expected) - //nolint:errorlint errKV, ok = errEnriched2.(enrichedError) - assert.True(t, ok, "error does not implement enrichedError interface") - assert.Equal(t, []interface{}{"bInt", big.NewInt(42), "block_hash", "0X0"}, errKV.Tuples()) + require.True(t, ok, "error does not implement enrichedError interface") + require.Equal(t, []interface{}{"bInt", big.NewInt(42), "block_hash", "0X0"}, errKV.Tuples()) }) } @@ -272,13 +264,13 @@ func Test_Unwrap(t *testing.T) { require.Error(t, errWrap, "it is not an error") expected := "oops: failed" - assert.EqualError(t, errWrap, expected, "error message mismatch, got %s want %s", errWrap, expected) + require.EqualError(t, errWrap, expected, "error message mismatch, got %s want %s", errWrap, expected) uErr := errors.Unwrap(errWrap) - require.NotNil(t, uErr, "err does not implement Unwrap interface") + require.Error(t, uErr, "err does not implement Unwrap interface") expected = "failed" - assert.EqualError(t, uErr, expected, "error message mismatch, got %s want %s", uErr, expected) + require.EqualError(t, uErr, expected, "error message mismatch, got %s want %s", uErr, expected) }) t.Run("Unwrap for errors.Wrapf", func(t *testing.T) { @@ -290,13 +282,13 @@ func Test_Unwrap(t *testing.T) { require.Error(t, errWrap, "it is not an error") expected := "oops id 5: failed" - assert.EqualError(t, errWrap, expected, "error message mismatch, got %s want %s", errWrap, expected) + require.EqualError(t, errWrap, expected, "error message mismatch, got %s want %s", errWrap, expected) uErr := errors.Unwrap(errWrap) - require.NotNil(t, uErr, "err does not implement Unwrap interface") + require.Error(t, uErr, "err does not implement Unwrap interface") expected = "failed" - assert.EqualError(t, uErr, expected, "error message mismatch, got %s want %s", uErr, expected) + require.EqualError(t, uErr, expected, "error message mismatch, got %s want %s", uErr, expected) }) t.Run("Unwrap for errors.WrapWithError", func(t *testing.T) { @@ -309,10 +301,10 @@ func Test_Unwrap(t *testing.T) { require.Error(t, errWrap, "it is not an error") uErr := errors.Unwrap(errWrap) - require.NotNil(t, uErr, "err does not implement Unwrap interface") + require.Error(t, uErr, "err does not implement Unwrap interface") expected := "oops" - assert.EqualError(t, uErr, expected, "error message mismatch, got %s want %s", uErr, expected) + require.EqualError(t, uErr, expected, "error message mismatch, got %s want %s", uErr, expected) }) t.Run("Unwrap for errors.Enrich", func(t *testing.T) { @@ -324,10 +316,10 @@ func Test_Unwrap(t *testing.T) { require.Error(t, errEnriched, "it is not an error") uErr := errors.Unwrap(errEnriched) - require.NotNil(t, uErr, "err does not implement Unwrap interface") + require.Error(t, uErr, "err does not implement Unwrap interface") expected := "failed" - assert.EqualError(t, uErr, expected, "error message mismatch, got %s want %s", uErr, expected) + require.EqualError(t, uErr, expected, "error message mismatch, got %s want %s", uErr, expected) }) t.Run("Unwrap for errors.EnrichWrapWithError", func(t *testing.T) { @@ -340,24 +332,23 @@ func Test_Unwrap(t *testing.T) { require.Error(t, errEnriched, "it is not an error") expected := "oops: failed" - assert.EqualError(t, errEnriched, expected, "error message mismatch, got %s want %s", errEnriched, expected) + require.EqualError(t, errEnriched, expected, "error message mismatch, got %s want %s", errEnriched, expected) - //nolint:errorlint errKV, ok := errEnriched.(enrichedError) - assert.True(t, ok, "error does not implement enrichedError interface") - assert.Equal(t, []interface{}{"id", 5}, errKV.Tuples()) + require.True(t, ok, "error does not implement enrichedError interface") + require.Equal(t, []interface{}{"id", 5}, errKV.Tuples()) errWrap := errors.Unwrap(errEnriched) - require.NotNil(t, errWrap, "err does not implement Unwrap interface") + require.Error(t, errWrap, "err does not implement Unwrap interface") expected = "oops: failed" - assert.EqualError(t, errWrap, expected, "error message mismatch, got %s want %s", errWrap, expected) + require.EqualError(t, errWrap, expected, "error message mismatch, got %s want %s", errWrap, expected) uErr := errors.Unwrap(errWrap) - require.NotNil(t, uErr, "err does not implement Unwrap interface") + require.Error(t, uErr, "err does not implement Unwrap interface") expected = "oops" - assert.EqualError(t, uErr, expected, "error message mismatch, got %s want %s", uErr, expected) + require.EqualError(t, uErr, expected, "error message mismatch, got %s want %s", uErr, expected) }) } @@ -374,10 +365,10 @@ func Test_Cause(t *testing.T) { require.Error(t, errWrap, "it is not an error") cErr := errors.Cause(errWrap) - require.NotNil(t, cErr, "err does not implement Cause interface") + require.Error(t, cErr, "err does not implement Cause interface") expected := "failed" - assert.EqualError(t, cErr, expected, "error message mismatch, got %s want %s", cErr, expected) + require.EqualError(t, cErr, expected, "error message mismatch, got %s want %s", cErr, expected) }) } @@ -391,7 +382,7 @@ func Test_Is(t *testing.T) { require.Error(t, err, "it is not an error") expected := errors.New("failed") - assert.ErrorIs(t, err, expected) + require.ErrorIs(t, err, expected) }) t.Run("no Is for errors.New", func(t *testing.T) { @@ -400,7 +391,7 @@ func Test_Is(t *testing.T) { err := errors.New("failed") require.Error(t, err, "it is not an error") - assert.NotErrorIs(t, err, context.Canceled) + require.NotErrorIs(t, err, context.Canceled) }) t.Run("Is for errors.Newf", func(t *testing.T) { @@ -410,7 +401,7 @@ func Test_Is(t *testing.T) { require.Error(t, err, "it is not an error") expected := errors.New("oops: failed") - assert.ErrorIs(t, err, expected) + require.ErrorIs(t, err, expected) }) t.Run("Is for errors.Wrap", func(t *testing.T) { @@ -422,7 +413,7 @@ func Test_Is(t *testing.T) { require.Error(t, errWrap, "it is not an error") expected := errors.New("failed") - assert.ErrorIs(t, errWrap, expected) + require.ErrorIs(t, errWrap, expected) }) t.Run("Is for errors.Wrapf", func(t *testing.T) { @@ -434,7 +425,7 @@ func Test_Is(t *testing.T) { require.Error(t, errWrap, "it is not an error") expected := errors.New("failed") - assert.ErrorIs(t, errWrap, expected) + require.ErrorIs(t, errWrap, expected) }) t.Run("Is for errors.WrapWithError", func(t *testing.T) { @@ -446,11 +437,11 @@ func Test_Is(t *testing.T) { errWrap := errors.WrapError(err, sErr) require.Error(t, errWrap, "it is not an error") - assert.EqualError(t, errWrap, "oops: failed") + require.EqualError(t, errWrap, "oops: failed") - assert.ErrorIs(t, errWrap, err) + require.ErrorIs(t, errWrap, err) - assert.ErrorIs(t, errWrap, sErr) + require.ErrorIs(t, errWrap, sErr) }) t.Run("no Is for errors.WrapWithError", func(t *testing.T) { @@ -462,7 +453,7 @@ func Test_Is(t *testing.T) { errWrap := errors.WrapError(err, sErr) require.Error(t, errWrap, "it is not an error") - assert.NotErrorIs(t, errWrap, context.Canceled) + require.NotErrorIs(t, errWrap, context.Canceled) }) t.Run("Is for errors.WrapWithError two levels", func(t *testing.T) { @@ -477,11 +468,11 @@ func Test_Is(t *testing.T) { errWrap = errors.WrapError(errWrap, sErr2) require.Error(t, errWrap, "it is not an error") - assert.ErrorIs(t, errWrap, sErr1) + require.ErrorIs(t, errWrap, sErr1) - assert.ErrorIs(t, errWrap, sErr2) + require.ErrorIs(t, errWrap, sErr2) - assert.ErrorIs(t, errWrap, context.Canceled) + require.ErrorIs(t, errWrap, context.Canceled) }) t.Run("Is for errors.Enrich", func(t *testing.T) { @@ -492,14 +483,13 @@ func Test_Is(t *testing.T) { errEnrich := errors.Enrich(err, "id", 5) require.Error(t, errEnrich, "it is not an error") - assert.EqualError(t, errEnrich, "failed") + require.EqualError(t, errEnrich, "failed") - //nolint:errorlint errKV, ok := errEnrich.(enrichedError) - assert.True(t, ok, "error does not implement enrichedError interface") - assert.Equal(t, []interface{}{"id", 5}, errKV.Tuples()) + require.True(t, ok, "error does not implement enrichedError interface") + require.Equal(t, []interface{}{"id", 5}, errKV.Tuples()) - assert.ErrorIs(t, errEnrich, err) + require.ErrorIs(t, errEnrich, err) }) t.Run("no Is for errors.Enrich", func(t *testing.T) { @@ -510,6 +500,6 @@ func Test_Is(t *testing.T) { errEnrich := errors.Enrich(err, "id", 5) require.Error(t, errEnrich, "it is not an error") - assert.NotErrorIs(t, errEnrich, context.Canceled) + require.NotErrorIs(t, errEnrich, context.Canceled) }) } diff --git a/go.mod b/go.mod index 3b939f1..fa77ea6 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,11 @@ module github.com/dohernandez/errors -go 1.19 +go 1.23.3 -require github.com/stretchr/testify v1.8.4 +require github.com/stretchr/testify v1.9.0 require ( + github.com/bool64/dev v0.2.36 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index fa4b6e6..6bda475 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,13 @@ +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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=