From cbd877e4aa7bd616b98a1708331ba771726aab2d Mon Sep 17 00:00:00 2001 From: Roger Guldbrandsen <8797880+kinbiko@users.noreply.github.com> Date: Thu, 6 Jul 2023 23:35:28 +0900 Subject: [PATCH] [chore] Update Go and linter (#60) --- .github/workflows/go.yml | 52 +++++++++++----------- .golangci.yml | 34 +++++++------- builds/http.go | 24 +++++++--- builds/http_test.go | 10 ++--- builds/payload.go | 17 +++---- builds/validation.go | 43 +++++++++++------- builds/validation_test.go | 1 - cmd/bugsnag/integration_test.go | 6 +-- cmd/bugsnag/main.go | 11 +++-- cmd/bugsnag/release.go | 78 ++++++++++++++++++--------------- cmd/bugsnag/util.go | 15 +++++-- context.go | 12 ++--- doc.go | 7 +++ error.go | 4 +- error_test.go | 3 +- go.mod | 2 +- notifier.go | 18 ++++---- notifier_test.go | 4 +- session.go | 5 ++- 19 files changed, 195 insertions(+), 151 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index f23a977..348e1e6 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -1,42 +1,40 @@ name: Go on: [push] jobs: - build: name: Build runs-on: ubuntu-latest steps: + - name: Set up Go + uses: actions/setup-go@v1 + with: + go-version: 1.20 + id: go - - name: Set up Go 1.16 - uses: actions/setup-go@v1 - with: - go-version: 1.16 - id: go - - - name: Check out code into the Go module directory - uses: actions/checkout@v1 + - name: Check out code into the Go module directory + uses: actions/checkout@v1 - - name: Get dependencies - run: go get -v -t -d ./... + - name: Get dependencies + run: go get -v -t -d ./... - - name: Build - run: go build -v . + - name: Build + run: go build -v . - # Running tests with and without the race checker, as certain tests are - # only run when the race checker is not enabled - - name: Test - run: go test -v -coverprofile=profile.cov ./... + # Running tests with and without the race checker, as certain tests are + # only run when the race checker is not enabled + - name: Test + run: go test -v -coverprofile=profile.cov ./... - - name: Coverage - uses: shogo82148/actions-goveralls@v1 - with: - path-to-profile: profile.cov + - name: Coverage + uses: shogo82148/actions-goveralls@v1 + with: + path-to-profile: profile.cov - - name: Test (race) - run: go test -race -v ./... + - name: Test (race) + run: go test -race -v ./... - - name: Install Linter - run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.45.2 + - name: Install Linter + run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.53.2 - - name: Lint - run: ./bin/golangci-lint run . + - name: Lint + run: ./bin/golangci-lint run . diff --git a/.golangci.yml b/.golangci.yml index ffbf864..4595053 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -45,7 +45,6 @@ run: # the dependency descriptions in go.mod. modules-download-mode: readonly - # output configuration options output: # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" @@ -57,7 +56,6 @@ output: # print linter name in the end of issue text, default is true print-linter-name: true - # all available settings of specific linters linters-settings: errcheck: @@ -78,10 +76,6 @@ linters-settings: # see https://github.com/kisielk/errcheck#excluding-functions for details # exclude: /path/to/file.txt - funlen: - lines: 35 - statements: 20 - govet: # report about shadowed variables check-shadowing: true @@ -114,6 +108,9 @@ linters-settings: # where nested if/for is weighted more, and only one point regardless of # cases in a switch. min-complexity: 11 + gomnd: + ignored-numbers: + - "2" dupl: # tokens count to trigger issue, 150 by default threshold: 100 @@ -123,14 +120,15 @@ linters-settings: # minimal occurrences count to trigger, 3 by default min-occurrences: 3 depguard: - list-type: blacklist - include-go-root: false - packages: - - github.com/satori/go.uuid - - # packages-with-error-messages: - # specify an error message to output when a blacklisted package is used - # github.com/sirupsen/logrus: "logging is allowed only by logutils.Log" + rules: + all: + files: + - "$all" + - "$test" + allow: + - "$gostd" + - "github.com/kinbiko/bugsnag" + - "github.com/kinbiko/jsonassert" misspell: # Correct spellings using locale preferences for US or UK. # Default is to use a neutral variety of English. @@ -203,7 +201,7 @@ linters-settings: max-blank-identifiers: 2 whitespace: - multi-if: false # Enforces newlines (or comments) after every multi-line if statement + multi-if: false # Enforces newlines (or comments) after every multi-line if statement multi-func: false # Enforces newlines (or comments) after every multi-line function signature wsl: # If true append is only allowed to be cuddled if appending value is @@ -253,14 +251,13 @@ linters: - unused fast: false - issues: # List of regexps of issue texts to exclude, empty list by default. # But independently from this option we use default exclude patterns, # it can be disabled by `exclude-use-default: false`. To list all # excluded by default patterns execute `golangci-lint run --help` # exclude: - # - abcdef + # - abcdef # Excluding configuration per-path, per-linter, per-text and per-source exclude-rules: @@ -272,19 +269,20 @@ issues: - dupl - errcheck - errchkjson - - exhaustivestruct - funlen - gocognit - gocyclo - gomnd - lll - paralleltest + - staticcheck - stylecheck - testpackage - varnamelen - path: \.go linters: - goerr113 + - exhaustruct # Independently from option `exclude` we use default exclude patterns, # it can be disabled by this option. To list all diff --git a/builds/http.go b/builds/http.go index c664d39..64d8910 100644 --- a/builds/http.go +++ b/builds/http.go @@ -1,13 +1,19 @@ +// Package builds is a package for sending build requests to the Bugsnag Build API, as defined here: +// https://bugsnagbuildapi.docs.apiary.io/ package builds import ( "bytes" + "context" "encoding/json" "fmt" "io" "net/http" + "time" ) +const timeout = 10 * time.Second + // DefaultPublisher returns a publisher for requests against the Bugsnag SaaS // endpoint. If you need to target your own on-premise installation, please use // NewPublisher. @@ -23,7 +29,7 @@ func NewPublisher(endpoint string) *Publisher { } // Publisher is a type for sending build requests to the Bugsnag Build API, as defined here: -//https://bugsnagbuildapi.docs.apiary.io/ +// https://bugsnagbuildapi.docs.apiary.io/ type Publisher struct { endpoint string } @@ -34,13 +40,14 @@ func (p *Publisher) Publish(req *JSONBuildRequest) error { return fmt.Errorf("publisher created incorrectly; please use NewPublisher or DefaultPublisher to construct your builds.Publisher") } - b, err := json.Marshal(req) + jsonBody, err := json.Marshal(req) if err != nil { return fmt.Errorf("unable to marshal JSON: %w", err) } - httpReq, err := http.NewRequest("POST", p.endpoint, bytes.NewBuffer(b)) - + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, p.endpoint, bytes.NewBuffer(jsonBody)) if err != nil { return fmt.Errorf("error when POST-ing request to '%s': %w", p.endpoint, err) } @@ -48,12 +55,15 @@ func (p *Publisher) Publish(req *JSONBuildRequest) error { httpRes, err := http.DefaultClient.Do(httpReq) if err != nil { - return err + return fmt.Errorf("unable to make HTTP call: %w", err) } + defer func() { + _ = httpRes.Body.Close() + }() got, err := io.ReadAll(httpRes.Body) if err != nil { - return err + return fmt.Errorf("unable to read response body: %w", err) } type response struct { @@ -63,7 +73,7 @@ func (p *Publisher) Publish(req *JSONBuildRequest) error { } var res response if err := json.Unmarshal(got, &res); err != nil { - return err + return fmt.Errorf("unable to read response body as JSON: %w", err) } if res.Status == "error" { return fmt.Errorf("error when sending message: %s", res.Errors[0]) diff --git a/builds/http_test.go b/builds/http_test.go index 96df9c7..54d0728 100644 --- a/builds/http_test.go +++ b/builds/http_test.go @@ -1,14 +1,15 @@ package builds_test import ( - "io/ioutil" + "io" "net/http" "net/http/httptest" "testing" "time" - "github.com/kinbiko/bugsnag/builds" "github.com/kinbiko/jsonassert" + + "github.com/kinbiko/bugsnag/builds" ) func TestNonConstructedPublisher(t *testing.T) { @@ -21,9 +22,9 @@ func TestPublishingBuilds(t *testing.T) { testServer := func() (*httptest.Server, chan string) { reqs := make(chan string, 10) return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - body, _ := ioutil.ReadAll(r.Body) + body, _ := io.ReadAll(r.Body) reqs <- string(body) - w.Write([]byte(`{"status": "ok"}`)) + _, _ = w.Write([]byte(`{"status": "ok"}`)) })), reqs } @@ -82,5 +83,4 @@ func TestPublishingBuilds(t *testing.T) { "appVersion": "1.5.2" }`) }) - } diff --git a/builds/payload.go b/builds/payload.go index 8ff8d9f..a170deb 100644 --- a/builds/payload.go +++ b/builds/payload.go @@ -11,12 +11,12 @@ type JSONBuildRequest struct { // the build relates to. AppVersion string `json:"appVersion"` // E.g. "1.5.2" - //The release stage (eg, production, staging) that is being released (if - //applicable). Normally the fact that a build has been released to a - //release stage is detected automatically when an error event or session is - //received for the build. However if you would like to manually notify - //Bugsnag of the build being released you can specify the stage that the - //build was released to. + // The release stage (eg, production, staging) that is being released (if + // applicable). Normally the fact that a build has been released to a + // release stage is detected automatically when an error event or session is + // received for the build. However if you would like to manually notify + // Bugsnag of the build being released you can specify the stage that the + // build was released to. ReleaseStage string `json:"releaseStage,omitempty"` // E.g. "staging" // The name of the entity that triggered the build. Could be a user, @@ -54,8 +54,9 @@ type JSONBuildRequest struct { AutoAssignRelease bool `json:"autoAssignRelease,omitempty"` } -// Information about the source control of the code. This can be used to -// link errors to the source code (for supported source control tools) +// JSONSourceControl is information about the source control of the code. +// This can be used to link errors to the source code (for supported source +// control tools) type JSONSourceControl struct { // If the provider can be inferred from the repository then it is not // required. Must be one of: "github", "github-enterprise", "bitbucket", diff --git a/builds/validation.go b/builds/validation.go index 68da31d..eab14db 100644 --- a/builds/validation.go +++ b/builds/validation.go @@ -6,6 +6,8 @@ import ( "strings" ) +// Validate checks that the given JSONBuildRequest is valid. +// If it is not valid, an error is returned. func (r *JSONBuildRequest) Validate() error { if re := regexp.MustCompile("^[0-9a-f]{32}$"); !re.MatchString(r.APIKey) { return fmt.Errorf(`APIKey must be 32 hex characters, but got "%s"`, r.APIKey) @@ -15,23 +17,32 @@ func (r *JSONBuildRequest) Validate() error { return fmt.Errorf(`AppVersion must be present`) } - if r.SourceControl != nil { - if r.SourceControl.Repository == "" { - return fmt.Errorf(`SourceControl.Repository must be present when SourceControl is set`) - } - if r.SourceControl.Revision == "" { - return fmt.Errorf(`SourceControl.Revision must be present when SourceControl is set`) - } - if r.SourceControl.Provider != "" { - validProviders := []string{"github", "github-enterprise", "bitbucket", "bitbucket-server", "gitlab", "gitlab-onpremise"} - found := false - for _, p := range validProviders { - found = found || p == r.SourceControl.Provider - } - if !found { - return fmt.Errorf(`SourceControl.Provider must be unset (for automatic inference) or one of %v`, validProviders) - } + if r.SourceControl == nil { + return nil + } + + if r.SourceControl.Repository == "" { + return fmt.Errorf(`SourceControl.Repository must be present when SourceControl is set`) + } + if r.SourceControl.Revision == "" { + return fmt.Errorf(`SourceControl.Revision must be present when SourceControl is set`) + } + if provider := r.SourceControl.Provider; provider != "" { + if err := validateSourceControlProvider(provider); err != nil { + return err } } return nil } + +func validateSourceControlProvider(provider string) error { + validProviders := []string{"github", "github-enterprise", "bitbucket", "bitbucket-server", "gitlab", "gitlab-onpremise"} + found := false + for _, p := range validProviders { + found = found || p == provider + } + if !found { + return fmt.Errorf(`SourceControl.Provider must be unset (for automatic inference) or one of %v`, validProviders) + } + return nil +} diff --git a/builds/validation_test.go b/builds/validation_test.go index 46c7232..7dee0e9 100644 --- a/builds/validation_test.go +++ b/builds/validation_test.go @@ -46,7 +46,6 @@ func TestValidate(t *testing.T) { if err := makeBigValidReq().Validate(); err != nil { t.Errorf("unexpected error: %v", err) } - }) t.Run("only bare-minimum populated", func(t *testing.T) { if err := makeSmallValidReq().Validate(); err != nil { diff --git a/cmd/bugsnag/integration_test.go b/cmd/bugsnag/integration_test.go index cbaa546..5c3fe0d 100644 --- a/cmd/bugsnag/integration_test.go +++ b/cmd/bugsnag/integration_test.go @@ -2,7 +2,7 @@ package main import ( "fmt" - "io/ioutil" + "io" "net/http" "net/http/httptest" "strings" @@ -16,9 +16,9 @@ func TestRelease(t *testing.T) { testServer := func() (*httptest.Server, chan string) { reqs := make(chan string, 10) return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - body, _ := ioutil.ReadAll(r.Body) + body, _ := io.ReadAll(r.Body) reqs <- string(body) - w.Write([]byte(`{"status": "ok"}`)) + _, _ = w.Write([]byte(`{"status": "ok"}`)) })), reqs } diff --git a/cmd/bugsnag/main.go b/cmd/bugsnag/main.go index 2b75364..2cbfbef 100644 --- a/cmd/bugsnag/main.go +++ b/cmd/bugsnag/main.go @@ -1,3 +1,4 @@ +// Package main is the entrypoint for the bugsnag command-line tool. package main import ( @@ -25,7 +26,7 @@ type application struct { func main() { if err := run(os.Args[1:], splitByEquals(os.Environ())); err != nil { - fmt.Printf("%s\n", err.Error()) + logf("%s\n", err.Error()) os.Exit(1) } } @@ -37,9 +38,11 @@ func run(args []string, envvars map[string]string) error { if len(args) == 0 { return fmt.Errorf(usage) } - switch args[0] { - case "release": - releaseCmd.Parse(args[1:]) + if args[0] == "release" { + err := releaseCmd.Parse(args[1:]) + if err != nil { + return fmt.Errorf("%w:\n%s", err, usage) + } return app.runRelease(envvars) } return fmt.Errorf(usage) diff --git a/cmd/bugsnag/release.go b/cmd/bugsnag/release.go index cf10b1f..2a45946 100644 --- a/cmd/bugsnag/release.go +++ b/cmd/bugsnag/release.go @@ -26,6 +26,7 @@ type releaseFlags struct { debug *bool } +//nolint:funlen // This function is long but it's just a bunch of flag declarations. func newReleaseFlags(releaseCmd *flag.FlagSet) *releaseFlags { return &releaseFlags{ apiKey: releaseCmd.String( @@ -110,64 +111,69 @@ The SHA (or 7-character shorthand) of the git commit associated with the build.` } } -func (app *application) runRelease(envVars map[string]string) error { - rf := app.releaseFlags - if *rf.debug { - app.printReleaseDebug() - } - +func makeRelease(flags *releaseFlags) *builds.JSONBuildRequest { req := &builds.JSONBuildRequest{ - APIKey: *rf.apiKey, - AppVersion: *rf.appVersion, - ReleaseStage: *rf.releaseStage, - BuilderName: *rf.builder, - Metadata: splitByEquals(strings.Split(*rf.metadata, ",")), - AppVersionCode: *rf.appVersionCode, - AppBundleVersion: *rf.appBundleVersion, - AutoAssignRelease: *rf.autoAssignRelease, + APIKey: *flags.apiKey, + AppVersion: *flags.appVersion, + ReleaseStage: *flags.releaseStage, + BuilderName: *flags.builder, + Metadata: splitByEquals(strings.Split(*flags.metadata, ",")), + AppVersionCode: *flags.appVersionCode, + AppBundleVersion: *flags.appBundleVersion, + AutoAssignRelease: *flags.autoAssignRelease, + SourceControl: nil, } - if *rf.repository != "" || *rf.revision != "" { + if *flags.repository != "" || *flags.revision != "" { req.SourceControl = &builds.JSONSourceControl{ - Provider: *rf.provider, - Repository: *rf.repository, - Revision: *rf.revision, + Provider: *flags.provider, + Repository: *flags.repository, + Revision: *flags.revision, } } + return req +} + +func (app *application) runRelease(envVars map[string]string) error { + flags := app.releaseFlags + if *flags.debug { + app.printReleaseDebug() + } + req := makeRelease(flags) populateReleaseDefaults(req, envVars) if err := req.Validate(); err != nil { - return fmt.Errorf("Invalid build data: %w\nSee 'bugsnag release --help'", err) + return fmt.Errorf("invalid build data: %w\nSee 'bugsnag release --help'", err) } publisher := builds.DefaultPublisher() - if endpoint := *rf.endpoint; endpoint != "" { + if endpoint := *flags.endpoint; endpoint != "" { publisher = builds.NewPublisher(endpoint) } if err := publisher.Publish(req); err != nil { - return err + return fmt.Errorf("unable to publish: %w", err) } - fmt.Printf("release info published for version %s\n", req.AppVersion) + logf("release info published for version %s\n", req.AppVersion) return nil } func (app *application) printReleaseDebug() { - rf := app.releaseFlags - fmt.Printf("--api-key=%s\n", *rf.apiKey) - fmt.Printf("--app-version=%s\n", *rf.appVersion) - fmt.Printf("--release-stage=%s\n", *rf.releaseStage) - fmt.Printf("--provider=%s\n", *rf.provider) - fmt.Printf("--repository=%s\n", *rf.repository) - fmt.Printf("--revision=%s\n", *rf.revision) - fmt.Printf("--builder=%s\n", *rf.builder) - fmt.Printf("--metadata=%s\n", *rf.metadata) - fmt.Printf("--auto-assign-release=%v\n", *rf.autoAssignRelease) - fmt.Printf("--endpoint=%s\n", *rf.endpoint) - fmt.Printf("--app-version-code=%d\n", *rf.appVersionCode) - fmt.Printf("--app-bundle-version=%s\n", *rf.appBundleVersion) - fmt.Printf("--debug=%v\n", *rf.debug) + flags := app.releaseFlags + logf("--api-key=%s\n", *flags.apiKey) + logf("--app-version=%s\n", *flags.appVersion) + logf("--release-stage=%s\n", *flags.releaseStage) + logf("--provider=%s\n", *flags.provider) + logf("--repository=%s\n", *flags.repository) + logf("--revision=%s\n", *flags.revision) + logf("--builder=%s\n", *flags.builder) + logf("--metadata=%s\n", *flags.metadata) + logf("--auto-assign-release=%v\n", *flags.autoAssignRelease) + logf("--endpoint=%s\n", *flags.endpoint) + logf("--app-version-code=%d\n", *flags.appVersionCode) + logf("--app-bundle-version=%s\n", *flags.appBundleVersion) + logf("--debug=%v\n", *flags.debug) } func populateReleaseDefaults(req *builds.JSONBuildRequest, envVars map[string]string) { diff --git a/cmd/bugsnag/util.go b/cmd/bugsnag/util.go index 3f2c8f9..584ee5f 100644 --- a/cmd/bugsnag/util.go +++ b/cmd/bugsnag/util.go @@ -1,14 +1,21 @@ package main -import "strings" +import ( + "log" + "strings" +) func splitByEquals(strs []string) map[string]string { - m := map[string]string{} + kvps := map[string]string{} for _, kvp := range strs { if kvp != "" { pair := strings.SplitN(kvp, "=", 2) - m[pair[0]] = pair[1] + kvps[pair[0]] = pair[1] } } - return m + return kvps +} + +func logf(msg string, args ...interface{}) { + log.Printf(msg, args...) } diff --git a/context.go b/context.go index 44e7b9e..2929a77 100644 --- a/context.go +++ b/context.go @@ -42,7 +42,7 @@ func (n *Notifier) Deserialize(ctx context.Context, data []byte) context.Context n.cfg.InternalErrorCallback(err) return ctx } - cd := &ctxData{} // nolint:exhaustivestruct // we're about to fill the data dynamically + cd := &ctxData{} if err := json.Unmarshal(jsonData, cd); err != nil { n.cfg.InternalErrorCallback(err) return ctx @@ -209,7 +209,8 @@ func (n *Notifier) WithBugsnagContext(ctx context.Context, bContext string) cont // WithMetadatum attaches the given key and value under the provided tab in the // Bugsnag dashboard. You may use the following tab names to add data to // existing/common tabs in the dashboard with the same name: -// "user", "app", "device", "request" +// +// "user", "app", "device", "request" func (n *Notifier) WithMetadatum(ctx context.Context, tab, key string, value interface{}) context.Context { if ctx == nil { return nil @@ -222,7 +223,8 @@ func (n *Notifier) WithMetadatum(ctx context.Context, tab, key string, value int // WithMetadata attaches the given data under the provided tab in the // Bugsnag dashboard. You may use the following tab names to add data to // existing/common tabs in the dashboard with the same name: -// "user", "app", "device", "request" +// +// "user", "app", "device", "request" func (n *Notifier) WithMetadata(ctx context.Context, tab string, data map[string]interface{}) context.Context { if ctx == nil { return nil @@ -331,7 +333,7 @@ func (data *jsonCtxData) updateFromCtx(ctx context.Context, unhandled bool) { func getAttachedContextData(ctx context.Context) *ctxData { if val := ctx.Value(ctxDataKey); val != nil { - return val.(*ctxData) // nolint:forcetypeassert // This is safe. We own the key => we own the type + return val.(*ctxData) //nolint:forcetypeassert // This is safe. We own the key => we own the type } - return &ctxData{} // nolint:exhaustivestruct // this saves lots of nil checks elsewhere + return &ctxData{} } diff --git a/doc.go b/doc.go index d055bc7..b020051 100644 --- a/doc.go +++ b/doc.go @@ -1,6 +1,7 @@ // Package bugsnag exposes an alternative implementation of the Bugsnag Go notifier. // // Create a new *bugsnag.Notifier: +// // n, err := bugsnag.New(bugsnag.Configuration{ // APIKey: "<>", // AppVersion: "1.3.5", // Some semver @@ -10,18 +11,23 @@ // panic(err) // } // defer n.Close() // Close once you know there are no further calls to n.Notify or n.StartSession. +// // Note: There are other configuration options you may set, which enable some // advanced and very powerful features of the Notifier. See // bugsnag.Configuration for more information. // // After creating the notifier, you can then report any errors that appear in // your application: +// // n.Notify(ctx, err) +// // You can attach a lot of useful data to context.Context instances that get // reflected in your dashboard. See the various With*(ctx, ...) funcs for more // details. // You can also attach a stacktrace to your errors by calling +// // err = Wrap(ctx, err) +// // to wrap another error. // Another benefit of using Wrap is that the diagnostic data attached to the // ctx given in the call to Wrap is preserved in the returned err. Meaning that @@ -34,5 +40,6 @@ // // To start using session tracking to enable your stability score calculation // you should call n.StartSession on a per-request basis. +// // ctx = n.StartSession(ctx) package bugsnag diff --git a/error.go b/error.go index 9d9fb65..3657842 100644 --- a/error.go +++ b/error.go @@ -24,7 +24,7 @@ type Error struct { Severity severity err error - ctx context.Context // nolint:containedctx // We're storing it for valid reasons + ctx context.Context //nolint:containedctx // We're storing it for valid reasons stacktrace []*JSONStackframe msg string } @@ -96,7 +96,7 @@ func makeStacktrace(module string) []*JSONStackframe { pcs := ptrs[0:runtime.Callers(0, ptrs[:])] stacktrace := make([]*JSONStackframe, len(pcs)) - for i, pc := range pcs { // nolint:varnamelen // indexes are conventionally i + for i, pc := range pcs { //nolint:varnamelen // indexes are conventionally i pc-- // pc - 1 is the *real* program counter, for reasons beyond me. file, lineNumber, method := "unknown", 0, "unknown" diff --git a/error_test.go b/error_test.go index 5ff77ef..24b0ad0 100644 --- a/error_test.go +++ b/error_test.go @@ -8,6 +8,7 @@ import ( func TestSeverityReasonType(t *testing.T) { t.Parallel() + for _, tc := range []struct { exp string err Error @@ -54,7 +55,7 @@ func TestWrap(t *testing.T) { t.Parallel() t.Run("no real input", func(t *testing.T) { t.Parallel() - if wrappedErr := Wrap(nil, nil); wrappedErr != nil { //nolint:staticcheck // Testing that we don't do a dumb when users do a dumb + if wrappedErr := Wrap(nil, nil); wrappedErr != nil { t.Errorf("expected no error returned but got: %s", wrappedErr) } }) diff --git a/go.mod b/go.mod index 65ad2d5..dc7ad51 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,5 @@ module github.com/kinbiko/bugsnag -go 1.16 +go 1.20 require github.com/kinbiko/jsonassert v1.1.1 diff --git a/notifier.go b/notifier.go index 882cc57..c4945b4 100644 --- a/notifier.go +++ b/notifier.go @@ -204,7 +204,7 @@ func (n *Notifier) sendErrorReport(r *JSONErrorReport) error { if err != nil { return fmt.Errorf("unable to marshal JSON: %w", err) } - req, err := http.NewRequest("POST", n.cfg.EndpointNotify, bytes.NewBuffer(b)) + req, err := http.NewRequest(http.MethodPost, n.cfg.EndpointNotify, bytes.NewBuffer(b)) if err != nil { return fmt.Errorf("unable to create new request: %w", err) } @@ -292,7 +292,7 @@ func makeExceptions(err error) []*JSONException { } eps := make([]*JSONException, len(errs)) - for i, err := range errs { // nolint:varnamelen // indexes are conventionally i + for i, err := range errs { //nolint:varnamelen // indexes are conventionally i var stacktrace []*JSONStackframe if berr, ok := err.(*Error); ok { stacktrace = berr.stacktrace @@ -383,13 +383,13 @@ func makeNotifier(cfg *Configuration) *JSONNotifier { // dashboard because the deepest "exception" (the non-Bugsnag err) which // gets given a default stackframe of: // -// { -// (... other fluff ...) -// "file": "unknown file", -// "in_project": null, -// "line_number": 0, -// "method": "unknown method" -// } +// { +// (... other fluff ...) +// "file": "unknown file", +// "in_project": null, +// "line_number": 0, +// "method": "unknown method" +// } // // Even though this frame is not in project (or rather "null in project", // whatever that means), lower exceptions take priority over frames being diff --git a/notifier_test.go b/notifier_test.go index d3ba1e6..0dcbe2a 100644 --- a/notifier_test.go +++ b/notifier_test.go @@ -123,7 +123,7 @@ func TestInternalErrorCallback(t *testing.T) { if err != nil { t.Fatal(err) } - n.Notify(nil, nil) //nolint:staticcheck // Need to verify that the notifier doesn't die + n.Notify(nil, nil) if got == nil { t.Error("expected an error in the error callback but got none") @@ -137,6 +137,6 @@ func TestInternalErrorCallback(t *testing.T) { t.Fatal(err) } - n.Notify(nil, nil) //nolint:staticcheck // Need to verify that the notifier doesn't die + n.Notify(nil, nil) }) } diff --git a/session.go b/session.go index 48a2fcc..1fab543 100644 --- a/session.go +++ b/session.go @@ -64,7 +64,7 @@ func (n *Notifier) publishSessions(cfg *Configuration, sessions []*session) erro return fmt.Errorf("unable to marshal json: %w", err) } - req, err := http.NewRequest("POST", cfg.EndpointSessions, bytes.NewBuffer(payload)) + req, err := http.NewRequest(http.MethodPost, cfg.EndpointSessions, bytes.NewBuffer(payload)) if err != nil { return fmt.Errorf("unable to create request: %w", err) } @@ -135,7 +135,8 @@ func (n *Notifier) makeJSONSessionReport(cfg *Configuration, sessions []*session // uuidv4 returns a randomly generated UUID v4. // Returns a canonical RFC-4122 string representation of the UUID: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. -// nolint:gomnd // magic numbers from RFC algorithm +// +//nolint:gomnd // magic numbers from RFC algorithm func uuidv4() string { var uuid [16]byte _, _ = io.ReadFull(rand.Reader, uuid[:])