diff --git a/cmd/pint/main_test.go b/cmd/pint/main_test.go index ae51b671..945a94f2 100644 --- a/cmd/pint/main_test.go +++ b/cmd/pint/main_test.go @@ -15,6 +15,7 @@ import ( "net/http" "os" "path" + "regexp" "strconv" "strings" "sync" @@ -84,7 +85,7 @@ func httpServer(ts *testscript.TestScript, _ bool, args []string) { ts.Fatalf("! http response command requires '$NAME $PATH $CODE $BODY' args, got [%s]", strings.Join(args, " ")) } name := args[1] - path := args[2] + path := regexp.MustCompile(args[2]) code, err := strconv.Atoi(args[3]) ts.Check(err) body := strings.Join(args[4:], " ") @@ -99,7 +100,7 @@ func httpServer(ts *testscript.TestScript, _ bool, args []string) { } name := args[1] meth := args[2] - path := args[3] + path := regexp.MustCompile(args[3]) code, err := strconv.Atoi(args[4]) ts.Check(err) body := strings.Join(args[5:], " ") @@ -114,7 +115,7 @@ func httpServer(ts *testscript.TestScript, _ bool, args []string) { ts.Fatalf("! http response command requires '$NAME $PATH $USER $PASS $CODE $BODY' args, got [%s]", strings.Join(args, " ")) } name := args[1] - path := args[2] + path := regexp.MustCompile(args[2]) user := args[3] pass := args[4] code, err := strconv.Atoi(args[5]) @@ -136,7 +137,7 @@ func httpServer(ts *testscript.TestScript, _ bool, args []string) { ts.Fatalf("! http response command requires '$NAME $PATH $DELAY $CODE $BODY' args, got [%s]", strings.Join(args, " ")) } name := args[1] - path := args[2] + path := regexp.MustCompile(args[2]) delay, err := time.ParseDuration(args[3]) ts.Check(err) code, err := strconv.Atoi(args[4]) @@ -154,7 +155,7 @@ func httpServer(ts *testscript.TestScript, _ bool, args []string) { ts.Fatalf("! http redirect command requires '$NAME $SRCPATH $DSTPATH' args, got [%s]", strings.Join(args, " ")) } name := args[1] - srcpath := args[2] + srcpath := regexp.MustCompile(args[2]) dstpath := args[3] mocks.add(name, httpMock{pattern: srcpath, handler: func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Location", dstpath) @@ -181,10 +182,10 @@ func httpServer(ts *testscript.TestScript, _ bool, args []string) { for n, mockList := range mocks.responses() { if n == name { for _, mock := range mockList { - if mock.pattern != "/" && (r.URL.Path != mock.pattern || !strings.HasPrefix(r.URL.Path, mock.pattern)) { + if mock.method != "" && mock.method != r.Method { continue } - if mock.method != "" && mock.method != r.Method { + if !mock.pattern.MatchString(r.URL.Path) { continue } mock.handler(w, r) @@ -226,7 +227,7 @@ func httpServer(ts *testscript.TestScript, _ bool, args []string) { } type httpMock struct { - pattern string + pattern *regexp.Regexp method string handler func(http.ResponseWriter, *http.Request) } diff --git a/cmd/pint/tests/0031_ci_bitbucket.txt b/cmd/pint/tests/0031_ci_bitbucket.txt index a8ceee52..c1f1eec9 100644 --- a/cmd/pint/tests/0031_ci_bitbucket.txt +++ b/cmd/pint/tests/0031_ci_bitbucket.txt @@ -1,4 +1,5 @@ -http response bitbucket / 200 OK +http response bitbucket /rest/insights/1.0/projects/prometheus/repos/rules/commits/.*/reports/pint 200 OK +http response bitbucket /rest/api/1.0/projects/prometheus/repos/rules/commits/.*/pull-requests 200 {} http start bitbucket 127.0.0.1:6031 mkdir testrepo @@ -21,10 +22,10 @@ exec git commit -am 'v2' env BITBUCKET_AUTH_TOKEN="12345" pint.ok -l debug --no-color ci ! stdout . -stderr 'level=DEBUG msg="Sending a request to BitBucket" method=PUT' -stderr 'level=DEBUG msg="BitBucket request completed" status=200' -stderr 'level=DEBUG msg="Sending a request to BitBucket" method=DELETE' -stderr 'level=DEBUG msg="BitBucket request completed" status=200' +stderr 'msg="Sending a request to BitBucket" method=PUT' +stderr 'msg="BitBucket request completed" status=200' +stderr 'msg="Sending a request to BitBucket" method=DELETE' +stderr 'msg="BitBucket request completed" status=200' -- src/v1.yml -- - alert: rule1 diff --git a/cmd/pint/tests/0068_skip_ci.txt b/cmd/pint/tests/0068_skip_ci.txt index 9c9b705c..676009e5 100644 --- a/cmd/pint/tests/0068_skip_ci.txt +++ b/cmd/pint/tests/0068_skip_ci.txt @@ -1,4 +1,5 @@ -http response bitbucket / 200 OK +http response bitbucket /rest/insights/1.0/projects/prometheus/repos/rules/commits/.*/reports/pint 200 OK +http response bitbucket /rest/api/1.0/projects/prometheus/repos/rules/commits/.*/pull-requests 200 {} http start bitbucket 127.0.0.1:6068 mkdir testrepo @@ -22,10 +23,10 @@ env BITBUCKET_AUTH_TOKEN="12345" pint.ok -l debug --no-color ci ! stdout . stderr 'level=INFO msg="Found a commit with ''\[skip ci\]'', skipping all checks" commit=.*' -stderr 'level=DEBUG msg="Sending a request to BitBucket" method=PUT' -stderr 'level=DEBUG msg="BitBucket request completed" status=200' -stderr 'level=DEBUG msg="Sending a request to BitBucket" method=DELETE' -stderr 'level=DEBUG msg="BitBucket request completed" status=200' +stderr 'msg="Sending a request to BitBucket" method=PUT' +stderr 'msg="BitBucket request completed" status=200' +stderr 'msg="Sending a request to BitBucket" method=DELETE' +stderr 'msg="BitBucket request completed" status=200' -- src/v1.yml -- - alert: rule1 diff --git a/cmd/pint/tests/0069_bitbucket_skip_unmodified.txt b/cmd/pint/tests/0069_bitbucket_skip_unmodified.txt index ee3aeac6..360f365e 100644 --- a/cmd/pint/tests/0069_bitbucket_skip_unmodified.txt +++ b/cmd/pint/tests/0069_bitbucket_skip_unmodified.txt @@ -1,4 +1,5 @@ -http response bitbucket / 200 OK +http response bitbucket /rest/insights/1.0/projects/prometheus/repos/rules/commits/.*/reports/pint 200 OK +http response bitbucket /rest/api/1.0/projects/prometheus/repos/rules/commits/.*/pull-requests 200 {} http start bitbucket 127.0.0.1:6069 mkdir testrepo diff --git a/cmd/pint/tests/0070_bitbucket_strict.txt b/cmd/pint/tests/0070_bitbucket_strict.txt index 51745297..5da1aefd 100644 --- a/cmd/pint/tests/0070_bitbucket_strict.txt +++ b/cmd/pint/tests/0070_bitbucket_strict.txt @@ -1,4 +1,5 @@ -http response bitbucket / 200 OK +http response bitbucket /rest/insights/1.0/projects/prometheus/repos/rules/commits/.*/reports/pint 200 OK +http response bitbucket /rest/api/1.0/projects/prometheus/repos/rules/commits/.*/pull-requests 200 {} http start bitbucket 127.0.0.1:6070 mkdir testrepo @@ -23,10 +24,10 @@ pint.error -l debug --no-color ci ! stdout . stderr 'result":"FAIL"' stderr ',"line":3,' -stderr 'level=DEBUG msg="Sending a request to BitBucket" method=PUT' -stderr 'level=DEBUG msg="BitBucket request completed" status=200' -stderr 'level=DEBUG msg="Sending a request to BitBucket" method=DELETE' -stderr 'level=DEBUG msg="BitBucket request completed" status=200' +stderr 'msg="Sending a request to BitBucket" method=PUT' +stderr 'msg="BitBucket request completed" status=200' +stderr 'msg="Sending a request to BitBucket" method=DELETE' +stderr 'msg="BitBucket request completed" status=200' -- src/v1.yml -- - alert: rule1 diff --git a/cmd/pint/tests/0071_ci_owner.txt b/cmd/pint/tests/0071_ci_owner.txt index 61338844..b1e2323f 100644 --- a/cmd/pint/tests/0071_ci_owner.txt +++ b/cmd/pint/tests/0071_ci_owner.txt @@ -1,4 +1,5 @@ -http response bitbucket / 200 OK +http response bitbucket /rest/insights/1.0/projects/prometheus/repos/rules/commits/.*/reports/pint 200 OK +http response bitbucket /rest/api/1.0/projects/prometheus/repos/rules/commits/.*/pull-requests 200 {} http start bitbucket 127.0.0.1:6071 mkdir testrepo diff --git a/cmd/pint/tests/0072_bitbucket_move_bug_to_modified.txt b/cmd/pint/tests/0072_bitbucket_move_bug_to_modified.txt index d9b7a9f4..c8c0c2b0 100644 --- a/cmd/pint/tests/0072_bitbucket_move_bug_to_modified.txt +++ b/cmd/pint/tests/0072_bitbucket_move_bug_to_modified.txt @@ -1,4 +1,5 @@ -http response bitbucket / 200 OK +http response bitbucket /rest/insights/1.0/projects/prometheus/repos/rules/commits/.*/reports/pint 200 OK +http response bitbucket /rest/api/1.0/projects/prometheus/repos/rules/commits/.*/pull-requests 200 {} http start bitbucket 127.0.0.1:6072 mkdir testrepo @@ -24,10 +25,10 @@ pint.error --no-color -l debug ci stderr 'level=INFO msg="Problems found" Fatal=1' stderr 'result":"FAIL"' stderr ',"line":3,' -stderr 'level=DEBUG msg="Sending a request to BitBucket" method=PUT' -stderr 'level=DEBUG msg="BitBucket request completed" status=200' -stderr 'level=DEBUG msg="Sending a request to BitBucket" method=DELETE' -stderr 'level=DEBUG msg="BitBucket request completed" status=200' +stderr 'msg="Sending a request to BitBucket" method=PUT' +stderr 'msg="BitBucket request completed" status=200' +stderr 'msg="Sending a request to BitBucket" method=DELETE' +stderr 'msg="BitBucket request completed" status=200' -- src/v1.yml -- - alert: rule1 diff --git a/cmd/pint/tests/0075_ci_strict.txt b/cmd/pint/tests/0075_ci_strict.txt index 0309b6fa..5ee57a78 100644 --- a/cmd/pint/tests/0075_ci_strict.txt +++ b/cmd/pint/tests/0075_ci_strict.txt @@ -1,4 +1,5 @@ -http response bitbucket / 200 OK +http response bitbucket /rest/insights/1.0/projects/prometheus/repos/rules/commits/.*/reports/pint 200 OK +http response bitbucket /rest/api/1.0/projects/prometheus/repos/rules/commits/.*/pull-requests 200 {} http start bitbucket 127.0.0.1:6075 mkdir testrepo @@ -21,10 +22,10 @@ exec git commit -am 'v2' env BITBUCKET_AUTH_TOKEN="12345" pint.error -l debug --no-color ci --require-owner ! stdout . -stderr 'level=DEBUG msg="Sending a request to BitBucket" method=PUT' -stderr 'level=DEBUG msg="BitBucket request completed" status=200' -stderr 'level=DEBUG msg="Sending a request to BitBucket" method=DELETE' -stderr 'level=DEBUG msg="BitBucket request completed" status=200' +stderr 'msg="Sending a request to BitBucket" method=PUT' +stderr 'msg="BitBucket request completed" status=200' +stderr 'msg="Sending a request to BitBucket" method=DELETE' +stderr 'msg="BitBucket request completed" status=200' stderr 'level=INFO msg="Problems found" Fatal=1 Bug=1' ! stderr 'parse error: unclosed left parenthesis' diff --git a/cmd/pint/tests/0076_ci_group_errors.txt b/cmd/pint/tests/0076_ci_group_errors.txt index eefc1eef..73f9d7fd 100644 --- a/cmd/pint/tests/0076_ci_group_errors.txt +++ b/cmd/pint/tests/0076_ci_group_errors.txt @@ -1,5 +1,6 @@ -http response prometheus / 200 OK -http start prometheus 127.0.0.1:6076 +http response bitbucket /rest/insights/1.0/projects/prometheus/repos/rules/commits/.*/reports/pint 200 OK +http response bitbucket /rest/api/1.0/projects/prometheus/repos/rules/commits/.*/pull-requests 200 {} +http start bitbucket 127.0.0.1:6076 mkdir testrepo cd testrepo diff --git a/cmd/pint/tests/0093_ci_bitbucket_ignore_file.txt b/cmd/pint/tests/0093_ci_bitbucket_ignore_file.txt index 1c2bd68f..05529546 100644 --- a/cmd/pint/tests/0093_ci_bitbucket_ignore_file.txt +++ b/cmd/pint/tests/0093_ci_bitbucket_ignore_file.txt @@ -1,4 +1,5 @@ -http response bitbucket / 200 OK +http response bitbucket /rest/insights/1.0/projects/prometheus/repos/rules/commits/.*/reports/pint 200 OK +http response bitbucket /rest/api/1.0/projects/prometheus/repos/rules/commits/.*/pull-requests 200 {} http start bitbucket 127.0.0.1:6093 mkdir testrepo @@ -25,10 +26,10 @@ stderr 'level=INFO msg="Problems found" Information=1' stderr 'result":"PASS"' stderr ',"line":7,' stderr '"message":"ignore/file:' -stderr 'level=DEBUG msg="Sending a request to BitBucket" method=PUT' -stderr 'level=DEBUG msg="BitBucket request completed" status=200' -stderr 'level=DEBUG msg="Sending a request to BitBucket" method=DELETE' -stderr 'level=DEBUG msg="BitBucket request completed" status=200' +stderr 'msg="Sending a request to BitBucket" method=PUT' +stderr 'msg="BitBucket request completed" status=200' +stderr 'msg="Sending a request to BitBucket" method=DELETE' +stderr 'msg="BitBucket request completed" status=200' -- src/v1.yml -- # pint ignore/file diff --git a/cmd/pint/tests/0094_rule_file_symlink_bb.txt b/cmd/pint/tests/0094_rule_file_symlink_bb.txt index 71161658..f2867134 100644 --- a/cmd/pint/tests/0094_rule_file_symlink_bb.txt +++ b/cmd/pint/tests/0094_rule_file_symlink_bb.txt @@ -12,7 +12,8 @@ http response prometheus5m /api/v1/query_range 200 {"status":"success","data":{" http response prometheus5m /api/v1/query 200 {"status":"success","data":{"resultType":"vector","result":[]}} http start prometheus5m 127.0.0.1:2094 -http response bitbucket / 200 OK +http response bitbucket /rest/insights/1.0/projects/prometheus/repos/rules/commits/.*/reports/pint 200 OK +http response bitbucket /rest/api/1.0/projects/prometheus/repos/rules/commits/.*/pull-requests 200 {} http start bitbucket 127.0.0.1:6094 mkdir testrepo diff --git a/cmd/pint/tests/0100_ci_alerts_count.txt b/cmd/pint/tests/0100_ci_alerts_count.txt index 2c9a137e..deb646b6 100644 --- a/cmd/pint/tests/0100_ci_alerts_count.txt +++ b/cmd/pint/tests/0100_ci_alerts_count.txt @@ -5,7 +5,8 @@ http response prometheus /api/v1/query_range 200 {"status":"success","data":{"re http response prometheus /api/v1/query 200 {"status":"success","data":{"resultType":"vector","result":[]}} http start prometheus 127.0.0.1:2100 -http response bitbucket / 200 OK +http response bitbucket /rest/insights/1.0/projects/prometheus/repos/rules/commits/.*/reports/pint 200 OK +http response bitbucket /rest/api/1.0/projects/prometheus/repos/rules/commits/.*/pull-requests 200 {} http start bitbucket 127.0.0.1:6100 mkdir testrepo diff --git a/cmd/pint/tests/0123_ci_owner_allowed.txt b/cmd/pint/tests/0123_ci_owner_allowed.txt index da4e03f9..dfea7de9 100644 --- a/cmd/pint/tests/0123_ci_owner_allowed.txt +++ b/cmd/pint/tests/0123_ci_owner_allowed.txt @@ -1,4 +1,5 @@ -http response bitbucket / 200 OK +http response bitbucket /rest/insights/1.0/projects/prometheus/repos/rules/commits/.*/reports/pint 200 OK +http response bitbucket /rest/api/1.0/projects/prometheus/repos/rules/commits/.*/pull-requests 200 {} http start bitbucket 127.0.0.1:6123 mkdir testrepo diff --git a/docs/changelog.md b/docs/changelog.md index 25b09985..24b61ffe 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -13,6 +13,9 @@ and add that information to the report. This allows pint to flag rules that are most likely deployed to the wrong servers, using missing scrape jobs. +- Reporting problems to BitBucket will now use comments instead of annotations. + This is only if there is an open pull request for tested branch, if there is no + open pull request problems will be reported using code insight annotations. ## v0.48.2 diff --git a/docs/index.md b/docs/index.md index 94023a4a..e6111b2d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -49,10 +49,8 @@ It currently supports git for which it will find all commits on the current bran present in the parent branch and scan all modified files included in those changes. Results can optionally be reported using -[BitBucket API](https://docs.atlassian.com/bitbucket-server/rest/7.8.0/bitbucket-code-insights-rest.html) +[BitBucket API](https://developer.atlassian.com/server/bitbucket/rest/) or [GitHub API](https://docs.github.com/en/rest) to generate a report with any found issues. -If you are using BitBucket API then each issue will create an inline annotation in BitBucket with a description of -the issue. If you are using GitHub API then each issue will appear as a comment on your pull request. Exit code will be one (1) if any issues were detected with severity `Bug` or higher. This permits running `pint` in your CI system whilst at the same you will get detailed reports on your source control system. diff --git a/go.mod b/go.mod index 0faf74c9..fe88c16d 100644 --- a/go.mod +++ b/go.mod @@ -10,10 +10,11 @@ require ( github.com/google/go-github/v55 v55.0.0 github.com/hashicorp/hcl/v2 v2.19.1 github.com/klauspost/compress v1.17.2 + github.com/neilotoole/slogt v1.1.0 github.com/prometheus/client_golang v1.17.0 github.com/prometheus/client_model v0.5.0 github.com/prometheus/common v0.45.0 - github.com/prometheus/prometheus v0.47.2 + github.com/prometheus/prometheus v0.48.0-rc.2 github.com/prymitive/current v0.1.0 github.com/rogpeppe/go-internal v1.11.0 github.com/stretchr/testify v1.8.4 @@ -22,25 +23,25 @@ require ( go.uber.org/atomic v1.11.0 go.uber.org/automaxprocs v1.5.3 go.uber.org/ratelimit v0.3.0 - golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 + golang.org/x/exp v0.0.0-20231006140011-7918f672742d golang.org/x/oauth2 v0.13.0 gopkg.in/yaml.v3 v3.0.1 ) require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect - github.com/aws/aws-sdk-go v1.44.302 // indirect - github.com/benbjohnson/clock v1.3.0 // indirect + github.com/aws/aws-sdk-go v1.47.2 // indirect + github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cloudflare/circl v1.3.3 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/cloudflare/circl v1.3.6 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dennwc/varint v1.0.0 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect @@ -48,14 +49,14 @@ require ( github.com/gkampitakis/go-diff v1.3.2 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v5 v5.0.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.4.0 // indirect github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect @@ -64,7 +65,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -75,30 +76,24 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/common/sigv4 v0.1.0 // indirect - github.com/prometheus/procfs v0.11.1 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/sergi/go-diff v1.2.0 // indirect github.com/tidwall/gjson v1.16.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/tidwall/sjson v1.2.5 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - go.opentelemetry.io/otel v1.16.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect - go.opentelemetry.io/otel/trace v1.16.0 // indirect - go.uber.org/goleak v1.2.1 // indirect + go.opentelemetry.io/otel v1.19.0 // indirect + go.opentelemetry.io/otel/metric v1.19.0 // indirect + go.opentelemetry.io/otel/trace v1.19.0 // indirect + go.uber.org/goleak v1.3.0 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/sync v0.3.0 // indirect + golang.org/x/sync v0.4.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect - golang.org/x/tools v0.11.0 // indirect - google.golang.org/appengine v1.6.7 // indirect + golang.org/x/tools v0.14.0 // indirect + google.golang.org/appengine v1.6.8 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) - -exclude ( - cloud.google.com/go v0.34.0 - cloud.google.com/go v0.65.0 -) diff --git a/go.sum b/go.sum index 0238de5d..9b839fc8 100644 --- a/go.sum +++ b/go.sum @@ -1,33 +1,55 @@ -github.com/Azure/azure-sdk-for-go v65.0.0+incompatible h1:HzKLt3kIwMm4KeJYTdx9EbjRYTySD/t8i1Ee/W5EGXw= -github.com/Azure/azure-sdk-for-go v65.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 h1:8q4SaHjFsClSvuVne0ID/5Ka8u3fcIHyqkLjcFpNRHQ= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= -github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= -github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw= -github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs= -github.com/Azure/go-autorest/autorest/adal v0.9.23 h1:Yepx8CvFxwNKpH6ja7RZ+sKX+DWYNldbLiALMC3BTz8= -github.com/Azure/go-autorest/autorest/adal v0.9.23/go.mod h1:5pcMqFkdPhviJdlEy3kC/v1ZLnQl0MH6XA5YCcMhy4c= -github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= -github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= -github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= -github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac= -github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= -github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= -github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= -github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY= -github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 h1:9kDVnTz3vbfweTqAUmk/a/pH5pWFCHtvRpHYC0G/dcA= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 h1:d81/ng9rET2YqdVkVwkb6EXeRrLJIwyGnJcAlAWKwhs= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1 h1:UPeCRD+XY7QlaGQte2EVI2iOcWvUYA2XY8w5T/8v0NQ= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1/go.mod h1:oGV6NlB0cvi1ZbYRR2UN44QHxWFyGk+iylgD0qaMXjA= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.1.0 h1:QM6sE5k2ZT/vI5BEe0r7mqjsUSnhVBFbOsVkEuaEfiA= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1 h1:bWh0Z2rOEDfB/ywv/l0iHN1JgyazE6kW/aIA89+CEK0= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1/go.mod h1:Bzf34hhAE9NSxailk8xVeLEZbUjOXcC+GnU1mMKdhLw= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 h1:hVeq+yCyUi+MsoO/CU95yqCIcdzra5ovzk8Q2BBpV2M= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA= -github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= +github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c h1:kMFnB0vCcX7IL/m9Y5LO+KQYv+t1CQOiFe6+SV2J7bE= +github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -42,25 +64,31 @@ github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmms github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.44.302 h1:ST3ko6GrJKn3Xi+nAvxjG3uk/V1pW8KC52WLeIxqqNk= -github.com/aws/aws-sdk-go v1.44.302/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= -github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/aws/aws-sdk-go v1.47.2 h1:KEdO2PbjfEBmHvnEwbYEpr65ZIkmwK5aB85Gj19ASuA= +github.com/aws/aws-sdk-go v1.47.2/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= -github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.6 h1:/xbKIqSHbZXHwkhbrhrt2YOHIwYJlXH94E3tI/gDlUg= +github.com/cloudflare/circl v1.3.6/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -68,14 +96,14 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= -github.com/digitalocean/godo v1.99.0 h1:gUHO7n9bDaZFWvbzOum4bXE0/09ZuYA9yA8idQHX57E= -github.com/digitalocean/godo v1.99.0/go.mod h1:SsS2oXo2rznfM/nORlZ/6JaUJZFhmKTib1YhopUc8NA= +github.com/digitalocean/godo v1.104.1 h1:SZNxjAsskM/su0YW9P8Wx3gU0W1Z13b6tZlYNpl5BnA= +github.com/digitalocean/godo v1.104.1/go.mod h1:VAI/L5YDzMuPRU01lEEUSQ/sp5Z//1HnnFv/RBTEdbg= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v24.0.4+incompatible h1:s/LVDftw9hjblvqIeTiGYXBCD95nOEEl7qRsRrIOuQI= -github.com/docker/docker v24.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE= +github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -84,8 +112,12 @@ github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM= github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= @@ -98,6 +130,9 @@ github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZ github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk= github.com/gkampitakis/go-snaps v0.4.11 h1:7qKaozbTQEvHeG0bt6osdjdTDTnWYdIrLx43a7DEDu4= github.com/gkampitakis/go-snaps v0.4.11/go.mod h1:N4TpqxI4CqKUfHzDFqrqZ5UP0I0ESz2g2NMslh7MiJw= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -109,8 +144,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= @@ -129,28 +164,50 @@ github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= -github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -163,16 +220,28 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gophercloud/gophercloud v1.5.0 h1:cDN6XFCLKiiqvYpjQLq9AiM7RDRbIC9450WpPH+yvXo= -github.com/gophercloud/gophercloud v1.5.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gophercloud/gophercloud v1.7.0 h1:fyJGKh0LBvIZKLvBWvQdIgkaV5yTM3Jh9EYUh+UNCAs= +github.com/gophercloud/gophercloud v1.7.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd h1:PpuIBO5P3e9hpqBD0O/HjhShYuM6XE0i/lbE6J94kww= github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A= -github.com/hashicorp/consul/api v1.22.0 h1:ydEvDooB/A0c/xpsBd8GSt7P2/zYPBui4KrNip0xGjE= -github.com/hashicorp/consul/api v1.22.0/go.mod h1:zHpYgZ7TeYqS6zaszjwSt128OwESRpnhU9aGa6ue3Eg= +github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE= +github.com/hashicorp/consul/api v1.25.1/go.mod h1:iiLVwR/htV7mas/sy0O+XSuEnrdBUUydemjxcUrAt4g= github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= @@ -189,20 +258,23 @@ github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZn github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl/v2 v2.19.1 h1://i05Jqznmb2EXqa39Nsvyan2o5XyMowW5fnCKW5RPI= github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE= -github.com/hashicorp/nomad/api v0.0.0-20230718173136-3a687930bd3e h1:sr4lujmn9heD030xx/Pd4B/JSmvRhFzuotNXaaV0WLs= -github.com/hashicorp/nomad/api v0.0.0-20230718173136-3a687930bd3e/go.mod h1:O23qLAZuCx4htdY9zBaO4cJPXgleSFEdq6D/sezGgYE= +github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c h1:Nc3Mt2BAnq0/VoLEntF/nipX+K1S7pG+RgwiitSv6v0= +github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c/go.mod h1:O23qLAZuCx4htdY9zBaO4cJPXgleSFEdq6D/sezGgYE= github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= -github.com/hetznercloud/hcloud-go/v2 v2.0.0 h1:Sg1DJ+MAKvbYAqaBaq9tPbwXBS2ckPIaMtVdUjKu+4g= -github.com/hetznercloud/hcloud-go/v2 v2.0.0/go.mod h1:4iUG2NG8b61IAwNx6UsMWQ6IfIf/i1RsG0BbsKAyR5Q= +github.com/hetznercloud/hcloud-go/v2 v2.4.0 h1:MqlAE+w125PLvJRCpAJmEwrIxoVdUdOyuFUhE/Ukbok= +github.com/hetznercloud/hcloud-go/v2 v2.4.0/go.mod h1:l7fA5xsncFBzQTyw29/dw5Yr88yEGKKdc6BHf24ONS0= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/ionos-cloud/sdk-go/v6 v6.1.8 h1:493wE/BkZxJf7x79UCE0cYGPZoqQcPiEBALvt7uVGY0= -github.com/ionos-cloud/sdk-go/v6 v6.1.8/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= +github.com/ionos-cloud/sdk-go/v6 v6.1.9 h1:Iq3VIXzeEbc8EbButuACgfLMiY5TPVWUPNrF+Vsddo4= +github.com/ionos-cloud/sdk-go/v6 v6.1.9/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -216,6 +288,8 @@ github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/ github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -236,20 +310,20 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/linode/linodego v1.19.0 h1:n4WJrcr9+30e9JGZ6DI0nZbm5SdAj1kSwvvt/998YUw= -github.com/linode/linodego v1.19.0/go.mod h1:XZFR+yJ9mm2kwf6itZ6SCpu+6w3KnIevV0Uu5HNWJgQ= +github.com/linode/linodego v1.23.0 h1:s0ReCZtuN9Z1IoUN9w1RLeYO1dMZUGPwOQ/IBFsBHtU= +github.com/linode/linodego v1.23.0/go.mod h1:0U7wj/UQOqBNbKv1FYTXiBUXueR8DY4HvIotwE0ENgg= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= -github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= -github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= +github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= @@ -268,14 +342,16 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/neilotoole/slogt v1.1.0 h1:c7qE92sq+V0yvCuaxph+RQ2jOKL61c4hqS1Bv9W7FZE= +github.com/neilotoole/slogt v1.1.0/go.mod h1:RCrGXkPc/hYybNulqQrMHRtvlQ7F6NktNVLuLwk6V+w= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/ovh/go-ovh v1.4.1 h1:VBGa5wMyQtTP7Zb+w97zRCh9sLtM/2YKRyy+MEJmWaM= -github.com/ovh/go-ovh v1.4.1/go.mod h1:6bL6pPyUT7tBfI0pqOegJgRjgjuO+mOo+MyXd1EEC0M= +github.com/ovh/go-ovh v1.4.3 h1:Gs3V823zwTFpzgGLZNI6ILS4rmxZgJwJCz54Er9LwD0= +github.com/ovh/go-ovh v1.4.3/go.mod h1:AkPXVtgwB6xlKblMjRKJJmjRp+ogrE7fz2lVgcQY8SY= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -296,6 +372,7 @@ github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1 github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= @@ -311,21 +388,22 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= -github.com/prometheus/prometheus v0.47.2 h1:jWcnuQHz1o1Wu3MZ6nMJDuTI0kU5yJp9pkxh8XEkNvI= -github.com/prometheus/prometheus v0.47.2/go.mod h1:J/bmOSjgH7lFxz2gZhrWEZs2i64vMS+HIuZfmYNhJ/M= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/prometheus/prometheus v0.48.0-rc.2 h1:CFAdPbWVDduOZFn1/35lsPGLw/PrWRyF3CGY5BYl+xg= +github.com/prometheus/prometheus v0.48.0-rc.2/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= github.com/prymitive/current v0.1.0 h1:j0qvhMUKEz4rZE7YgftTYnBcaujmv6RVGvvmEC+p+6E= github.com/prymitive/current v0.1.0/go.mod h1:ZKbTBHjDMGAM3YPcnkA2I4L5U/vYfbXyVTKZJWhTCoc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.20 h1:a9hSJdJcd16e0HoMsnFvaHvxB3pxSD+SC7+CISp7xY0= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.20/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= -github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= -github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21 h1:yWfiTPwYxB0l5fGMhl/G+liULugVIHD9AU77iNLrURQ= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -357,79 +435,170 @@ github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZ github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA= github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= +go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= +go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= +go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/ratelimit v0.3.0 h1:IdZd9wqvFXnvLvSEBo0KPcGfkoBGNkpTHlrE3Rcjkjw= go.uber.org/ratelimit v0.3.0/go.mod h1:So5LG7CV1zWpY1sHe+DXTJqQvOx+FFPFaAs2SnoyBaI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -437,67 +606,184 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= -golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753 h1:+VoAg+OKmWaommL56xmZSE2sUK8A7m6SUO7X89F2tbw= -google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753/go.mod h1:iqkVr8IRpZ53gx1dEnWlCUIEwDWqWARWrbzpasaTNYM= -google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753 h1:lCbbUxUDD+DiXx9Q6F/ttL0aAu7N2pz8XnmMm8ZW4NE= -google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753 h1:XUODHrpzJEUeWmVo/jfNTLj0YyVveOo28oE6vkFbkO4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= -google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0= +google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= +google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a h1:myvhA4is3vrit1a6NZCWBIwN0kNEnX21DJOJX/NvIfI= +google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:SUBoKXbI1Efip18FClrQVGjWcyd0QZd8KkvdP34t7ww= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c h1:jHkCUWkseRf+W+edG5hMzr/Uh1xkDREY4caybAq4dpY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= +google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= @@ -513,19 +799,29 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.27.3 h1:yR6oQXXnUEBWEWcvPWS0jQL575KoAboQPfJAuKNrw5Y= -k8s.io/api v0.27.3/go.mod h1:C4BNvZnQOF7JA/0Xed2S+aUyJSfTGkGFxLXz9MnpIpg= -k8s.io/apimachinery v0.27.3 h1:Ubye8oBufD04l9QnNtW05idcOe9Z3GQN8+7PqmuVcUM= -k8s.io/apimachinery v0.27.3/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= -k8s.io/client-go v0.27.3 h1:7dnEGHZEJld3lYwxvLl7WoehK6lAq7GvgjxpA3nv1E8= -k8s.io/client-go v0.27.3/go.mod h1:2MBEKuTo6V1lbKy3z1euEGnhPfGZLKTS9tiJ2xodM48= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= +k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= +k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= +k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= +k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY= +k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230525220651-2546d827e515 h1:OmK1d0WrkD3IPfkskvroRykOulHVHf0s0ZIFRjyt+UI= -k8s.io/kube-openapi v0.0.0-20230525220651-2546d827e515/go.mod h1:kzo02I3kQ4BTtEfVLaPbjvCkX97YqGve33wzlb3fofQ= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI5yiP5WwlfDoIyc= k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= diff --git a/internal/checks/base_test.go b/internal/checks/base_test.go index 62401198..24c97677 100644 --- a/internal/checks/base_test.go +++ b/internal/checks/base_test.go @@ -14,6 +14,7 @@ import ( "testing" "time" + "github.com/neilotoole/slogt" v1 "github.com/prometheus/client_golang/api/prometheus/v1" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/model" @@ -21,7 +22,6 @@ import ( "github.com/cloudflare/pint/internal/checks" "github.com/cloudflare/pint/internal/discovery" - "github.com/cloudflare/pint/internal/log" "github.com/cloudflare/pint/internal/output" "github.com/cloudflare/pint/internal/parser" "github.com/cloudflare/pint/internal/promapi" @@ -105,10 +105,11 @@ type checkTest struct { } func runTests(t *testing.T, testCases []checkTest) { - log.Level.Set(slog.LevelError) for _, tc := range testCases { // original test t.Run(tc.description, func(t *testing.T) { + slog.SetDefault(slogt.New(t)) + var uri string if len(tc.mocks) > 0 { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/internal/reporter/bitbucket.go b/internal/reporter/bitbucket.go index 6baac57f..6c9c8fa9 100644 --- a/internal/reporter/bitbucket.go +++ b/internal/reporter/bitbucket.go @@ -1,17 +1,11 @@ package reporter import ( - "bytes" - "encoding/json" "fmt" - "io" "log/slog" - "net/http" "time" - "github.com/cloudflare/pint/internal/checks" "github.com/cloudflare/pint/internal/git" - "github.com/cloudflare/pint/internal/output" ) const ( @@ -20,234 +14,102 @@ const ( "Checks can be either offline (static checks using only rule definition) or online (validate rule against live Prometheus server)." ) -type BitBucketReport struct { - Reporter string `json:"reporter"` - Title string `json:"title"` - Result string `json:"result"` - Details string `json:"details"` - Link string `json:"link"` - Data []BitBucketReportData `json:"data"` -} - -type DataType string - -const ( - BooleanType DataType = "BOOLEAN" - DateType DataType = "DATA" - DurationType DataType = "DURATION" - LinkType DataType = "LINK" - NumberType DataType = "NUMBER" - PercentageType DataType = "PERCENTAGE" - TextType DataType = "TEXT" -) - -type BitBucketReportData struct { - Title string `json:"title"` - Type DataType `json:"type"` - Value any `json:"value"` -} - -type BitBucketAnnotation struct { - Path string `json:"path"` - Line int `json:"line"` - Message string `json:"message"` - Severity string `json:"severity"` - Type string `json:"type"` - Link string `json:"link"` -} - -type BitBucketAnnotations struct { - Annotations []BitBucketAnnotation `json:"annotations"` -} - func NewBitBucketReporter(version, uri string, timeout time.Duration, token, project, repo string, gitCmd git.CommandRunner) BitBucketReporter { return BitBucketReporter{ - version: version, - uri: uri, - timeout: timeout, - authToken: token, - project: project, - repo: repo, - gitCmd: gitCmd, + api: newBitBucketAPI(version, uri, timeout, token, project, repo), + gitCmd: gitCmd, } } // BitBucketReporter send linter results to BitBucket using // https://docs.atlassian.com/bitbucket-server/rest/7.8.0/bitbucket-code-insights-rest.html type BitBucketReporter struct { - version string - uri string - timeout time.Duration - authToken string - project string - repo string - gitCmd git.CommandRunner + api *bitBucketAPI + gitCmd git.CommandRunner } func (r BitBucketReporter) Submit(summary Summary) (err error) { - headCommit, err := git.HeadCommit(r.gitCmd) - if err != nil { + var headCommit string + if headCommit, err = git.HeadCommit(r.gitCmd); err != nil { return fmt.Errorf("failed to get HEAD commit: %w", err) } slog.Info("Got HEAD commit from git", slog.String("commit", headCommit)) - annotations := []BitBucketAnnotation{} - for _, report := range summary.Reports() { - annotations = append(annotations, r.makeAnnotation(report)...) + if err = r.api.deleteReport(headCommit); err != nil { + return fmt.Errorf("failed to delete old BitBucket report: %w", err) } - isPassing := true - for _, ann := range annotations { - if ann.Type == "BUG" { - isPassing = false - break - } + if err = r.api.createReport(summary, headCommit); err != nil { + return fmt.Errorf("failed to create BitBucket report: %w", err) } - if err = r.postReport(headCommit, isPassing, annotations, summary); err != nil { - return err + var headBranch string + if headBranch, err = git.CurrentBranch(r.gitCmd); err != nil { + return fmt.Errorf("failed to get current branch: %w", err) } - if summary.HasFatalProblems() { - return fmt.Errorf("fatal error(s) reported") + var pr *bitBucketPR + if pr, err = r.api.findPullRequestForBranch(headBranch, headCommit); err != nil { + return fmt.Errorf("failed to get open pull requests from BitBucket: %w", err) } - return nil -} - -func (r BitBucketReporter) makeAnnotation(report Report) (annotations []BitBucketAnnotation) { - if !shouldReport(report) { - slog.Debug( - "Problem reported on unmodified line, skipping", - slog.String("path", report.SourcePath), - slog.String("lines", output.FormatLineRangeString(report.Problem.Lines)), + if pr != nil { + slog.Info( + "Found open pull request, reporting problems using comments", + slog.Int("id", pr.ID), + slog.String("srcBranch", pr.srcBranch), + slog.String("srcCommit", pr.srcHead), + slog.String("dstBranch", pr.dstBranch), + slog.String("dstCommit", pr.dstHead), ) - return annotations - } - var msgPrefix string - reportLine, srcLine := moveReportedLine(report) - if reportLine != srcLine { - msgPrefix = fmt.Sprintf("Problem reported on unmodified line %d, annotation moved here: ", srcLine) - } - if report.ReportedPath != report.SourcePath { - if msgPrefix == "" { - msgPrefix = fmt.Sprintf("Problem detected on symlinked file %s: ", report.SourcePath) - } else { - msgPrefix = fmt.Sprintf("Problem detected on symlinked file %s. %s", report.SourcePath, msgPrefix) + slog.Info("Getting pull request changes from BitBucket") + var changes *bitBucketPRChanges + if changes, err = r.api.getPullRequestChanges(pr); err != nil { + return fmt.Errorf("failed to get pull request changes from BitBucket: %w", err) } - } - - var severity, atype string - switch report.Problem.Severity { - case checks.Fatal: - severity = "HIGH" - atype = "BUG" - case checks.Bug: - severity = "MEDIUM" - atype = "BUG" - case checks.Warning, checks.Information: - severity = "LOW" - atype = "CODE_SMELL" - } - - a := BitBucketAnnotation{ - Path: report.ReportedPath, - Line: reportLine, - Message: fmt.Sprintf("%s%s: %s", msgPrefix, report.Problem.Reporter, report.Problem.Text), - Severity: severity, - Type: atype, - Link: fmt.Sprintf("https://cloudflare.github.io/pint/checks/%s.html", report.Problem.Reporter), - } - annotations = append(annotations, a) - - return annotations -} - -func (r BitBucketReporter) bitBucketRequest(method, url string, body []byte) error { - slog.Debug("Sending a request to BitBucket", slog.String("method", method), slog.String("url", url)) - slog.Debug("Request payload", slog.String("body", string(body))) - req, err := http.NewRequest(method, url, bytes.NewBuffer(body)) - if err != nil { - return err - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", r.authToken)) - - netClient := &http.Client{ - Timeout: r.timeout, - } + slog.Info("Got modified files from BitBucket", slog.Any("files", changes.pathModifiedLines)) - resp, err := netClient.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - - slog.Debug("BitBucket request completed", slog.Int("status", resp.StatusCode)) - if resp.StatusCode >= 300 { - body, err := io.ReadAll(resp.Body) - if err != nil { - slog.Error("Failed to read response body", slog.Any("err", err)) + var existingComments []bitBucketComment + if existingComments, err = r.api.getPullRequestComments(pr); err != nil { + return fmt.Errorf("failed to get pull request comments from BitBucket: %w", err) } - slog.Error("Got a non 2xx response", slog.String("body", string(body)), slog.String("url", url), slog.Int("code", resp.StatusCode)) - return fmt.Errorf("%s request failed", method) - } + slog.Info("Got existing pull request comments from BitBucket", slog.Int("count", len(existingComments))) - return nil -} + pendingComments := r.api.makeComments(summary, changes) + slog.Info("Generated comments to add to BitBucket", slog.Int("count", len(pendingComments))) -func (r BitBucketReporter) createAnnotations(commit string, annotations []BitBucketAnnotation) error { - payload, _ := json.Marshal(BitBucketAnnotations{Annotations: annotations}) - url := fmt.Sprintf("%s/rest/insights/1.0/projects/%s/repos/%s/commits/%s/reports/pint/annotations", - r.uri, r.project, r.repo, commit) - return r.bitBucketRequest(http.MethodPost, url, payload) -} + slog.Info("Deleting stale comments from BitBucket") + if err = r.api.pruneComments(pr, existingComments, pendingComments); err != nil { + return fmt.Errorf("failed to delete stale BitBucket pull request comments: %w", err) + } -func (r BitBucketReporter) deleteAnnotations(commit string) error { - url := fmt.Sprintf("%s/rest/insights/1.0/projects/%s/repos/%s/commits/%s/reports/pint/annotations", - r.uri, r.project, r.repo, commit) - return r.bitBucketRequest(http.MethodDelete, url, nil) -} + slog.Info("Adding missing comments to BitBucket") + if err = r.api.addComments(pr, existingComments, pendingComments, changes); err != nil { + return fmt.Errorf("failed to create BitBucket pull request comments: %w", err) + } -func (r BitBucketReporter) postReport(commit string, isPassing bool, annotations []BitBucketAnnotation, summary Summary) error { - result := "PASS" - if !isPassing { - result = "FAIL" - } - payload, _ := json.Marshal(BitBucketReport{ - Title: fmt.Sprintf("pint %s", r.version), - Result: result, - Reporter: "Prometheus rule linter", - Details: BitBucketDescription, - Link: "https://cloudflare.github.io/pint/", - Data: []BitBucketReportData{ - {Title: "Number of rules checked", Type: NumberType, Value: summary.Entries}, - {Title: "Number of problems found", Type: NumberType, Value: len(annotations)}, - {Title: "Number of offline checks", Type: NumberType, Value: summary.OfflineChecks}, - {Title: "Number of online checks", Type: NumberType, Value: summary.OnlineChecks}, - {Title: "Checks duration", Type: DurationType, Value: summary.Duration.Milliseconds()}, - }, - }) + } else { + slog.Info( + "No open pull request found, reporting problems using code insight annotations", + slog.String("branch", headBranch), + slog.String("commit", headCommit), + ) - url := fmt.Sprintf("%s/rest/insights/1.0/projects/%s/repos/%s/commits/%s/reports/pint", - r.uri, r.project, r.repo, commit) - if err := r.bitBucketRequest(http.MethodPut, url, payload); err != nil { - return fmt.Errorf("failed to create BitBucket report: %w", err) - } + if err = r.api.deleteAnnotations(headCommit); err != nil { + return fmt.Errorf("failed to delete existing BitBucket code insight annotations: %w", err) + } - // Try to delete annotations when that happens so we don't end up with stale data if we run - // pint twice, first with problems found, and second without any. - if err := r.deleteAnnotations(commit); err != nil { - return err + if err = r.api.createAnnotations(summary, headCommit); err != nil { + return fmt.Errorf("failed to create BitBucket code insight annotations: %w", err) + } } - // BitBucket API requires at least one annotation, if there aren't any report is PASS anyway - if len(annotations) == 0 { - return nil + if summary.HasFatalProblems() { + return fmt.Errorf("fatal error(s) reported") } - return r.createAnnotations(commit, annotations) + return nil } // BitBucket only allows us to report annotations for modified lines. diff --git a/internal/reporter/bitbucket_api.go b/internal/reporter/bitbucket_api.go new file mode 100644 index 00000000..76bcc375 --- /dev/null +++ b/internal/reporter/bitbucket_api.go @@ -0,0 +1,663 @@ +package reporter + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "log/slog" + "net/http" + "slices" + "strings" + "time" + + "github.com/cloudflare/pint/internal/checks" + "github.com/cloudflare/pint/internal/output" +) + +type BitBucketReport struct { + Reporter string `json:"reporter"` + Title string `json:"title"` + Result string `json:"result"` + Details string `json:"details"` + Link string `json:"link"` + Data []BitBucketReportData `json:"data"` +} + +type DataType string + +const ( + BooleanType DataType = "BOOLEAN" + DateType DataType = "DATA" + DurationType DataType = "DURATION" + LinkType DataType = "LINK" + NumberType DataType = "NUMBER" + PercentageType DataType = "PERCENTAGE" + TextType DataType = "TEXT" +) + +type BitBucketReportData struct { + Title string `json:"title"` + Type DataType `json:"type"` + Value any `json:"value"` +} + +type BitBucketAnnotation struct { + Path string `json:"path"` + Line int `json:"line"` + Message string `json:"message"` + Severity string `json:"severity"` + Type string `json:"type"` + Link string `json:"link"` +} + +type BitBucketAnnotations struct { + Annotations []BitBucketAnnotation `json:"annotations"` +} + +type BitBucketRef struct { + ID string `json:"id"` + Commit string `json:"latestCommit"` +} + +type BitBucketPullRequest struct { + ID int `json:"id"` + Open bool `json:"open"` + FromRef BitBucketRef `json:"fromRef"` + ToRef BitBucketRef `json:"toRef"` +} + +type BitBucketPullRequests struct { + Start int `json:"start"` + NextPageStart int `json:"nextPageStart"` + IsLastPage bool `json:"isLastPage"` + Values []BitBucketPullRequest `json:"values"` +} + +type bitBucketPR struct { + ID int + srcBranch string + srcHead string + dstBranch string + dstHead string +} + +type bitBucketPRChanges struct { + pathModifiedLines map[string][]int + pathLineMapping map[string]map[int]int +} + +type BitBucketPath struct { + ToString string `json:"toString"` +} + +type BitBucketPullRequestChange struct { + Path BitBucketPath `json:"path"` +} + +type BitBucketPullRequestChanges struct { + Start int `json:"start"` + NextPageStart int `json:"nextPageStart"` + IsLastPage bool `json:"isLastPage"` + Values []BitBucketPullRequestChange `json:"values"` +} + +type BitBucketDiffLine struct { + Source int `json:"source"` + Destination int `json:"destination"` +} + +type BitBucketDiffSegment struct { + Type string `json:"type"` + Lines []BitBucketDiffLine `json:"lines"` +} + +type BitBucketDiffHunk struct { + Segments []BitBucketDiffSegment `json:"segments"` +} + +type BitBucketFileDiff struct { + Hunks []BitBucketDiffHunk `json:"hunks"` +} + +type BitBucketFileDiffs struct { + Diffs []BitBucketFileDiff `json:"diffs"` +} + +type bitBucketComment struct { + id int + version int + onCommit bool + text string + path string + line int +} + +type BitBucketCommentAuthor struct { + Name string `json:"name"` +} + +type BitBucketPullRequestComment struct { + ID int `json:"id"` + Version int `json:"version"` + State string `json:"state"` + Author BitBucketCommentAuthor `json:"author"` + Text string `json:"text"` +} + +type BitBucketCommentAnchor struct { + Orphaned bool `json:"orphaned"` + DiffType string `json:"diffType"` + Path string `json:"path"` + Line int `json:"line"` +} + +type BitBucketPullRequestActivity struct { + Action string `json:"action"` + CommentAction string `json:"commentAction"` + CommentAnchor BitBucketCommentAnchor `json:"commentAnchor"` + Comment BitBucketPullRequestComment `json:"comment"` +} + +type BitBucketPullRequestActivities struct { + Start int `json:"start"` + NextPageStart int `json:"nextPageStart"` + IsLastPage bool `json:"isLastPage"` + Values []BitBucketPullRequestActivity `json:"values"` +} + +type pendingComment struct { + text string + path string + line int +} + +func (pc pendingComment) toBitBucketComment(changes *bitBucketPRChanges) BitBucketPendingComment { + c := BitBucketPendingComment{ + Anchor: BitBucketPendingCommentAnchor{ + Path: pc.path, + Line: pc.line, + DiffType: "EFFECTIVE", + LineType: "CONTEXT", + FileType: "FROM", + }, + Text: pc.text, + Severity: "NORMAL", + } + + if changes != nil { + if lines, ok := changes.pathModifiedLines[pc.path]; ok && slices.Contains(lines, pc.line) { + c.Anchor.LineType = "ADDED" + c.Anchor.FileType = "TO" + } + if m, ok := changes.pathLineMapping[pc.path]; ok { + if v, found := m[pc.line]; found { + c.Anchor.Line = v + } + } + } + + return c +} + +type BitBucketPendingCommentAnchor struct { + Path string `json:"path"` + Line int `json:"line"` + LineType string `json:"lineType"` + FileType string `json:"fileType"` + DiffType string `json:"diffType"` +} + +type BitBucketPendingComment struct { + Text string `json:"text"` + Severity string `json:"severity"` + Anchor BitBucketPendingCommentAnchor `json:"anchor"` +} + +func newBitBucketAPI(pintVersion, uri string, timeout time.Duration, token, project, repo string) *bitBucketAPI { + return &bitBucketAPI{ + pintVersion: pintVersion, + uri: uri, + timeout: timeout, + authToken: token, + project: project, + repo: repo, + } +} + +type bitBucketAPI struct { + pintVersion string + uri string + timeout time.Duration + authToken string + project string + repo string +} + +func (bb bitBucketAPI) request(method, path string, body io.Reader) ([]byte, error) { + slog.Info("Sending a request to BitBucket", slog.String("method", method), slog.String("path", path)) + + if body != nil { + payload, _ := io.ReadAll(body) + slog.Debug("Request payload", slog.String("body", string(payload))) + body = bytes.NewReader(payload) + } + + req, err := http.NewRequest(method, bb.uri+path, body) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", bb.authToken)) + + netClient := &http.Client{ + Timeout: bb.timeout, + } + + resp, err := netClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + data, err := io.ReadAll(resp.Body) + if err != nil { + return data, err + } + + slog.Info("BitBucket request completed", slog.Int("status", resp.StatusCode)) + slog.Debug("BitBucket response body", slog.Int("code", resp.StatusCode), slog.String("body", string(data))) + if resp.StatusCode >= 300 { + slog.Error( + "Got a non 2xx response", + slog.String("body", string(data)), + slog.String("path", path), + slog.Int("code", resp.StatusCode), + ) + return data, fmt.Errorf("%s request failed", method) + } + + return data, err +} + +func (bb bitBucketAPI) whoami() (string, error) { + resp, err := bb.request(http.MethodGet, "/plugins/servlet/applinks/whoami", nil) + if err != nil { + return "", err + } + return strings.TrimSuffix(string(resp), "\n"), nil +} + +func (bb bitBucketAPI) deleteReport(commit string) error { + _, err := bb.request( + http.MethodDelete, + fmt.Sprintf("/rest/insights/1.0/projects/%s/repos/%s/commits/%s/reports/pint", bb.project, bb.repo, commit), + nil, + ) + return err +} + +func (bb bitBucketAPI) createReport(summary Summary, commit string) error { + result := "PASS" + var reportedProblems int + for _, report := range summary.reports { + if !shouldReport(report) { + continue + } + reportedProblems++ + if report.Problem.Severity >= checks.Bug { + result = "FAIL" + } + } + + payload, _ := json.Marshal(BitBucketReport{ + Title: fmt.Sprintf("pint %s", bb.pintVersion), + Result: result, + Reporter: "Prometheus rule linter", + Details: BitBucketDescription, + Link: "https://cloudflare.github.io/pint/", + Data: []BitBucketReportData{ + {Title: "Number of rules checked", Type: NumberType, Value: summary.Entries}, + {Title: "Number of problems found", Type: NumberType, Value: reportedProblems}, + {Title: "Number of offline checks", Type: NumberType, Value: summary.OfflineChecks}, + {Title: "Number of online checks", Type: NumberType, Value: summary.OnlineChecks}, + {Title: "Checks duration", Type: DurationType, Value: summary.Duration.Milliseconds()}, + }, + }) + + _, err := bb.request( + http.MethodPut, + fmt.Sprintf("/rest/insights/1.0/projects/%s/repos/%s/commits/%s/reports/pint", bb.project, bb.repo, commit), + bytes.NewReader(payload), + ) + return err +} + +func (bb bitBucketAPI) createAnnotations(summary Summary, commit string) error { + annotations := make([]BitBucketAnnotation, 0, len(summary.reports)) + for _, report := range summary.reports { + if !shouldReport(report) { + slog.Debug( + "Problem reported on unmodified line, skipping", + slog.String("path", report.SourcePath), + slog.String("lines", output.FormatLineRangeString(report.Problem.Lines)), + ) + continue + } + annotations = append(annotations, reportToAnnotation(report)) + } + + if len(annotations) == 0 { + return nil + } + + payload, _ := json.Marshal(BitBucketAnnotations{Annotations: annotations}) + _, err := bb.request( + http.MethodPost, + fmt.Sprintf("/rest/insights/1.0/projects/%s/repos/%s/commits/%s/reports/pint/annotations", bb.project, bb.repo, commit), + bytes.NewReader(payload), + ) + return err +} + +func (bb bitBucketAPI) deleteAnnotations(commit string) error { + _, err := bb.request( + http.MethodDelete, + fmt.Sprintf("/rest/insights/1.0/projects/%s/repos/%s/commits/%s/reports/pint/annotations", bb.project, bb.repo, commit), + nil, + ) + return err +} + +func (bb bitBucketAPI) findPullRequestForBranch(branch, commit string) (*bitBucketPR, error) { + var start int + for { + resp, err := bb.request( + http.MethodGet, + fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/commits/%s/pull-requests?start=%d", bb.project, bb.repo, commit, start), + nil, + ) + if err != nil { + return nil, err + } + + var prs BitBucketPullRequests + if err = json.Unmarshal(resp, &prs); err != nil { + return nil, err + } + + for _, pr := range prs.Values { + if !pr.Open { + continue + } + srcBranch := strings.TrimPrefix(pr.FromRef.ID, "refs/heads/") + dstBranch := strings.TrimPrefix(pr.ToRef.ID, "refs/heads/") + if srcBranch == branch { + return &bitBucketPR{ + ID: pr.ID, + srcBranch: srcBranch, + srcHead: pr.FromRef.Commit, + dstBranch: dstBranch, + dstHead: pr.ToRef.Commit, + }, nil + } + } + + if prs.IsLastPage || prs.NextPageStart == start { + break + } + start = prs.NextPageStart + } + + return nil, nil +} + +func (bb bitBucketAPI) getPullRequestChanges(pr *bitBucketPR) (*bitBucketPRChanges, error) { + prChanges := bitBucketPRChanges{ + pathModifiedLines: map[string][]int{}, + pathLineMapping: map[string]map[int]int{}, + } + + var start int + for { + resp, err := bb.request( + http.MethodGet, + fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/pull-requests/%d/changes?start=%d", bb.project, bb.repo, pr.ID, start), + nil, + ) + if err != nil { + return nil, err + } + + var changes BitBucketPullRequestChanges + if err = json.Unmarshal(resp, &changes); err != nil { + return nil, err + } + + for _, ch := range changes.Values { + modifiedLines, lineMap, err := bb.getFileDiff(pr, ch.Path.ToString) + if err != nil { + return nil, err + } + prChanges.pathModifiedLines[ch.Path.ToString] = modifiedLines + prChanges.pathLineMapping[ch.Path.ToString] = lineMap + } + + if changes.IsLastPage || changes.NextPageStart == start { + break + } + start = changes.NextPageStart + } + + return &prChanges, nil +} + +func (bb bitBucketAPI) getFileDiff(pr *bitBucketPR, path string) ([]int, map[int]int, error) { + resp, err := bb.request( + http.MethodGet, + fmt.Sprintf( + "/rest/api/latest/projects/%s/repos/%s/commits/%s/diff/%s?contextLines=10000&since=%s&whitespace=show&withComments=false", + bb.project, bb.repo, + pr.srcHead, + path, + pr.dstHead, + ), + nil, + ) + if err != nil { + return nil, nil, err + } + + var fileDiffs BitBucketFileDiffs + if err = json.Unmarshal(resp, &fileDiffs); err != nil { + return nil, nil, err + } + + modifiedLines := []int{} + lineMap := map[int]int{} + for _, diff := range fileDiffs.Diffs { + for _, hunk := range diff.Hunks { + for _, seg := range hunk.Segments { + for _, line := range seg.Lines { + if seg.Type == "ADDED" { + modifiedLines = append(modifiedLines, line.Destination) + } + if seg.Type == "CONTEXT" || seg.Type == "ADDED" { + lineMap[line.Destination] = line.Source + } + } + } + } + } + + return modifiedLines, lineMap, nil +} + +func (bb bitBucketAPI) getPullRequestComments(pr *bitBucketPR) ([]bitBucketComment, error) { + username, err := bb.whoami() + if err != nil { + return nil, err + } + + comments := []bitBucketComment{} + + var start int + for { + resp, err := bb.request( + http.MethodGet, + fmt.Sprintf( + "/rest/api/latest/projects/%s/repos/%s/pull-requests/%d/activities?start=%d", + bb.project, bb.repo, + pr.ID, + start, + ), + nil, + ) + if err != nil { + return nil, err + } + + var acts BitBucketPullRequestActivities + if err = json.Unmarshal(resp, &acts); err != nil { + return nil, err + } + + for _, act := range acts.Values { + if act.Action == "COMMENTED" && + act.CommentAction == "ADDED" && + act.Comment.State == "OPEN" && + act.Comment.Author.Name == username && + !act.CommentAnchor.Orphaned { + comments = append(comments, bitBucketComment{ + id: act.Comment.ID, + version: act.Comment.Version, + onCommit: act.CommentAnchor.DiffType == "COMMIT", + text: act.Comment.Text, + path: act.CommentAnchor.Path, + line: act.CommentAnchor.Line, + }) + } + } + + if acts.IsLastPage || acts.NextPageStart == start { + break + } + start = acts.NextPageStart + } + + return comments, nil +} + +func (bb bitBucketAPI) makeComments(summary Summary, changes *bitBucketPRChanges) []pendingComment { + comments := []pendingComment{} + for _, report := range summary.reports { + if _, ok := changes.pathModifiedLines[report.ReportedPath]; !ok { + continue + } + comments = append(comments, pendingComment{ + path: report.ReportedPath, + line: report.Problem.Lines[0], + text: report.Problem.Text, + }) + } + return comments +} + +func (bb bitBucketAPI) pruneComments(pr *bitBucketPR, currentComments []bitBucketComment, pendingComments []pendingComment) error { + for _, cur := range currentComments { + var keep bool + for _, pend := range pendingComments { + if cur.path == pend.path && cur.line == pend.line && cur.text == pend.text { + keep = true + break + } + if cur.onCommit { + keep = false + } + } + if !keep { + _, err := bb.request( + http.MethodDelete, + fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/pull-requests/%d/comments/%d?version=%d", + bb.project, bb.repo, + pr.ID, + cur.id, cur.version, + ), + nil, + ) + if err != nil { + return err + } + } + } + + return nil +} + +func (bb bitBucketAPI) addComments(pr *bitBucketPR, currentComments []bitBucketComment, pendingComments []pendingComment, changes *bitBucketPRChanges) error { + var added int + for _, pend := range pendingComments { + add := true + for _, cur := range currentComments { + if cur.path == pend.path && cur.line == pend.line && cur.text == pend.text { + add = false + } + if cur.onCommit { + add = true + } + } + if add { + payload, _ := json.Marshal(pend.toBitBucketComment(changes)) + _, err := bb.request( + http.MethodPost, + fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/pull-requests/%d/comments", + bb.project, bb.repo, + pr.ID, + ), + bytes.NewReader(payload), + ) + if err != nil { + return err + } + added++ + } + } + slog.Info("Added pull request comments to BitBucket", slog.Int("count", added)) + return nil +} + +func reportToAnnotation(report Report) BitBucketAnnotation { + var msgPrefix, severity, atype string + reportLine, srcLine := moveReportedLine(report) + if reportLine != srcLine { + msgPrefix = fmt.Sprintf("Problem reported on unmodified line %d, annotation moved here: ", srcLine) + } + if report.ReportedPath != report.SourcePath { + if msgPrefix == "" { + msgPrefix = fmt.Sprintf("Problem detected on symlinked file %s: ", report.SourcePath) + } else { + msgPrefix = fmt.Sprintf("Problem detected on symlinked file %s. %s", report.SourcePath, msgPrefix) + } + } + + switch report.Problem.Severity { + case checks.Fatal: + severity = "HIGH" + atype = "BUG" + case checks.Bug: + severity = "MEDIUM" + atype = "BUG" + case checks.Warning, checks.Information: + severity = "LOW" + atype = "CODE_SMELL" + } + + return BitBucketAnnotation{ + Path: report.ReportedPath, + Line: reportLine, + Message: fmt.Sprintf("%s%s: %s", msgPrefix, report.Problem.Reporter, report.Problem.Text), + Severity: severity, + Type: atype, + Link: fmt.Sprintf("https://cloudflare.github.io/pint/checks/%s.html", report.Problem.Reporter), + } +} diff --git a/internal/reporter/bitbucket_api_test.go b/internal/reporter/bitbucket_api_test.go new file mode 100644 index 00000000..50ce0bdf --- /dev/null +++ b/internal/reporter/bitbucket_api_test.go @@ -0,0 +1,270 @@ +package reporter + +import ( + "log/slog" + "testing" + + "github.com/neilotoole/slogt" + "github.com/stretchr/testify/require" + + "github.com/cloudflare/pint/internal/checks" +) + +func TestPendingCommentToBitBucketComment(t *testing.T) { + type testCaseT struct { + description string + input pendingComment + output BitBucketPendingComment + changes *bitBucketPRChanges + } + + testCases := []testCaseT{ + { + description: "nil changes", + input: pendingComment{ + text: "this is text", + path: "foo.yaml", + line: 5, + }, + output: BitBucketPendingComment{ + Text: "this is text", + Severity: "NORMAL", + Anchor: BitBucketPendingCommentAnchor{ + Path: "foo.yaml", + Line: 5, + DiffType: "EFFECTIVE", + LineType: "CONTEXT", + FileType: "FROM", + }, + }, + changes: nil, + }, + { + description: "path not found in changes", + input: pendingComment{ + text: "this is text", + path: "foo.yaml", + line: 5, + }, + output: BitBucketPendingComment{ + Text: "this is text", + Severity: "NORMAL", + Anchor: BitBucketPendingCommentAnchor{ + Path: "foo.yaml", + Line: 5, + DiffType: "EFFECTIVE", + LineType: "CONTEXT", + FileType: "FROM", + }, + }, + changes: &bitBucketPRChanges{ + pathModifiedLines: map[string][]int{"bar.yaml": {1, 2, 3}}, + pathLineMapping: map[string]map[int]int{"bar.yaml": {1: 1, 2: 5, 3: 3}}, + }, + }, + { + description: "path found in changes", + input: pendingComment{ + text: "this is text", + path: "foo.yaml", + line: 5, + }, + output: BitBucketPendingComment{ + Text: "this is text", + Severity: "NORMAL", + Anchor: BitBucketPendingCommentAnchor{ + Path: "foo.yaml", + Line: 4, + DiffType: "EFFECTIVE", + LineType: "ADDED", + FileType: "TO", + }, + }, + changes: &bitBucketPRChanges{ + pathModifiedLines: map[string][]int{"foo.yaml": {1, 3, 5}}, + pathLineMapping: map[string]map[int]int{"foo.yaml": {1: 1, 3: 3, 5: 4}}, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + slog.SetDefault(slogt.New(t)) + out := tc.input.toBitBucketComment(tc.changes) + require.Equal(t, tc.output, out, "pendingComment.toBitBucketComment() returned wrong BitBucketPendingComment") + }) + } +} + +func TestReportToAnnotation(t *testing.T) { + type testCaseT struct { + description string + input Report + output BitBucketAnnotation + } + + testCases := []testCaseT{ + { + description: "fatal report on modified line", + input: Report{ + ReportedPath: "foo.yaml", + SourcePath: "foo.yaml", + ModifiedLines: []int{4, 5, 6}, + Problem: checks.Problem{ + Lines: []int{5}, + Reporter: "mock", + Text: "report text", + Severity: checks.Fatal, + }, + }, + output: BitBucketAnnotation{ + Path: "foo.yaml", + Line: 5, + Message: "mock: report text", + Severity: "HIGH", + Type: "BUG", + Link: "https://cloudflare.github.io/pint/checks/mock.html", + }, + }, + { + description: "bug report on modified line", + input: Report{ + ReportedPath: "foo.yaml", + SourcePath: "foo.yaml", + ModifiedLines: []int{4, 5, 6}, + Problem: checks.Problem{ + Lines: []int{5}, + Reporter: "mock", + Text: "report text", + Severity: checks.Bug, + }, + }, + output: BitBucketAnnotation{ + Path: "foo.yaml", + Line: 5, + Message: "mock: report text", + Severity: "MEDIUM", + Type: "BUG", + Link: "https://cloudflare.github.io/pint/checks/mock.html", + }, + }, + { + description: "warning report on modified line", + input: Report{ + ReportedPath: "foo.yaml", + SourcePath: "foo.yaml", + ModifiedLines: []int{4, 5, 6}, + Problem: checks.Problem{ + Lines: []int{5}, + Reporter: "mock", + Text: "report text", + Severity: checks.Warning, + }, + }, + output: BitBucketAnnotation{ + Path: "foo.yaml", + Line: 5, + Message: "mock: report text", + Severity: "LOW", + Type: "CODE_SMELL", + Link: "https://cloudflare.github.io/pint/checks/mock.html", + }, + }, + { + description: "information report on modified line", + input: Report{ + ReportedPath: "foo.yaml", + SourcePath: "foo.yaml", + ModifiedLines: []int{4, 5, 6}, + Problem: checks.Problem{ + Lines: []int{5}, + Reporter: "mock", + Text: "report text", + Severity: checks.Information, + }, + }, + output: BitBucketAnnotation{ + Path: "foo.yaml", + Line: 5, + Message: "mock: report text", + Severity: "LOW", + Type: "CODE_SMELL", + Link: "https://cloudflare.github.io/pint/checks/mock.html", + }, + }, + { + description: "fatal report on symlinked file", + input: Report{ + ReportedPath: "foo.yaml", + SourcePath: "bar.yaml", + ModifiedLines: []int{4, 5, 6}, + Problem: checks.Problem{ + Lines: []int{5}, + Reporter: "mock", + Text: "report text", + Severity: checks.Fatal, + }, + }, + output: BitBucketAnnotation{ + Path: "foo.yaml", + Line: 5, + Message: "Problem detected on symlinked file bar.yaml: mock: report text", + Severity: "HIGH", + Type: "BUG", + Link: "https://cloudflare.github.io/pint/checks/mock.html", + }, + }, + { + description: "fatal report on symlinked file on unmodified line", + input: Report{ + ReportedPath: "foo.yaml", + SourcePath: "bar.yaml", + ModifiedLines: []int{4, 5, 6}, + Problem: checks.Problem{ + Lines: []int{7}, + Reporter: "mock", + Text: "report text", + Severity: checks.Fatal, + }, + }, + output: BitBucketAnnotation{ + Path: "foo.yaml", + Line: 4, + Message: "Problem detected on symlinked file bar.yaml. Problem reported on unmodified line 7, annotation moved here: mock: report text", + Severity: "HIGH", + Type: "BUG", + Link: "https://cloudflare.github.io/pint/checks/mock.html", + }, + }, + { + description: "information report on unmodified line", + input: Report{ + ReportedPath: "foo.yaml", + SourcePath: "foo.yaml", + ModifiedLines: []int{4, 5, 6}, + Problem: checks.Problem{ + Lines: []int{1}, + Reporter: "mock", + Text: "report text", + Severity: checks.Information, + }, + }, + output: BitBucketAnnotation{ + Path: "foo.yaml", + Line: 4, + Message: "Problem reported on unmodified line 1, annotation moved here: mock: report text", + Severity: "LOW", + Type: "CODE_SMELL", + Link: "https://cloudflare.github.io/pint/checks/mock.html", + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + slog.SetDefault(slogt.New(t)) + out := reportToAnnotation(tc.input) + require.Equal(t, tc.output, out, "reportToAnnotation() returned wrong BitBucketAnnotation") + }) + } +} diff --git a/internal/reporter/bitbucket_test.go b/internal/reporter/bitbucket_test.go index d2dd11d7..536222a0 100644 --- a/internal/reporter/bitbucket_test.go +++ b/internal/reporter/bitbucket_test.go @@ -8,31 +8,35 @@ import ( "net" "net/http" "net/http/httptest" + "strings" "testing" "time" + "github.com/neilotoole/slogt" "github.com/stretchr/testify/require" "github.com/cloudflare/pint/internal/checks" "github.com/cloudflare/pint/internal/git" - "github.com/cloudflare/pint/internal/log" "github.com/cloudflare/pint/internal/parser" "github.com/cloudflare/pint/internal/reporter" ) func TestBitBucketReporter(t *testing.T) { - log.Level.Set(slog.LevelError) - type errorCheck func(err error) error type testCaseT struct { - description string - gitCmd git.CommandRunner - reports []reporter.Report - httpHandler http.Handler - report reporter.BitBucketReport - annotations reporter.BitBucketAnnotations - errorHandler errorCheck + description string + gitCmd git.CommandRunner + reports []reporter.Report + httpHandler http.Handler + report reporter.BitBucketReport + annotations reporter.BitBucketAnnotations + pullRequests reporter.BitBucketPullRequests + pullRequestChanges reporter.BitBucketPullRequestChanges + pullRequestActivities reporter.BitBucketPullRequestActivities + pullRequestFileDiffs map[string]reporter.BitBucketFileDiffs + pullRequestComments []reporter.BitBucketPendingComment + errorHandler errorCheck } p := parser.NewParser() @@ -43,11 +47,36 @@ func TestBitBucketReporter(t *testing.T) { expr: sum(errors) by (job) `)) + fakeGit := func(args ...string) ([]byte, error) { + if args[0] == "rev-parse" && args[1] == "--verify" && args[2] == "HEAD" { + return []byte("fake-commit-id"), nil + } + if args[0] == "rev-parse" && args[1] == "--abbrev-ref" && args[2] == "HEAD" { + return []byte("fake-branch"), nil + } + return nil, nil + } + + emptyReport := reporter.BitBucketReport{ + Reporter: "Prometheus rule linter", + Title: "pint v0.0.0", + Details: reporter.BitBucketDescription, + Link: "https://cloudflare.github.io/pint/", + Result: "PASS", + Data: []reporter.BitBucketReportData{ + {Title: "Number of rules checked", Type: reporter.NumberType, Value: float64(0)}, + {Title: "Number of problems found", Type: reporter.NumberType, Value: float64(0)}, + {Title: "Number of offline checks", Type: reporter.NumberType, Value: float64(0)}, + {Title: "Number of online checks", Type: reporter.NumberType, Value: float64(0)}, + {Title: "Checks duration", Type: reporter.DurationType, Value: float64(0)}, + }, + } + testCases := []testCaseT{ { description: "returns an error on git head failure", gitCmd: func(args ...string) ([]byte, error) { - if args[0] == "rev-parse" { + if args[0] == "rev-parse" && args[1] == "--verify" && args[2] == "HEAD" { return nil, errors.New("git head error") } return nil, nil @@ -60,13 +89,27 @@ func TestBitBucketReporter(t *testing.T) { }, }, { - description: "returns an error on non-200 HTTP response", + description: "returns an error on git branch failure", gitCmd: func(args ...string) ([]byte, error) { - if args[0] == "rev-parse" { + if args[0] == "rev-parse" && args[1] == "--verify" && args[2] == "HEAD" { return []byte("fake-commit-id"), nil } + if args[0] == "rev-parse" && args[1] == "--abbrev-ref" && args[2] == "HEAD" { + return nil, errors.New("git branch error") + } return nil, nil }, + errorHandler: func(err error) error { + if err != nil && err.Error() == "failed to get current branch: git branch error" { + return nil + } + return fmt.Errorf("Expected git branch error, got %w", err) + }, + report: emptyReport, + }, + { + description: "returns an error on non-200 HTTP response", + gitCmd: fakeGit, reports: []reporter.Report{ { ReportedPath: "foo.txt", @@ -81,20 +124,16 @@ func TestBitBucketReporter(t *testing.T) { _, _ = w.Write([]byte("Bad Request")) }), errorHandler: func(err error) error { - if err != nil && err.Error() == "failed to create BitBucket report: PUT request failed" { + if err != nil && err.Error() == "failed to delete old BitBucket report: DELETE request failed" { return nil } - return fmt.Errorf("Expected 'PUT request failed', got %w", err) + return fmt.Errorf("Expected 'DELETE request failed', got %w", err) }, }, { description: "returns an error on HTTP response headers timeout", - gitCmd: func(args ...string) ([]byte, error) { - if args[0] == "rev-parse" { - return []byte("fake-commit-id"), nil - } - return nil, nil - }, + gitCmd: fakeGit, + report: emptyReport, reports: []reporter.Report{ { ReportedPath: "foo.txt", @@ -119,12 +158,7 @@ func TestBitBucketReporter(t *testing.T) { }, { description: "returns an error on HTTP response body timeout", - gitCmd: func(args ...string) ([]byte, error) { - if args[0] == "rev-parse" { - return []byte("fake-commit-id"), nil - } - return nil, nil - }, + gitCmd: fakeGit, reports: []reporter.Report{ { ReportedPath: "foo.txt", @@ -148,13 +182,57 @@ func TestBitBucketReporter(t *testing.T) { }, }, { - description: "sends a correct report", - gitCmd: func(args ...string) ([]byte, error) { - if args[0] == "rev-parse" { - return []byte("fake-commit-id"), nil + description: "sends a correct report that fails", + gitCmd: fakeGit, + report: emptyReport, + httpHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodDelete { + w.WriteHeader(200) + return } - return nil, nil + w.WriteHeader(500) + _, _ = w.Write([]byte("Internal error")) + }), + errorHandler: func(err error) error { + if err.Error() != "failed to create BitBucket report: PUT request failed" { + return fmt.Errorf("Unpexpected error: %w", err) + } + return nil + }, + }, + { + description: "sends a correct report but fails to delete annotations", + gitCmd: fakeGit, + report: emptyReport, + httpHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/rest/insights/1.0/projects/proj/repos/repo/commits/fake-commit-id/reports/pint" { + w.WriteHeader(200) + return + } + if r.URL.Path == "/rest/api/1.0/projects/proj/repos/repo/commits/fake-commit-id/pull-requests" { + data, err := json.Marshal(reporter.BitBucketPullRequests{ + IsLastPage: true, + Values: []reporter.BitBucketPullRequest{}, + }) + require.NoError(t, err) + w.WriteHeader(200) + _, err = w.Write(data) + require.NoError(t, err) + return + } + w.WriteHeader(500) + _, _ = w.Write([]byte("Internal error")) + }), + errorHandler: func(err error) error { + if err.Error() != "failed to delete existing BitBucket code insight annotations: DELETE request failed" { + return fmt.Errorf("Unpexpected error: %w", err) + } + return nil }, + }, + { + description: "sends a correct report but fails to create annotations", + gitCmd: fakeGit, reports: []reporter.Report{ { ReportedPath: "foo.txt", @@ -264,35 +342,218 @@ func TestBitBucketReporter(t *testing.T) { }, }, }, + httpHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/rest/insights/1.0/projects/proj/repos/repo/commits/fake-commit-id/reports/pint" { + w.WriteHeader(200) + return + } + if r.URL.Path == "/rest/api/1.0/projects/proj/repos/repo/commits/fake-commit-id/pull-requests" { + data, err := json.Marshal(reporter.BitBucketPullRequests{ + IsLastPage: true, + Values: []reporter.BitBucketPullRequest{}, + }) + require.NoError(t, err) + w.WriteHeader(200) + _, err = w.Write(data) + require.NoError(t, err) + return + } + if r.Method == http.MethodDelete { + w.WriteHeader(200) + return + } + w.WriteHeader(500) + _, _ = w.Write([]byte("Internal error")) + }), errorHandler: func(err error) error { - if err.Error() != "fatal error(s) reported" { + if err.Error() != "failed to create BitBucket code insight annotations: POST request failed" { return fmt.Errorf("Unpexpected error: %w", err) } return nil }, }, { - description: "FATAL errors are always reported, regardless of line number", - gitCmd: func(args ...string) ([]byte, error) { - if args[0] == "rev-parse" { - return []byte("fake-commit-id"), nil + description: "pull requests get fails", + gitCmd: fakeGit, + report: emptyReport, + httpHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + w.WriteHeader(200) + return } - return nil, nil + w.WriteHeader(500) + _, _ = w.Write([]byte("Internal error")) + }), + errorHandler: func(err error) error { + if err.Error() != "failed to get open pull requests from BitBucket: GET request failed" { + return fmt.Errorf("Unpexpected error: %w", err) + } + return nil }, + }, + { + description: "pull request changes get fails", + gitCmd: fakeGit, + report: emptyReport, + httpHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/rest/api/1.0/projects/proj/repos/repo/commits/fake-commit-id/pull-requests" { + data, err := json.Marshal(reporter.BitBucketPullRequests{ + IsLastPage: true, + Values: []reporter.BitBucketPullRequest{ + { + ID: 102, + Open: true, + FromRef: reporter.BitBucketRef{ + ID: "refs/heads/fake-branch", + Commit: "fake-commit-id", + }, + ToRef: reporter.BitBucketRef{ + ID: "refs/heads/main", + Commit: "main-commit-id", + }, + }, + }, + }) + require.NoError(t, err) + w.WriteHeader(200) + _, err = w.Write(data) + require.NoError(t, err) + } + if strings.HasSuffix(r.URL.Path, "/changes") { + w.WriteHeader(500) + _, _ = w.Write([]byte("Internal error")) + return + } + w.WriteHeader(200) + }), + errorHandler: func(err error) error { + if err.Error() != "failed to get pull request changes from BitBucket: GET request failed" { + return fmt.Errorf("Unpexpected error: %w", err) + } + return nil + }, + }, + { + description: "pull request comments get fails", + gitCmd: fakeGit, + report: emptyReport, + httpHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/rest/api/1.0/projects/proj/repos/repo/commits/fake-commit-id/pull-requests" { + data, err := json.Marshal(reporter.BitBucketPullRequests{ + IsLastPage: true, + Values: []reporter.BitBucketPullRequest{ + { + ID: 102, + Open: true, + FromRef: reporter.BitBucketRef{ + ID: "refs/heads/fake-branch", + Commit: "fake-commit-id", + }, + ToRef: reporter.BitBucketRef{ + ID: "refs/heads/main", + Commit: "main-commit-id", + }, + }, + }, + }) + require.NoError(t, err) + w.WriteHeader(200) + _, err = w.Write(data) + require.NoError(t, err) + } + if r.URL.Path == "/rest/api/1.0/projects/proj/repos/repo/pull-requests/102/changes" { + data, err := json.Marshal(reporter.BitBucketPullRequestChanges{ + IsLastPage: true, + Values: []reporter.BitBucketPullRequestChange{}, + }) + require.NoError(t, err) + w.WriteHeader(200) + _, err = w.Write(data) + require.NoError(t, err) + } + if r.URL.Path == "/rest/api/latest/projects/proj/repos/repo/pull-requests/102/activities" { + w.WriteHeader(500) + _, _ = w.Write([]byte("Internal error")) + return + } + w.WriteHeader(200) + }), + errorHandler: func(err error) error { + if err.Error() != "failed to get pull request comments from BitBucket: GET request failed" { + return fmt.Errorf("Unpexpected error: %w", err) + } + return nil + }, + }, + { + description: "sends a correct report", + gitCmd: fakeGit, reports: []reporter.Report{ { ReportedPath: "foo.txt", SourcePath: "foo.txt", - ModifiedLines: []int{3, 4}, + ModifiedLines: []int{2, 4}, Rule: mockRules[1], Problem: checks.Problem{ - Fragment: "syntax error", + Fragment: "up", Lines: []int{1}, - Reporter: "test/mock", - Text: "syntax error", + Reporter: "mock", + Text: "this should be ignored, line is not part of the diff", + Severity: checks.Bug, + }, + }, + { + ReportedPath: "bar.txt", + SourcePath: "bar.txt", + ModifiedLines: []int{}, + Rule: mockRules[1], + Problem: checks.Problem{ + Fragment: "up", + Lines: []int{1}, + Reporter: "mock", + Text: "this should be ignored, file is not part of the diff", + Severity: checks.Bug, + }, + }, + { + ReportedPath: "foo.txt", + SourcePath: "foo.txt", + ModifiedLines: []int{2, 4}, + Rule: mockRules[1], + Problem: checks.Problem{ + Fragment: "up", + Lines: []int{2}, + Reporter: "mock", + Text: "bad name", Severity: checks.Fatal, }, }, + { + ReportedPath: "foo.txt", + SourcePath: "foo.txt", + ModifiedLines: []int{2, 4}, + Rule: mockRules[0], + Problem: checks.Problem{ + Fragment: "up == 0", + Lines: []int{2}, + Reporter: "mock", + Text: "mock text", + Severity: checks.Bug, + }, + }, + { + ReportedPath: "foo.txt", + SourcePath: "foo.txt", + ModifiedLines: []int{2, 4}, + Rule: mockRules[1], + Problem: checks.Problem{ + Fragment: "errors", + Lines: []int{4}, + Reporter: "mock", + Text: "mock text 2", + Severity: checks.Warning, + }, + }, }, report: reporter.BitBucketReport{ Reporter: "Prometheus rule linter", @@ -302,7 +563,7 @@ func TestBitBucketReporter(t *testing.T) { Result: "FAIL", Data: []reporter.BitBucketReportData{ {Title: "Number of rules checked", Type: reporter.NumberType, Value: float64(0)}, - {Title: "Number of problems found", Type: reporter.NumberType, Value: float64(1)}, + {Title: "Number of problems found", Type: reporter.NumberType, Value: float64(3)}, {Title: "Number of offline checks", Type: reporter.NumberType, Value: float64(0)}, {Title: "Number of online checks", Type: reporter.NumberType, Value: float64(0)}, {Title: "Checks duration", Type: reporter.DurationType, Value: float64(0)}, @@ -312,11 +573,27 @@ func TestBitBucketReporter(t *testing.T) { Annotations: []reporter.BitBucketAnnotation{ { Path: "foo.txt", - Line: 3, - Message: "Problem reported on unmodified line 1, annotation moved here: test/mock: syntax error", + Line: 2, + Message: "mock: bad name", Severity: "HIGH", Type: "BUG", - Link: "https://cloudflare.github.io/pint/checks/test/mock.html", + Link: "https://cloudflare.github.io/pint/checks/mock.html", + }, + { + Path: "foo.txt", + Line: 2, + Message: "mock: mock text", + Severity: "MEDIUM", + Type: "BUG", + Link: "https://cloudflare.github.io/pint/checks/mock.html", + }, + { + Path: "foo.txt", + Line: 4, + Message: "mock: mock text 2", + Severity: "LOW", + Type: "CODE_SMELL", + Link: "https://cloudflare.github.io/pint/checks/mock.html", }, }, }, @@ -328,42 +605,70 @@ func TestBitBucketReporter(t *testing.T) { }, }, { - description: "sends a correct empty report", - gitCmd: func(args ...string) ([]byte, error) { - if args[0] == "rev-parse" { - return []byte("fake-commit-id"), nil - } - return nil, nil + description: "FATAL errors are always reported, regardless of line number", + gitCmd: fakeGit, + reports: []reporter.Report{ + { + ReportedPath: "foo.txt", + SourcePath: "foo.txt", + ModifiedLines: []int{3, 4}, + Rule: mockRules[1], + Problem: checks.Problem{ + Fragment: "syntax error", + Lines: []int{1}, + Reporter: "test/mock", + Text: "syntax error", + Severity: checks.Fatal, + }, + }, }, report: reporter.BitBucketReport{ Reporter: "Prometheus rule linter", Title: "pint v0.0.0", Details: reporter.BitBucketDescription, Link: "https://cloudflare.github.io/pint/", - Result: "PASS", + Result: "FAIL", Data: []reporter.BitBucketReportData{ {Title: "Number of rules checked", Type: reporter.NumberType, Value: float64(0)}, - {Title: "Number of problems found", Type: reporter.NumberType, Value: float64(0)}, + {Title: "Number of problems found", Type: reporter.NumberType, Value: float64(1)}, {Title: "Number of offline checks", Type: reporter.NumberType, Value: float64(0)}, {Title: "Number of online checks", Type: reporter.NumberType, Value: float64(0)}, {Title: "Checks duration", Type: reporter.DurationType, Value: float64(0)}, }, }, + annotations: reporter.BitBucketAnnotations{ + Annotations: []reporter.BitBucketAnnotation{ + { + Path: "foo.txt", + Line: 3, + Message: "Problem reported on unmodified line 1, annotation moved here: test/mock: syntax error", + Severity: "HIGH", + Type: "BUG", + Link: "https://cloudflare.github.io/pint/checks/test/mock.html", + }, + }, + }, errorHandler: func(err error) error { - if err != nil { + if err.Error() != "fatal error(s) reported" { return fmt.Errorf("Unpexpected error: %w", err) } return nil }, }, { - description: "ignores failures from unmodified lines", - gitCmd: func(args ...string) ([]byte, error) { - if args[0] == "rev-parse" { - return []byte("fake-commit-id"), nil + description: "sends a correct empty report", + gitCmd: fakeGit, + report: emptyReport, + errorHandler: func(err error) error { + if err != nil { + return fmt.Errorf("Unpexpected error: %w", err) } - return nil, nil + return nil }, + }, + { + description: "ignores failures from unmodified lines", + gitCmd: fakeGit, reports: []reporter.Report{ { ReportedPath: "foo.txt", @@ -426,34 +731,357 @@ func TestBitBucketReporter(t *testing.T) { }, }, }, + report: emptyReport, + errorHandler: func(err error) error { + if err != nil { + return fmt.Errorf("Unpexpected error: %w", err) + } + return nil + }, + }, + { + description: "sends a correct report with pull request open", + gitCmd: fakeGit, + report: emptyReport, + pullRequests: reporter.BitBucketPullRequests{ + IsLastPage: true, + Values: []reporter.BitBucketPullRequest{ + { + ID: 101, + Open: false, + FromRef: reporter.BitBucketRef{ + ID: "refs/heads/feature", + Commit: "pr-commit-id", + }, + ToRef: reporter.BitBucketRef{ + ID: "refs/heads/main", + Commit: "main-commit-id", + }, + }, + { + ID: 102, + Open: true, + FromRef: reporter.BitBucketRef{ + ID: "refs/heads/fake-branch", + Commit: "fake-commit-id", + }, + ToRef: reporter.BitBucketRef{ + ID: "refs/heads/main", + Commit: "main-commit-id", + }, + }, + }, + }, + errorHandler: func(err error) error { + if err != nil { + return fmt.Errorf("Unpexpected error: %w", err) + } + return nil + }, + }, + { + description: "sends a correct report using comments, deleting stale ones", + gitCmd: fakeGit, + reports: []reporter.Report{ + { + ReportedPath: "foo.txt", + SourcePath: "foo.txt", + ModifiedLines: []int{2, 4}, + Rule: mockRules[1], + Problem: checks.Problem{ + Fragment: "up", + Lines: []int{1}, + Reporter: "mock", + Text: "this should be ignored, line is not part of the diff", + Severity: checks.Bug, + }, + }, + { + ReportedPath: "bar.txt", + SourcePath: "bar.txt", + ModifiedLines: []int{}, + Rule: mockRules[1], + Problem: checks.Problem{ + Fragment: "up", + Lines: []int{1}, + Reporter: "mock", + Text: "this should be ignored, file is not part of the diff", + Severity: checks.Bug, + }, + }, + { + ReportedPath: "foo.txt", + SourcePath: "foo.txt", + ModifiedLines: []int{2, 4}, + Rule: mockRules[1], + Problem: checks.Problem{ + Fragment: "up", + Lines: []int{2}, + Reporter: "mock", + Text: "bad name", + Severity: checks.Fatal, + }, + }, + { + ReportedPath: "foo.txt", + SourcePath: "foo.txt", + ModifiedLines: []int{2, 4}, + Rule: mockRules[0], + Problem: checks.Problem{ + Fragment: "up == 0", + Lines: []int{2}, + Reporter: "mock", + Text: "mock text", + Severity: checks.Bug, + }, + }, + { + ReportedPath: "foo.txt", + SourcePath: "foo.txt", + ModifiedLines: []int{2, 4}, + Rule: mockRules[1], + Problem: checks.Problem{ + Fragment: "errors", + Lines: []int{4}, + Reporter: "mock", + Text: "mock text 2", + Severity: checks.Warning, + }, + }, + }, report: reporter.BitBucketReport{ Reporter: "Prometheus rule linter", Title: "pint v0.0.0", Details: reporter.BitBucketDescription, Link: "https://cloudflare.github.io/pint/", - Result: "PASS", + Result: "FAIL", Data: []reporter.BitBucketReportData{ {Title: "Number of rules checked", Type: reporter.NumberType, Value: float64(0)}, - {Title: "Number of problems found", Type: reporter.NumberType, Value: float64(0)}, + {Title: "Number of problems found", Type: reporter.NumberType, Value: float64(3)}, {Title: "Number of offline checks", Type: reporter.NumberType, Value: float64(0)}, {Title: "Number of online checks", Type: reporter.NumberType, Value: float64(0)}, {Title: "Checks duration", Type: reporter.DurationType, Value: float64(0)}, }, }, - annotations: reporter.BitBucketAnnotations{ - Annotations: []reporter.BitBucketAnnotation{ - { + pullRequestComments: []reporter.BitBucketPendingComment{ + { + Text: "this should be ignored, line is not part of the diff", + Severity: "NORMAL", + Anchor: reporter.BitBucketPendingCommentAnchor{ + Path: "foo.txt", + Line: 1, + LineType: "CONTEXT", + FileType: "FROM", + DiffType: "EFFECTIVE", + }, + }, + { + Text: "bad name", + Severity: "NORMAL", + Anchor: reporter.BitBucketPendingCommentAnchor{ + Path: "foo.txt", + Line: 2, + LineType: "ADDED", + FileType: "TO", + DiffType: "EFFECTIVE", + }, + }, + { + Text: "mock text", + Severity: "NORMAL", + Anchor: reporter.BitBucketPendingCommentAnchor{ + Path: "foo.txt", + Line: 2, + LineType: "ADDED", + FileType: "TO", + DiffType: "EFFECTIVE", + }, + }, + { + Text: "mock text 2", + Severity: "NORMAL", + Anchor: reporter.BitBucketPendingCommentAnchor{ Path: "foo.txt", Line: 4, - Message: "mock: mock text 2", - Severity: "LOW", - Type: "CODE_SMELL", - Link: "https://cloudflare.github.io/pint/checks/mock.html", + LineType: "CONTEXT", + FileType: "FROM", + DiffType: "EFFECTIVE", + }, + }, + }, + pullRequests: reporter.BitBucketPullRequests{ + IsLastPage: true, + Values: []reporter.BitBucketPullRequest{ + { + ID: 102, + Open: true, + FromRef: reporter.BitBucketRef{ + ID: "refs/heads/fake-branch", + Commit: "fake-commit-id", + }, + ToRef: reporter.BitBucketRef{ + ID: "refs/heads/main", + Commit: "main-commit-id", + }, + }, + }, + }, + pullRequestChanges: reporter.BitBucketPullRequestChanges{ + IsLastPage: true, + Values: []reporter.BitBucketPullRequestChange{ + { + Path: reporter.BitBucketPath{ + ToString: "index.txt", + }, + }, + { + Path: reporter.BitBucketPath{ + ToString: "foo.txt", + }, + }, + }, + }, + pullRequestFileDiffs: map[string]reporter.BitBucketFileDiffs{ + "index.txt": { + Diffs: []reporter.BitBucketFileDiff{ + { + Hunks: []reporter.BitBucketDiffHunk{ + { + Segments: []reporter.BitBucketDiffSegment{ + { + Type: "ADDED", + Lines: []reporter.BitBucketDiffLine{ + {Source: 1, Destination: 1}, + {Source: 5, Destination: 5}, + }, + }, + { + Type: "CONTEXT", + Lines: []reporter.BitBucketDiffLine{ + {Source: 10, Destination: 6}, + }, + }, + }, + }, + }, + }, + }, + }, + "foo.txt": { + Diffs: []reporter.BitBucketFileDiff{ + { + Hunks: []reporter.BitBucketDiffHunk{ + { + Segments: []reporter.BitBucketDiffSegment{ + { + Type: "ADDED", + Lines: []reporter.BitBucketDiffLine{ + {Source: 2, Destination: 2}, + }, + }, + }, + }, + }, + }, + { + Hunks: []reporter.BitBucketDiffHunk{ + { + Segments: []reporter.BitBucketDiffSegment{ + { + Type: "MODIFIED", + Lines: []reporter.BitBucketDiffLine{ + {Source: 3, Destination: 4}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + pullRequestActivities: reporter.BitBucketPullRequestActivities{ + IsLastPage: true, + Values: []reporter.BitBucketPullRequestActivity{ + { + Action: "APPROVED", + }, + { + Action: "COMMENTED", + CommentAction: "ADDED", + CommentAnchor: reporter.BitBucketCommentAnchor{ + Orphaned: true, + DiffType: "EFFECTIVE", + Path: "foo.txt", + Line: 3, + }, + Comment: reporter.BitBucketPullRequestComment{ + ID: 1001, + Version: 0, + State: "OPEN", + Author: reporter.BitBucketCommentAuthor{ + Name: "pint_user", + }, + }, + }, + { + Action: "COMMENTED", + CommentAction: "ADDED", + CommentAnchor: reporter.BitBucketCommentAnchor{ + Orphaned: true, + DiffType: "COMMIT", + Path: "foo.txt", + Line: 10, + }, + Comment: reporter.BitBucketPullRequestComment{ + ID: 1002, + Version: 1, + State: "OPEN", + Author: reporter.BitBucketCommentAuthor{ + Name: "pint_user", + }, + }, + }, + { + Action: "COMMENTED", + CommentAction: "ADDED", + CommentAnchor: reporter.BitBucketCommentAnchor{ + Orphaned: false, + DiffType: "EFFECTIVE", + Path: "foo.txt", + Line: 3, + }, + Comment: reporter.BitBucketPullRequestComment{ + ID: 2001, + Version: 0, + State: "OPEN", + Author: reporter.BitBucketCommentAuthor{ + Name: "pint_user", + }, + }, + }, + { + Action: "COMMENTED", + CommentAction: "ADDED", + CommentAnchor: reporter.BitBucketCommentAnchor{ + Orphaned: false, + DiffType: "COMMIT", + Path: "foo.txt", + Line: 4, + }, + Comment: reporter.BitBucketPullRequestComment{ + ID: 2002, + Version: 1, + State: "OPEN", + Author: reporter.BitBucketCommentAuthor{ + Name: "pint_user", + }, + }, }, }, }, errorHandler: func(err error) error { - if err != nil { + if err.Error() != "fatal error(s) reported" { return fmt.Errorf("Unpexpected error: %w", err) } return nil @@ -463,6 +1091,10 @@ func TestBitBucketReporter(t *testing.T) { for _, tc := range testCases { t.Run(tc.description, func(t *testing.T) { + slog.SetDefault(slogt.New(t)) + + var commentIndex int + var srv *httptest.Server if tc.httpHandler == nil { srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -473,6 +1105,20 @@ func TestBitBucketReporter(t *testing.T) { return } + if strings.HasPrefix(r.URL.Path, "/rest/api/latest/projects/proj/repos/repo/commits/fake-commit-id/diff/") { + filename := strings.TrimPrefix(r.URL.Path, "/rest/api/latest/projects/proj/repos/repo/commits/fake-commit-id/diff/") + require.NotNil(t, tc.pullRequestFileDiffs) + v, ok := tc.pullRequestFileDiffs[filename] + require.True(t, ok, "file is missing from pullRequestFileDiffs: %s", filename) + + data, err := json.Marshal(v) + require.NoError(t, err) + w.WriteHeader(200) + _, err = w.Write(data) + require.NoError(t, err) + return + } + switch r.URL.Path { case "/rest/insights/1.0/projects/proj/repos/repo/commits/fake-commit-id/reports/pint": var resp reporter.BitBucketReport @@ -486,6 +1132,35 @@ func TestBitBucketReporter(t *testing.T) { t.Errorf("JSON decode error: %s", err) } require.Equal(t, tc.annotations, resp, "Got wrong bitbucket annotations") + case "/rest/api/1.0/projects/proj/repos/repo/commits/fake-commit-id/pull-requests": + data, err := json.Marshal(tc.pullRequests) + require.NoError(t, err) + w.WriteHeader(200) + _, err = w.Write(data) + require.NoError(t, err) + case "/rest/api/1.0/projects/proj/repos/repo/pull-requests/102/changes": + data, err := json.Marshal(tc.pullRequestChanges) + require.NoError(t, err) + w.WriteHeader(200) + _, err = w.Write(data) + require.NoError(t, err) + case "/rest/api/latest/projects/proj/repos/repo/pull-requests/102/activities": + data, err := json.Marshal(tc.pullRequestActivities) + require.NoError(t, err) + w.WriteHeader(200) + _, err = w.Write(data) + require.NoError(t, err) + case "/rest/api/1.0/projects/proj/repos/repo/pull-requests/102/comments": + var comment reporter.BitBucketPendingComment + if err := json.NewDecoder(r.Body).Decode(&comment); err != nil { + t.Errorf("JSON decode error: %s", err) + } + require.Equal(t, tc.pullRequestComments[commentIndex], comment) + commentIndex++ + case "/plugins/servlet/applinks/whoami": + w.WriteHeader(200) + _, err := w.Write([]byte("pint_user")) + require.NoError(t, err) default: w.WriteHeader(500) _, _ = w.Write([]byte(fmt.Sprintf("Unhandled path: %s", r.URL.Path))) diff --git a/internal/reporter/github_test.go b/internal/reporter/github_test.go index b74b6fff..a5dc303c 100644 --- a/internal/reporter/github_test.go +++ b/internal/reporter/github_test.go @@ -8,18 +8,16 @@ import ( "testing" "time" + "github.com/neilotoole/slogt" "github.com/stretchr/testify/require" "github.com/cloudflare/pint/internal/checks" "github.com/cloudflare/pint/internal/git" - "github.com/cloudflare/pint/internal/log" "github.com/cloudflare/pint/internal/parser" "github.com/cloudflare/pint/internal/reporter" ) func TestGithubReporter(t *testing.T) { - log.Level.Set(slog.LevelError) - type testCaseT struct { description string reports []reporter.Report @@ -121,6 +119,8 @@ filename %s }, } { t.Run(tc.description, func(t *testing.T) { + slog.SetDefault(slogt.New(t)) + var handler http.Handler if tc.httpHandler != nil { handler = tc.httpHandler