From a085541885915f535540e5f69a573099553b351a Mon Sep 17 00:00:00 2001 From: Dan Lorenc Date: Tue, 31 Aug 2021 21:12:00 -0500 Subject: [PATCH] Bump the go-scm, docker/cli and docker/docker libraries. Both of these were quite out of date and have enough transitive dependencies that it's worth keeping closer to HEAD. It might be possible to detangle and update separately, but I couldn't get it to work on my first try. There was one manual change to error strings in pkg/pullrequest/api_test.go. I also had to re-run codegen and update the golden test data for new fields.. Signed-off-by: Dan Lorenc --- go.mod | 7 +- go.sum | 28 +- pkg/pullrequest/api_test.go | 4 +- test/pullrequest/testdata/golden/base.json | 2 +- .../testdata/golden/comments/494418247.json | 2 +- test/pullrequest/testdata/golden/head.json | 2 +- test/pullrequest/testdata/golden/pr.json | 2 +- .../testdata/golden/status/tekton-e2e.json | 2 +- .../docker/cli/cli/config/config.go | 40 +- .../cli/config/credentials/default_store.go | 2 +- .../jenkins-x/go-scm/pkg/hmac/hmac.go | 4 +- vendor/github.com/jenkins-x/go-scm/scm/app.go | 1 + .../github.com/jenkins-x/go-scm/scm/client.go | 25 +- .../github.com/jenkins-x/go-scm/scm/commit.go | 54 + .../github.com/jenkins-x/go-scm/scm/const.go | 13 + .../jenkins-x/go-scm/scm/content.go | 2 + .../github.com/jenkins-x/go-scm/scm/deploy.go | 2 + .../go-scm/scm/driver/fake/content.go | 141 ++ .../jenkins-x/go-scm/scm/driver/fake/data.go | 13 + .../go-scm/scm/driver/fake/deploy.go | 110 + .../jenkins-x/go-scm/scm/driver/fake/fake.go | 10 +- .../jenkins-x/go-scm/scm/driver/fake/git.go | 8 + .../jenkins-x/go-scm/scm/driver/fake/issue.go | 12 + .../jenkins-x/go-scm/scm/driver/fake/org.go | 52 +- .../jenkins-x/go-scm/scm/driver/fake/pr.go | 90 +- .../go-scm/scm/driver/fake/release.go | 112 + .../jenkins-x/go-scm/scm/driver/fake/repo.go | 75 +- .../go-scm/scm/driver/fake/review.go | 16 + .../go-scm/scm/driver/fake/test_helpers.go | 35 + .../jenkins-x/go-scm/scm/driver/fake/user.go | 39 +- .../go-scm/scm/driver/github/content.go | 27 +- .../go-scm/scm/driver/github/deploy.go | 71 +- .../jenkins-x/go-scm/scm/driver/github/git.go | 31 + .../go-scm/scm/driver/github/github.go | 18 +- .../go-scm/scm/driver/github/issue.go | 40 + .../go-scm/scm/driver/github/milestone.go | 111 + .../jenkins-x/go-scm/scm/driver/github/org.go | 83 +- .../jenkins-x/go-scm/scm/driver/github/pr.go | 69 +- .../go-scm/scm/driver/github/release.go | 131 ++ .../go-scm/scm/driver/github/repo.go | 117 +- .../go-scm/scm/driver/github/review.go | 124 +- .../go-scm/scm/driver/github/user.go | 51 + .../go-scm/scm/driver/github/util.go | 35 + .../go-scm/scm/driver/github/webhook.go | 169 +- .../go-scm/scm/driver/gitlab/commit.go | 99 + .../go-scm/scm/driver/gitlab/content.go | 76 +- .../jenkins-x/go-scm/scm/driver/gitlab/git.go | 46 +- .../go-scm/scm/driver/gitlab/gitlab.go | 82 +- .../go-scm/scm/driver/gitlab/issue.go | 25 + .../go-scm/scm/driver/gitlab/milestone.go | 166 ++ .../jenkins-x/go-scm/scm/driver/gitlab/org.go | 55 +- .../jenkins-x/go-scm/scm/driver/gitlab/pr.go | 198 +- .../go-scm/scm/driver/gitlab/release.go | 111 + .../go-scm/scm/driver/gitlab/repo.go | 262 ++- .../go-scm/scm/driver/gitlab/review.go | 16 + .../go-scm/scm/driver/gitlab/user.go | 57 +- .../go-scm/scm/driver/gitlab/util.go | 51 + .../go-scm/scm/driver/gitlab/webhook.go | 251 ++- vendor/github.com/jenkins-x/go-scm/scm/git.go | 9 +- .../github.com/jenkins-x/go-scm/scm/issue.go | 11 + .../jenkins-x/go-scm/scm/milestone.go | 42 + vendor/github.com/jenkins-x/go-scm/scm/org.go | 42 +- vendor/github.com/jenkins-x/go-scm/scm/pr.go | 51 +- .../jenkins-x/go-scm/scm/release.go | 67 + .../github.com/jenkins-x/go-scm/scm/repo.go | 21 +- .../github.com/jenkins-x/go-scm/scm/review.go | 67 +- .../github.com/jenkins-x/go-scm/scm/user.go | 30 + .../github.com/jenkins-x/go-scm/scm/util.go | 14 +- .../jenkins-x/go-scm/scm/webhook.go | 504 ++++- .../mitchellh/copystructure/.travis.yml | 12 + .../mitchellh/copystructure/LICENSE | 21 + .../mitchellh/copystructure/README.md | 21 + .../mitchellh/copystructure/copier_time.go | 15 + .../mitchellh/copystructure/copystructure.go | 548 +++++ .../github.com/mitchellh/copystructure/go.mod | 3 + .../github.com/mitchellh/copystructure/go.sum | 2 + .../mitchellh/reflectwalk/.travis.yml | 1 + .../github.com/mitchellh/reflectwalk/LICENSE | 21 + .../mitchellh/reflectwalk/README.md | 6 + .../github.com/mitchellh/reflectwalk/go.mod | 1 + .../mitchellh/reflectwalk/location.go | 19 + .../mitchellh/reflectwalk/location_string.go | 16 + .../mitchellh/reflectwalk/reflectwalk.go | 401 ++++ vendor/github.com/pmezard/go-difflib/LICENSE | 27 + .../pmezard/go-difflib/difflib/difflib.go | 772 +++++++ vendor/github.com/stretchr/testify/LICENSE | 21 + .../testify/assert/assertion_compare.go | 394 ++++ .../testify/assert/assertion_format.go | 741 +++++++ .../testify/assert/assertion_format.go.tmpl | 5 + .../testify/assert/assertion_forward.go | 1470 +++++++++++++ .../testify/assert/assertion_forward.go.tmpl | 5 + .../testify/assert/assertion_order.go | 81 + .../stretchr/testify/assert/assertions.go | 1774 ++++++++++++++++ .../github.com/stretchr/testify/assert/doc.go | 45 + .../stretchr/testify/assert/errors.go | 10 + .../testify/assert/forward_assertions.go | 16 + .../testify/assert/http_assertions.go | 162 ++ .../stretchr/testify/require/doc.go | 28 + .../testify/require/forward_requirements.go | 16 + .../stretchr/testify/require/require.go | 1879 +++++++++++++++++ .../stretchr/testify/require/require.go.tmpl | 6 + .../testify/require/require_forward.go | 1471 +++++++++++++ .../testify/require/require_forward.go.tmpl | 5 + .../stretchr/testify/require/requirements.go | 29 + vendor/modules.txt | 15 +- 105 files changed, 13893 insertions(+), 501 deletions(-) create mode 100644 vendor/github.com/jenkins-x/go-scm/scm/commit.go create mode 100644 vendor/github.com/jenkins-x/go-scm/scm/driver/fake/content.go create mode 100644 vendor/github.com/jenkins-x/go-scm/scm/driver/fake/deploy.go create mode 100644 vendor/github.com/jenkins-x/go-scm/scm/driver/fake/release.go create mode 100644 vendor/github.com/jenkins-x/go-scm/scm/driver/fake/test_helpers.go create mode 100644 vendor/github.com/jenkins-x/go-scm/scm/driver/github/milestone.go create mode 100644 vendor/github.com/jenkins-x/go-scm/scm/driver/github/release.go create mode 100644 vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/commit.go create mode 100644 vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/milestone.go create mode 100644 vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/release.go create mode 100644 vendor/github.com/jenkins-x/go-scm/scm/milestone.go create mode 100644 vendor/github.com/jenkins-x/go-scm/scm/release.go create mode 100644 vendor/github.com/mitchellh/copystructure/.travis.yml create mode 100644 vendor/github.com/mitchellh/copystructure/LICENSE create mode 100644 vendor/github.com/mitchellh/copystructure/README.md create mode 100644 vendor/github.com/mitchellh/copystructure/copier_time.go create mode 100644 vendor/github.com/mitchellh/copystructure/copystructure.go create mode 100644 vendor/github.com/mitchellh/copystructure/go.mod create mode 100644 vendor/github.com/mitchellh/copystructure/go.sum create mode 100644 vendor/github.com/mitchellh/reflectwalk/.travis.yml create mode 100644 vendor/github.com/mitchellh/reflectwalk/LICENSE create mode 100644 vendor/github.com/mitchellh/reflectwalk/README.md create mode 100644 vendor/github.com/mitchellh/reflectwalk/go.mod create mode 100644 vendor/github.com/mitchellh/reflectwalk/location.go create mode 100644 vendor/github.com/mitchellh/reflectwalk/location_string.go create mode 100644 vendor/github.com/mitchellh/reflectwalk/reflectwalk.go create mode 100644 vendor/github.com/pmezard/go-difflib/LICENSE create mode 100644 vendor/github.com/pmezard/go-difflib/difflib/difflib.go create mode 100644 vendor/github.com/stretchr/testify/LICENSE create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_compare.go create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_format.go create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_forward.go create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_order.go create mode 100644 vendor/github.com/stretchr/testify/assert/assertions.go create mode 100644 vendor/github.com/stretchr/testify/assert/doc.go create mode 100644 vendor/github.com/stretchr/testify/assert/errors.go create mode 100644 vendor/github.com/stretchr/testify/assert/forward_assertions.go create mode 100644 vendor/github.com/stretchr/testify/assert/http_assertions.go create mode 100644 vendor/github.com/stretchr/testify/require/doc.go create mode 100644 vendor/github.com/stretchr/testify/require/forward_requirements.go create mode 100644 vendor/github.com/stretchr/testify/require/require.go create mode 100644 vendor/github.com/stretchr/testify/require/require.go.tmpl create mode 100644 vendor/github.com/stretchr/testify/require/require_forward.go create mode 100644 vendor/github.com/stretchr/testify/require/require_forward.go.tmpl create mode 100644 vendor/github.com/stretchr/testify/require/requirements.go diff --git a/go.mod b/go.mod index 90110aa0335..036d18d4264 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.13 require ( github.com/aws/aws-sdk-go v1.31.12 // indirect github.com/cloudevents/sdk-go/v2 v2.1.0 - github.com/docker/cli v20.10.2+incompatible // indirect - github.com/docker/docker v20.10.2+incompatible // indirect + github.com/docker/cli v20.10.8+incompatible // indirect + github.com/docker/docker v20.10.8+incompatible // indirect github.com/emicklei/go-restful v2.15.0+incompatible // indirect github.com/ghodss/yaml v1.0.0 github.com/go-openapi/spec v0.20.2 @@ -17,9 +17,8 @@ require ( github.com/googleapis/gnostic v0.5.3 // indirect github.com/hashicorp/go-multierror v1.1.0 github.com/hashicorp/golang-lru v0.5.4 - github.com/jenkins-x/go-scm v1.5.117 + github.com/jenkins-x/go-scm v1.10.10 github.com/mitchellh/go-homedir v1.1.0 - github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 // indirect github.com/pkg/errors v0.9.1 github.com/tektoncd/plumbing v0.0.0-20210514044347-f8a9689d5bd5 go.opencensus.io v0.23.0 diff --git a/go.sum b/go.sum index bdbbb3aefe5..3e1b88291a9 100644 --- a/go.sum +++ b/go.sum @@ -34,6 +34,7 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo 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= +code.gitea.io/sdk/gitea v0.14.0/go.mod h1:89WiyOX1KEcvjP66sRHdu0RafojGo60bT9UqW17VbWs= contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d h1:LblfooH1lKOpp1hIhukktmSAxFkqMPFk9KR6iZ0MJNI= contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d/go.mod h1:IshRmMJBhDfFj5Y67nVhMYTTIze91RUeT73ipWKs/GY= contrib.go.opencensus.io/exporter/prometheus v0.4.0 h1:0QfIkj9z/iVZgK31D9H9ohjjIDApI2GOPScCKwxedbs= @@ -121,6 +122,7 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= +github.com/bluekeyes/go-gitdiff v0.4.0/go.mod h1:QpfYYO1E0fTVHVZAZKiRjtSGY9823iCdvGXBcEzHGbM= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -169,13 +171,13 @@ github.com/dgryski/go-lttb v0.0.0-20180810165845-318fcdf10a77/go.mod h1:Va5MyIzk github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/cli v20.10.2+incompatible h1:CR/6BZX5w3TLgAHZTyRpVh3yi+Q8Sj5j1fCsb0J2rCk= -github.com/docker/cli v20.10.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v20.10.8+incompatible h1:/zO/6y9IOpcehE49yMRTV9ea0nBpb8OeqSskXLNfH1E= +github.com/docker/cli v20.10.8+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v20.10.2+incompatible h1:vFgEHPqWBTp4pTjdLwjAA4bSo3gvIGOYwuJTlEjVBCw= -github.com/docker/docker v20.10.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.8+incompatible h1:RVqD337BgQicVCzYrrlhLDWhq6OAD2PJDUg2LsEUvKM= +github.com/docker/docker v20.10.8+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= @@ -378,8 +380,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/h2non/gock v1.0.9 h1:17gCehSo8ZOgEsFKpQgqHiR7VLyjxdAG3lkhVvO9QZU= -github.com/h2non/gock v1.0.9/go.mod h1:CZMcB0Lg5IWnr9bF79pPMg9WeV6WumxQiUJ1UvdO1iE= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= @@ -395,6 +397,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= 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= @@ -416,8 +420,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/influxdata/tdigest v0.0.0-20180711151920-a7d76c6f093a/go.mod h1:9GkyshztGufsdPQWjH+ifgnIr3xNUL5syI70g2dzU1o= github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jenkins-x/go-scm v1.5.117 h1:D7d1sDWUU+xocCNLQVoYKpMjVKnQvsPva+hPzruchbM= -github.com/jenkins-x/go-scm v1.5.117/go.mod h1:PCT338UhP/pQ0IeEeMEf/hoLTYKcH7qjGEKd7jPkeYg= +github.com/jenkins-x/go-scm v1.10.10 h1:Fuxje/9mHONI7+AQ32N/S9CXWt/0hVStbj8dBVraQz4= +github.com/jenkins-x/go-scm v1.10.10/go.mod h1:z7xTO9/VzqW3xEbEMH2z5cpOGrZ8+nOHOWfU1ngFGxs= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= @@ -479,6 +483,8 @@ github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88J github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.17/go.mod h1:WgzbA6oji13JREwiNsRDNfl7jYdPnmz+VEuLrA+/48M= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -487,6 +493,8 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= @@ -769,6 +777,7 @@ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191021144547-ec77196f6094/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914/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= @@ -1090,6 +1099,9 @@ gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/h2non/gentleman.v1 v1.0.4/go.mod h1:JYuHVdFzS4MKOXe0o+chKJ4hCe6tqKKw9XH9YP6WFrg= +gopkg.in/h2non/gock.v1 v1.0.16 h1:F11k+OafeuFENsjei5t2vMTSTs9L62AdyTe4E1cgdG8= +gopkg.in/h2non/gock.v1 v1.0.16/go.mod h1:XVuDAssexPLwgxCLMvDTWNU5eqklsydR6I5phZ9oPB8= gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= diff --git a/pkg/pullrequest/api_test.go b/pkg/pullrequest/api_test.go index 91e5d9945f2..c03d85bf49c 100644 --- a/pkg/pullrequest/api_test.go +++ b/pkg/pullrequest/api_test.go @@ -289,8 +289,8 @@ func TestUpload_Invalid_Status(t *testing.T) { } expectedErrors := []string{ - "invalid status: \"State\" is empty or has invalid value: {unknown Tekton Status with empty State field https://tekton.dev}", - "invalid status: \"Label\" should not be empty: {success Status without label https://tekton.dev}", + "invalid status: \"State\" is empty or has invalid value: {unknown Tekton Status with empty State field https://tekton.dev }", + "invalid status: \"Label\" should not be empty: {success Status without label https://tekton.dev }", } err := h.Upload(ctx, r) if err == nil { diff --git a/test/pullrequest/testdata/golden/base.json b/test/pullrequest/testdata/golden/base.json index e8ae87db341..11038c4d6f5 100644 --- a/test/pullrequest/testdata/golden/base.json +++ b/test/pullrequest/testdata/golden/base.json @@ -1 +1 @@ -{"Ref":"master","Sha":"c7becbd850add03130ec9797600711b0d6ecaf34","Repo":{"ID":"27785726","Namespace":"wlynch","Name":"test","FullName":"wlynch/test","Perm":{"Pull":false,"Push":false,"Admin":false},"Branch":"master","Private":false,"Clone":"https://github.com/wlynch/test.git","CloneSSH":"git@github.com:wlynch/test.git","Link":"https://github.com/wlynch/test","Created":"2014-12-09T20:32:35Z","Updated":"2020-01-10T18:34:39Z"}} \ No newline at end of file +{"Ref":"master","Sha":"c7becbd850add03130ec9797600711b0d6ecaf34","Repo":{"ID":"27785726","Namespace":"wlynch","Name":"test","FullName":"wlynch/test","Perm":{"Pull":false,"Push":false,"Admin":false},"Branch":"master","Private":false,"Archived":false,"Clone":"https://github.com/wlynch/test.git","CloneSSH":"git@github.com:wlynch/test.git","Link":"https://github.com/wlynch/test","Created":"2014-12-09T20:32:35Z","Updated":"2020-01-10T18:34:39Z"}} \ No newline at end of file diff --git a/test/pullrequest/testdata/golden/comments/494418247.json b/test/pullrequest/testdata/golden/comments/494418247.json index a96dd46541e..aa9423223c1 100644 --- a/test/pullrequest/testdata/golden/comments/494418247.json +++ b/test/pullrequest/testdata/golden/comments/494418247.json @@ -1 +1 @@ -{"ID":494418247,"Body":"test comment","Author":{"ID":0,"Login":"wlynch","Name":"","Email":"","Avatar":"https://avatars3.githubusercontent.com/u/1844673?v=4","Link":"","Created":"0001-01-01T00:00:00Z","Updated":"0001-01-01T00:00:00Z"},"Link":"https://github.com/wlynch/test/pull/1#issuecomment-494418247","Created":"2019-05-21T14:34:46Z","Updated":"2019-05-21T14:34:46Z"} +{"ID":494418247,"Body":"test comment","Author":{"ID":0,"Login":"wlynch","Name":"","Email":"","Avatar":"https://avatars3.githubusercontent.com/u/1844673?v=4","Link":"","Created":"0001-01-01T00:00:00Z","Updated":"0001-01-01T00:00:00Z"},"Link":"https://github.com/wlynch/test/pull/1#issuecomment-494418247","Version":0,"Created":"2019-05-21T14:34:46Z","Updated":"2019-05-21T14:34:46Z"} diff --git a/test/pullrequest/testdata/golden/head.json b/test/pullrequest/testdata/golden/head.json index 71738ca76d7..8fd6f247e60 100644 --- a/test/pullrequest/testdata/golden/head.json +++ b/test/pullrequest/testdata/golden/head.json @@ -1 +1 @@ -{"Ref":"dev","Sha":"db165c3a71dc45d096aebd0f49f07ec565ad1e08","Repo":{"ID":"27785726","Namespace":"wlynch","Name":"test","FullName":"wlynch/test","Perm":{"Pull":false,"Push":false,"Admin":false},"Branch":"master","Private":false,"Clone":"https://github.com/wlynch/test.git","CloneSSH":"git@github.com:wlynch/test.git","Link":"https://github.com/wlynch/test","Created":"2014-12-09T20:32:35Z","Updated":"2020-01-10T18:34:39Z"}} \ No newline at end of file +{"Ref":"dev","Sha":"db165c3a71dc45d096aebd0f49f07ec565ad1e08","Repo":{"ID":"27785726","Namespace":"wlynch","Name":"test","FullName":"wlynch/test","Perm":{"Pull":false,"Push":false,"Admin":false},"Branch":"master","Private":false,"Archived":false,"Clone":"https://github.com/wlynch/test.git","CloneSSH":"git@github.com:wlynch/test.git","Link":"https://github.com/wlynch/test","Created":"2014-12-09T20:32:35Z","Updated":"2020-01-10T18:34:39Z"}} diff --git a/test/pullrequest/testdata/golden/pr.json b/test/pullrequest/testdata/golden/pr.json index 9bacc5af485..2ee3ea45967 100644 --- a/test/pullrequest/testdata/golden/pr.json +++ b/test/pullrequest/testdata/golden/pr.json @@ -1 +1 @@ -{"Number":1,"Title":"test","Body":"","Labels":[{"ID":0,"URL":"https://api.github.com/repos/wlynch/test/labels/my-label","Name":"my-label","Description":"","Color":"ededed"}],"Sha":"db165c3a71dc45d096aebd0f49f07ec565ad1e08","Ref":"refs/pull/1/head","Source":"dev","Target":"master","Base":{"Ref":"master","Sha":"c7becbd850add03130ec9797600711b0d6ecaf34","Repo":{"ID":"27785726","Namespace":"wlynch","Name":"test","FullName":"wlynch/test","Perm":{"Pull":false,"Push":false,"Admin":false},"Branch":"master","Private":false,"Clone":"https://github.com/wlynch/test.git","CloneSSH":"git@github.com:wlynch/test.git","Link":"https://github.com/wlynch/test","Created":"2014-12-09T20:32:35Z","Updated":"2020-01-10T18:34:39Z"}},"Head":{"Ref":"dev","Sha":"db165c3a71dc45d096aebd0f49f07ec565ad1e08","Repo":{"ID":"27785726","Namespace":"wlynch","Name":"test","FullName":"wlynch/test","Perm":{"Pull":false,"Push":false,"Admin":false},"Branch":"master","Private":false,"Clone":"https://github.com/wlynch/test.git","CloneSSH":"git@github.com:wlynch/test.git","Link":"https://github.com/wlynch/test","Created":"2014-12-09T20:32:35Z","Updated":"2020-01-10T18:34:39Z"}},"Fork":"wlynch/test","Link":"https://github.com/wlynch/test/pull/1.diff","State":"open","Closed":false,"Draft":false,"Merged":false,"Mergeable":false,"Rebaseable":false,"MergeableState":"","MergeSha":"0b5320d67796506663ef41e5c5fa0b7bf8a06f58","Author":{"ID":1844673,"Login":"wlynch","Name":"","Email":"","Avatar":"https://avatars3.githubusercontent.com/u/1844673?v=4","Link":"https://github.com/wlynch","Created":"0001-01-01T00:00:00Z","Updated":"0001-01-01T00:00:00Z"},"Assignees":null,"Milestone":{"Number":0,"ID":0,"Title":"","Description":"","Link":"","State":""},"Created":"2018-05-15T16:22:34Z","Updated":"2019-12-26T16:37:05Z"} +{"Number":1,"Title":"test","Body":"","Labels":[{"ID":0,"URL":"https://api.github.com/repos/wlynch/test/labels/my-label","Name":"my-label","Description":"","Color":"ededed"}],"Sha":"db165c3a71dc45d096aebd0f49f07ec565ad1e08","Ref":"refs/pull/1/head","Source":"dev","Target":"master","Base":{"Ref":"master","Sha":"c7becbd850add03130ec9797600711b0d6ecaf34","Repo":{"ID":"27785726","Namespace":"wlynch","Name":"test","FullName":"wlynch/test","Perm":{"Pull":false,"Push":false,"Admin":false},"Branch":"master","Private":false,"Archived":false,"Clone":"https://github.com/wlynch/test.git","CloneSSH":"git@github.com:wlynch/test.git","Link":"https://github.com/wlynch/test","Created":"2014-12-09T20:32:35Z","Updated":"2020-01-10T18:34:39Z"}},"Head":{"Ref":"dev","Sha":"db165c3a71dc45d096aebd0f49f07ec565ad1e08","Repo":{"ID":"27785726","Namespace":"wlynch","Name":"test","FullName":"wlynch/test","Perm":{"Pull":false,"Push":false,"Admin":false},"Branch":"master","Private":false,"Archived":false,"Clone":"https://github.com/wlynch/test.git","CloneSSH":"git@github.com:wlynch/test.git","Link":"https://github.com/wlynch/test","Created":"2014-12-09T20:32:35Z","Updated":"2020-01-10T18:34:39Z"}},"Fork":"wlynch/test","State":"open","Closed":false,"Draft":false,"Merged":false,"Mergeable":false,"Rebaseable":false,"MergeableState":"","MergeSha":"0b5320d67796506663ef41e5c5fa0b7bf8a06f58","Author":{"ID":1844673,"Login":"wlynch","Name":"","Email":"","Avatar":"https://avatars3.githubusercontent.com/u/1844673?v=4","Link":"https://github.com/wlynch","Created":"0001-01-01T00:00:00Z","Updated":"0001-01-01T00:00:00Z"},"Assignees":null,"Reviewers":null,"Milestone":{"Number":0,"ID":0,"Title":"","Description":"","Link":"","State":"","DueDate":null},"Created":"2018-05-15T16:22:34Z","Updated":"2019-12-26T16:37:05Z","Link":"https://github.com/wlynch/test/pull/1","DiffLink":"https://github.com/wlynch/test/pull/1.diff"} \ No newline at end of file diff --git a/test/pullrequest/testdata/golden/status/tekton-e2e.json b/test/pullrequest/testdata/golden/status/tekton-e2e.json index 302dd5e4681..cfbaa7f2bb9 100644 --- a/test/pullrequest/testdata/golden/status/tekton-e2e.json +++ b/test/pullrequest/testdata/golden/status/tekton-e2e.json @@ -1 +1 @@ -{"State":"success","Label":"tekton-e2e","Desc":"tekton-e2e","Target":"https://tekton.dev"} \ No newline at end of file +{"State":"success","Label":"tekton-e2e","Desc":"tekton-e2e","Target":"https://tekton.dev", "Link":"https://api.github.com/repos/wlynch/test/statuses/db165c3a71dc45d096aebd0f49f07ec565ad1e08"} \ No newline at end of file diff --git a/vendor/github.com/docker/cli/cli/config/config.go b/vendor/github.com/docker/cli/cli/config/config.go index 703fa30f48f..93275f3d985 100644 --- a/vendor/github.com/docker/cli/cli/config/config.go +++ b/vendor/github.com/docker/cli/cli/config/config.go @@ -24,17 +24,38 @@ const ( ) var ( - initConfigDir sync.Once + initConfigDir = new(sync.Once) configDir string + homeDir string ) +// resetHomeDir is used in testing to reset the "homeDir" package variable to +// force re-lookup of the home directory between tests. +func resetHomeDir() { + homeDir = "" +} + +func getHomeDir() string { + if homeDir == "" { + homeDir = homedir.Get() + } + return homeDir +} + +// resetConfigDir is used in testing to reset the "configDir" package variable +// and its sync.Once to force re-lookup between tests. +func resetConfigDir() { + configDir = "" + initConfigDir = new(sync.Once) +} + func setConfigDir() { if configDir != "" { return } configDir = os.Getenv("DOCKER_CONFIG") if configDir == "" { - configDir = filepath.Join(homedir.Get(), configFileDir) + configDir = filepath.Join(getHomeDir(), configFileDir) } } @@ -83,10 +104,15 @@ func LoadFromReader(configData io.Reader) (*configfile.ConfigFile, error) { return &configFile, err } +// TODO remove this temporary hack, which is used to warn about the deprecated ~/.dockercfg file +var printLegacyFileWarning bool + // Load reads the configuration files in the given directory, and sets up // the auth config information and returns values. // FIXME: use the internal golang config parser func Load(configDir string) (*configfile.ConfigFile, error) { + printLegacyFileWarning = false + if configDir == "" { configDir = Dir() } @@ -109,12 +135,9 @@ func Load(configDir string) (*configfile.ConfigFile, error) { } // Can't find latest config file so check for the old one - home, err := os.UserHomeDir() - if err != nil { - return configFile, errors.Wrap(err, oldConfigfile) - } - filename = filepath.Join(home, oldConfigfile) + filename = filepath.Join(getHomeDir(), oldConfigfile) if file, err := os.Open(filename); err == nil { + printLegacyFileWarning = true defer file.Close() if err := configFile.LegacyLoadFromReader(file); err != nil { return configFile, errors.Wrap(err, filename) @@ -130,6 +153,9 @@ func LoadDefaultConfigFile(stderr io.Writer) *configfile.ConfigFile { if err != nil { fmt.Fprintf(stderr, "WARNING: Error loading config file: %v\n", err) } + if printLegacyFileWarning { + _, _ = fmt.Fprintln(stderr, "WARNING: Support for the legacy ~/.dockercfg configuration file and file-format is deprecated and will be removed in an upcoming release") + } if !configFile.ContainsAuth() { configFile.CredentialsStore = credentials.DetectDefaultStore(configFile.CredentialsStore) } diff --git a/vendor/github.com/docker/cli/cli/config/credentials/default_store.go b/vendor/github.com/docker/cli/cli/config/credentials/default_store.go index 7a760f1a979..402235bff02 100644 --- a/vendor/github.com/docker/cli/cli/config/credentials/default_store.go +++ b/vendor/github.com/docker/cli/cli/config/credentials/default_store.go @@ -1,7 +1,7 @@ package credentials import ( - "os/exec" + exec "golang.org/x/sys/execabs" ) // DetectDefaultStore return the default credentials store for the platform if diff --git a/vendor/github.com/jenkins-x/go-scm/pkg/hmac/hmac.go b/vendor/github.com/jenkins-x/go-scm/pkg/hmac/hmac.go index ba3fdf89df9..9a90caed2e9 100644 --- a/vendor/github.com/jenkins-x/go-scm/pkg/hmac/hmac.go +++ b/vendor/github.com/jenkins-x/go-scm/pkg/hmac/hmac.go @@ -6,7 +6,7 @@ package hmac import ( "crypto/hmac" - "crypto/sha1" + "crypto/sha1" // #nosec "crypto/sha256" "encoding/hex" "hash" @@ -42,7 +42,7 @@ func ValidatePrefix(message, key []byte, signature string) bool { func validate(h func() hash.Hash, message, key, signature []byte) bool { mac := hmac.New(h, key) - mac.Write(message) + mac.Write(message) // #nosec sum := mac.Sum(nil) return hmac.Equal(signature, sum) } diff --git a/vendor/github.com/jenkins-x/go-scm/scm/app.go b/vendor/github.com/jenkins-x/go-scm/scm/app.go index b03783c9461..0a7cddc06dc 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/app.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/app.go @@ -6,6 +6,7 @@ import ( ) type ( + // InstallationToken is the token used for interacting with the app InstallationToken struct { Token string ExpiresAt *time.Time diff --git a/vendor/github.com/jenkins-x/go-scm/scm/client.go b/vendor/github.com/jenkins-x/go-scm/scm/client.go index d1b1ea6ec4f..5f59f99f9b4 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/client.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/client.go @@ -7,8 +7,10 @@ package scm import ( "context" "errors" + "io" "net/http" + "net/url" "strconv" "strings" @@ -27,6 +29,11 @@ var ( // authorized or the user does not have access to the // resource. ErrNotAuthorized = errors.New("Not Authorized") + + // ErrForbidden indicates the user does not have access to + // the resource, this is similar to 401, but in this case, + // re-authenticating will make no difference. + ErrForbidden = errors.New("Forbidden") ) type ( @@ -73,6 +80,8 @@ type ( URL string Page int Size int + From string + To string } // GraphQLService the API to performing GraphQL queries @@ -92,6 +101,9 @@ type ( BaseURL *url.URL GraphQLURL *url.URL + // Username is the optional user name for the client + Username string + // Services used for communicating with the API. Driver Driver Apps AppService @@ -101,11 +113,14 @@ type ( GraphQL GraphQLService Organizations OrganizationService Issues IssueService + Milestones MilestoneService + Releases ReleaseService PullRequests PullRequestService Repositories RepositoryService Reviews ReviewService Users UserService Webhooks WebhookService + Commits CommitService // DumpResponse optionally specifies a function to // dump the the response body for debugging purposes. @@ -173,9 +188,9 @@ func (c *Client) Do(ctx context.Context, in *Request) (*Response, error) { // dumps the response for debugging purposes. if c.DumpResponse != nil { - c.DumpResponse(res, true) + _, err = c.DumpResponse(res, true) } - return newResponse(res), nil + return newResponse(res), err } // newResponse creates a new Response for the provided @@ -186,17 +201,17 @@ func newResponse(r *http.Response) *Response { Header: r.Header, Body: r.Body, } - res.populatePageValues() + res.PopulatePageValues() return res } -// populatePageValues parses the HTTP Link response headers +// PopulatePageValues parses the HTTP Link response headers // and populates the various pagination link values in the // Response. // // Copyright 2013 The go-github AUTHORS. All rights reserved. // https://github.com/google/go-github -func (r *Response) populatePageValues() { +func (r *Response) PopulatePageValues() { links := strings.Split(r.Header.Get("Link"), ",") for _, link := range links { segments := strings.Split(strings.TrimSpace(link), ";") diff --git a/vendor/github.com/jenkins-x/go-scm/scm/commit.go b/vendor/github.com/jenkins-x/go-scm/scm/commit.go new file mode 100644 index 00000000000..934fd56b16d --- /dev/null +++ b/vendor/github.com/jenkins-x/go-scm/scm/commit.go @@ -0,0 +1,54 @@ +package scm + +import ( + "context" + "time" +) + +type ( + // CommitStatus for commit status + CommitStatus struct { + Status string + Created time.Time + Started time.Time + Name string + AllowFailure bool + Author CommitStatusAuthor + Description string + Sha string + TargetURL string + Finished time.Time + ID int + Ref string + Coverage float64 + } + + // CommitStatusAuthor for commit author + CommitStatusAuthor struct { + Username string + State string + WebURL string + AvatarURL string + ID int + Name string + } + + // CommitStatusUpdateOptions for update options + CommitStatusUpdateOptions struct { + ID string + Sha string + State string + Ref string + Name string + TargetURL string + Description string + Coverage float64 + PipelineID *int + } +) + +// CommitService commit interface +type CommitService interface { + UpdateCommitStatus(ctx context.Context, + repo string, sha string, options CommitStatusUpdateOptions) (*CommitStatus, *Response, error) +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/const.go b/vendor/github.com/jenkins-x/go-scm/scm/const.go index 49e2e2181c6..8cb7378c16f 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/const.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/const.go @@ -71,10 +71,12 @@ func ToState(s string) State { } } +// MarshalJSON marshals State to JSON func (s State) MarshalJSON() ([]byte, error) { return []byte(fmt.Sprintf(`"%s"`, s.String())), nil } +// UnmarshalJSON unmarshals JSON to State func (s *State) UnmarshalJSON(b []byte) error { *s = ToState(strings.Trim(string(b), `"`)) return nil @@ -102,6 +104,7 @@ const ( ActionReviewRequested ActionReviewRequestRemoved ActionReadyForReview + ActionConvertedToDraft // reviews ActionEdited @@ -151,6 +154,8 @@ func (a Action) String() (s string) { return "review_request_removed" case ActionReadyForReview: return "ready_for_review" + case ActionConvertedToDraft: + return "converted_to_draft" case ActionCompleted: return "completed" default: @@ -194,6 +199,14 @@ func (a *Action) UnmarshalJSON(data []byte) error { *a = ActionCompleted case "ready_for_review": *a = ActionReadyForReview + case "converted_to_draft": + *a = ActionConvertedToDraft + case "submitted": + *a = ActionSubmitted + case "dismissed": + *a = ActionDismissed + case "edited": + *a = ActionEdited } return nil } diff --git a/vendor/github.com/jenkins-x/go-scm/scm/content.go b/vendor/github.com/jenkins-x/go-scm/scm/content.go index b3f9cc9df7c..76abd6c5a53 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/content.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/content.go @@ -11,6 +11,7 @@ type ( Content struct { Path string Data []byte + Sha string } // ContentParams provide parameters for creating and @@ -20,6 +21,7 @@ type ( Branch string Message string Data []byte + Sha string } // FileEntry returns the details of a file diff --git a/vendor/github.com/jenkins-x/go-scm/scm/deploy.go b/vendor/github.com/jenkins-x/go-scm/scm/deploy.go index 212b3a2f9b8..131e12a846a 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/deploy.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/deploy.go @@ -14,6 +14,7 @@ type ( Link string Sha string Ref string + Task string FullName string Description string OriginalEnvironment string @@ -25,6 +26,7 @@ type ( Updated time.Time TransientEnvironment bool ProductionEnvironment bool + Payload interface{} } // DeploymentInput the input to create a new deployment diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/content.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/content.go new file mode 100644 index 00000000000..83c9176f87b --- /dev/null +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/content.go @@ -0,0 +1,141 @@ +package fake + +import ( + "context" + "io/ioutil" + "os" + "path/filepath" + + "github.com/jenkins-x/go-scm/scm" + "github.com/pkg/errors" +) + +const ( + + // DefaultFileWritePermissions default permissions when creating a file + DefaultFileWritePermissions = 0644 +) + +type contentService struct { + client *wrapper + data *Data +} + +func (c contentService) Find(_ context.Context, repo, path, ref string) (*scm.Content, *scm.Response, error) { + f, err := c.path(repo, path, ref) + if err != nil { + return nil, nil, err + } + _, err = os.Stat(f) + if os.IsNotExist(err) { + return nil, &scm.Response{ + Status: 404, + }, errors.Wrapf(err, "file %s does not exist", f) + } + data, err := ioutil.ReadFile(f) // #nosec + if err != nil { + return nil, nil, errors.Wrapf(err, "failed to read file %s", f) + } + return &scm.Content{ + Path: path, + Data: data, + Sha: ref, + }, nil, nil +} + +func (c contentService) List(_ context.Context, repo, path, ref string) ([]*scm.FileEntry, *scm.Response, error) { + dir, err := c.path(repo, path, ref) + if err != nil { + return nil, nil, err + } + fileNames, err := ioutil.ReadDir(dir) + if err != nil { + return nil, nil, errors.Wrapf(err, "failed to list files in directory %s", dir) + } + var answer []*scm.FileEntry + for _, f := range fileNames { + name := f.Name() + t := "file" + if f.IsDir() { + t = "dir" + } + path := filepath.Join(dir, name) + answer = append(answer, &scm.FileEntry{ + Name: name, + Path: path, + Type: t, + Size: int(f.Size()), + Sha: ref, + Link: "file://" + path, + }) + } + return answer, nil, nil +} + +func (c contentService) Create(_ context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { + f, err := c.path(repo, path, "") + if err != nil { + return nil, err + } + err = ioutil.WriteFile(f, params.Data, DefaultFileWritePermissions) + if err != nil { + return nil, errors.Wrapf(err, "failed to write file %s", f) + } + return nil, nil +} + +func (c contentService) Update(_ context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { + f, err := c.path(repo, path, "") + if err != nil { + return nil, err + } + err = ioutil.WriteFile(f, params.Data, DefaultFileWritePermissions) + if err != nil { + return nil, errors.Wrapf(err, "failed to write file %s", f) + } + return nil, nil +} + +func (c contentService) Delete(_ context.Context, repo, path, ref string) (*scm.Response, error) { + f, err := c.path(repo, path, ref) + if err != nil { + return nil, err + } + err = os.Remove(f) + if err != nil { + return nil, errors.Wrapf(err, "failed to delete file %s", f) + } + return nil, nil +} + +func (c contentService) path(repo string, path string, ref string) (string, error) { + if c.data.ContentDir == "" { + return "", errors.Errorf("no data.ContentDir configured") + } + if ref == "" { + ref = "master" + } + repoDir := filepath.Join(c.data.ContentDir, repo) + + // lets see if there's a 'refs' folder for testing out different files in different ref/shas + refDir := filepath.Join(repoDir, "refs", ref) + exists, err := DirExists(refDir) + if err != nil { + return repoDir, errors.Wrapf(err, "failed to check if refs dir %s exists", refDir) + } + if exists { + repoDir = refDir + } + return filepath.Join(repoDir, path), nil +} + +// DirExists checks if path exists and is a directory +func DirExists(path string) (bool, error) { + info, err := os.Stat(path) + if err == nil { + return info.IsDir(), nil + } else if os.IsNotExist(err) { + return false, nil + } + return false, err +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/data.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/data.go index 9f57a1b6b5a..dde99d409a7 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/data.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/data.go @@ -2,6 +2,7 @@ package fake import "github.com/jenkins-x/go-scm/scm" +// Data is used to store/represent test data for the fake client type Data struct { Issues map[int][]*scm.Issue OrgMembers map[string][]string @@ -30,6 +31,9 @@ type Data struct { CurrentUser scm.User Users []*scm.User Hooks map[string][]*scm.Hook + Releases map[string]map[int]*scm.Release + Deployments map[string][]*scm.Deployment + DeploymentStatus map[string][]*scm.DeploymentStatus //All Labels That Exist In The Repo RepoLabelsExisting []string @@ -66,8 +70,15 @@ type Data struct { RefsDeleted []DeletedRef UserPermissions map[string]map[string]string + + // Invitations the current pending invitations + Invitations []*scm.Invitation + + // ContentDir the directory used to implement the Content service to access files and directories + ContentDir string } +// DeletedRef represents a ref that has been deleted type DeletedRef struct { Org, Repo, Ref string } @@ -104,5 +115,7 @@ func NewData() *Data { AssigneesAdded: []string{}, UserPermissions: map[string]map[string]string{}, Hooks: map[string][]*scm.Hook{}, + Deployments: map[string][]*scm.Deployment{}, + DeploymentStatus: map[string][]*scm.DeploymentStatus{}, } } diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/deploy.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/deploy.go new file mode 100644 index 00000000000..d09bd5601a8 --- /dev/null +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/deploy.go @@ -0,0 +1,110 @@ +package fake + +import ( + "context" + "strconv" + "time" + + "github.com/jenkins-x/go-scm/scm" +) + +type deploymentService struct { + client *wrapper + data *Data +} + +func (s *deploymentService) Find(ctx context.Context, repoFullName string, deploymentID string) (*scm.Deployment, *scm.Response, error) { + for _, d := range s.data.Deployments[repoFullName] { + if d.ID == deploymentID { + return d, nil, nil + } + } + return nil, nil, scm.ErrNotFound +} + +func (s *deploymentService) List(ctx context.Context, repoFullName string, opts scm.ListOptions) ([]*scm.Deployment, *scm.Response, error) { + return s.data.Deployments[repoFullName], nil, nil +} + +func (s *deploymentService) Create(ctx context.Context, repoFullName string, input *scm.DeploymentInput) (*scm.Deployment, *scm.Response, error) { + deployments := s.data.Deployments[repoFullName] + owner, name := scm.Split(repoFullName) + + d := &scm.Deployment{ + ID: "deployment-" + strconv.Itoa(len(deployments)+1), + Namespace: owner, + Name: name, + Link: "", + Sha: "", + Ref: input.Ref, + Task: input.Task, + FullName: "", + Description: input.Description, + OriginalEnvironment: input.Environment, + Environment: input.Environment, + RepositoryLink: "", + StatusLink: "", + Author: nil, + Created: time.Time{}, + Updated: time.Time{}, + TransientEnvironment: input.TransientEnvironment, + ProductionEnvironment: input.ProductionEnvironment, + Payload: input.Payload, + } + + s.data.Deployments[repoFullName] = append(deployments, d) + return d, nil, nil +} + +func (s *deploymentService) Delete(ctx context.Context, repoFullName string, deploymentID string) (*scm.Response, error) { + deployments := s.data.Deployments[repoFullName] + for i, d := range deployments { + if d.ID == deploymentID { + result := deployments[0:i] + if i+1 < len(deployments) { + result = append(result, deployments[i+1:]...) + } + s.data.Deployments[repoFullName] = result + return nil, nil + } + } + return nil, scm.ErrNotFound +} + +func (s *deploymentService) FindStatus(ctx context.Context, repoFullName string, deploymentID string, statusID string) (*scm.DeploymentStatus, *scm.Response, error) { + key := scm.Join(repoFullName, deploymentID) + for _, d := range s.data.DeploymentStatus[key] { + if d.ID == statusID { + return d, nil, nil + } + } + return nil, nil, scm.ErrNotFound +} + +func (s *deploymentService) ListStatus(ctx context.Context, repoFullName string, deploymentID string, opts scm.ListOptions) ([]*scm.DeploymentStatus, *scm.Response, error) { + key := scm.Join(repoFullName, deploymentID) + return s.data.DeploymentStatus[key], nil, nil +} + +func (s *deploymentService) CreateStatus(ctx context.Context, repoFullName string, deploymentID string, input *scm.DeploymentStatusInput) (*scm.DeploymentStatus, *scm.Response, error) { + key := scm.Join(repoFullName, deploymentID) + statuses := s.data.DeploymentStatus[key] + + status := &scm.DeploymentStatus{ + ID: "status-" + strconv.Itoa(len(statuses)+1), + State: input.State, + Author: nil, + Description: input.Description, + Environment: input.Environment, + DeploymentLink: "", + EnvironmentLink: input.EnvironmentLink, + LogLink: input.LogLink, + RepositoryLink: "", + TargetLink: input.LogLink, + Created: time.Time{}, + Updated: time.Time{}, + } + + s.data.DeploymentStatus[key] = append(statuses, status) + return status, nil, nil +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/fake.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/fake.go index f44d3f262a6..0e3cfc78d9d 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/fake.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/fake.go @@ -11,8 +11,9 @@ import ( // scm operations have been performed func NewDefault() (*scm.Client, *Data) { data := NewData() - data.CurrentUser.Login = "dummy" - data.CurrentUser.Name = "dummy" + data.CurrentUser.Login = "fakeuser" + data.CurrentUser.Name = "fakeuser" + data.ContentDir = "test_data" client := &wrapper{new(scm.Client)} client.BaseURL = &url.URL{ @@ -22,17 +23,20 @@ func NewDefault() (*scm.Client, *Data) { // initialize services client.Driver = scm.DriverFake + client.Contents = &contentService{client: client, data: data} + client.Deployments = &deploymentService{client: client, data: data} client.Git = &gitService{client: client, data: data} client.Issues = &issueService{client: client, data: data} client.Organizations = &organizationService{client: client, data: data} client.PullRequests = &pullService{client: client, data: data} client.Repositories = &repositoryService{client: client, data: data} + client.Releases = &releaseService{client: client, data: data} client.Reviews = &reviewService{client: client, data: data} client.Users = &userService{client: client, data: data} + client.Username = data.CurrentUser.Login // TODO /* - client.Contents = &contentService{client} client.Webhooks = &webhookService{client} */ return client.Client, data diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/git.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/git.go index d55b0bd0217..18a46cc4088 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/git.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/git.go @@ -18,6 +18,10 @@ func (s *gitService) FindRef(ctx context.Context, repo, ref string) (string, *sc return f.TestRef, nil, nil } +func (s *gitService) CreateRef(ctx context.Context, repo, ref, sha string) (*scm.Reference, *scm.Response, error) { + panic("implement me") +} + func (s *gitService) DeleteRef(ctx context.Context, repo, ref string) (*scm.Response, error) { f := s.data paths := strings.SplitN(repo, "/", 2) @@ -55,6 +59,10 @@ func (s *gitService) ListChanges(ctx context.Context, repo, ref string, opts scm panic("implement me") } +func (s *gitService) CompareCommits(ctx context.Context, repo, ref1, ref2 string, opts scm.ListOptions) ([]*scm.Change, *scm.Response, error) { + panic("implement me") +} + func (s *gitService) ListTags(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Reference, *scm.Response, error) { panic("implement me") } diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/issue.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/issue.go index 8fa2a15a544..f3a0ec29735 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/issue.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/issue.go @@ -169,6 +169,10 @@ func (s *issueService) Close(context.Context, string, int) (*scm.Response, error panic("implement me") } +func (s *issueService) Reopen(context.Context, string, int) (*scm.Response, error) { + panic("implement me") +} + func (s *issueService) Lock(context.Context, string, int) (*scm.Response, error) { panic("implement me") } @@ -176,3 +180,11 @@ func (s *issueService) Lock(context.Context, string, int) (*scm.Response, error) func (s *issueService) Unlock(context.Context, string, int) (*scm.Response, error) { panic("implement me") } + +func (s *issueService) SetMilestone(ctx context.Context, repo string, issueID int, number int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + +func (s *issueService) ClearMilestone(ctx context.Context, repo string, id int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/org.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/org.go index 3744a5bb03e..46723ee098e 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/org.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/org.go @@ -27,6 +27,14 @@ type organizationService struct { data *Data } +func (s *organizationService) Create(context.Context, *scm.OrganizationInput) (*scm.Organization, *scm.Response, error) { + panic("implement me") +} + +func (s *organizationService) Delete(context.Context, string) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + func (s *organizationService) IsMember(ctx context.Context, org string, user string) (bool, *scm.Response, error) { panic("implement me") } @@ -54,9 +62,9 @@ func (s *organizationService) List(context.Context, scm.ListOptions) ([]*scm.Org Name: fmt.Sprintf("organisation%d", i), Avatar: fmt.Sprintf("https://github.com/organisation%d.png", i), Permissions: scm.Permissions{ - true, - true, - true, + MembersCreatePrivate: true, + MembersCreatePublic: true, + MembersCreateInternal: true, }, } orgs = append(orgs, &org) @@ -96,3 +104,41 @@ func (s *organizationService) ListTeamMembers(ctx context.Context, teamID int, r func (s *organizationService) ListOrgMembers(ctx context.Context, org string, ops scm.ListOptions) ([]*scm.TeamMember, *scm.Response, error) { return nil, nil, scm.ErrNotSupported } +func (s *organizationService) ListPendingInvitations(_ context.Context, org string, opts scm.ListOptions) ([]*scm.OrganizationPendingInvite, *scm.Response, error) { + for _, o := range s.data.Organizations { + if o.Name == org { + return []*scm.OrganizationPendingInvite{{ + ID: 123, + Login: "fred", + InviterLogin: "charles", + }}, nil, nil + } + } + return nil, nil, scm.ErrNotFound +} + +func (s *organizationService) ListMemberships(ctx context.Context, opts scm.ListOptions) ([]*scm.Membership, *scm.Response, error) { + + return []*scm.Membership{ + { + OrganizationName: "test-org1", + State: "active", + Role: "admin", + }, + { + OrganizationName: "test-org2", + State: "pending", + Role: "member", + }, + }, nil, nil + +} + +func (s *organizationService) AcceptOrganizationInvitation(_ context.Context, org string) (*scm.Response, error) { + for _, o := range s.data.Organizations { + if o.Name == org { + return nil, nil + } + } + return nil, scm.ErrNotFound +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/pr.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/pr.go index c0dffa97301..4956ae46130 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/pr.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/pr.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "regexp" + "strings" "github.com/jenkins-x/go-scm/scm" "k8s.io/apimachinery/pkg/util/sets" @@ -20,9 +21,6 @@ func (s *pullService) Find(ctx context.Context, repo string, number int) (*scm.P if !exists { return nil, nil, fmt.Errorf("Pull request number %d does not exit", number) } - if labels, _, err := s.client.Issues.ListLabels(ctx, repo, number, scm.ListOptions{}); err == nil { - val.Labels = labels - } return val, nil, nil } @@ -30,8 +28,20 @@ func (s *pullService) FindComment(context.Context, string, int, int) (*scm.Comme panic("implement me") } -func (s *pullService) List(context.Context, string, scm.PullRequestListOptions) ([]*scm.PullRequest, *scm.Response, error) { - panic("implement me") +func (s *pullService) List(ctx context.Context, fullName string, opts scm.PullRequestListOptions) ([]*scm.PullRequest, *scm.Response, error) { + var answer []*scm.PullRequest + f := s.data + for _, pr := range f.PullRequests { + repo := pr.Repository() + fn := repo.FullName + if fn == "" { + fn = scm.Join(repo.Namespace, repo.Name) + } + if fn == fullName { + answer = append(answer, pr) + } + } + return answer, nil, nil } func (s *pullService) ListChanges(ctx context.Context, repo string, number int, opts scm.ListOptions) ([]*scm.Change, *scm.Response, error) { @@ -67,6 +77,22 @@ func (s *pullService) ListEvents(context.Context, string, int, scm.ListOptions) func (s *pullService) AddLabel(ctx context.Context, repo string, number int, label string) (*scm.Response, error) { f := s.data + pr := s.data.PullRequests[number] + if pr != nil { + found := false + for _, l := range pr.Labels { + if l.Name == label { + found = true + break + } + } + if !found { + pr.Labels = append(pr.Labels, &scm.Label{ + ID: int64(len(pr.Labels)), + Name: label, + }) + } + } labelString := fmt.Sprintf("%s#%d:%s", repo, number, label) if sets.NewString(f.PullRequestLabelsAdded...).Has(labelString) { return nil, fmt.Errorf("cannot add %v to %s/#%d", label, repo, number) @@ -95,7 +121,19 @@ func (s *pullService) DeleteLabel(ctx context.Context, repo string, number int, return nil, fmt.Errorf("cannot remove %v from %s/#%d", label, repo, number) } -func (s *pullService) Merge(context.Context, string, int, *scm.PullRequestMergeOptions) (*scm.Response, error) { +func (s *pullService) Merge(ctx context.Context, repo string, number int, mergeOpts *scm.PullRequestMergeOptions) (*scm.Response, error) { + pr, ok := s.data.PullRequests[number] + if !ok || pr == nil { + return nil, fmt.Errorf("pull request %d not found", number) + } + pr.Merged = true + pr.State = "closed" + pr.Closed = true + pr.Mergeable = false + return nil, nil +} + +func (s *pullService) Update(ctx context.Context, repo string, number int, prInput *scm.PullRequestInput) (*scm.PullRequest, *scm.Response, error) { panic("implement me") } @@ -103,6 +141,10 @@ func (s *pullService) Close(context.Context, string, int) (*scm.Response, error) panic("implement me") } +func (s *pullService) Reopen(context.Context, string, int) (*scm.Response, error) { + panic("implement me") +} + func (s *pullService) CreateComment(ctx context.Context, repo string, number int, comment *scm.CommentInput) (*scm.Comment, *scm.Response, error) { f := s.data f.PullRequestCommentsAdded = append(f.PullRequestCommentsAdded, fmt.Sprintf("%s#%d:%s", repo, number, comment.Body)) @@ -135,7 +177,19 @@ func (s *pullService) EditComment(ctx context.Context, repo string, number int, } func (s *pullService) AssignIssue(ctx context.Context, repo string, number int, logins []string) (*scm.Response, error) { - panic("implement me") + f := s.data + var m scm.MissingUsers + for _, a := range logins { + if a == "not-in-the-org" { + m.Users = append(m.Users, a) + continue + } + f.AssigneesAdded = append(f.AssigneesAdded, fmt.Sprintf("%s#%d:%s", repo, number, a)) + } + if m.Users == nil { + return nil, nil + } + return nil, m } func (s *pullService) UnassignIssue(ctx context.Context, repo string, number int, logins []string) (*scm.Response, error) { @@ -150,15 +204,27 @@ func (s *pullService) UnrequestReview(ctx context.Context, repo string, number i return nil, scm.ErrNotSupported } -func (s *pullService) Create(ctx context.Context, repo string, input *scm.PullRequestInput) (*scm.PullRequest, *scm.Response, error) { +func (s *pullService) Create(_ context.Context, fullName string, input *scm.PullRequestInput) (*scm.PullRequest, *scm.Response, error) { f := s.data f.PullRequestID++ + namespace := "" + name := "" + paths := strings.SplitN(fullName, "/", 2) + if len(paths) > 1 { + namespace = paths[0] + name = paths[1] + } answer := &scm.PullRequest{ Number: f.PullRequestID, Title: input.Title, Body: input.Body, Base: scm.PullRequestBranch{ Ref: input.Base, + Repo: scm.Repository{ + Namespace: namespace, + Name: name, + FullName: fullName, + }, }, Head: scm.PullRequestBranch{ Ref: input.Head, @@ -168,3 +234,11 @@ func (s *pullService) Create(ctx context.Context, repo string, input *scm.PullRe f.PullRequests[f.PullRequestID] = answer return answer, nil, nil } + +func (s *pullService) SetMilestone(ctx context.Context, repo string, prID int, number int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + +func (s *pullService) ClearMilestone(ctx context.Context, repo string, prID int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/release.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/release.go new file mode 100644 index 00000000000..a690f2f9869 --- /dev/null +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/release.go @@ -0,0 +1,112 @@ +package fake + +import ( + "context" + "strconv" + "time" + + "github.com/jenkins-x/go-scm/scm" +) + +type releaseService struct { + client *wrapper + data *Data +} + +func (r *releaseService) Find(_ context.Context, repo string, number int) (*scm.Release, *scm.Response, error) { + release := r.releaseMap(repo)[number] + if release == nil { + return nil, nil, scm.ErrNotFound + } + return release, nil, nil +} + +func (r *releaseService) releaseMap(repo string) map[int]*scm.Release { + if r.data.Releases == nil { + r.data.Releases = map[string]map[int]*scm.Release{} + } + releaseMap := r.data.Releases[repo] + if releaseMap == nil { + releaseMap = map[int]*scm.Release{} + r.data.Releases[repo] = releaseMap + } + return releaseMap +} + +func (r *releaseService) FindByTag(_ context.Context, repo string, tag string) (*scm.Release, *scm.Response, error) { + for _, rel := range r.releaseMap(repo) { + if rel.Tag == tag { + return rel, nil, nil + } + } + return nil, nil, scm.ErrNotFound +} + +func (r *releaseService) List(_ context.Context, repo string, options scm.ReleaseListOptions) ([]*scm.Release, *scm.Response, error) { + var answer []*scm.Release + for _, rel := range r.releaseMap(repo) { + answer = append(answer, rel) + } + if len(answer) == 0 { + return nil, nil, scm.ErrNotFound + } + return answer, nil, nil +} + +func (r *releaseService) Create(_ context.Context, repo string, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + m := r.releaseMap(repo) + id := len(m) + now := time.Now() + release := &scm.Release{ + ID: id, + Title: input.Title, + Description: input.Description, + Link: "https://fake.git/" + repo + "/releases/release/" + strconv.Itoa(id), + Tag: input.Tag, + Commitish: input.Commitish, + Draft: input.Draft, + Prerelease: input.Prerelease, + Created: now, + Published: now, + } + m[id] = release + return release, nil, nil +} + +func (r *releaseService) Update(_ context.Context, repo string, number int, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + rel := r.releaseMap(repo)[number] + if rel == nil { + return nil, nil, scm.ErrNotFound + } + if input.Commitish != "" { + rel.Commitish = input.Commitish + } + if input.Description != "" { + rel.Description = input.Description + } + if input.Tag != "" { + rel.Tag = input.Tag + } + if input.Title != "" { + rel.Title = input.Title + } + rel.Draft = input.Draft + rel.Prerelease = input.Prerelease + return nil, nil, nil +} + +func (r *releaseService) UpdateByTag(ctx context.Context, repo string, tag string, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + rel, _, _ := r.FindByTag(ctx, repo, tag) + return r.Update(ctx, repo, rel.ID, input) +} + +func (r *releaseService) Delete(_ context.Context, repo string, number int) (*scm.Response, error) { + m := r.releaseMap(repo) + delete(m, number) + return nil, nil +} + +func (r *releaseService) DeleteByTag(ctx context.Context, repo string, tag string) (*scm.Response, error) { + rel, _, _ := r.FindByTag(ctx, repo, tag) + return r.Delete(ctx, repo, rel.ID) +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/repo.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/repo.go index 6be5729bf82..83a28a4b808 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/repo.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/repo.go @@ -55,6 +55,51 @@ func (s *repositoryService) ListUser(context.Context, string, scm.ListOptions) ( panic("implement me") } +func (s *repositoryService) AddCollaborator(ctx context.Context, repo, user, permission string) (bool, bool, *scm.Response, error) { + s.data.Collaborators = append(s.data.Collaborators, user) + if len(s.data.UserPermissions) == 0 { + s.data.UserPermissions = make(map[string]map[string]string) + } + m := s.data.UserPermissions[repo] + if len(m) == 0 { + m = make(map[string]string) + } + + alreadyExists := false + if _, ok := m[user]; ok { + alreadyExists = true + } + m[user] = permission + + s.data.UserPermissions[repo] = m + + // lets add an invitation if the user isn't already in the repo... + if !alreadyExists { + id := int64(len(s.data.Invitations) + 1) + names := strings.SplitN(repo, "/", 2) + owner := "" + repoName := "" + if len(names) == 2 { + owner = names[0] + repoName = names[1] + } + s.data.Invitations = append(s.data.Invitations, &scm.Invitation{ + ID: id, + Repo: &scm.Repository{ + Namespace: owner, + Name: repoName, + FullName: repo, + }, + Invitee: &scm.User{}, + Inviter: &scm.User{}, + Permissions: permission, + Created: time.Now(), + }) + } + + return true, alreadyExists, nil, nil +} + func (s *repositoryService) IsCollaborator(ctx context.Context, repo, login string) (bool, *scm.Response, error) { f := s.data normed := NormLogin(login) @@ -78,10 +123,10 @@ func (s *repositoryService) ListCollaborators(ctx context.Context, repo string, func (s *repositoryService) Find(ctx context.Context, fullName string) (*scm.Repository, *scm.Response, error) { for _, repo := range s.data.Repositories { if repo.FullName == fullName { - return repo, nil, nil + return repo, &scm.Response{Status: 200}, nil } } - return nil, nil, scm.ErrNotFound + return nil, &scm.Response{Status: 404}, scm.ErrNotFound } func (s *repositoryService) List(ctx context.Context, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { @@ -108,23 +153,35 @@ func (s *repositoryService) ListStatus(ctx context.Context, repo string, ref str func (s *repositoryService) Create(ctx context.Context, input *scm.RepositoryInput) (*scm.Repository, *scm.Response, error) { s.data.CreateRepositories = append(s.data.CreateRepositories, input) - fullName := scm.Join(input.Namespace, input.Name) + namespace := input.Namespace + if namespace == "" { + namespace = s.client.Username + } + fullName := scm.Join(namespace, input.Name) + link := fmt.Sprintf("https://fake.com/%s.git", fullName) repo := &scm.Repository{ - Namespace: input.Namespace, + Namespace: namespace, Name: input.Name, FullName: fullName, - Link: fmt.Sprintf("https://fake.com/%s.git", fullName), + Link: link, + Clone: link, Created: time.Now(), } s.data.Repositories = append(s.data.Repositories, repo) return repo, nil, nil } +func (s *repositoryService) Fork(ctx context.Context, input *scm.RepositoryInput, origRepo string) (*scm.Repository, *scm.Response, error) { + // TODO: Actually make this fork rather than just duplicate Create. + return s.Create(ctx, input) +} + func (s *repositoryService) ListHooks(ctx context.Context, fullName string, opts scm.ListOptions) ([]*scm.Hook, *scm.Response, error) { return s.data.Hooks[fullName], nil, nil } func (s *repositoryService) CreateHook(ctx context.Context, fullName string, input *scm.HookInput) (*scm.Hook, *scm.Response, error) { + /* #nosec */ hook := &scm.Hook{ ID: fmt.Sprintf("%d", rand.Int()), Name: input.Name, @@ -135,6 +192,10 @@ func (s *repositoryService) CreateHook(ctx context.Context, fullName string, inp return hook, nil, nil } +func (s *repositoryService) UpdateHook(ctx context.Context, repo string, input *scm.HookInput) (*scm.Hook, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + func (s *repositoryService) DeleteHook(ctx context.Context, fullName string, hookID string) (*scm.Response, error) { hooks := s.data.Hooks[fullName] for i, h := range hooks { @@ -163,3 +224,7 @@ func (s *repositoryService) CreateStatus(ctx context.Context, repo string, ref s s.data.Statuses[ref] = statuses return status, nil, nil } + +func (s *repositoryService) Delete(context.Context, string) (*scm.Response, error) { + panic("implement me") +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/review.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/review.go index 4f37835acc3..ce555f0e56c 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/review.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/review.go @@ -44,3 +44,19 @@ func (s *reviewService) Create(ctx context.Context, repo string, number int, inp func (s *reviewService) Delete(context.Context, string, int, int) (*scm.Response, error) { panic("implement me") } + +func (s *reviewService) ListComments(ctx context.Context, repo string, prID int, reviewID int, options scm.ListOptions) ([]*scm.ReviewComment, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *reviewService) Update(ctx context.Context, repo string, prID int, reviewID int, body string) (*scm.Review, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *reviewService) Submit(ctx context.Context, repo string, prID int, reviewID int, input *scm.ReviewSubmitInput) (*scm.Review, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *reviewService) Dismiss(ctx context.Context, repo string, prID int, reviewID int, msg string) (*scm.Review, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/test_helpers.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/test_helpers.go new file mode 100644 index 00000000000..e68e9aaaa83 --- /dev/null +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/test_helpers.go @@ -0,0 +1,35 @@ +package fake + +import ( + "context" + "github.com/jenkins-x/go-scm/scm" + "github.com/stretchr/testify/require" + "testing" +) + +// AssertRepoExists asserts that the repository exists +func AssertRepoExists(t *testing.T, ctx context.Context, client *scm.Client, repo string) *scm.Repository { + require.NotEmpty(t, repo, "no repository name") + require.NotNil(t, client, "no scm client") + require.NotNil(t, client.Repositories, "scm client does not support Repositories") + + repository, _, err := client.Repositories.Find(ctx, repo) + + if err != nil && scm.IsScmNotFound(err) { + err = nil + } + require.NoError(t, err, "failed to find repo %s", repo) + require.NotNil(t, repository, "no repository returned for %s", repo) + return repository +} + +// AssertNoRepoExists asserts that the repository does not exist +func AssertNoRepoExists(t *testing.T, ctx context.Context, client *scm.Client, repo string) { + require.NotEmpty(t, repo, "no repository name") + require.NotNil(t, client, "no scm client") + require.NotNil(t, client.Repositories, "scm client does not support Repositories") + + _, _, err := client.Repositories.Find(ctx, repo) + require.Error(t, err, "expected not found error when looking up repo %s", repo) + require.True(t, scm.IsScmNotFound(err), "should have returned an is not found error for repo %s", repo) +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/user.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/user.go index 6bad084d659..e73c9561a88 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/user.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/fake/user.go @@ -11,19 +11,46 @@ type userService struct { data *Data } -func (u *userService) Find(ctx context.Context) (*scm.User, *scm.Response, error) { - return &u.data.CurrentUser, nil, nil +func (s *userService) CreateToken(context.Context, string, string) (*scm.UserToken, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported } -func (u *userService) FindEmail(ctx context.Context) (string, *scm.Response, error) { - return u.data.CurrentUser.Email, nil, nil +func (s *userService) DeleteToken(context.Context, int64) (*scm.Response, error) { + return nil, scm.ErrNotSupported } -func (u *userService) FindLogin(ctx context.Context, login string) (*scm.User, *scm.Response, error) { - for _, user := range u.data.Users { +func (s *userService) Find(ctx context.Context) (*scm.User, *scm.Response, error) { + return &s.data.CurrentUser, nil, nil +} + +func (s *userService) FindEmail(ctx context.Context) (string, *scm.Response, error) { + return s.data.CurrentUser.Email, nil, nil +} + +func (s *userService) FindLogin(ctx context.Context, login string) (*scm.User, *scm.Response, error) { + for _, user := range s.data.Users { if user.Login == login { return user, nil, nil } } return nil, nil, nil } + +func (s *userService) ListInvitations(context.Context) ([]*scm.Invitation, *scm.Response, error) { + return s.data.Invitations, nil, nil +} + +func (s *userService) AcceptInvitation(_ context.Context, id int64) (*scm.Response, error) { + invitations := s.data.Invitations + for i, invite := range invitations { + if invite.ID == id { + remaining := invitations[0:i] + if i+1 < len(invitations) { + remaining = append(remaining, invitations[i+1:]...) + } + s.data.Invitations = remaining + return nil, nil + } + } + return nil, scm.ErrNotSupported +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/content.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/content.go index b9234b8fdba..347b29efad5 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/content.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/content.go @@ -25,6 +25,7 @@ func (s *contentService) Find(ctx context.Context, repo, path, ref string) (*scm return &scm.Content{ Path: out.Path, Data: raw, + Sha: out.Sha, }, res, err } @@ -36,11 +37,26 @@ func (s *contentService) List(ctx context.Context, repo, path, ref string) ([]*s } func (s *contentService) Create(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { - return nil, scm.ErrNotSupported + endpoint := fmt.Sprintf("repos/%s/contents/%s", repo, path) + body := &contentBody{ + Message: params.Message, + Content: params.Data, + Branch: params.Branch, + } + + return s.client.do(ctx, "PUT", endpoint, &body, nil) } func (s *contentService) Update(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { - return nil, scm.ErrNotSupported + endpoint := fmt.Sprintf("repos/%s/contents/%s", repo, path) + body := &contentBody{ + Message: params.Message, + Content: params.Data, + Branch: params.Branch, + Sha: params.Sha, + } + + return s.client.do(ctx, "PUT", endpoint, &body, nil) } func (s *contentService) Delete(ctx context.Context, repo, path, ref string) (*scm.Response, error) { @@ -79,6 +95,13 @@ type contentUpdate struct { } `json:"committer"` } +type contentBody struct { + Message string `json:"message"` + Content []byte `json:"content"` + Sha string `json:"sha,omitempty"` + Branch string `json:"branch,omitempty"` +} + func convertEntryList(out []*entry) []*scm.FileEntry { answer := make([]*scm.FileEntry, 0, len(out)) for _, o := range out { diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/deploy.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/deploy.go index 81050901135..69873a0dbfe 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/deploy.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/deploy.go @@ -3,10 +3,13 @@ package github import ( "context" "fmt" + "io/ioutil" "strconv" "strings" "time" + "github.com/pkg/errors" + "github.com/jenkins-x/go-scm/scm" ) @@ -18,29 +21,32 @@ type deployment struct { Namespace string Name string FullName string - ID int `json:"id"` - Link string `json:"url"` - Sha string `json:"sha"` - Ref string `json:"ref"` - Description string `json:"description"` - OriginalEnvironment string `json:"original_environment"` - Environment string `json:"environment"` - RepositoryLink string `json:"repository_url"` - StatusLink string `json:"statuses_url"` - Author *user `json:"creator"` - Created time.Time `json:"created_at"` - Updated time.Time `json:"updated_at"` - TransientEnvironment bool `json:"transient_environment"` - ProductionEnvironment bool `json:"production_environment"` + ID int `json:"id"` + Link string `json:"url"` + Sha string `json:"sha"` + Ref string `json:"ref"` + Task string `json:"task"` + Description string `json:"description"` + OriginalEnvironment string `json:"original_environment"` + Environment string `json:"environment"` + EnvironmentURL string `json:"environment_url"` + RepositoryLink string `json:"repository_url"` + StatusLink string `json:"statuses_url"` + Author *user `json:"creator"` + Created time.Time `json:"created_at"` + Updated time.Time `json:"updated_at"` + TransientEnvironment bool `json:"transient_environment"` + ProductionEnvironment bool `json:"production_environment"` + Payload interface{} `json:"payload"` } type deploymentInput struct { - Ref string `json:"ref"` - Task string `json:"task"` - Payload string `json:"payload"` - Environment string `json:"environment"` - Description string `json:"description"` - RequiredContexts []string `json:"required_contexts"` + Ref string `json:"ref,omitempty"` + Task string `json:"task,omitempty"` + Payload string `json:"payload,omitempty"` + Environment string `json:"environment,omitempty"` + Description string `json:"description,omitempty"` + RequiredContexts []string `json:"required_contexts,omitempty"` AutoMerge bool `json:"auto_merge"` TransientEnvironment bool `json:"transient_environment"` ProductionEnvironment bool `json:"production_environment"` @@ -75,14 +81,14 @@ func (s *deploymentService) Find(ctx context.Context, repoFullName string, deplo path := fmt.Sprintf("repos/%s/deployments/%s", repoFullName, deploymentID) out := new(deployment) res, err := s.client.do(ctx, "GET", path, nil, out) - return convertDeployment(out, repoFullName), res, err + return convertDeployment(out, repoFullName), res, wrapError(res, err) } func (s *deploymentService) List(ctx context.Context, repoFullName string, opts scm.ListOptions) ([]*scm.Deployment, *scm.Response, error) { path := fmt.Sprintf("repos/%s/deployments?%s", repoFullName, encodeListOptions(opts)) out := []*deployment{} res, err := s.client.do(ctx, "GET", path, nil, &out) - return convertDeploymentList(out, repoFullName), res, err + return convertDeploymentList(out, repoFullName), res, wrapError(res, err) } func (s *deploymentService) Create(ctx context.Context, repoFullName string, deploymentInput *scm.DeploymentInput) (*scm.Deployment, *scm.Response, error) { @@ -90,7 +96,7 @@ func (s *deploymentService) Create(ctx context.Context, repoFullName string, dep in := convertToDeploymentInput(deploymentInput) out := new(deployment) res, err := s.client.do(ctx, "POST", path, in, out) - return convertDeployment(out, repoFullName), res, err + return convertDeployment(out, repoFullName), res, wrapError(res, err) } func (s *deploymentService) Delete(ctx context.Context, repoFullName string, deploymentID string) (*scm.Response, error) { @@ -102,14 +108,14 @@ func (s *deploymentService) FindStatus(ctx context.Context, repoFullName string, path := fmt.Sprintf("repos/%s/deployments/%s/statuses/%s", repoFullName, deploymentID, statusID) out := new(deploymentStatus) res, err := s.client.do(ctx, "GET", path, nil, out) - return convertDeploymentStatus(out), res, err + return convertDeploymentStatus(out), res, wrapError(res, err) } func (s *deploymentService) ListStatus(ctx context.Context, repoFullName string, deploymentID string, opts scm.ListOptions) ([]*scm.DeploymentStatus, *scm.Response, error) { path := fmt.Sprintf("repos/%s/deployments/%s/statuses?%s", repoFullName, deploymentID, encodeListOptions(opts)) out := []*deploymentStatus{} res, err := s.client.do(ctx, "GET", path, nil, &out) - return convertDeploymentStatusList(out), res, err + return convertDeploymentStatusList(out), res, wrapError(res, err) } func (s *deploymentService) CreateStatus(ctx context.Context, repoFullName string, deploymentID string, deploymentStatusInput *scm.DeploymentStatusInput) (*scm.DeploymentStatus, *scm.Response, error) { @@ -117,7 +123,18 @@ func (s *deploymentService) CreateStatus(ctx context.Context, repoFullName strin in := convertToDeploymentStatusInput(deploymentStatusInput) out := new(deploymentStatus) res, err := s.client.do(ctx, "POST", path, in, out) - return convertDeploymentStatus(out), res, err + return convertDeploymentStatus(out), res, wrapError(res, err) +} + +func wrapError(res *scm.Response, err error) error { + if res == nil { + return err + } + data, err2 := ioutil.ReadAll(res.Body) + if err2 != nil { + return errors.Wrapf(err, "http status %d", res.Status) + } + return errors.Wrapf(err, "http status %d mesage %s", res.Status, string(data)) } func convertDeploymentList(out []*deployment, fullName string) []*scm.Deployment { @@ -158,6 +175,7 @@ func convertDeployment(from *deployment, fullName string) *scm.Deployment { Sha: from.Sha, Ref: from.Ref, FullName: fullName, + Task: from.Task, Description: from.Description, OriginalEnvironment: from.OriginalEnvironment, Environment: from.Environment, @@ -168,6 +186,7 @@ func convertDeployment(from *deployment, fullName string) *scm.Deployment { Updated: from.Updated, TransientEnvironment: from.TransientEnvironment, ProductionEnvironment: from.ProductionEnvironment, + Payload: from.Payload, } names := strings.Split(fullName, "/") if len(names) > 1 { diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/git.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/git.go index 44eff5e7e61..44a79eff5ce 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/git.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/git.go @@ -43,6 +43,30 @@ func (s *gitService) FindRef(ctx context.Context, repo, ref string) (string, *sc return out.Object["sha"], res, err } +// CreateRef creates a new ref +func (s *gitService) CreateRef(ctx context.Context, repo, ref, sha string) (*scm.Reference, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/git/refs", repo) + in := &struct { + Ref string `json:"ref"` + Sha string `json:"sha"` + }{Ref: ref, Sha: sha} + + out := &struct { + Ref string `json:"ref"` + Object struct { + Sha string + } `json:"object"` + }{} + + res, err := s.client.do(ctx, http.MethodPost, path, in, out) + scmRef := &scm.Reference{ + Name: out.Ref, + Sha: out.Object.Sha, + Path: out.Ref, + } + return scmRef, res, err +} + // DeleteRef deletes the given ref // // See https://developer.github.com/v3/git/refs/#delete-a-reference @@ -84,6 +108,13 @@ func (s *gitService) ListChanges(ctx context.Context, repo, ref string, _ scm.Li return convertChangeList(out.Files), res, err } +func (s *gitService) CompareCommits(ctx context.Context, repo, ref1, ref2 string, _ scm.ListOptions) ([]*scm.Change, *scm.Response, error) { + path := fmt.Sprintf("/repos/%s/compare/%s...%s", repo, ref1, ref2) + out := new(commit) + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertChangeList(out.Files), res, err +} + type branch struct { Name string `json:"name"` Commit commit `json:"commit"` diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/github.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/github.go index 90d3e67eb79..f0f23b94f26 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/github.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/github.go @@ -9,6 +9,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "net/http" "net/url" @@ -25,6 +26,11 @@ import ( // but will prevent an indefinite stall if GitHub never responds. const maxRequestTime = 5 * time.Minute +// NewWebHookService creates a new instance of the webhook service without the rest of the client +func NewWebHookService() scm.WebhookService { + return &webhookService{nil} +} + // New returns a new GitHub API client. func New(uri string) (*scm.Client, error) { base, err := url.Parse(uri) @@ -42,6 +48,8 @@ func New(uri string) (*scm.Client, error) { client.Deployments = &deploymentService{client} client.Git = &gitService{client} client.Issues = &issueService{client} + client.Milestones = &milestoneService{client} + client.Releases = &releaseService{client} client.Organizations = &organizationService{client} client.PullRequests = &pullService{&issueService{client}} client.Repositories = &repositoryService{client} @@ -50,9 +58,9 @@ func New(uri string) (*scm.Client, error) { client.Webhooks = &webhookService{client} client.Apps = &appService{client} - graphqlEndpoint := scm.UrlJoin(uri, "/graphql") + graphqlEndpoint := scm.URLJoin(uri, "/graphql") if strings.HasSuffix(uri, "/api/v3") { - graphqlEndpoint = scm.UrlJoin(uri[0:len(uri)-2], "graphql") + graphqlEndpoint = scm.URLJoin(uri[0:len(uri)-2], "graphql") } client.GraphQLURL, err = url.Parse(graphqlEndpoint) if err != nil { @@ -153,9 +161,9 @@ func (c *wrapper) doRequest(ctx context.Context, req *scm.Request, in, out inter if res.Status == 404 { return res, scm.ErrNotFound } - err := new(Error) - json.NewDecoder(res.Body).Decode(err) - return res, err + return res, errors.New( + http.StatusText(res.Status), + ) } if out == nil { diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/issue.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/issue.go index 311202f7c73..37321f0bdb4 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/issue.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/issue.go @@ -202,6 +202,14 @@ func (s *issueService) Close(ctx context.Context, repo string, number int) (*scm return res, err } +func (s *issueService) Reopen(ctx context.Context, repo string, number int) (*scm.Response, error) { + path := fmt.Sprintf("repos/%s/issues/%d", repo, number) + data := map[string]string{"state": "open"} + out := new(issue) + res, err := s.client.do(ctx, "PATCH", path, &data, out) + return res, err +} + func (s *issueService) Lock(ctx context.Context, repo string, number int) (*scm.Response, error) { path := fmt.Sprintf("repos/%s/issues/%d/lock", repo, number) res, err := s.client.do(ctx, "PUT", path, nil, nil) @@ -214,6 +222,26 @@ func (s *issueService) Unlock(ctx context.Context, repo string, number int) (*sc return res, err } +func (s *issueService) SetMilestone(ctx context.Context, repo string, issueID int, number int) (*scm.Response, error) { + path := fmt.Sprintf("repos/%s/issues/%d", repo, issueID) + in := &struct { + Milestone int `json:"milestone"` + }{ + Milestone: number, + } + res, err := s.client.do(ctx, "PATCH", path, in, nil) + return res, err +} + +func (s *issueService) ClearMilestone(ctx context.Context, repo string, id int) (*scm.Response, error) { + path := fmt.Sprintf("repos/%s/issues/%d", repo, id) + in := &struct { + Milestone interface{} `json:"milestone"` + }{} + res, err := s.client.do(ctx, "PATCH", path, in, nil) + return res, err +} + type issue struct { ID int `json:"id"` HTMLURL string `json:"html_url"` @@ -225,6 +253,10 @@ type issue struct { Login string `json:"login"` AvatarURL string `json:"avatar_url"` } `json:"user"` + ClosedBy *struct { + Login string `json:"login"` + AvatarURL string `json:"avatar_url"` + } `json:"closed_by"` Labels []struct { Name string `json:"name"` } `json:"labels"` @@ -310,6 +342,13 @@ func populateRepositoryFromURL(repo *scm.Repository, u string) { // helper function to convert from the gogs issue structure to // the common issue structure. func convertIssue(from *issue) *scm.Issue { + var closedBy *scm.User + if from.ClosedBy != nil { + closedBy = &scm.User{ + Login: from.ClosedBy.Login, + Avatar: from.ClosedBy.AvatarURL, + } + } return &scm.Issue{ Number: from.Number, Title: from.Title, @@ -323,6 +362,7 @@ func convertIssue(from *issue) *scm.Issue { Login: from.User.Login, Avatar: from.User.AvatarURL, }, + ClosedBy: closedBy, Assignees: convertUsers(from.Assignees), PullRequest: from.PullRequest != nil, Created: from.CreatedAt, diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/milestone.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/milestone.go new file mode 100644 index 00000000000..fc3f9dcc6c5 --- /dev/null +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/milestone.go @@ -0,0 +1,111 @@ +package github + +import ( + "context" + "fmt" + "time" + + "github.com/jenkins-x/go-scm/scm" +) + +type milestoneService struct { + client *wrapper +} + +type milestone struct { + ID int `json:"id"` + Number int `json:"number"` + Title string `json:"title"` + Description string `json:"description"` + State string `json:"state"` + DueOn time.Time `json:"due_on"` + URL string `json:"url"` + HTMLURL string `json:"html_url"` + LabelsURL string `json:"labels_url"` + Creator user `json:"creator"` + OpenIssues int `json:"open_issues"` + ClosedIssues int `json:"closed_issues"` + NodeID string `json:"node_id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + ClosedAt time.Time `json:"closed_at"` +} + +type milestoneInput struct { + Title string `json:"title"` + State string `json:"state"` + Description string `json:"description"` + DueOn time.Time `json:"due_on"` +} + +func (s *milestoneService) Find(ctx context.Context, repo string, id int) (*scm.Milestone, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/milestones/%d", repo, id) + out := new(milestone) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertMilestone(out), res, err +} + +func (s *milestoneService) List(ctx context.Context, repo string, opts scm.MilestoneListOptions) ([]*scm.Milestone, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/milestones?%s", repo, encodeMilestoneListOptions(opts)) + out := []*milestone{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertMilestoneList(out), res, err +} + +func (s *milestoneService) Create(ctx context.Context, repo string, input *scm.MilestoneInput) (*scm.Milestone, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/milestones", repo) + in := &milestoneInput{ + Title: input.Title, + State: input.State, + Description: input.Description, + DueOn: *input.DueDate, + } + out := new(milestone) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertMilestone(out), res, err +} + +func (s *milestoneService) Delete(ctx context.Context, repo string, id int) (*scm.Response, error) { + path := fmt.Sprintf("repos/%s/milestones/%d", repo, id) + return s.client.do(ctx, "DELETE", path, nil, nil) +} + +func (s *milestoneService) Update(ctx context.Context, repo string, id int, input *scm.MilestoneInput) (*scm.Milestone, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/milestones/%d", repo, id) + in := &milestoneInput{} + if input.Title != "" { + in.Title = input.Title + } + if input.State != "" { + in.State = input.State + } + if input.Description != "" { + in.Description = input.Description + } + if input.DueDate != nil { + in.DueOn = *input.DueDate + } + out := new(milestone) + res, err := s.client.do(ctx, "PATCH", path, in, out) + return convertMilestone(out), res, err +} + +func convertMilestoneList(from []*milestone) []*scm.Milestone { + var to []*scm.Milestone + for _, m := range from { + to = append(to, convertMilestone(m)) + } + return to +} + +func convertMilestone(from *milestone) *scm.Milestone { + return &scm.Milestone{ + Number: from.Number, + ID: from.ID, + Title: from.Title, + Description: from.Description, + Link: from.HTMLURL, + State: from.State, + DueDate: &from.DueOn, + } +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/org.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/org.go index fa79c3508b4..a0429fc0f4a 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/org.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/org.go @@ -40,12 +40,35 @@ type team struct { ParentTeamID *int `json:"parent_team_id,omitempty"` // Only valid in creates/edits } +type pendingInvitations struct { + ID int `json:"id"` + Login string `json:"login"` + Role string `json:"role"` + Inviter inviter `json:"inviter"` +} + +type inviter struct { + ID int `json:"id"` + Login string `json:"login"` +} + type teamMember struct { Login string `json:"login"` } type membership struct { - Role string `json:"role"` + Role string `json:"role"` + State string `json:"state"` + User user `json:"user"` + Organization organization `json:"organization"` +} + +func (s *organizationService) Create(context.Context, *scm.OrganizationInput) (*scm.Organization, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *organizationService) Delete(context.Context, string) (*scm.Response, error) { + return nil, scm.ErrNotSupported } func (s *organizationService) IsMember(ctx context.Context, org string, user string) (bool, *scm.Response, error) { @@ -143,6 +166,64 @@ func (s *organizationService) ListTeamMembers(ctx context.Context, id int, role return convertTeamMembers(out), res, err } +// ListPendingInvitations lists the pending invitations for an organisation +// see https://developer.github.com/v3/orgs/members/#list-pending-organization-invitations +func (s *organizationService) ListPendingInvitations(ctx context.Context, org string, opts scm.ListOptions) ([]*scm.OrganizationPendingInvite, *scm.Response, error) { + req := &scm.Request{ + Method: http.MethodGet, + Path: fmt.Sprintf("orgs/%s/invitations?%s", org, encodeListOptions(opts)), + } + out := []*pendingInvitations{} + res, err := s.client.doRequest(ctx, req, nil, &out) + return convertOrganisationPendingInvites(out), res, err +} + +// ListMemberships lists organisation memberships for the authenticated user +// see https://developer.github.com/v3/orgs/members/#list-organization-memberships-for-the-authenticated-user +func (s *organizationService) ListMemberships(ctx context.Context, opts scm.ListOptions) ([]*scm.Membership, *scm.Response, error) { + req := &scm.Request{ + Method: http.MethodGet, + Path: fmt.Sprintf("/user/memberships/orgs?%s", encodeListOptions(opts)), + } + out := []*membership{} + res, err := s.client.doRequest(ctx, req, nil, &out) + return convertMemberships(out), res, err +} + +// AcceptOrganizationInvitation accepts an invitation for an organisation +func (s *organizationService) AcceptOrganizationInvitation(ctx context.Context, org string) (*scm.Response, error) { + req := &scm.Request{ + Method: http.MethodPatch, + Path: fmt.Sprintf("/user/memberships/orgs/%s", org), + } + values := map[string]string{"state": "active"} + return s.client.doRequest(ctx, req, values, nil) +} + +func convertOrganisationPendingInvites(from []*pendingInvitations) []*scm.OrganizationPendingInvite { + to := []*scm.OrganizationPendingInvite{} + for _, v := range from { + to = append(to, &scm.OrganizationPendingInvite{ + ID: v.ID, + Login: v.Login, + InviterLogin: v.Inviter.Login, + }) + } + return to +} + +func convertMemberships(from []*membership) []*scm.Membership { + to := []*scm.Membership{} + for _, v := range from { + to = append(to, &scm.Membership{ + OrganizationName: v.Organization.Login, + State: v.State, + Role: v.Role, + }) + } + return to +} + func convertOrganizationList(from []*organization) []*scm.Organization { to := []*scm.Organization{} for _, v := range from { diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/pr.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/pr.go index 215c641e712..30ab298d3ba 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/pr.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/pr.go @@ -59,6 +59,13 @@ func (s *pullService) Close(ctx context.Context, repo string, number int) (*scm. return res, err } +func (s *pullService) Reopen(ctx context.Context, repo string, number int) (*scm.Response, error) { + path := fmt.Sprintf("repos/%s/pulls/%d", repo, number) + data := map[string]string{"state": "open"} + res, err := s.client.do(ctx, "PATCH", path, &data, nil) + return res, err +} + func (s *pullService) Create(ctx context.Context, repo string, input *scm.PullRequestInput) (*scm.PullRequest, *scm.Response, error) { path := fmt.Sprintf("repos/%s/pulls", repo) in := &prInput{ @@ -73,6 +80,27 @@ func (s *pullService) Create(ctx context.Context, repo string, input *scm.PullRe return convertPullRequest(out), res, err } +func (s *pullService) Update(ctx context.Context, repo string, number int, input *scm.PullRequestInput) (*scm.PullRequest, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/pulls/%d", repo, number) + in := &prInput{} + if input.Title != "" { + in.Title = input.Title + } + if input.Body != "" { + in.Body = input.Body + } + if input.Head != "" { + in.Head = input.Head + } + if input.Base != "" { + in.Base = input.Base + } + + out := new(pr) + res, err := s.client.do(ctx, "PATCH", path, in, out) + return convertPullRequest(out), res, err +} + func (s *pullService) RequestReview(ctx context.Context, repo string, number int, logins []string) (*scm.Response, error) { _, resp, err := s.tryRequestReview(ctx, repo, number, logins) // At least one invalid user. Try adding them individually. @@ -177,14 +205,6 @@ type prBranch struct { User user `json:"user"` Repo repository `json:"repo"` } -type milestone struct { - Number int `json:"number"` - ID int `json:"id"` - Title string `json:"title"` - Description string `json:"Description"` - Link string `json:"html_url"` - State string `json:"state"` -} type pr struct { Number int `json:"number"` @@ -193,6 +213,7 @@ type pr struct { Body string `json:"body"` Labels []*label `json:"labels"` DiffURL string `json:"diff_url"` + HTMLURL string `json:"html_url"` User user `json:"user"` RequestedReviewers []user `json:"requested_reviewers"` Assignees []user `json:"assignees"` @@ -223,10 +244,10 @@ type file struct { } type prInput struct { - Title string `json:"title"` - Body string `json:"body"` - Head string `json:"head"` - Base string `json:"base"` + Title string `json:"title,omitempty"` + Body string `json:"body,omitempty"` + Head string `json:"head,omitempty"` + Base string `json:"base,omitempty"` } func convertPullRequestList(from []*pr) []*scm.PullRequest { @@ -251,7 +272,8 @@ func convertPullRequest(from *pr) *scm.PullRequest { Fork: from.Head.Repo.FullName, Base: *convertPullRequestBranch(&from.Base), Head: *convertPullRequestBranch(&from.Head), - Link: from.DiffURL, + DiffLink: from.DiffURL, + Link: from.HTMLURL, Closed: from.State != "open", Draft: from.Draft, MergeSha: from.MergeSha, @@ -261,6 +283,7 @@ func convertPullRequest(from *pr) *scm.PullRequest { Rebaseable: from.Rebaseable, Author: *convertUser(&from.User), Assignees: convertUsers(from.Assignees), + Reviewers: convertUsers(from.RequestedReviewers), Created: from.CreatedAt, Updated: from.UpdatedAt, } @@ -298,14 +321,16 @@ func convertChangeList(from []*file) []*scm.Change { func convertChange(from *file) *scm.Change { return &scm.Change{ - Path: from.Filename, - Added: from.Status == "added", - Deleted: from.Status == "deleted", - Renamed: from.Status == "moved", - Additions: from.Additions, - Deletions: from.Deletions, - Changes: from.Changes, - BlobURL: from.BlobURL, - Sha: from.Sha, + Path: from.Filename, + PreviousPath: from.PreviousFilename, + Added: from.Status == "added", + Deleted: from.Status == "deleted", + Renamed: from.Status == "moved", + Patch: from.Patch, + Additions: from.Additions, + Deletions: from.Deletions, + Changes: from.Changes, + BlobURL: from.BlobURL, + Sha: from.Sha, } } diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/release.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/release.go new file mode 100644 index 00000000000..ed43eac0eff --- /dev/null +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/release.go @@ -0,0 +1,131 @@ +package github + +import ( + "context" + "fmt" + "time" + + "github.com/jenkins-x/go-scm/scm" +) + +type releaseService struct { + client *wrapper +} + +type release struct { + ID int `json:"id"` + Title string `json:"name"` + Description string `json:"body"` + Link string `json:"html_url,omitempty"` + Tag string `json:"tag_name,omitempty"` + Commitish string `json:"target_commitish,omitempty"` + Draft bool `json:"draft"` + Prerelease bool `json:"prerelease"` + Created time.Time `json:"created_at"` + Published time.Time `json:"published_at"` +} + +type releaseInput struct { + Title string `json:"name"` + Description string `json:"body"` + Tag string `json:"tag_name"` + Commitish string `json:"target_commitish"` + Draft bool `json:"draft"` + Prerelease bool `json:"prerelease"` +} + +func (s *releaseService) Find(ctx context.Context, repo string, id int) (*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/releases/%d", repo, id) + out := new(release) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertRelease(out), res, err +} + +func (s *releaseService) FindByTag(ctx context.Context, repo string, tag string) (*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/releases/tags/%s", repo, tag) + out := new(release) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertRelease(out), res, err +} + +func (s *releaseService) List(ctx context.Context, repo string, opts scm.ReleaseListOptions) ([]*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/releases?%s", repo, encodeReleaseListOptions(opts)) + out := []*release{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertReleaseList(out), res, err +} + +func (s *releaseService) Create(ctx context.Context, repo string, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/releases", repo) + in := &releaseInput{ + Title: input.Title, + Commitish: input.Commitish, + Description: input.Description, + Draft: input.Draft, + Prerelease: input.Prerelease, + Tag: input.Tag, + } + out := new(release) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertRelease(out), res, err +} + +func (s *releaseService) Delete(ctx context.Context, repo string, id int) (*scm.Response, error) { + path := fmt.Sprintf("repos/%s/releases/%d", repo, id) + return s.client.do(ctx, "DELETE", path, nil, nil) +} + +func (s *releaseService) DeleteByTag(ctx context.Context, repo string, tag string) (*scm.Response, error) { + rel, _, _ := s.FindByTag(ctx, repo, tag) + return s.Delete(ctx, repo, rel.ID) +} + +func (s *releaseService) Update(ctx context.Context, repo string, id int, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/releases/%d", repo, id) + in := &releaseInput{} + if input.Title != "" { + in.Title = input.Title + } + if input.Description != "" { + in.Description = input.Description + } + if input.Commitish != "" { + in.Commitish = input.Commitish + } + if input.Tag != "" { + in.Tag = input.Tag + } + in.Draft = input.Draft + in.Prerelease = input.Prerelease + out := new(release) + res, err := s.client.do(ctx, "PATCH", path, in, out) + return convertRelease(out), res, err +} + +func (s *releaseService) UpdateByTag(ctx context.Context, repo string, tag string, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + rel, _, _ := s.FindByTag(ctx, repo, tag) + return s.Update(ctx, repo, rel.ID, input) +} + +func convertReleaseList(from []*release) []*scm.Release { + var to []*scm.Release + for _, m := range from { + to = append(to, convertRelease(m)) + } + return to +} + +func convertRelease(from *release) *scm.Release { + return &scm.Release{ + ID: from.ID, + Title: from.Title, + Description: from.Description, + Link: from.Link, + Tag: from.Tag, + Commitish: from.Commitish, + Draft: from.Draft, + Prerelease: from.Prerelease, + Created: from.Created, + Published: from.Published, + } +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/repo.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/repo.go index 3c8cf5bce86..e893913020e 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/repo.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/repo.go @@ -24,6 +24,7 @@ type repository struct { Name string `json:"name"` FullName string `json:"full_name"` Private bool `json:"private"` + Archived bool `json:"archived"` Fork bool `json:"fork"` HTMLURL string `json:"html_url"` SSHURL string `json:"ssh_url"` @@ -54,13 +55,48 @@ type hook struct { URL string `json:"url"` Secret string `json:"secret"` ContentType string `json:"content_type"` + InsecureSSL string `json:"insecure_ssl"` } `json:"config"` } +type collaboratorBody struct { + Permission string `json:"permission"` +} + type repositoryService struct { client *wrapper } +// AddCollaborator adds a collaborator to the repo. +// See https://developer.github.com/v3/repos/collaborators/#add-user-as-a-collaborator +func (s *repositoryService) AddCollaborator(ctx context.Context, repo, user, permission string) (bool, bool, *scm.Response, error) { + req := &scm.Request{ + Method: http.MethodPut, + Path: fmt.Sprintf("repos/%s/collaborators/%s", repo, user), + Header: map[string][]string{ + // This accept header enables the nested teams preview. + // https://developer.github.com/changes/2017-08-30-preview-nested-teams/ + "Accept": {"application/vnd.github.hellcat-preview+json"}, + }, + } + body := collaboratorBody{ + Permission: permission, + } + res, err := s.client.doRequest(ctx, req, &body, nil) + if err != nil && res == nil { + return false, false, res, err + } + code := res.Status + if code == 201 { + return true, false, res, nil + } else if code == 204 { + return false, true, res, nil + } else if code == 404 { + return false, false, res, nil + } + return false, false, res, fmt.Errorf("unexpected status: %d", code) +} + // IsCollaborator returns whether or not the user is a collaborator of the repo. // From GitHub's API reference: // For organization-owned repositories, the list of collaborators includes @@ -153,9 +189,17 @@ func (s *repositoryService) FindUserPermission(ctx context.Context, repo string, // List returns the user repository list. func (s *repositoryService) List(ctx context.Context, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { - path := fmt.Sprintf("user/repos?%s", encodeListOptions(opts)) + req := &scm.Request{ + Method: http.MethodGet, + Path: fmt.Sprintf("user/repos?visibility=all&affiliation=owner&%s", encodeListOptions(opts)), + Header: map[string][]string{ + // This accept header enables the visibility parameter. + // https://developer.github.com/changes/2019-12-03-internal-visibility-changes/ + "Accept": {"application/vnd.github.nebula-preview+json"}, + }, + } out := []*repository{} - res, err := s.client.do(ctx, "GET", path, nil, &out) + res, err := s.client.doRequest(ctx, req, nil, &out) return convertRepositoryList(out), res, err } @@ -210,9 +254,9 @@ func (s *repositoryService) ListLabels(ctx context.Context, repo string, opts sc // Create creates a new repository func (s *repositoryService) Create(ctx context.Context, input *scm.RepositoryInput) (*scm.Repository, *scm.Response, error) { - path := "/user/repos" + path := "user/repos" if input.Namespace != "" { - path = fmt.Sprintf("/orgs/%s/repos", input.Namespace) + path = fmt.Sprintf("orgs/%s/repos", input.Namespace) } in := new(repositoryInput) @@ -225,6 +269,23 @@ func (s *repositoryService) Create(ctx context.Context, input *scm.RepositoryInp return convertRepository(out), res, err } +type forkInput struct { + Organization string `json:"organization,omitempty"` +} + +func (s *repositoryService) Fork(ctx context.Context, input *scm.RepositoryInput, origRepo string) (*scm.Repository, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/forks", origRepo) + + in := new(forkInput) + if input.Namespace != "" { + in.Organization = input.Namespace + } + + out := new(repository) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertRepository(out), res, err +} + // CreateHook creates a new repository webhook. func (s *repositoryService) CreateHook(ctx context.Context, repo string, input *scm.HookInput) (*scm.Hook, *scm.Response, error) { path := fmt.Sprintf("repos/%s/hooks", repo) @@ -234,6 +295,11 @@ func (s *repositoryService) CreateHook(ctx context.Context, repo string, input * in.Config.Secret = input.Secret in.Config.ContentType = "json" in.Config.URL = input.Target + if input.SkipVerify { + in.Config.InsecureSSL = "1" + } else { + in.Config.InsecureSSL = "0" + } in.Events = append( input.NativeEvents, convertHookEvents(input.Events)..., @@ -243,6 +309,10 @@ func (s *repositoryService) CreateHook(ctx context.Context, repo string, input * return convertHook(out), res, err } +func (s *repositoryService) UpdateHook(ctx context.Context, repo string, input *scm.HookInput) (*scm.Hook, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + // CreateStatus creates a new commit status. func (s *repositoryService) CreateStatus(ctx context.Context, repo, ref string, input *scm.StatusInput) (*scm.Status, *scm.Response, error) { path := fmt.Sprintf("repos/%s/statuses/%s", repo, ref) @@ -263,12 +333,19 @@ func (s *repositoryService) DeleteHook(ctx context.Context, repo string, id stri return s.client.do(ctx, "DELETE", path, nil, nil) } +func (s *repositoryService) Delete(ctx context.Context, repo string) (*scm.Response, error) { + path := fmt.Sprintf("repos/%s", repo) + return s.client.do(ctx, "DELETE", path, nil, nil) +} + // helper function to convert from the gogs repository list to // the common repository structure. func convertRepositoryList(from []*repository) []*scm.Repository { to := []*scm.Repository{} for _, v := range from { - to = append(to, convertRepository(v)) + if v != nil { + to = append(to, convertRepository(v)) + } } return to } @@ -289,6 +366,7 @@ func convertRepository(from *repository) *scm.Repository { Link: from.HTMLURL, Branch: from.DefaultBranch, Private: from.Private, + Archived: from.Archived, Clone: from.CloneURL, CloneSSH: from.SSHURL, Created: from.CreatedAt, @@ -305,11 +383,18 @@ func convertHookList(from []*hook) []*scm.Hook { } func convertHook(from *hook) *scm.Hook { + + skipVerify := false + if from.Config.InsecureSSL == "1" { + skipVerify = true + } + return &scm.Hook{ - ID: strconv.Itoa(from.ID), - Active: from.Active, - Target: from.Config.URL, - Events: from.Events, + ID: strconv.Itoa(from.ID), + Active: from.Active, + Target: from.Config.URL, + SkipVerify: skipVerify, + Events: from.Events, } } @@ -321,6 +406,9 @@ func convertHookEvents(from scm.HookEvents) []string { if from.PullRequest { events = append(events, "pull_request") } + if from.Review { + events = append(events, "pull_request_review") + } if from.PullRequestComment { events = append(events, "pull_request_review_comment") } @@ -334,6 +422,15 @@ func convertHookEvents(from scm.HookEvents) []string { events = append(events, "create") events = append(events, "delete") } + if from.Deployment { + events = append(events, "deployment") + } + if from.DeploymentStatus { + events = append(events, "deployment_status") + } + if from.Release { + events = append(events, "release") + } return events } @@ -348,6 +445,7 @@ type status struct { UpdatedAt time.Time `json:"updated_at"` State string `json:"state"` TargetURL string `json:"target_url"` + URL string `json:"url"` Description string `json:"description"` Context string `json:"context"` } @@ -384,6 +482,7 @@ func convertStatus(from *status) *scm.Status { Label: from.Context, Desc: from.Description, Target: from.TargetURL, + Link: from.URL, } } diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/review.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/review.go index 0745ffd5bf8..ff0aa88d9f3 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/review.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/review.go @@ -17,26 +17,32 @@ type reviewService struct { } func (s *reviewService) Find(ctx context.Context, repo string, number, id int) (*scm.Review, *scm.Response, error) { - path := fmt.Sprintf("repos/%s/pulls/comments/%d", repo, id) + path := fmt.Sprintf("repos/%s/pulls/%d/reviews/%d", repo, number, id) out := new(review) res, err := s.client.do(ctx, "GET", path, nil, out) return convertReview(out), res, err } func (s *reviewService) List(ctx context.Context, repo string, number int, opts scm.ListOptions) ([]*scm.Review, *scm.Response, error) { - path := fmt.Sprintf("repos/%s/pulls/%d/comments?%s", repo, number, encodeListOptions(opts)) + path := fmt.Sprintf("repos/%s/pulls/%d/reviews?%s", repo, number, encodeListOptions(opts)) out := []*review{} res, err := s.client.do(ctx, "GET", path, nil, &out) return convertReviewList(out), res, err } func (s *reviewService) Create(ctx context.Context, repo string, number int, input *scm.ReviewInput) (*scm.Review, *scm.Response, error) { - path := fmt.Sprintf("repos/%s/pulls/%d/comments", repo, number) + path := fmt.Sprintf("repos/%s/pulls/%d/reviews", repo, number) in := &reviewInput{ Body: input.Body, - Path: input.Path, - Position: input.Line, CommitID: input.Sha, + Event: input.Event, + } + for _, c := range input.Comments { + in.Comments = append(in.Comments, &reviewCommentInput{ + Body: c.Body, + Path: c.Path, + Position: c.Line, + }) } out := new(review) res, err := s.client.do(ctx, "POST", path, in, out) @@ -44,11 +50,53 @@ func (s *reviewService) Create(ctx context.Context, repo string, number int, inp } func (s *reviewService) Delete(ctx context.Context, repo string, number, id int) (*scm.Response, error) { - path := fmt.Sprintf("repos/%s/pulls/comments/%d", repo, id) + path := fmt.Sprintf("repos/%s/pulls/%d/reviews/%d", repo, number, id) return s.client.do(ctx, "DELETE", path, nil, nil) } -type review struct { +func (s *reviewService) ListComments(ctx context.Context, repo string, prID int, reviewID int, options scm.ListOptions) ([]*scm.ReviewComment, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/pulls/%d/reviews/%d/comments?%s", repo, prID, reviewID, encodeListOptions(options)) + out := []*reviewComment{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertReviewCommentList(out), res, err +} + +func (s *reviewService) Update(ctx context.Context, repo string, prID int, reviewID int, body string) (*scm.Review, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/pulls/%d/reviews/%d", repo, prID, reviewID) + in := &reviewUpdateInput{Body: body} + + out := new(review) + res, err := s.client.do(ctx, "PUT", path, in, out) + return convertReview(out), res, err +} + +func (s *reviewService) Submit(ctx context.Context, repo string, prID int, reviewID int, input *scm.ReviewSubmitInput) (*scm.Review, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/pulls/%d/reviews/%d/events", repo, prID, reviewID) + in := &reviewSubmitInput{ + Body: input.Body, + Event: input.Event, + } + + out := new(review) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertReview(out), res, err +} + +func (s *reviewService) Dismiss(ctx context.Context, repo string, prID int, reviewID int, msg string) (*scm.Review, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/pulls/%d/reviews/%d/dismissals", repo, prID, reviewID) + in := &reviewDismissInput{ + Message: msg, + } + if in.Message == "" { + in.Message = "Dismissing" + } + + out := new(review) + res, err := s.client.do(ctx, "PUT", path, in, out) + return convertReview(out), res, err +} + +type reviewComment struct { ID int `json:"id"` CommitID string `json:"commit_id"` Position int `json:"position"` @@ -60,18 +108,50 @@ type review struct { } `json:"user"` Body string `json:"body"` HTMLURL string `json:"html_url"` - State string `json:"state"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } type reviewInput struct { + Body string `json:"body,omitempty"` + CommitID string `json:"commit_id,omitempty"` + Event string `json:"event,omitempty"` + Comments []*reviewCommentInput `json:"comments,omitempty"` +} + +type reviewCommentInput struct { Body string `json:"body"` Path string `json:"path"` - CommitID string `json:"commit_id"` Position int `json:"position"` } +type reviewUpdateInput struct { + Body string `json:"body"` +} + +type reviewSubmitInput struct { + Body string `json:"body"` + Event string `json:"event"` +} + +type reviewDismissInput struct { + Message string `json:"message"` +} + +type review struct { + ID int `json:"id"` + Body string `json:"body"` + User struct { + ID int `json:"id"` + Login string `json:"login"` + AvatarURL string `json:"avatar_url"` + } `json:"user"` + SubmittedAt time.Time `json:"submitted_at"` + CommitID string `json:"commit_id"` + State string `json:"state"` + HTMLURL string `json:"html_url"` +} + func convertReviewList(from []*review) []*scm.Review { to := []*scm.Review{} for _, v := range from { @@ -84,8 +164,6 @@ func convertReview(from *review) *scm.Review { return &scm.Review{ ID: from.ID, Body: from.Body, - Path: from.Path, - Line: from.Position, Link: from.HTMLURL, State: from.State, Sha: from.CommitID, @@ -93,6 +171,30 @@ func convertReview(from *review) *scm.Review { Login: from.User.Login, Avatar: from.User.AvatarURL, }, + Created: from.SubmittedAt, + } +} + +func convertReviewCommentList(from []*reviewComment) []*scm.ReviewComment { + to := []*scm.ReviewComment{} + for _, v := range from { + to = append(to, convertReviewComment(v)) + } + return to +} + +func convertReviewComment(from *reviewComment) *scm.ReviewComment { + return &scm.ReviewComment{ + ID: 0, + Body: from.Body, + Path: from.Path, + Sha: from.CommitID, + Line: from.Position, + Link: from.HTMLURL, + Author: scm.User{ + Login: from.User.Login, + Avatar: from.User.AvatarURL, + }, Created: from.CreatedAt, Updated: from.UpdatedAt, } diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/user.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/user.go index 5c5771d1e4e..a3c638d129a 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/user.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/user.go @@ -17,6 +17,14 @@ type userService struct { client *wrapper } +func (s *userService) CreateToken(context.Context, string, string) (*scm.UserToken, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *userService) DeleteToken(context.Context, int64) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + func (s *userService) Find(ctx context.Context) (*scm.User, *scm.Response, error) { out := new(user) res, err := s.client.do(ctx, "GET", "user", nil, out) @@ -35,6 +43,25 @@ func (s *userService) FindEmail(ctx context.Context) (string, *scm.Response, err return user.Email, res, err } +func (s *userService) ListInvitations(ctx context.Context) ([]*scm.Invitation, *scm.Response, error) { + path := "user/repository_invitations" + out := []*repositoryInvitation{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + if err != nil { + return nil, res, err + } + var invites []*scm.Invitation + for _, orig := range out { + invites = append(invites, convertRepositoryInvitation(orig)) + } + return invites, res, nil +} + +func (s *userService) AcceptInvitation(ctx context.Context, invitationID int64) (*scm.Response, error) { + path := fmt.Sprintf("user/repository_invitations/%d", invitationID) + return s.client.do(ctx, "PATCH", path, nil, nil) +} + type user struct { ID int `json:"id"` Login string `json:"login"` @@ -46,6 +73,30 @@ type user struct { Updated time.Time `json:"updated_at"` } +type repositoryInvitation struct { + ID int64 `json:"id,omitempty"` + Repo repository `json:"repository,omitempty"` + Invitee user `json:"invitee,omitempty"` + Inviter user `json:"inviter,omitempty"` + + Permissions string `json:"permissions,omitempty"` + CreatedAt time.Time `json:"created_at,omitempty"` + URL string `json:"url,omitempty"` + HTMLURL string `json:"html_url,omitempty"` +} + +func convertRepositoryInvitation(from *repositoryInvitation) *scm.Invitation { + return &scm.Invitation{ + ID: from.ID, + Repo: convertRepository(&from.Repo), + Invitee: convertUser(&from.Invitee), + Inviter: convertUser(&from.Inviter), + Permissions: from.Permissions, + Link: from.URL, + Created: from.CreatedAt, + } +} + func convertUser(from *user) *scm.User { if from == nil { return nil diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/util.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/util.go index 718cfce482d..5216147a0e4 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/util.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/util.go @@ -40,6 +40,9 @@ func encodeCommitListOptions(opts scm.CommitListOptions) string { if opts.Ref != "" { params.Set("ref", opts.Ref) } + if opts.Sha != "" { + params.Set("sha", opts.Sha) + } return params.Encode() } @@ -89,6 +92,22 @@ func encodePullRequestListOptions(opts scm.PullRequestListOptions) string { return params.Encode() } +func encodeMilestoneListOptions(opts scm.MilestoneListOptions) string { + params := url.Values{} + if opts.Page != 0 { + params.Set("page", strconv.Itoa(opts.Page)) + } + if opts.Size != 0 { + params.Set("per_page", strconv.Itoa(opts.Size)) + } + if opts.Open && opts.Closed { + params.Set("state", "all") + } else if opts.Closed { + params.Set("state", "closed") + } + return params.Encode() +} + func encodePullRequestMergeOptions(opts *scm.PullRequestMergeOptions) *pullRequestMergeRequest { mr := &pullRequestMergeRequest{} if opts.MergeMethod != "" { @@ -102,3 +121,19 @@ func encodePullRequestMergeOptions(opts *scm.PullRequestMergeOptions) *pullReque } return mr } + +func encodeReleaseListOptions(opts scm.ReleaseListOptions) string { + params := url.Values{} + if opts.Page != 0 { + params.Set("page", strconv.Itoa(opts.Page)) + } + if opts.Size != 0 { + params.Set("per_page", strconv.Itoa(opts.Size)) + } + if opts.Open && opts.Closed { + params.Set("state", "all") + } else if opts.Closed { + params.Set("state", "closed") + } + return params.Encode() +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/webhook.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/webhook.go index a8040dc086c..8e8f79be673 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/github/webhook.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/github/webhook.go @@ -16,7 +16,6 @@ import ( "github.com/jenkins-x/go-scm/pkg/hmac" "github.com/jenkins-x/go-scm/scm" - "github.com/jenkins-x/go-scm/scm/driver/internal/null" "github.com/sirupsen/logrus" ) @@ -45,7 +44,7 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo guid := req.Header.Get("X-GitHub-Delivery") if guid == "" { - return nil, scm.MissingHeader{"X-GitHub-Delivery"} + return nil, scm.MissingHeader{Header: "X-GitHub-Delivery"} } var hook scm.Webhook @@ -68,7 +67,7 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo case "issues": hook, err = s.parseIssueHook(data) case "issue_comment": - hook, err = s.parseIssueCommentHook(data) + hook, err = s.parseIssueCommentHook(data, guid) case "installation", "integration_installation": hook, err = s.parseInstallationHook(data) case "installation_repositories", "integration_installation_repositories": @@ -84,7 +83,7 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo case "pull_request_review": hook, err = s.parsePullRequestReviewHook(data, guid) case "pull_request_review_comment": - hook, err = s.parsePullRequestReviewCommentHook(data) + hook, err = s.parsePullRequestReviewCommentHook(data, guid) case "release": hook, err = s.parseReleaseHook(data) case "repository": @@ -95,7 +94,7 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo hook, err = s.parseWatchHook(data) default: log.WithField("Event", event).Warnf("unknown webhook") - return nil, scm.UnknownWebhook{event} + return nil, scm.UnknownWebhook{Event: event} } if err != nil { return nil, err @@ -330,17 +329,22 @@ func (s *webhookService) parsePullRequestHook(data []byte, guid string) (scm.Web dst.Action = scm.ActionSync case "ready_for_review": dst.Action = scm.ActionReadyForReview + case "converted_to_draft": + dst.Action = scm.ActionConvertedToDraft } return dst, nil } -func (s *webhookService) parsePullRequestReviewCommentHook(data []byte) (scm.Webhook, error) { +func (s *webhookService) parsePullRequestReviewCommentHook(data []byte, guid string) (scm.Webhook, error) { src := new(pullRequestReviewCommentHook) err := json.Unmarshal(data, src) if err != nil { return nil, err } dst := convertPullRequestReviewCommentHook(src) + if dst != nil { + dst.GUID = guid + } return dst, nil } @@ -354,13 +358,16 @@ func (s *webhookService) parseIssueHook(data []byte) (*scm.IssueHook, error) { return dst, nil } -func (s *webhookService) parseIssueCommentHook(data []byte) (*scm.IssueCommentHook, error) { +func (s *webhookService) parseIssueCommentHook(data []byte, guid string) (*scm.IssueCommentHook, error) { src := new(issueCommentHook) err := json.Unmarshal(data, src) if err != nil { return nil, err } dst := convertIssueCommentHook(src) + if dst != nil { + dst.GUID = guid + } return dst, nil } @@ -439,8 +446,9 @@ type ( Installation *installationRef `json:"installation"` } - // github deployment_status payload - deploymentStatusHook struct { + // github deployment webhook payload + deploymentHook struct { + Deployment deployment `json:"deployment"` Action string `json:"action"` Repository repository `json:"repository"` Sender user `json:"sender"` @@ -448,6 +456,17 @@ type ( Installation *installationRef `json:"installation"` } + // github deployment_status payload + deploymentStatusHook struct { + DeploymentStatus deploymentStatus `json:"deployment_status"` + Deployment deployment `json:"deployment"` + Action string `json:"action"` + Repository repository `json:"repository"` + Sender user `json:"sender"` + Label label `json:"label"` + Installation *installationRef `json:"installation"` + } + // github deployment_status payload forkHook struct { Repository repository `json:"repository"` @@ -468,6 +487,7 @@ type ( releaseHook struct { Action string `json:"action"` Repository repository `json:"repository"` + Release release `json:"release"` Sender user `json:"sender"` Label label `json:"label"` Installation *installationRef `json:"installation"` @@ -603,11 +623,11 @@ type ( pullRequestReviewCommentHook struct { // Action see https://developer.github.com/v3/activity/events/types/#pullrequestreviewcommentevent - Action string `json:"action"` - PullRequest pr `json:"pull_request"` - Repository repository `json:"repository"` - Comment reviewComment `json:"comment"` - Installation *installationRef `json:"installation"` + Action string `json:"action"` + PullRequest pr `json:"pull_request"` + Repository repository `json:"repository"` + Comment reviewCommentFromHook `json:"comment"` + Installation *installationRef `json:"installation"` } issueHook struct { @@ -629,16 +649,17 @@ type ( } issueCommentHook struct { - Action string `json:"action"` - Issue issue `json:"issue"` - Repository repository `json:"repository"` - Comment issueComment `json:"comment"` - Sender user `json:"sender"` + Action string `json:"action"` + Issue issue `json:"issue"` + Repository repository `json:"repository"` + Comment issueComment `json:"comment"` + Sender user `json:"sender"` + Installation *installationRef `json:"installation"` } - // reviewComment describes a Pull Request d comment - reviewComment struct { + // reviewCommentFromHook describes a Pull Request d comment + reviewCommentFromHook struct { ID int `json:"id"` ReviewID int `json:"pull_request_review_id"` User user `json:"user"` @@ -652,23 +673,6 @@ type ( Position *int `json:"position"` } - // github deployment webhook payload - deploymentHook struct { - Deployment struct { - Creator user `json:"creator"` - Description null.String `json:"description"` - Environment null.String `json:"environment"` - EnvironmentURL null.String `json:"environment_url"` - Sha null.String `json:"sha"` - Ref null.String `json:"ref"` - Task null.String `json:"task"` - Payload interface{} `json:"payload"` - } `json:"deployment"` - Repository repository `json:"repository"` - Sender user `json:"sender"` - Installation *installationRef `json:"installation"` - } - // installationHook a webhook invoked when the GitHub App is installed installationHook struct { Action string `json:"action"` @@ -844,13 +848,37 @@ func convertCheckSuiteHook(dst *checkSuiteHook) *scm.CheckSuiteHook { } } +func convertDeploymentHook(src *deploymentHook) *scm.DeployHook { + dst := &scm.DeployHook{ + Deployment: *convertDeployment(&src.Deployment, src.Repository.FullName), + Ref: scm.Reference{ + Name: src.Deployment.Ref, + Path: src.Deployment.Ref, + Sha: src.Deployment.Sha, + }, + Action: convertAction(src.Action), + Repo: *convertRepository(&src.Repository), + Sender: *convertUser(&src.Sender), + Label: convertLabel(src.Label), + Installation: convertInstallationRef(src.Installation), + } + if tagRE.MatchString(dst.Ref.Name) { + dst.Ref.Path = scm.ExpandRef(dst.Ref.Path, "refs/tags/") + } else { + dst.Ref.Path = scm.ExpandRef(dst.Ref.Path, "refs/heads/") + } + return dst +} + func convertDeploymentStatusHook(dst *deploymentStatusHook) *scm.DeploymentStatusHook { return &scm.DeploymentStatusHook{ - Action: convertAction(dst.Action), - Repo: *convertRepository(&dst.Repository), - Sender: *convertUser(&dst.Sender), - Label: convertLabel(dst.Label), - Installation: convertInstallationRef(dst.Installation), + Deployment: *convertDeployment(&dst.Deployment, dst.Repository.FullName), + DeploymentStatus: *convertDeploymentStatus(&dst.DeploymentStatus), + Action: convertAction(dst.Action), + Repo: *convertRepository(&dst.Repository), + Sender: *convertUser(&dst.Sender), + Label: convertLabel(dst.Label), + Installation: convertInstallationRef(dst.Installation), } } @@ -876,6 +904,7 @@ func convertReleaseHook(dst *releaseHook) *scm.ReleaseHook { return &scm.ReleaseHook{ Action: convertAction(dst.Action), Repo: *convertRepository(&dst.Repository), + Release: *convertRelease(&dst.Release), Sender: *convertUser(&dst.Sender), Label: convertLabel(dst.Label), Installation: convertInstallationRef(dst.Installation), @@ -980,6 +1009,7 @@ func convertBranchHook(src *createDeleteHook) *scm.BranchHook { ID: fmt.Sprint(src.Repository.ID), Namespace: src.Repository.Owner.Login, Name: src.Repository.Name, + FullName: src.Repository.FullName, Branch: src.Repository.DefaultBranch, Private: src.Repository.Private, Clone: src.Repository.CloneURL, @@ -1000,6 +1030,7 @@ func convertTagHook(src *createDeleteHook) *scm.TagHook { ID: fmt.Sprint(src.Repository.ID), Namespace: src.Repository.Owner.Login, Name: src.Repository.Name, + FullName: src.Repository.FullName, Branch: src.Repository.DefaultBranch, Private: src.Repository.Private, Clone: src.Repository.CloneURL, @@ -1018,6 +1049,7 @@ func convertPullRequestHook(src *pullRequestHook) *scm.PullRequestHook { ID: fmt.Sprint(src.Repository.ID), Namespace: src.Repository.Owner.Login, Name: src.Repository.Name, + FullName: src.Repository.FullName, Branch: src.Repository.DefaultBranch, Private: src.Repository.Private, Clone: src.Repository.CloneURL, @@ -1050,7 +1082,7 @@ func convertLabel(src label) scm.Label { func convertPullRequestReviewHook(src *pullRequestReviewHook) *scm.ReviewHook { return &scm.ReviewHook{ - Action: convertAction(src.Action), + Action: convertReviewAction(src.Action), PullRequest: *convertPullRequest(&src.PullRequest), Repo: *convertRepository(&src.Repository), Review: *convertReview(&src.Review), @@ -1065,6 +1097,7 @@ func convertPullRequestReviewCommentHook(src *pullRequestReviewCommentHook) *scm ID: fmt.Sprint(src.Repository.ID), Namespace: src.Repository.Owner.Login, Name: src.Repository.Name, + FullName: src.Repository.FullName, Branch: src.Repository.DefaultBranch, Private: src.Repository.Private, Clone: src.Repository.CloneURL, @@ -1099,7 +1132,7 @@ func convertIssueCommentHook(dst *issueCommentHook) *scm.IssueCommentHook { } } -func convertPullRequestComment(comment *reviewComment) *scm.Comment { +func convertPullRequestComment(comment *reviewCommentFromHook) *scm.Comment { return &scm.Comment{ ID: comment.ID, Body: comment.Body, @@ -1109,43 +1142,23 @@ func convertPullRequestComment(comment *reviewComment) *scm.Comment { } } -func convertDeploymentHook(src *deploymentHook) *scm.DeployHook { - dst := &scm.DeployHook{ - Data: src.Deployment.Payload, - Desc: src.Deployment.Description.String, - Ref: scm.Reference{ - Name: src.Deployment.Ref.String, - Path: src.Deployment.Ref.String, - Sha: src.Deployment.Sha.String, - }, - Repo: scm.Repository{ - ID: fmt.Sprint(src.Repository.ID), - Namespace: src.Repository.Owner.Login, - Name: src.Repository.Name, - Branch: src.Repository.DefaultBranch, - Private: src.Repository.Private, - Clone: src.Repository.CloneURL, - CloneSSH: src.Repository.SSHURL, - Link: src.Repository.HTMLURL, - }, - Sender: *convertUser(&src.Sender), - Task: src.Deployment.Task.String, - Target: src.Deployment.Environment.String, - TargetURL: src.Deployment.EnvironmentURL.String, - Installation: convertInstallationRef(src.Installation), - } - if tagRE.MatchString(dst.Ref.Name) { - dst.Ref.Path = scm.ExpandRef(dst.Ref.Path, "refs/tags/") - } else { - dst.Ref.Path = scm.ExpandRef(dst.Ref.Path, "refs/heads/") - } - return dst -} - // regexp help determine if the named git object is a tag. // this is not meant to be 100% accurate. var tagRE = regexp.MustCompile("^v?(\\d+).(.+)") +func convertReviewAction(src string) (action scm.Action) { + switch src { + case "submit", "submitted": + return scm.ActionSubmitted + case "edit", "edited": + return scm.ActionEdited + case "dismiss", "dismissed": + return scm.ActionDismissed + default: + return + } +} + func convertAction(src string) (action scm.Action) { switch src { case "create", "created": diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/commit.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/commit.go new file mode 100644 index 00000000000..be54ca40ad3 --- /dev/null +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/commit.go @@ -0,0 +1,99 @@ +package gitlab + +import ( + "context" + "fmt" + "time" + + "github.com/jenkins-x/go-scm/scm" +) + +type commitService struct { + client *wrapper +} + +func (s *commitService) UpdateCommitStatus(ctx context.Context, + repo string, sha string, options scm.CommitStatusUpdateOptions) (*scm.CommitStatus, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/statuses/%s", encode(repo), sha) + + out := new(commitStatus) + opts := convertCommitStatusUpdateOptions(options) + + res, err := s.client.do(ctx, "POST", path, opts, out) + return convertCommitStatus(out), res, err +} + +func convertCommitStatusUpdateOptions(from scm.CommitStatusUpdateOptions) commitStatusUpdateOptions { + return commitStatusUpdateOptions{ + ID: from.ID, + Sha: from.Sha, + State: from.State, + Ref: from.Ref, + Name: from.Name, + TargetURL: from.TargetURL, + Description: from.Description, + Coverage: from.Coverage, + PipelineID: from.PipelineID, + } +} + +func convertCommitStatus(from *commitStatus) *scm.CommitStatus { + return &scm.CommitStatus{ + Status: from.Status, + Created: from.Created, + Started: from.Started, + Name: from.Name, + AllowFailure: from.AllowFailure, + Author: scm.CommitStatusAuthor{ + Username: from.Author.Username, + WebURL: from.Author.WebURL, + AvatarURL: from.Author.AvatarURL, + ID: from.Author.ID, + State: from.Author.State, + Name: from.Author.Name, + }, + Description: from.Description, + Sha: from.Sha, + TargetURL: from.TargetURL, + ID: from.ID, + Ref: from.Ref, + Coverage: from.Coverage, + } +} + +type commitStatusUpdateOptions struct { + ID string `json:"id"` + Sha string `json:"sha"` + State string `json:"state"` + Ref string `json:"ref"` + Name string `json:"name"` + TargetURL string `json:"target_url"` + Description string `json:"description"` + Coverage float64 `json:"coverage"` + PipelineID *int `json:"pipeline_id,omitempty"` +} + +type commitStatus struct { + Status string `json:"status"` + Created time.Time `json:"created_at"` + Started time.Time `json:"updated_at"` + Name string `json:"name"` + AllowFailure bool `json:"allow_failure"` + Author commitStatusAuthor `json:"author"` + Description string `json:"description"` + Sha string `json:"sha"` + TargetURL string `json:"target_url"` + Finished time.Time `json:"finished_at"` + ID int `json:"id"` + Ref string `json:"ref"` + Coverage float64 `json:"coverage"` +} + +type commitStatusAuthor struct { + Username string `json:"username"` + State string `json:"state"` + WebURL string `json:"web_url"` + AvatarURL string `json:"avatar_url"` + ID int `json:"id"` + Name string `json:"name"` +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/content.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/content.go index ca1442cc113..b419ce042f8 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/content.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/content.go @@ -40,15 +40,37 @@ func (s *contentService) Find(ctx context.Context, repo, path, ref string) (*scm } func (s *contentService) List(ctx context.Context, repo, path, ref string) ([]*scm.FileEntry, *scm.Response, error) { - return nil, nil, scm.ErrNotSupported + endpoint := fmt.Sprintf("api/v4/projects/%s/repository/tree?path=%s&ref=%s", encode(repo), path, ref) + out := []*entry{} + res, err := s.client.do(ctx, "GET", endpoint, nil, &out) + return convertEntryList(out), res, err } func (s *contentService) Create(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { - return nil, scm.ErrNotSupported + endpoint := fmt.Sprintf("api/v4/projects/%s/repository/commits", encode(repo)) + + body := &createCommitBody{ + Message: params.Message, + ID: encode(repo), + Branch: params.Branch, + Actions: []createCommitAction{ + {Action: "create", Path: path, Content: params.Data, Encoding: "base64"}, + }, + } + return s.client.do(ctx, "POST", endpoint, &body, nil) } func (s *contentService) Update(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { - return nil, scm.ErrNotSupported + path = url.QueryEscape(path) + path = strings.Replace(path, ".", "%2E", -1) + endpoint := fmt.Sprintf("api/v4/projects/%s/repository/files/%s", encode(repo), path) + + body := &updateContentBody{ + Message: params.Message, + Branch: params.Branch, + Content: string(params.Data), + } + return s.client.do(ctx, "PUT", endpoint, &body, nil) } func (s *contentService) Delete(ctx context.Context, repo, path, ref string) (*scm.Response, error) { @@ -66,3 +88,51 @@ type content struct { CommitID string `json:"commit_id"` LastCommitID string `json:"last_commit_id"` } + +type createCommitAction struct { + Action string `json:"action"` + Path string `json:"file_path"` + Content []byte `json:"content"` + Encoding string `json:"encoding"` +} + +type createCommitBody struct { + Branch string `json:"branch"` + ID string `json:"id"` + Message string `json:"commit_message"` + Actions []createCommitAction `json:"actions"` +} + +type updateContentBody struct { + Branch string `json:"branch"` + Content string `json:"content"` + Message string `json:"commit_message"` +} + +type entry struct { + ID string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` + Path string `json:"path"` + Mode string `json:"mode"` +} + +func convertEntryList(out []*entry) []*scm.FileEntry { + answer := make([]*scm.FileEntry, 0, len(out)) + for _, o := range out { + answer = append(answer, convertEntry(o)) + } + return answer +} + +func convertEntry(from *entry) *scm.FileEntry { + t := "file" + if from.Type == "tree" { + t = "dir" + } + return &scm.FileEntry{ + Name: from.Name, + Path: from.Path, + Type: t, + } +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/git.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/git.go index 00a99e67ee8..c5b5219a1e6 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/git.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/git.go @@ -7,6 +7,7 @@ package gitlab import ( "context" "fmt" + "net/url" "strings" "time" @@ -40,26 +41,48 @@ func (s *gitService) FindRef(ctx context.Context, repo, ref string) (string, *sc } +func (s *gitService) CreateRef(ctx context.Context, repo, ref, sha string) (*scm.Reference, *scm.Response, error) { + params := url.Values{ + "branch": []string{ref}, + "ref": []string{sha}, + } + path := fmt.Sprintf("api/v4/projects/%s/repository/branches?%s", encode(repo), params.Encode()) + + out := &struct { + Name string `json:"name"` + Commit struct { + ID string `json:"id"` + } `json:"commit"` + }{} + + res, err := s.client.do(ctx, "POST", path, nil, out) + scmRef := &scm.Reference{ + Name: out.Name, + Sha: out.Commit.ID, + } + return scmRef, res, err +} + func (s *gitService) DeleteRef(ctx context.Context, repo, ref string) (*scm.Response, error) { return nil, scm.ErrNotSupported } func (s *gitService) FindBranch(ctx context.Context, repo, name string) (*scm.Reference, *scm.Response, error) { - path := fmt.Sprintf("api/v4/projects/%s/repository/branches/%s", encode(repo), name) + path := fmt.Sprintf("api/v4/projects/%s/repository/branches/%s", encode(repo), encode(name)) out := new(branch) res, err := s.client.do(ctx, "GET", path, nil, out) return convertBranch(out), res, err } func (s *gitService) FindCommit(ctx context.Context, repo, ref string) (*scm.Commit, *scm.Response, error) { - path := fmt.Sprintf("api/v4/projects/%s/repository/commits/%s", encode(repo), ref) + path := fmt.Sprintf("api/v4/projects/%s/repository/commits/%s", encode(repo), encode(scm.TrimRef(ref))) out := new(commit) res, err := s.client.do(ctx, "GET", path, nil, out) return convertCommit(out), res, err } func (s *gitService) FindTag(ctx context.Context, repo, name string) (*scm.Reference, *scm.Response, error) { - path := fmt.Sprintf("api/v4/projects/%s/repository/tags/%s", encode(repo), name) + path := fmt.Sprintf("api/v4/projects/%s/repository/tags/%s", encode(repo), encode(name)) out := new(branch) res, err := s.client.do(ctx, "GET", path, nil, out) return convertTag(out), res, err @@ -87,12 +110,25 @@ func (s *gitService) ListTags(ctx context.Context, repo string, opts scm.ListOpt } func (s *gitService) ListChanges(ctx context.Context, repo, ref string, opts scm.ListOptions) ([]*scm.Change, *scm.Response, error) { - path := fmt.Sprintf("api/v4/projects/%s/repository/commits/%s/diff", encode(repo), ref) + path := fmt.Sprintf("api/v4/projects/%s/repository/commits/%s/diff", encode(repo), encode(ref)) out := []*change{} res, err := s.client.do(ctx, "GET", path, nil, &out) return convertChangeList(out), res, err } +func (s *gitService) CompareCommits(ctx context.Context, repo, ref1, ref2 string, opts scm.ListOptions) ([]*scm.Change, *scm.Response, error) { + opts.From = encode(ref1) + opts.To = encode(ref2) + path := fmt.Sprintf("api/v4/projects/%s/repository/compare?%s", encode(repo), encodeListOptions(opts)) + out := compare{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertChangeList(out.Diffs), res, err +} + +type compare struct { + Diffs []*change `json:"diffs"` +} + type branch struct { Name string `json:"name"` Commit struct { @@ -111,6 +147,7 @@ type commit struct { CommitterName string `json:"committer_name"` CommitterEmail string `json:"committer_email"` Created time.Time `json:"created_at"` + URL string `json:"web_url"` } func convertCommitList(from []*commit) []*scm.Commit { @@ -125,6 +162,7 @@ func convertCommit(from *commit) *scm.Commit { return &scm.Commit{ Message: from.Message, Sha: from.ID, + Link: from.URL, Author: scm.Signature{ Login: from.AuthorName, Name: from.AuthorName, diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/gitlab.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/gitlab.go index b7c8880461e..526f3505b10 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/gitlab.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/gitlab.go @@ -9,14 +9,23 @@ import ( "bytes" "context" "encoding/json" + "errors" + "fmt" + "net/http" "net/url" "strconv" "strings" "time" "github.com/jenkins-x/go-scm/scm" + "github.com/shurcooL/graphql" ) +// NewWebHookService creates a new instance of the webhook service without the rest of the client +func NewWebHookService() scm.WebhookService { + return &webhookService{nil, nil} +} + // New returns a new GitLab API client. func New(uri string) (*scm.Client, error) { base, err := url.Parse(uri) @@ -33,15 +42,54 @@ func New(uri string) (*scm.Client, error) { client.Contents = &contentService{client} client.Git = &gitService{client} client.Issues = &issueService{client} + client.Releases = &releaseService{client} + client.Milestones = &milestoneService{client} client.Organizations = &organizationService{client} client.PullRequests = &pullService{client} client.Repositories = &repositoryService{client} client.Reviews = &reviewService{client} - client.Users = &userService{client} - client.Webhooks = &webhookService{client} + client.Commits = &commitService{client} + + //add the user service to the webhook service so it can be used for fetching users + us := &userService{client} + client.Users = us + client.Webhooks = &webhookService{ + client: client, + userService: us, + } + + graphqlEndpoint := scm.URLJoin(uri, "/api/graphql") + client.GraphQLURL, err = url.Parse(graphqlEndpoint) + if err != nil { + return nil, err + } + client.GraphQL = &dynamicGraphQLClient{client, graphqlEndpoint} return client.Client, nil } +type dynamicGraphQLClient struct { + wrapper *wrapper + graphqlEndpoint string +} + +func (d *dynamicGraphQLClient) Query(ctx context.Context, q interface{}, vars map[string]interface{}) error { + httpClient := d.wrapper.Client.Client + if httpClient != nil { + + transport := httpClient.Transport + if transport != nil { + query := graphql.NewClient( + d.graphqlEndpoint, + &http.Client{ + Transport: transport, + }) + return query.Query(ctx, q, vars) + } + } + fmt.Println("WARNING: no http transport configured for GraphQL and Gitlab") + return nil +} + // NewDefault returns a new GitLab API client using the // default gitlab.com address. func NewDefault() *scm.Client { @@ -55,6 +103,30 @@ type wrapper struct { *scm.Client } +type gitlabNamespace struct { + ID int `json:"id"` + Name string `json:"name"` + Path string `json:"path"` + Kind string `json:"kind"` + FullPath string `json:"full_path"` + ParentID int `json:"parent_id"` + MembersCountWithDescendants int `json:"members_count_with_descendants"` +} + +// findNamespaceByName will look up the namespace for the given name +func (c *wrapper) findNamespaceByName(ctx context.Context, name string) (*gitlabNamespace, error) { + in := url.Values{} + in.Set("search", name) + path := fmt.Sprintf("api/v4/namespaces?%s", in.Encode()) + + var out []*gitlabNamespace + _, err := c.do(ctx, "GET", path, nil, &out) + if len(out) > 0 { + return out[0], err + } + return nil, err +} + // do wraps the Client.Do function by creating the Request and // unmarshalling the response. func (c *wrapper) do(ctx context.Context, method, path string, in, out interface{}) (*scm.Response, error) { @@ -100,9 +172,9 @@ func (c *wrapper) do(ctx context.Context, method, path string, in, out interface // if an error is encountered, unmarshal and return the // error response. if res.Status > 300 { - err := new(Error) - json.NewDecoder(res.Body).Decode(err) - return res, err + return res, errors.New( + http.StatusText(res.Status), + ) } if out == nil { diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/issue.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/issue.go index 350a2ef7f57..7595e21ffd3 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/issue.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/issue.go @@ -210,6 +210,12 @@ func (s *issueService) Close(ctx context.Context, repo string, number int) (*scm return res, err } +func (s *issueService) Reopen(ctx context.Context, repo string, number int) (*scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/issues/%d?state_event=reopen", encode(repo), number) + res, err := s.client.do(ctx, "PUT", path, nil, nil) + return res, err +} + func (s *issueService) Lock(ctx context.Context, repo string, number int) (*scm.Response, error) { path := fmt.Sprintf("api/v4/projects/%s/issues/%d?discussion_locked=true", encode(repo), number) res, err := s.client.do(ctx, "PUT", path, nil, nil) @@ -222,6 +228,25 @@ func (s *issueService) Unlock(ctx context.Context, repo string, number int) (*sc return res, err } +func (s *issueService) SetMilestone(ctx context.Context, repo string, issueID int, number int) (*scm.Response, error) { + in := &updateIssueOptions{ + MilestoneID: &number, + } + path := fmt.Sprintf("api/v4/projects/%s/issues/%d", encode(repo), issueID) + + return s.client.do(ctx, "PUT", path, in, nil) +} + +func (s *issueService) ClearMilestone(ctx context.Context, repo string, id int) (*scm.Response, error) { + zeroVal := 0 + in := &updateIssueOptions{ + MilestoneID: &zeroVal, + } + path := fmt.Sprintf("api/v4/projects/%s/issues/%d", encode(repo), id) + + return s.client.do(ctx, "PUT", path, in, nil) +} + type updateIssueOptions struct { Title *string `json:"title,omitempty"` Description *string `json:"description,omitempty"` diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/milestone.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/milestone.go new file mode 100644 index 00000000000..e6956e5553b --- /dev/null +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/milestone.go @@ -0,0 +1,166 @@ +package gitlab + +import ( + "context" + "errors" + "fmt" + "net/url" + "time" + + "github.com/jenkins-x/go-scm/scm" +) + +type milestoneService struct { + client *wrapper +} + +// isoTime represents an ISO 8601 formatted date +type isoTime time.Time + +// ISO 8601 date format +const iso8601 = "2006-01-02" + +// MarshalJSON implements the json.Marshaler interface +func (t isoTime) MarshalJSON() ([]byte, error) { + if y := time.Time(t).Year(); y < 0 || y >= 10000 { + // ISO 8901 uses 4 digits for the years + return nil, errors.New("json: ISOTime year outside of range [0,9999]") + } + + b := make([]byte, 0, len(iso8601)+2) + b = append(b, '"') + b = time.Time(t).AppendFormat(b, iso8601) + b = append(b, '"') + + return b, nil +} + +// UnmarshalJSON implements the json.Unmarshaler interface +func (t *isoTime) UnmarshalJSON(data []byte) error { + // Ignore null, like in the main JSON package + if string(data) == "null" { + return nil + } + + isotime, err := time.Parse(`"`+iso8601+`"`, string(data)) + *t = isoTime(isotime) + + return err +} + +// EncodeValues implements the query.Encoder interface +func (t *isoTime) EncodeValues(key string, v *url.Values) error { + if t == nil || (time.Time(*t)).IsZero() { + return nil + } + v.Add(key, t.String()) + return nil +} + +// String implements the Stringer interface +func (t isoTime) String() string { + return time.Time(t).Format(iso8601) +} + +type milestone struct { + ID int `json:"id"` + IID int `json:"iid"` + ProjectID int `json:"project_id"` + Title string `json:"title"` + Description string `json:"description"` + State string `json:"state"` + DueDate isoTime `json:"due_date"` + StartDate isoTime `json:"start_date"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Expired bool `json:"expired"` +} + +type milestoneInput struct { + Title *string `json:"title"` + StateEvent *string `json:"state_event,omitempty"` + Description *string `json:"description"` + DueDate *isoTime `json:"due_date"` +} + +func (s *milestoneService) Find(ctx context.Context, repo string, id int) (*scm.Milestone, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/milestones/%d", encode(repo), id) + out := new(milestone) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertMilestone(out), res, err +} + +func (s *milestoneService) List(ctx context.Context, repo string, opts scm.MilestoneListOptions) ([]*scm.Milestone, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/milestones?%s", encode(repo), encodeMilestoneListOptions(opts)) + out := []*milestone{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertMilestoneList(out), res, err +} + +func (s *milestoneService) Create(ctx context.Context, repo string, input *scm.MilestoneInput) (*scm.Milestone, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/milestones", encode(repo)) + dueDateIso := isoTime(*input.DueDate) + in := &milestoneInput{ + Title: &input.Title, + Description: &input.Description, + DueDate: &dueDateIso, + } + out := new(milestone) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertMilestone(out), res, err +} + +func (s *milestoneService) Delete(ctx context.Context, repo string, id int) (*scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/milestones/%d", encode(repo), id) + res, err := s.client.do(ctx, "DELETE", path, nil, nil) + return res, err +} + +func (s *milestoneService) Update(ctx context.Context, repo string, id int, input *scm.MilestoneInput) (*scm.Milestone, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/milestones/%d", encode(repo), id) + in := &milestoneInput{} + if input.Title != "" { + in.Title = &input.Title + } + if input.State != "" { + if input.State == "open" { + activate := "activate" + in.StateEvent = &activate + } else { + in.StateEvent = &input.State + } + } + if input.Description != "" { + in.Description = &input.Description + } + if input.DueDate != nil { + dueDateIso := isoTime(*input.DueDate) + in.DueDate = &dueDateIso + } + out := new(milestone) + res, err := s.client.do(ctx, "PATCH", path, in, out) + return convertMilestone(out), res, err +} + +func convertMilestoneList(from []*milestone) []*scm.Milestone { + var to []*scm.Milestone + for _, m := range from { + to = append(to, convertMilestone(m)) + } + return to +} + +func convertMilestone(from *milestone) *scm.Milestone { + if from == nil || from.Title == "" { + return nil + } + dueDate := time.Time(from.DueDate) + return &scm.Milestone{ + Number: from.ID, + ID: from.ID, + Title: from.Title, + Description: from.Description, + State: from.State, + DueDate: &dueDate, + } +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/org.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/org.go index 91b7ce29e6f..8f0e5843ead 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/org.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/org.go @@ -16,19 +16,36 @@ type organizationService struct { client *wrapper } +func (s *organizationService) Create(context.Context, *scm.OrganizationInput) (*scm.Organization, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *organizationService) Delete(context.Context, string) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + func (s *organizationService) IsMember(ctx context.Context, org string, user string) (bool, *scm.Response, error) { - users, res, err := s.ListMemberUsers(ctx, org) - if err != nil { - return false, res, err + var resp *scm.Response + var users []scm.User + var err error + firstRun := false + opts := scm.ListOptions{ + Page: 1, } - member := false - for _, u := range users { - if u.Login == user { - member = true - break + for !firstRun || (resp != nil && opts.Page <= resp.Page.Last) { + users, resp, err = s.ListMemberUsers(ctx, org, opts) + if err != nil { + return false, resp, err + } + firstRun = true + for _, u := range users { + if u.Login == user { + return true, resp, nil + } } + opts.Page++ } - return member, res, err + return false, resp, err } func (s *organizationService) IsAdmin(ctx context.Context, org string, user string) (bool, *scm.Response, error) { @@ -47,7 +64,7 @@ func (s *organizationService) ListTeamMembers(ctx context.Context, id int, role } func (s *organizationService) ListOrgMembers(ctx context.Context, org string, ops scm.ListOptions) ([]*scm.TeamMember, *scm.Response, error) { - users, res, err := s.ListMemberUsers(ctx, org) + users, res, err := s.ListMemberUsers(ctx, org, ops) if err != nil { return nil, res, err } @@ -58,8 +75,8 @@ func (s *organizationService) ListOrgMembers(ctx context.Context, org string, op return members, res, nil } -func (s *organizationService) ListMemberUsers(ctx context.Context, org string) ([]scm.User, *scm.Response, error) { - path := fmt.Sprintf("api/v4/projects/%s/members/all", org) +func (s *organizationService) ListMemberUsers(ctx context.Context, org string, opts scm.ListOptions) ([]scm.User, *scm.Response, error) { + path := fmt.Sprintf("api/v4/groups/%s/members/all?%s", org, encodeListOptions(opts)) out := []*user{} res, err := s.client.do(ctx, "GET", path, nil, &out) return convertUserList(out), res, err @@ -79,7 +96,20 @@ func (s *organizationService) List(ctx context.Context, opts scm.ListOptions) ([ return convertOrganizationList(out), res, err } +func (s *organizationService) ListPendingInvitations(ctx context.Context, org string, opts scm.ListOptions) ([]*scm.OrganizationPendingInvite, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *organizationService) AcceptOrganizationInvitation(ctx context.Context, org string) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + +func (s *organizationService) ListMemberships(ctx context.Context, opts scm.ListOptions) ([]*scm.Membership, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + type organization struct { + ID int `json:"id"` Name string `json:"name"` Path string `json:"path"` Avatar null.String `json:"avatar_url"` @@ -95,6 +125,7 @@ func convertOrganizationList(from []*organization) []*scm.Organization { func convertOrganization(from *organization) *scm.Organization { return &scm.Organization{ + ID: from.ID, Name: from.Path, Avatar: from.Avatar.String, } diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/pr.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/pr.go index f43a97146c7..5275b337de1 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/pr.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/pr.go @@ -9,9 +9,10 @@ import ( "fmt" "net/url" "strconv" - "strings" "time" + "github.com/mitchellh/copystructure" + "github.com/jenkins-x/go-scm/scm" ) @@ -23,7 +24,14 @@ func (s *pullService) Find(ctx context.Context, repo string, number int) (*scm.P path := fmt.Sprintf("api/v4/projects/%s/merge_requests/%d", encode(repo), number) out := new(pr) res, err := s.client.do(ctx, "GET", path, nil, out) - return convertPullRequest(out), res, err + if err != nil { + return nil, res, err + } + convRepo, convRes, err := s.convertPullRequest(ctx, out) + if err != nil { + return nil, convRes, err + } + return convRepo, res, nil } func (s *pullService) FindComment(ctx context.Context, repo string, index, id int) (*scm.Comment, *scm.Response, error) { @@ -37,7 +45,14 @@ func (s *pullService) List(ctx context.Context, repo string, opts scm.PullReques path := fmt.Sprintf("api/v4/projects/%s/merge_requests?%s", encode(repo), encodePullRequestListOptions(opts)) out := []*pr{} res, err := s.client.do(ctx, "GET", path, nil, &out) - return convertPullRequestList(out), res, err + if err != nil { + return nil, res, err + } + convRepos, convRes, err := s.convertPullRequestList(ctx, out) + if err != nil { + return nil, convRes, err + } + return convRepos, res, nil } func (s *pullService) ListChanges(ctx context.Context, repo string, number int, opts scm.ListOptions) ([]*scm.Change, *scm.Response, error) { @@ -71,48 +86,21 @@ func (s *pullService) ListEvents(ctx context.Context, repo string, index int, op } func (s *pullService) AddLabel(ctx context.Context, repo string, number int, label string) (*scm.Response, error) { - existingLabels, _, err := s.ListLabels(ctx, repo, number, scm.ListOptions{}) - if err != nil { - return nil, err - } - - allLabels := map[string]struct{}{} - for _, l := range existingLabels { - allLabels[l.Name] = struct{}{} - } - allLabels[label] = struct{}{} - - labelNames := []string{} - for l := range allLabels { - labelNames = append(labelNames, l) - } + return s.setLabels(ctx, repo, number, label, "add_labels") +} - return s.setLabels(ctx, repo, number, labelNames) +func (s *pullService) DeleteLabel(ctx context.Context, repo string, number int, label string) (*scm.Response, error) { + return s.setLabels(ctx, repo, number, label, "remove_labels") } -func (s *pullService) setLabels(ctx context.Context, repo string, number int, labels []string) (*scm.Response, error) { +func (s *pullService) setLabels(ctx context.Context, repo string, number int, labelsStr string, operation string) (*scm.Response, error) { in := url.Values{} - labelsStr := strings.Join(labels, ",") - in.Set("labels", labelsStr) + in.Set(operation, labelsStr) path := fmt.Sprintf("api/v4/projects/%s/merge_requests/%d?%s", encode(repo), number, in.Encode()) return s.client.do(ctx, "PUT", path, nil, nil) } -func (s *pullService) DeleteLabel(ctx context.Context, repo string, number int, label string) (*scm.Response, error) { - existingLabels, _, err := s.ListLabels(ctx, repo, number, scm.ListOptions{}) - if err != nil { - return nil, err - } - labels := []string{} - for _, l := range existingLabels { - if l.Name != label { - labels = append(labels, l.Name) - } - } - return s.setLabels(ctx, repo, number, labels) -} - func (s *pullService) CreateComment(ctx context.Context, repo string, index int, input *scm.CommentInput) (*scm.Comment, *scm.Response, error) { in := url.Values{} in.Set("body", input.Body) @@ -138,7 +126,7 @@ func (s *pullService) EditComment(ctx context.Context, repo string, number int, func (s *pullService) Merge(ctx context.Context, repo string, number int, options *scm.PullRequestMergeOptions) (*scm.Response, error) { path := fmt.Sprintf("api/v4/projects/%s/merge_requests/%d/merge", encode(repo), number) - res, err := s.client.do(ctx, "PUT", path, nil, nil) + res, err := s.client.do(ctx, "PUT", path, encodePullRequestMergeOptions(options), nil) return res, err } @@ -148,6 +136,12 @@ func (s *pullService) Close(ctx context.Context, repo string, number int) (*scm. return res, err } +func (s *pullService) Reopen(ctx context.Context, repo string, number int) (*scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/merge_requests/%d?state_event=reopen", encode(repo), number) + res, err := s.client.do(ctx, "PUT", path, nil, nil) + return res, err +} + func (s *pullService) AssignIssue(ctx context.Context, repo string, number int, logins []string) (*scm.Response, error) { pr, _, err := s.Find(ctx, repo, number) if err != nil { @@ -226,7 +220,45 @@ func (s *pullService) Create(ctx context.Context, repo string, input *scm.PullRe out := new(pr) res, err := s.client.do(ctx, "POST", path, in, out) - return convertPullRequest(out), res, err + if err != nil { + return nil, res, err + } + convRepo, convRes, err := s.convertPullRequest(ctx, out) + if err != nil { + return nil, convRes, err + } + return convRepo, res, nil +} + +func (s *pullService) Update(ctx context.Context, repo string, number int, input *scm.PullRequestInput) (*scm.PullRequest, *scm.Response, error) { + updateOpts := &updateMergeRequestOptions{} + if input.Title != "" { + updateOpts.Title = &input.Title + } + if input.Body != "" { + updateOpts.Description = &input.Body + } + if input.Base != "" { + updateOpts.TargetBranch = &input.Base + } + return s.updateMergeRequestField(ctx, repo, number, updateOpts) +} + +func (s *pullService) SetMilestone(ctx context.Context, repo string, prID int, number int) (*scm.Response, error) { + updateOpts := &updateMergeRequestOptions{ + MilestoneID: &number, + } + _, res, err := s.updateMergeRequestField(ctx, repo, prID, updateOpts) + return res, err +} + +func (s *pullService) ClearMilestone(ctx context.Context, repo string, prID int) (*scm.Response, error) { + zeroVal := 0 + updateOpts := &updateMergeRequestOptions{ + MilestoneID: &zeroVal, + } + _, res, err := s.updateMergeRequestField(ctx, repo, prID, updateOpts) + return res, err } type updateMergeRequestOptions struct { @@ -249,7 +281,14 @@ func (s *pullService) updateMergeRequestField(ctx context.Context, repo string, out := new(pr) res, err := s.client.do(ctx, "PUT", path, input, out) - return convertPullRequest(out), res, err + if err != nil { + return nil, res, err + } + convRepo, convRes, err := s.convertPullRequest(ctx, out) + if err != nil { + return nil, convRes, err + } + return convRepo, res, nil } type pr struct { @@ -288,6 +327,7 @@ type change struct { Added bool `json:"new_file"` Renamed bool `json:"renamed_file"` Deleted bool `json:"deleted_file"` + Diff string `json:"diff"` } type prInput struct { @@ -297,15 +337,28 @@ type prInput struct { TargetBranch string `json:"target_branch"` } -func convertPullRequestList(from []*pr) []*scm.PullRequest { +type pullRequestMergeRequest struct { + CommitMessage string `json:"merge_commit_message,omitempty"` + SquashCommitMessage string `json:"squash_commit_message,omitempty"` + Squash string `json:"squash,omitempty"` + RemoveSourceBranch string `json:"should_remove_source_branch,omitempty"` + SHA string `json:"sha,omitempty"` + MergeWhenPipelineSucceeds string `json:"merge_when_pipeline_succeeds,omitempty"` +} + +func (s *pullService) convertPullRequestList(ctx context.Context, from []*pr) ([]*scm.PullRequest, *scm.Response, error) { to := []*scm.PullRequest{} for _, v := range from { - to = append(to, convertPullRequest(v)) + converted, res, err := s.convertPullRequest(ctx, v) + if err != nil { + return nil, res, err + } + to = append(to, converted) } - return to + return to, nil, nil } -func convertPullRequest(from *pr) *scm.PullRequest { +func (s *pullService) convertPullRequest(ctx context.Context, from *pr) (*scm.PullRequest, *scm.Response, error) { // Diff refs only seem to be populated in more recent merge requests. Default // to from.Sha for compatibility / consistency, but fallback to HeadSHA if // it's not populated. @@ -320,6 +373,28 @@ func convertPullRequest(from *pr) *scm.PullRequest { for _, a := range from.Assignees { assignees = append(assignees, *convertUser(a)) } + var res *scm.Response + baseRepo, res, err := s.client.Repositories.Find(ctx, strconv.Itoa(from.TargetProjectID)) + if err != nil { + return nil, res, err + } + var headRepo *scm.Repository + if from.TargetProjectID == from.SourceProjectID { + repoCopy, err := copystructure.Copy(baseRepo) + if err != nil { + return nil, nil, err + } + headRepo = repoCopy.(*scm.Repository) + } else { + headRepo, res, err = s.client.Repositories.Find(ctx, strconv.Itoa(from.SourceProjectID)) + if err != nil { + return nil, res, err + } + } + sourceRepo, err := s.getSourceFork(ctx, from) + if err != nil { + return nil, res, err + } return &scm.PullRequest{ Number: from.Number, Title: from.Title, @@ -339,22 +414,29 @@ func convertPullRequest(from *pr) *scm.PullRequest { Author: *convertUser(&from.Author), Assignees: assignees, Head: scm.PullRequestBranch{ - Ref: from.SourceBranch, - Sha: headSHA, - Repo: scm.Repository{ - ID: strconv.Itoa(from.SourceProjectID), - }, + Ref: from.SourceBranch, + Sha: headSHA, + Repo: *headRepo, }, Base: scm.PullRequestBranch{ - Ref: from.TargetBranch, - Sha: from.DiffRefs.BaseSHA, - Repo: scm.Repository{ - ID: strconv.Itoa(from.TargetProjectID), - }, + Ref: from.TargetBranch, + Sha: from.DiffRefs.BaseSHA, + Repo: *baseRepo, }, Created: from.Created, Updated: from.Updated, + Fork: sourceRepo.PathNamespace, + }, nil, nil +} + +func (s *pullService) getSourceFork(ctx context.Context, from *pr) (repository, error) { + path := fmt.Sprintf("api/v4/projects/%d", from.SourceProjectID) + sourceRepo := repository{} + _, err := s.client.do(ctx, "GET", path, nil, &sourceRepo) + if err != nil { + return repository{}, err } + return sourceRepo, nil } func convertPullRequestLabels(from []*string) []*scm.Label { @@ -378,10 +460,12 @@ func convertChangeList(from []*change) []*scm.Change { func convertChange(from *change) *scm.Change { to := &scm.Change{ - Path: from.NewPath, - Added: from.Added, - Deleted: from.Deleted, - Renamed: from.Renamed, + Path: from.NewPath, + PreviousPath: from.OldPath, + Added: from.Added, + Deleted: from.Deleted, + Renamed: from.Renamed, + Patch: from.Diff, } if to.Path == "" { to.Path = from.OldPath diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/release.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/release.go new file mode 100644 index 00000000000..959963f620f --- /dev/null +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/release.go @@ -0,0 +1,111 @@ +package gitlab + +import ( + "context" + "fmt" + + "github.com/jenkins-x/go-scm/scm" +) + +type releaseService struct { + client *wrapper +} + +type release struct { + Title string `json:"name"` + Description string `json:"description"` + Tag string `json:"tag_name"` + Commit struct { + ID string `json:"id"` + } `json:"commit"` +} + +type releaseInput struct { + Title string `json:"name"` + Description string `json:"description"` + Tag string `json:"tag_name"` +} + +func (s *releaseService) Find(ctx context.Context, repo string, id int) (*scm.Release, *scm.Response, error) { + // this could be implemented by List and filter but would be to expensive + panic("gitlab only allows to find a release by tag") +} + +func (s *releaseService) FindByTag(ctx context.Context, repo string, tag string) (*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/releases/%s", encode(repo), tag) + out := new(release) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertRelease(out), res, err +} + +func (s *releaseService) List(ctx context.Context, repo string, opts scm.ReleaseListOptions) ([]*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/releases", encode(repo)) + out := []*release{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertReleaseList(out), res, err +} + +func (s *releaseService) Create(ctx context.Context, repo string, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/releases", encode(repo)) + in := &releaseInput{ + Title: input.Title, + Description: input.Description, + Tag: input.Tag, + } + out := new(release) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertRelease(out), res, err +} + +func (s *releaseService) Delete(ctx context.Context, repo string, id int) (*scm.Response, error) { + // this could be implemented by List and filter but would be to expensive + panic("gitlab only allows to delete a release by tag") +} + +func (s *releaseService) DeleteByTag(ctx context.Context, repo string, tag string) (*scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/releases/%s", encode(repo), tag) + return s.client.do(ctx, "DELETE", path, nil, nil) +} + +func (s *releaseService) Update(ctx context.Context, repo string, id int, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + // this could be implemented by List and filter but would be to expensive + panic("gitlab only allows to update a release by tag") +} + +func (s *releaseService) UpdateByTag(ctx context.Context, repo string, tag string, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/releases/%s", encode(repo), tag) + in := &releaseInput{} + if input.Title != "" { + in.Title = input.Title + } + if input.Description != "" { + in.Description = input.Description + } + if input.Tag != "" { + in.Tag = input.Tag + } + out := new(release) + res, err := s.client.do(ctx, "PUT", path, in, out) + return convertRelease(out), res, err +} + +func convertReleaseList(from []*release) []*scm.Release { + var to []*scm.Release + for _, m := range from { + to = append(to, convertRelease(m)) + } + return to +} + +func convertRelease(from *release) *scm.Release { + return &scm.Release{ + ID: 0, + Title: from.Title, + Description: from.Description, + Link: "", + Tag: from.Tag, + Commitish: from.Commit.ID, + Draft: false, // not supported by gitlab + Prerelease: false, // not supported by gitlab + } +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/repo.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/repo.go index 4207f3919b4..ca136259ab6 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/repo.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/repo.go @@ -14,6 +14,20 @@ import ( "github.com/jenkins-x/go-scm/scm" "github.com/jenkins-x/go-scm/scm/driver/internal/null" + "github.com/pkg/errors" +) + +const ( + noPermissions = 0 + guestPermissions = 10 + reporterPermissions = 20 + developerPermissions = 30 + maintainerPermissions = 40 + ownerPermissions = 50 + + privateVisibility = "private" + internalVisibility = "internal" + publicVisibility = "public" ) type repository struct { @@ -39,6 +53,25 @@ type permissions struct { GroupAccess access `json:"group_access"` } +type memberPermissions struct { + UserID int `json:"user_id"` + AccessLevel int `json:"access_level"` +} + +func stringToAccessLevel(perm string) int { + switch perm { + case scm.AdminPermission: + // owner permission only applies to groups, so fails for projects + return maintainerPermissions + case scm.WritePermission: + return developerPermissions + case scm.ReadPermission: + return guestPermissions + default: + return noPermissions + } +} + func accessLevelToString(level int) string { switch level { case 50: @@ -97,14 +130,71 @@ type repositoryService struct { client *wrapper } -func (s *repositoryService) Create(context.Context, *scm.RepositoryInput) (*scm.Repository, *scm.Response, error) { - return nil, nil, scm.ErrNotSupported +type repositoryInput struct { + Name string `json:"name"` + NamespaceID int `json:"namespace_id"` + Description string `json:"description,omitempty"` + Visibility string `json:"visibility"` } -func (s *repositoryService) FindCombinedStatus(ctx context.Context, repo, ref string) (*scm.CombinedStatus, *scm.Response, error) { - statuses, res, err := s.ListStatus(ctx, repo, ref, scm.ListOptions{}) +func (s *repositoryService) Create(ctx context.Context, input *scm.RepositoryInput) (*scm.Repository, *scm.Response, error) { + namespace, err := s.client.findNamespaceByName(ctx, input.Namespace) if err != nil { - return nil, res, err + return nil, nil, err + } + if namespace == nil { + return nil, nil, fmt.Errorf("no namespace found for %s", input.Namespace) + } + in := new(repositoryInput) + in.Name = input.Name + in.Description = input.Description + in.NamespaceID = namespace.ID + + if input.Private { + in.Visibility = privateVisibility + } else { + in.Visibility = publicVisibility + } + + path := "/api/v4/projects" + out := new(repository) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertRepository(out), res, err +} + +type forkInput struct { + Namespace string `json:"namespace_path,omitempty"` + Name string `json:"name,omitempty"` +} + +func (s *repositoryService) Fork(ctx context.Context, input *scm.RepositoryInput, origRepo string) (*scm.Repository, *scm.Response, error) { + in := new(forkInput) + in.Name = input.Name + in.Namespace = input.Namespace + + path := fmt.Sprintf("/api/v4/projects/%s/fork", encode(origRepo)) + out := new(repository) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertRepository(out), res, err +} + +func (s *repositoryService) FindCombinedStatus(ctx context.Context, repo, ref string) (*scm.CombinedStatus, *scm.Response, error) { + var resp *scm.Response + var statuses []*scm.Status + var statusesByPage []*scm.Status + var err error + firstRun := false + opts := scm.ListOptions{ + Page: 1, + } + for !firstRun || (resp != nil && opts.Page <= resp.Page.Last) { + statusesByPage, resp, err = s.ListStatus(ctx, repo, ref, opts) + if err != nil { + return nil, resp, err + } + statuses = append(statuses, statusesByPage...) + firstRun = true + opts.Page++ } combinedState := scm.StateUnknown @@ -120,33 +210,75 @@ func (s *repositoryService) FindCombinedStatus(ctx context.Context, repo, ref st State: combinedState, Sha: ref, Statuses: statuses, - }, res, err + }, resp, err } func (s *repositoryService) FindUserPermission(ctx context.Context, repo string, user string) (string, *scm.Response, error) { - path := fmt.Sprintf("api/v4/projects/%s/members/all", encode(repo)) - out := []*member{} - res, err := s.client.do(ctx, "GET", path, nil, &out) - if err != nil { - return scm.NoPermission, res, err - } - for _, u := range out { - if u.Username == user { - return accessLevelToString(u.AccessLevel), res, nil + var resp *scm.Response + var err error + firstRun := false + opts := scm.ListOptions{ + Page: 1, + } + for !firstRun || (resp != nil && opts.Page <= resp.Page.Last) { + path := fmt.Sprintf("api/v4/projects/%s/members/all?%s", encode(repo), encodeListOptions(opts)) + out := []*member{} + resp, err = s.client.do(ctx, "GET", path, nil, &out) + if err != nil { + return scm.NoPermission, resp, err } + firstRun = true + for _, u := range out { + if u.Username == user { + return accessLevelToString(u.AccessLevel), resp, nil + } + } + opts.Page++ } - return scm.NoPermission, res, nil + return scm.NoPermission, resp, nil } -func (s *repositoryService) IsCollaborator(ctx context.Context, repo, user string) (bool, *scm.Response, error) { - users, resp, err := s.ListCollaborators(ctx, repo, scm.ListOptions{}) +func (s *repositoryService) AddCollaborator(ctx context.Context, repo, username, permission string) (bool, bool, *scm.Response, error) { + userData, _, err := s.client.Users.FindLogin(ctx, username) + if err != nil { + return false, false, nil, errors.Wrapf(err, "couldn't look up ID for user %s", username) + } + if userData == nil { + return false, false, nil, fmt.Errorf("no user for %s found", username) + } + path := fmt.Sprintf("api/v4/projects/%s/members", encode(repo)) + out := new(user) + in := &memberPermissions{ + UserID: userData.ID, + AccessLevel: stringToAccessLevel(permission), + } + res, err := s.client.do(ctx, "POST", path, in, &out) if err != nil { - return false, resp, err + return false, false, res, err } - for _, u := range users { - if u.Name == user || u.Login == user { - return true, resp, err + return true, false, res, nil +} + +func (s *repositoryService) IsCollaborator(ctx context.Context, repo, user string) (bool, *scm.Response, error) { + var resp *scm.Response + var users []scm.User + var err error + firstRun := false + opts := scm.ListOptions{ + Page: 1, + } + for !firstRun || (resp != nil && opts.Page <= resp.Page.Last) { + users, resp, err = s.ListCollaborators(ctx, repo, opts) + if err != nil { + return false, resp, err } + firstRun = true + for _, u := range users { + if u.Name == user || u.Login == user { + return true, resp, err + } + } + opts.Page++ } return false, resp, err } @@ -224,25 +356,34 @@ func (s *repositoryService) CreateHook(ctx context.Context, repo string, input * if input.SkipVerify { params.Set("enable_ssl_verification", "true") } + hasStarEvents := false + for _, event := range input.NativeEvents { + if event == "*" { + hasStarEvents = true + } + } if input.Events.Branch { // no-op } - if input.Events.Issue { + if input.Events.Issue || hasStarEvents { params.Set("issues_events", "true") } if input.Events.IssueComment || - input.Events.PullRequestComment { + input.Events.PullRequestComment || hasStarEvents { params.Set("note_events", "true") } - if input.Events.PullRequest { + if input.Events.PullRequest || hasStarEvents { params.Set("merge_requests_events", "true") } - if input.Events.Push || input.Events.Branch { + if input.Events.Push || input.Events.Branch || hasStarEvents { params.Set("push_events", "true") } - if input.Events.Tag { + if input.Events.Tag || hasStarEvents { params.Set("tag_push_events", "true") } + if input.Events.Release || hasStarEvents { + params.Set("releases_events", "true") + } path := fmt.Sprintf("api/v4/projects/%s/hooks?%s", encode(repo), params.Encode()) out := new(hook) @@ -250,13 +391,72 @@ func (s *repositoryService) CreateHook(ctx context.Context, repo string, input * return convertHook(out), res, err } +func (s *repositoryService) UpdateHook(ctx context.Context, repo string, input *scm.HookInput) (*scm.Hook, *scm.Response, error) { + params := url.Values{} + hookID := input.Name + params.Set("url", input.Target) + if input.Secret != "" { + params.Set("token", input.Secret) + } + if input.SkipVerify { + params.Set("enable_ssl_verification", "true") + } + hasStarEvents := false + for _, event := range input.NativeEvents { + if event == "*" { + hasStarEvents = true + } + } + if input.Events.Branch { + // no-op + } + if input.Events.Issue || hasStarEvents { + params.Set("issues_events", "true") + } else { + params.Set("issues_events", "false") + } + if input.Events.IssueComment || + input.Events.PullRequestComment || hasStarEvents { + params.Set("note_events", "true") + } else { + params.Set("note_events", "false") + } + if input.Events.PullRequest || hasStarEvents { + params.Set("merge_requests_events", "true") + } else { + params.Set("merge_requests_events", "false") + } + if input.Events.Push || input.Events.Branch || hasStarEvents { + params.Set("push_events", "true") + } else { + params.Set("push_events", "false") + } + if input.Events.Tag || hasStarEvents { + params.Set("tag_push_events", "true") + } else { + params.Set("tag_push_events", "false") + } + + path := fmt.Sprintf("api/v4/projects/%s/hooks/%s?%s", encode(repo), hookID, params.Encode()) + out := new(hook) + res, err := s.client.do(ctx, "PUT", path, nil, out) + return convertHook(out), res, err +} + func (s *repositoryService) CreateStatus(ctx context.Context, repo, ref string, input *scm.StatusInput) (*scm.Status, *scm.Response, error) { params := url.Values{} params.Set("state", convertFromState(input.State)) params.Set("name", input.Label) params.Set("target_url", input.Target) params.Set("description", input.Desc) - path := fmt.Sprintf("api/v4/projects/%s/statuses/%s?%s", encode(repo), ref, params.Encode()) + var repoID string + // TODO to add a cache to reduce unnecessary network request + if repository, response, err := s.Find(ctx, repo); err == nil { + repoID = repository.ID + } else { + return nil, response, errors.Errorf("cannot found repository %s, %v", repo, err) + } + path := fmt.Sprintf("api/v4/projects/%s/statuses/%s?%s", repoID, ref, params.Encode()) out := new(status) res, err := s.client.do(ctx, "POST", path, nil, out) return convertStatus(out), res, err @@ -267,6 +467,10 @@ func (s *repositoryService) DeleteHook(ctx context.Context, repo string, id stri return s.client.do(ctx, "DELETE", path, nil, nil) } +func (s *repositoryService) Delete(context.Context, string) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + // helper function to convert from the gogs repository list to // the common repository structure. func convertRepositoryList(from []*repository) []*scm.Repository { @@ -284,10 +488,12 @@ func convertRepository(from *repository) *scm.Repository { ID: strconv.Itoa(from.ID), Namespace: from.Namespace.Path, Name: from.Path, + FullName: from.PathNamespace, Branch: from.DefaultBranch, Private: convertPrivate(from.Visibility), Clone: from.HTTPURL, CloneSSH: from.SSHURL, + Link: from.WebURL, Perm: &scm.Perm{ Pull: true, Push: canPush(from), diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/review.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/review.go index 3baf4346fca..a9677b4bb98 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/review.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/review.go @@ -29,3 +29,19 @@ func (s *reviewService) Create(ctx context.Context, repo string, number int, inp func (s *reviewService) Delete(ctx context.Context, repo string, number, id int) (*scm.Response, error) { return nil, scm.ErrNotSupported } + +func (s *reviewService) ListComments(ctx context.Context, repo string, prID int, reviewID int, options scm.ListOptions) ([]*scm.ReviewComment, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *reviewService) Update(ctx context.Context, repo string, prID int, reviewID int, body string) (*scm.Review, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *reviewService) Submit(ctx context.Context, repo string, prID int, reviewID int, input *scm.ReviewSubmitInput) (*scm.Review, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *reviewService) Dismiss(ctx context.Context, repo string, prID int, reviewID int, msg string) (*scm.Review, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/user.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/user.go index ca294fafc93..f1b6c69f57b 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/user.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/user.go @@ -7,6 +7,7 @@ package gitlab import ( "context" "fmt" + "net/http" "strings" "github.com/jenkins-x/go-scm/scm" @@ -17,6 +18,14 @@ type userService struct { client *wrapper } +func (s *userService) CreateToken(context.Context, string, string) (*scm.UserToken, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *userService) DeleteToken(context.Context, int64) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + func (s *userService) Find(ctx context.Context) (*scm.User, *scm.Response, error) { out := new(user) res, err := s.client.do(ctx, "GET", "api/v4/user", nil, out) @@ -24,16 +33,42 @@ func (s *userService) Find(ctx context.Context) (*scm.User, *scm.Response, error } func (s *userService) FindLogin(ctx context.Context, login string) (*scm.User, *scm.Response, error) { - path := fmt.Sprintf("api/v4/users?search=%s", login) - out := []*user{} - res, err := s.client.do(ctx, "GET", path, nil, &out) + var resp *scm.Response + var err error + firstRun := false + opts := scm.ListOptions{ + Page: 1, + } + for !firstRun || (resp != nil && opts.Page <= resp.Page.Last) { + out := []*user{} + path := fmt.Sprintf("api/v4/users?search=%s&%s", login, encodeListOptions(opts)) + resp, err = s.client.do(ctx, "GET", path, nil, &out) + if err != nil { + return nil, nil, err + } + firstRun = true + for _, u := range out { + if strings.EqualFold(u.Username, login) { + return convertUser(u), resp, err + } + } + opts.Page++ + } + return nil, resp, scm.ErrNotFound +} + +// FindLoginByID returns the scm.User object for the specified user id +func (s *userService) FindLoginByID(ctx context.Context, id int) (*scm.User, error) { + path := fmt.Sprintf("api/v4/users/%d", id) + out := &user{} + resp, err := s.client.do(ctx, "GET", path, nil, &out) if err != nil { - return nil, nil, err + return nil, err } - if len(out) != 1 || !strings.EqualFold(out[0].Username, login) { - return nil, nil, scm.ErrNotFound + if resp.Status == http.StatusOK { + return convertUser(out), err } - return convertUser(out[0]), res, err + return nil, scm.ErrNotFound } func (s *userService) FindEmail(ctx context.Context) (string, *scm.Response, error) { @@ -41,6 +76,14 @@ func (s *userService) FindEmail(ctx context.Context) (string, *scm.Response, err return user.Email, res, err } +func (s *userService) ListInvitations(context.Context) ([]*scm.Invitation, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *userService) AcceptInvitation(context.Context, int64) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + type user struct { ID int `json:"id"` Username string `json:"username"` diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/util.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/util.go index be220a5d77f..6ede52ca455 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/util.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/util.go @@ -24,6 +24,12 @@ func encodeListOptions(opts scm.ListOptions) string { if opts.Size != 0 { params.Set("per_page", strconv.Itoa(opts.Size)) } + if opts.From != "" { + params.Set("from", opts.From) + } + if opts.To != "" { + params.Set("to", opts.To) + } return params.Encode() } @@ -71,6 +77,22 @@ func encodeIssueListOptions(opts scm.IssueListOptions) string { return params.Encode() } +func encodeMilestoneListOptions(opts scm.MilestoneListOptions) string { + params := url.Values{} + if opts.Page != 0 { + params.Set("page", strconv.Itoa(opts.Page)) + } + if opts.Size != 0 { + params.Set("per_page", strconv.Itoa(opts.Size)) + } + if opts.Closed && !opts.Open { + params.Set("state", "closed") + } else if opts.Open && !opts.Closed { + params.Set("state", "active") + } + return params.Encode() +} + func encodePullRequestListOptions(opts scm.PullRequestListOptions) string { params := url.Values{} if opts.Page != 0 { @@ -104,6 +126,35 @@ func encodePullRequestListOptions(opts scm.PullRequestListOptions) string { return params.Encode() } +func encodePullRequestMergeOptions(opts *scm.PullRequestMergeOptions) *pullRequestMergeRequest { + var prRequest *pullRequestMergeRequest + if opts != nil { + prRequest = &pullRequestMergeRequest{} + if opts.SHA != "" { + prRequest.SHA = opts.SHA + } + switch opts.MergeMethod { + case "squash": + if opts.CommitTitle != "" { + prRequest.SquashCommitMessage = opts.CommitTitle + } + prRequest.Squash = "true" + default: + if opts.CommitTitle != "" { + prRequest.CommitMessage = opts.CommitTitle + } + } + if opts.MergeWhenPipelineSucceeds { + prRequest.MergeWhenPipelineSucceeds = "true" + } + if opts.DeleteSourceBranch { + prRequest.RemoveSourceBranch = "true" + } + + } + return prRequest +} + func gitlabStateToSCMState(glState string) string { switch glState { case "opened": diff --git a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/webhook.go b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/webhook.go index cfe4b5211b7..980192efe93 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/webhook.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/driver/gitlab/webhook.go @@ -5,6 +5,8 @@ package gitlab import ( + "context" + "crypto/subtle" "encoding/json" "fmt" "io" @@ -18,6 +20,13 @@ import ( type webhookService struct { client *wrapper + //need the user service as well + userService webhookUserService +} + +// an interface to provide a find login by id in gitlab +type webhookUserService interface { + FindLoginByID(ctx context.Context, id int) (*scm.User, error) } func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhook, error) { @@ -34,13 +43,15 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo case "Push Hook", "Tag Push Hook": hook, err = parsePushHook(data) case "Issue Hook": - return nil, scm.UnknownWebhook{event} + return nil, scm.UnknownWebhook{Event: event} case "Merge Request Hook": hook, err = parsePullRequestHook(data) case "Note Hook": - hook, err = parseCommentHook(data) + hook, err = parseCommentHook(s, data) + case "Release Hook": + hook, err = parseReleaseHook(s, data) default: - return nil, scm.UnknownWebhook{event} + return nil, scm.UnknownWebhook{Event: event} } if err != nil { return nil, err @@ -56,10 +67,9 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo return hook, nil } - if token != req.Header.Get("X-Gitlab-Token") { + if subtle.ConstantTimeCompare([]byte(req.Header.Get("X-Gitlab-Token")), []byte(token)) == 0 { return hook, scm.ErrSignatureInvalid } - return hook, nil } @@ -103,7 +113,7 @@ func parsePullRequestHook(data []byte) (scm.Webhook, error) { case "open", "close", "reopen", "merge", "update": // no-op default: - return nil, scm.UnknownWebhook{event} + return nil, scm.UnknownWebhook{Event: event} } switch { default: @@ -111,7 +121,7 @@ func parsePullRequestHook(data []byte) (scm.Webhook, error) { } } -func parseCommentHook(data []byte) (scm.Webhook, error) { +func parseCommentHook(s *webhookService, data []byte) (scm.Webhook, error) { src := new(commentHook) err := json.Unmarshal(data, src) if err != nil { @@ -123,17 +133,29 @@ func parseCommentHook(data []byte) (scm.Webhook, error) { kind := src.ObjectAttributes.NoteableType switch kind { case "MergeRequest": - return convertMergeRequestCommentHook(src), nil + return convertMergeRequestCommentHook(s, src) + case "Issue": + return convertIssueCommentHook(s, src) default: - return nil, scm.UnknownWebhook{kind} + return nil, scm.UnknownWebhook{Event: kind} } } +func parseReleaseHook(s *webhookService, data []byte) (scm.Webhook, error) { + src := new(releaseHook) + err := json.Unmarshal(data, src) + if err != nil { + return nil, err + } + return convertReleaseHook(src) +} + func convertPushHook(src *pushHook) *scm.PushHook { repo := *convertRepositoryHook(&src.Project) dst := &scm.PushHook{ - Ref: scm.ExpandRef(src.Ref, "refs/heads/"), - Repo: repo, + Ref: scm.ExpandRef(src.Ref, "refs/heads/"), + Repo: repo, + After: src.After, Commit: scm.Commit{ Sha: src.CheckoutSha, Message: "", // NOTE this is set below @@ -159,8 +181,9 @@ func convertPushHook(src *pushHook) *scm.PushHook { }, } if len(src.Commits) > 0 { - dst.Commit.Message = src.Commits[0].Message - dst.Commit.Link = src.Commits[0].URL + // get the last commit (most recent) + dst.Commit.Message = src.Commits[len(src.Commits)-1].Message + dst.Commit.Link = src.Commits[len(src.Commits)-1].URL } return dst } @@ -253,6 +276,7 @@ func convertPullRequestHook(src *pullRequestHook) *scm.PullRequestHook { Link: src.ObjectAttributes.URL, Closed: src.ObjectAttributes.State != "opened", Merged: src.ObjectAttributes.State == "merged", + MergeSha: src.ObjectAttributes.MergeCommitSha, // Created : src.ObjectAttributes.CreatedAt, // Updated : src.ObjectAttributes.UpdatedAt, // 2017-12-10 17:01:11 UTC Author: scm.User{ @@ -264,6 +288,13 @@ func convertPullRequestHook(src *pullRequestHook) *scm.PullRequestHook { } pr.Base.Repo = *convertRepositoryHook(src.ObjectAttributes.Target) pr.Head.Repo = *convertRepositoryHook(src.ObjectAttributes.Source) + changes := scm.PullRequestHookChanges{ + Base: scm.PullRequestHookBranch{ + Sha: scm.PullRequestHookBranchFrom{ + From: src.ObjectAttributes.OldRev, + }, + }, + } return &scm.PullRequestHook{ Action: action, PullRequest: pr, @@ -274,16 +305,59 @@ func convertPullRequestHook(src *pullRequestHook) *scm.PullRequestHook { Email: "", // TODO how do we get the pull request author email? Avatar: src.User.AvatarURL, }, + Changes: changes, + } +} + +func convertIssueCommentHook(s *webhookService, src *commentHook) (*scm.IssueCommentHook, error) { + commentAuthor, err := s.userService.FindLoginByID(context.TODO(), src.ObjectAttributes.AuthorID) + if err != nil { + return nil, fmt.Errorf("unable to find comment author %w", err) + } + + repo := *convertRepositoryHook(&src.Project) + createdAt, _ := time.Parse("2006-01-02 15:04:05 MST", src.ObjectAttributes.CreatedAt) + updatedAt, _ := time.Parse("2006-01-02 15:04:05 MST", src.ObjectAttributes.UpdatedAt) + + issue := scm.Issue{ + Number: src.Issue.Iid, + Title: src.Issue.Title, + Body: src.Issue.Description, + Author: *commentAuthor, + Created: createdAt, + Updated: updatedAt, + Closed: src.Issue.State != "opened", + PullRequest: false, + } + + hook := &scm.IssueCommentHook{ + Action: scm.ActionCreate, + Repo: repo, + Issue: issue, + Comment: scm.Comment{ + ID: src.ObjectAttributes.ID, + Body: src.ObjectAttributes.Note, + Author: *commentAuthor, + Created: createdAt, + Updated: updatedAt, + }, + Sender: *commentAuthor, } + return hook, nil } -func convertMergeRequestCommentHook(src *commentHook) *scm.PullRequestCommentHook { - user := scm.User{ - ID: src.ObjectAttributes.AuthorID, - Login: src.User.Username, - Name: src.User.Name, - Email: "", // TODO how do we get the pull request author email? - Avatar: src.User.AvatarURL, +func convertMergeRequestCommentHook(s *webhookService, src *commentHook) (*scm.PullRequestCommentHook, error) { + + // There are two users needed here: the comment author and the MergeRequest author. + // Since we only have the user name, we need to use the user service to fetch these. + commentAuthor, err := s.userService.FindLoginByID(context.TODO(), src.ObjectAttributes.AuthorID) + if err != nil { + return nil, fmt.Errorf("unable to find comment author %w", err) + } + + mrAuthor, err := s.userService.FindLoginByID(context.TODO(), src.MergeRequest.AuthorID) + if err != nil { + return nil, fmt.Errorf("unable to find mr author %w", err) } fork := scm.Join( @@ -297,8 +371,8 @@ func convertMergeRequestCommentHook(src *commentHook) *scm.PullRequestCommentHoo sha := src.MergeRequest.LastCommit.ID // Mon Jan 2 15:04:05 -0700 MST 2006 - created_pr_at, _ := time.Parse("2006-01-02 15:04:05 MST", src.MergeRequest.CreatedAt) - updated_pr_at, _ := time.Parse("2006-01-02 15:04:05 MST", src.MergeRequest.UpdatedAt) + prCreatedAt, _ := time.Parse("2006-01-02 15:04:05 MST", src.MergeRequest.CreatedAt) + prUpdatedAt, _ := time.Parse("2006-01-02 15:04:05 MST", src.MergeRequest.UpdatedAt) pr := scm.PullRequest{ Number: src.MergeRequest.Iid, Title: src.MergeRequest.Title, @@ -319,29 +393,30 @@ func convertMergeRequestCommentHook(src *commentHook) *scm.PullRequestCommentHoo Link: src.MergeRequest.URL, Closed: src.MergeRequest.State != "opened", Merged: src.MergeRequest.State == "merged", - Created: created_pr_at, - Updated: updated_pr_at, // 2017-12-10 17:01:11 UTC - Author: user, + Created: prCreatedAt, + Updated: prUpdatedAt, // 2017-12-10 17:01:11 UTC + Author: *mrAuthor, } pr.Base.Repo = *convertRepositoryHook(src.MergeRequest.Target) pr.Head.Repo = *convertRepositoryHook(src.MergeRequest.Source) - created_at, _ := time.Parse("2006-01-02 15:04:05 MST", src.ObjectAttributes.CreatedAt) - updated_at, _ := time.Parse("2006-01-02 15:04:05 MST", src.ObjectAttributes.UpdatedAt) + createdAt, _ := time.Parse("2006-01-02 15:04:05 MST", src.ObjectAttributes.CreatedAt) + updatedAt, _ := time.Parse("2006-01-02 15:04:05 MST", src.ObjectAttributes.UpdatedAt) - return &scm.PullRequestCommentHook{ + hook := &scm.PullRequestCommentHook{ Action: scm.ActionCreate, Repo: repo, PullRequest: pr, Comment: scm.Comment{ ID: src.ObjectAttributes.ID, Body: src.ObjectAttributes.Note, - Author: user, // TODO: is the user the author id ?? - Created: created_at, - Updated: updated_at, + Author: *commentAuthor, + Created: createdAt, + Updated: updatedAt, }, - Sender: user, + Sender: *commentAuthor, } + return hook, nil } func convertRepositoryHook(from *project) *scm.Repository { @@ -350,6 +425,7 @@ func convertRepositoryHook(from *project) *scm.Repository { ID: strconv.Itoa(from.ID), Namespace: namespace, Name: name, + FullName: from.PathWithNamespace, Clone: from.GitHTTPURL, CloneSSH: from.GitSSHURL, Link: from.WebURL, @@ -358,6 +434,43 @@ func convertRepositoryHook(from *project) *scm.Repository { } } +func convertReleaseHook(from *releaseHook) (*scm.ReleaseHook, error) { + created, err := time.Parse("2006-01-02 15:04:05 MST", from.CreatedAt) + if err != nil { + return nil, err + } + released, err := time.Parse("2006-01-02 15:04:05 MST", from.ReleasedAt) + if err != nil { + return nil, err + } + + return &scm.ReleaseHook{ + Action: convertAction(from.Action), + Repo: *convertRepositoryHook(&from.Project), + Release: scm.Release{ + ID: from.ID, + Title: from.Name, + Description: from.Description, + Link: from.URL, + Tag: from.Tag, + Commitish: from.Commit.ID, + Created: created, + Published: released, + }, + }, nil +} + +func convertAction(src string) (action scm.Action) { + switch src { + case "create": + return scm.ActionCreate + case "open": + return scm.ActionOpen + default: + return + } +} + type ( project struct { ID int `json:"id"` @@ -497,7 +610,7 @@ type ( Iid int `json:"iid"` LastEditedAt interface{} `json:"last_edited_at"` LastEditedByID interface{} `json:"last_edited_by_id"` - MergeCommitSha interface{} `json:"merge_commit_sha"` + MergeCommitSha string `json:"merge_commit_sha"` MergeError interface{} `json:"merge_error"` MergeParams struct { ForceRemoveSourceBranch string `json:"force_remove_source_branch"` @@ -533,6 +646,34 @@ type ( HumanTotalTimeSpent interface{} `json:"human_total_time_spent"` HumanTimeEstimate interface{} `json:"human_time_estimate"` } `json:"merge_request"` + Issue struct { + ID int `json:"id"` + Title string `json:"title"` + AssigneeIDs []string `json:"assignee_ids"` + AssigneeID string `json:"assignee_id"` + AuthorID int `json:"author_id"` + ProjectID int `json:"project_id"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + Position int `json:"position"` + BranchName string `json:"branch_name"` + Description string `json:"description"` + MilestoneID string `json:"milestone_id"` + State string `json:"state"` + Iid int `json:"iid"` + Labels []struct { + ID int `json:"id"` + Title string `json:"title"` + Color string `json:"color"` + ProjectID int `json:"project_id"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + Template bool `json:"template"` + Description string `json:"description"` + LabelType string `json:"type"` + GroupID int `json:"group_id"` + } `json:"labels"` + } `json:"issue"` } tagHook struct { @@ -581,6 +722,7 @@ type ( Name string `json:"name"` Username string `json:"username"` AvatarURL string `json:"avatar_url"` + Email string `json:"email"` } `json:"user"` Project project `json:"project"` ObjectAttributes struct { @@ -617,7 +759,7 @@ type ( ID int `json:"id"` Title string `json:"title"` Color string `json:"color"` - ProjectID int `json:"project_id"` + ProjectID string `json:"project_id"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` Template bool `json:"template"` @@ -669,7 +811,7 @@ type ( Iid int `json:"iid"` LastEditedAt interface{} `json:"last_edited_at"` LastEditedByID interface{} `json:"last_edited_by_id"` - MergeCommitSha interface{} `json:"merge_commit_sha"` + MergeCommitSha string `json:"merge_commit_sha"` MergeError interface{} `json:"merge_error"` MergeParams struct { ForceRemoveSourceBranch string `json:"force_remove_source_branch"` @@ -705,6 +847,7 @@ type ( HumanTotalTimeSpent interface{} `json:"human_total_time_spent"` HumanTimeEstimate interface{} `json:"human_time_estimate"` Action string `json:"action"` + OldRev string `json:"oldrev"` } `json:"object_attributes"` Labels []interface{} `json:"labels"` Changes struct { @@ -716,4 +859,42 @@ type ( Homepage string `json:"homepage"` } `json:"repository"` } + + releaseHook struct { + ID int `json:"id"` + CreatedAt string `json:"created_at"` + Description string `json:"description"` + Name string `json:"name"` + ReleasedAt string `json:"released_at"` + Tag string `json:"tag"` + ObjectKind string `json:"object_kind"` + Project project `json:"project"` + URL string `json:"url"` + Action string `json:"action"` + Assets struct { + Count int `json:"count"` + Links []struct { + ID int `json:"id"` + External bool `json:"external"` + LinkType string `json:"link_type"` + Name string `json:"name"` + URL string `json:"url"` + } `json:"links"` + Sources []struct { + Format string `json:"format"` + URL string `json:"url"` + } `json:"sources"` + } `json:"assets"` + Commit struct { + ID string `json:"id"` + Message string `json:"message"` + Title string `json:"title"` + Timestamp string `json:"timestamp"` + URL string `json:"url"` + Author struct { + Name string `json:"name"` + Email string `json:"email"` + } `json:"author"` + } `json:"commit"` + } ) diff --git a/vendor/github.com/jenkins-x/go-scm/scm/git.go b/vendor/github.com/jenkins-x/go-scm/scm/git.go index 66cc2273c52..e6663c2907c 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/git.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/git.go @@ -40,6 +40,7 @@ type ( // list of repository commits. CommitListOptions struct { Ref string + Sha string Page int Size int } @@ -73,9 +74,12 @@ type ( // ListCommits returns a list of git commits. ListCommits(ctx context.Context, repo string, opts CommitListOptions) ([]*Commit, *Response, error) - // ListChanges returns the changeset between two commits. + // ListChanges returns the changeset between a commit and its parent. ListChanges(ctx context.Context, repo, ref string, opts ListOptions) ([]*Change, *Response, error) + // ListChanges returns the changeset between two commits. + CompareCommits(ctx context.Context, repo, ref1, ref2 string, opts ListOptions) ([]*Change, *Response, error) + // ListTags returns a list of git tags. ListTags(ctx context.Context, repo string, opts ListOptions) ([]*Reference, *Response, error) @@ -84,5 +88,8 @@ type ( // DeleteRef deletes the given ref DeleteRef(ctx context.Context, repo, ref string) (*Response, error) + + // CreateRef creates a new ref + CreateRef(ctx context.Context, repo, ref, sha string) (*Reference, *Response, error) } ) diff --git a/vendor/github.com/jenkins-x/go-scm/scm/issue.go b/vendor/github.com/jenkins-x/go-scm/scm/issue.go index 2ada9e35839..8d2080c0466 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/issue.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/issue.go @@ -23,6 +23,7 @@ type ( Locked bool Author User Assignees []User + ClosedBy *User PullRequest bool Created time.Time Updated time.Time @@ -56,6 +57,7 @@ type ( Body string Author User Link string + Version int Created time.Time Updated time.Time } @@ -119,6 +121,9 @@ type ( // Close closes an issue. Close(context.Context, string, int) (*Response, error) + // Reopen reopens a closed issue. + Reopen(context.Context, string, int) (*Response, error) + // Lock locks an issue discussion. Lock(context.Context, string, int) (*Response, error) @@ -136,6 +141,12 @@ type ( // UnassignIssue removes the assignment of ne or more users on an issue UnassignIssue(ctx context.Context, repo string, number int, logins []string) (*Response, error) + + // SetMilestone adds a milestone to an issue + SetMilestone(ctx context.Context, repo string, issueID int, number int) (*Response, error) + + // ClearMilestone removes the milestone from an issue + ClearMilestone(ctx context.Context, repo string, id int) (*Response, error) } ) diff --git a/vendor/github.com/jenkins-x/go-scm/scm/milestone.go b/vendor/github.com/jenkins-x/go-scm/scm/milestone.go new file mode 100644 index 00000000000..54ed9683be8 --- /dev/null +++ b/vendor/github.com/jenkins-x/go-scm/scm/milestone.go @@ -0,0 +1,42 @@ +package scm + +import ( + "context" + "time" +) + +type ( + // MilestoneInput contains the information needed to create a milestone + MilestoneInput struct { + Title string + Description string + State string + DueDate *time.Time + } + + // MilestoneListOptions provides options for querying a list of repository milestones. + MilestoneListOptions struct { + Page int + Size int + Open bool + Closed bool + } + + // MilestoneService provides access to creating, listing, updating, and deleting milestones + MilestoneService interface { + // Find returns the milestone for the given number in the given repository + Find(context.Context, string, int) (*Milestone, *Response, error) + + // List returns a list of milestones in the given repository + List(context.Context, string, MilestoneListOptions) ([]*Milestone, *Response, error) + + // Create creates a milestone in the given repository + Create(context.Context, string, *MilestoneInput) (*Milestone, *Response, error) + + // Update updates a milestone in the given repository + Update(context.Context, string, int, *MilestoneInput) (*Milestone, *Response, error) + + // Delete deletes a milestone in the given repository + Delete(context.Context, string, int) (*Response, error) + } +) diff --git a/vendor/github.com/jenkins-x/go-scm/scm/org.go b/vendor/github.com/jenkins-x/go-scm/scm/org.go index 92f6d4502c4..9547b0e69de 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/org.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/org.go @@ -17,6 +17,23 @@ type ( Permissions Permissions } + // OrganizationPendingInvite represents a pending invite to an organisation + OrganizationPendingInvite struct { + ID int + Login string + InviterLogin string + } + + // OrganizationInput provides the input fields required for + // creating a new organization. + OrganizationInput struct { + Name string + Description string + Homepage string + Private bool + } + + // Permissions represents the possible permissions a user can have on an org Permissions struct { MembersCreatePrivate bool MembersCreatePublic bool @@ -39,7 +56,15 @@ type ( // TeamMember is a member of an organizational team TeamMember struct { - Login string `json:"login"` + Login string `json:"login"` + IsAdmin bool `json:"isAdmin,omitempty"` + } + + // Membership describes the membership a user has to an organisation + Membership struct { + State string + Role string + OrganizationName string } // OrganizationService provides access to organization resources. @@ -47,6 +72,12 @@ type ( // Find returns the organization by name. Find(context.Context, string) (*Organization, *Response, error) + // Create creates an organization. + Create(context.Context, *OrganizationInput) (*Organization, *Response, error) + + // Delete deletes an organization. + Delete(context.Context, string) (*Response, error) + // List returns the user organization list. List(context.Context, ListOptions) ([]*Organization, *Response, error) @@ -64,5 +95,14 @@ type ( // ListOrgMembers lists the members of the organization ListOrgMembers(ctx context.Context, org string, ops ListOptions) ([]*TeamMember, *Response, error) + + // ListPendingInvitations lists the pending invitations for an organisation + ListPendingInvitations(ctx context.Context, org string, ops ListOptions) ([]*OrganizationPendingInvite, *Response, error) + + // AcceptPendingInvitation accepts a pending invitation for an organisation + AcceptOrganizationInvitation(ctx context.Context, org string) (*Response, error) + + // ListMemberships lists organisation memberships for the authenticated user + ListMemberships(ctx context.Context, opts ListOptions) ([]*Membership, *Response, error) } ) diff --git a/vendor/github.com/jenkins-x/go-scm/scm/pr.go b/vendor/github.com/jenkins-x/go-scm/scm/pr.go index fee48c71f1a..f8bd4447ea5 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/pr.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/pr.go @@ -11,6 +11,7 @@ import ( ) type ( + // MergeableState represents whether the PR can be merged MergeableState string // PullRequest represents a repository pull request. @@ -26,7 +27,6 @@ type ( Base PullRequestBranch Head PullRequestBranch Fork string - Link string State string Closed bool Draft bool @@ -37,11 +37,19 @@ type ( MergeSha string Author User Assignees []User + Reviewers []User Milestone Milestone Created time.Time Updated time.Time + + // Link links to the main pull request page + Link string + + // DiffLink links to the diff report of a pull request + DiffLink string } + // PullRequestInput provides the input needed to create or update a PR. PullRequestInput struct { Title string Head string @@ -49,7 +57,7 @@ type ( Body string } - // Milestone the milestotne + // Milestone the milestone Milestone struct { Number int ID int @@ -57,6 +65,7 @@ type ( Description string Link string State string + DueDate *time.Time } // PullRequestListOptions provides options for querying @@ -82,15 +91,17 @@ type ( // Change represents a changed file. Change struct { - Path string - Added bool - Renamed bool - Deleted bool - Additions int - Deletions int - Changes int - BlobURL string - Sha string + Path string + PreviousPath string + Added bool + Renamed bool + Deleted bool + Patch string + Additions int + Deletions int + Changes int + BlobURL string + Sha string } // PullRequestMergeOptions lets you define how a pull request will be merged. @@ -100,6 +111,12 @@ type ( // The merge method to use. Possible values include: "merge", "squash", and "rebase" with the default being merge. (Optional.) MergeMethod string + + // Merge automatically once the pipeline completes. (Supported only in gitlab) + MergeWhenPipelineSucceeds bool + + // Signals to the SCM to remove the source branch during merge + DeleteSourceBranch bool } // PullRequestService provides access to pull request resources. @@ -107,6 +124,9 @@ type ( // Find returns the repository pull request by number. Find(context.Context, string, int) (*PullRequest, *Response, error) + // Update modifies an existing pull request. + Update(context.Context, string, int, *PullRequestInput) (*PullRequest, *Response, error) + // FindComment returns the pull request comment by id. FindComment(context.Context, string, int, int) (*Comment, *Response, error) @@ -131,6 +151,9 @@ type ( // Close closes the repository pull request. Close(context.Context, string, int) (*Response, error) + // Reopen reopens a closed repository pull request. + Reopen(context.Context, string, int) (*Response, error) + // CreateComment creates a new pull request comment. CreateComment(context.Context, string, int, *CommentInput) (*Comment, *Response, error) @@ -160,6 +183,12 @@ type ( // UnrequestReview removes one or more users as a reviewer on a pull request. UnrequestReview(ctx context.Context, repo string, number int, logins []string) (*Response, error) + + // SetMilestone adds a milestone to a pull request + SetMilestone(ctx context.Context, repo string, prID int, number int) (*Response, error) + + // ClearMilestone removes the milestone from a pull request + ClearMilestone(ctx context.Context, repo string, prID int) (*Response, error) } ) diff --git a/vendor/github.com/jenkins-x/go-scm/scm/release.go b/vendor/github.com/jenkins-x/go-scm/scm/release.go new file mode 100644 index 00000000000..119adf42829 --- /dev/null +++ b/vendor/github.com/jenkins-x/go-scm/scm/release.go @@ -0,0 +1,67 @@ +package scm + +import ( + "context" + "time" +) + +type ( + // Release the release + Release struct { + ID int + Title string + Description string + Link string + Tag string + Commitish string + Draft bool + Prerelease bool + Created time.Time + Published time.Time + } + + // ReleaseInput contains the information needed to create a release + ReleaseInput struct { + Title string + Description string + Tag string + Commitish string + Draft bool + Prerelease bool + } + + // ReleaseListOptions provides options for querying a list of repository releases. + ReleaseListOptions struct { + Page int + Size int + Open bool + Closed bool + } + + // ReleaseService provides access to creating, listing, updating, and deleting releases + ReleaseService interface { + // Find returns the release for the given number in the given repository + Find(context.Context, string, int) (*Release, *Response, error) + + // FindByTag returns the release for the given tag in the given repository + FindByTag(context.Context, string, string) (*Release, *Response, error) + + // List returns a list of releases in the given repository + List(context.Context, string, ReleaseListOptions) ([]*Release, *Response, error) + + // Create creates a release in the given repository + Create(context.Context, string, *ReleaseInput) (*Release, *Response, error) + + // Update updates a release in the given repository + Update(context.Context, string, int, *ReleaseInput) (*Release, *Response, error) + + // Update updates a release in the given repository by tag + UpdateByTag(context.Context, string, string, *ReleaseInput) (*Release, *Response, error) + + // Delete deletes a release in the given repository + Delete(context.Context, string, int) (*Response, error) + + // Delete deletes a release in the given repository by tag + DeleteByTag(context.Context, string, string) (*Response, error) + } +) diff --git a/vendor/github.com/jenkins-x/go-scm/scm/repo.go b/vendor/github.com/jenkins-x/go-scm/scm/repo.go index 2797fa1e778..28dfc79b9e8 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/repo.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/repo.go @@ -30,6 +30,7 @@ type ( Perm *Perm Branch string Private bool + Archived bool Clone string CloneSSH string Link string @@ -82,11 +83,15 @@ type ( // HookEvents represents supported hook events. HookEvents struct { Branch bool + Deployment bool + DeploymentStatus bool Issue bool IssueComment bool PullRequest bool PullRequestComment bool Push bool + Release bool + Review bool ReviewComment bool Tag bool } @@ -104,6 +109,7 @@ type ( Label string Desc string Target string + Link string } // StatusInput provides the input fields required for @@ -113,6 +119,7 @@ type ( Label string Desc string Target string + Link string } // RepositoryService provides access to repository resources. @@ -150,9 +157,15 @@ type ( // Create creates a new repository . Create(context.Context, *RepositoryInput) (*Repository, *Response, error) + // Fork creatings a new repository as a fork of an existing one. + Fork(context.Context, *RepositoryInput, string) (*Repository, *Response, error) + // CreateHook creates a new repository webhook. CreateHook(context.Context, string, *HookInput) (*Hook, *Response, error) + // UpdateHook edit a repository webhook + UpdateHook(context.Context, string, *HookInput) (*Hook, *Response, error) + // CreateStatus creates a new commit status. CreateStatus(context.Context, string, string, *StatusInput) (*Status, *Response, error) @@ -160,13 +173,19 @@ type ( DeleteHook(context.Context, string, string) (*Response, error) // IsCollaborator returns true if the user is a collaborator on the repository - IsCollaborator(ctx context.Context, repo, user string) (bool, *Response, error) + IsCollaborator(ctx context.Context, repo string, user string) (bool, *Response, error) + + // AddCollaborator adds a collaborator to the repository + AddCollaborator(ctx context.Context, repo, user, permission string) (bool, bool, *Response, error) // ListCollaborators lists the collaborators on a repository ListCollaborators(ctx context.Context, repo string, ops ListOptions) ([]User, *Response, error) // FindUserPermission returns the user's permission level for a repo FindUserPermission(ctx context.Context, repo string, user string) (string, *Response, error) + + // Delete deletes a repository + Delete(ctx context.Context, repo string) (*Response, error) } ) diff --git a/vendor/github.com/jenkins-x/go-scm/scm/review.go b/vendor/github.com/jenkins-x/go-scm/scm/review.go index a74d7db4a0e..548e222dd69 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/review.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/review.go @@ -10,15 +10,26 @@ import ( ) type ( - // Review represents a review comment. + // Review represents a review. Review struct { + ID int + Body string + Sha string + Link string + State string + Author User + Created time.Time + Updated time.Time + } + + // ReviewComment represents a review comment. + ReviewComment struct { ID int Body string Path string Sha string Line int Link string - State string Author User Created time.Time Updated time.Time @@ -35,35 +46,65 @@ type ( GUID string } - // ReviewInput provides the input fields required for + // ReviewCommentInput provides the input fields required for // creating a review comment. - ReviewInput struct { + ReviewCommentInput struct { Body string - Sha string Path string Line int } + // ReviewSubmitInput provides the input fields required for submitting a pending review. + ReviewSubmitInput struct { + Body string + Event string + } + + // ReviewInput provides the input fields required for creating or updating a review. + ReviewInput struct { + Body string + Sha string + Event string + Comments []*ReviewCommentInput + } + // ReviewService provides access to review resources. ReviewService interface { - // Find returns the review comment by id. + // Find returns the review by id. Find(context.Context, string, int, int) (*Review, *Response, error) - // List returns the review comment list. + // List returns the review list. List(context.Context, string, int, ListOptions) ([]*Review, *Response, error) - // Create creates a review comment. + // Create creates a review. Create(context.Context, string, int, *ReviewInput) (*Review, *Response, error) - // Delete deletes a review comment. + // Delete deletes a review. Delete(context.Context, string, int, int) (*Response, error) + + // ListComments returns comments from a review + ListComments(context.Context, string, int, int, ListOptions) ([]*ReviewComment, *Response, error) + + // Update updates the body of a review + Update(context.Context, string, int, int, string) (*Review, *Response, error) + + // Submit submits a pending review + Submit(context.Context, string, int, int, *ReviewSubmitInput) (*Review, *Response, error) + + // Dismiss dismisses a review + Dismiss(context.Context, string, int, int, string) (*Review, *Response, error) } ) const ( - ReviewStateApproved string = "APPROVED" + // ReviewStateApproved is used for approved reviews + ReviewStateApproved string = "APPROVED" + // ReviewStateChangesRequested is used for reviews with changes requested ReviewStateChangesRequested string = "CHANGES_REQUESTED" - ReviewStateCommented string = "COMMENTED" - ReviewStateDismissed string = "DISMISSED" - ReviewStatePending string = "PENDING" + // ReviewStateCommented is used for reviews with comments + ReviewStateCommented string = "COMMENTED" + // ReviewStateDismissed is used for reviews that have been dismissed + ReviewStateDismissed string = "DISMISSED" + // ReviewStatePending is used for reviews that are awaiting response + ReviewStatePending string = "PENDING" ) diff --git a/vendor/github.com/jenkins-x/go-scm/scm/user.go b/vendor/github.com/jenkins-x/go-scm/scm/user.go index bb3ef5ce4ef..d2b445012ae 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/user.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/user.go @@ -18,19 +18,49 @@ type ( Email string Avatar string Link string + IsAdmin bool `json:"isAdmin,omitempty"` Created time.Time Updated time.Time } + // UserToken represents a user token. + UserToken struct { + ID int64 + Token string + } + + // Invitation represents a repo invitation + Invitation struct { + ID int64 + Repo *Repository + Invitee *User + Inviter *User + Permissions string + Link string + Created time.Time + } + // UserService provides access to user account resources. UserService interface { // Find returns the authenticated user. Find(context.Context) (*User, *Response, error) + // CreateToken creates a user token. + CreateToken(context.Context, string, string) (*UserToken, *Response, error) + + // DeleteToken deletes a user token. + DeleteToken(context.Context, int64) (*Response, error) + // FindEmail returns the authenticated user email. FindEmail(context.Context) (string, *Response, error) // FindLogin returns the user account by username. FindLogin(context.Context, string) (*User, *Response, error) + + // ListInvitations lists repository or organization invitations for the current user + ListInvitations(context.Context) ([]*Invitation, *Response, error) + + // AcceptInvitation accepts an invitation for the current user + AcceptInvitation(context.Context, int64) (*Response, error) } ) diff --git a/vendor/github.com/jenkins-x/go-scm/scm/util.go b/vendor/github.com/jenkins-x/go-scm/scm/util.go index c693414e601..ca634493b03 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/util.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/util.go @@ -27,8 +27,8 @@ func Join(owner, name string) string { return owner + "/" + name } -// UrlJoin joins the given paths so that there is only ever one '/' character between the paths -func UrlJoin(paths ...string) string { +// URLJoin joins the given paths so that there is only ever one '/' character between the paths +func URLJoin(paths ...string) string { var buffer strings.Builder last := len(paths) - 1 for i, path := range paths { @@ -89,3 +89,13 @@ func ConvertStatusInputToStatus(input *StatusInput) *Status { Target: input.Target, } } + +// IsScmNotFound returns true if the resource is not found +func IsScmNotFound(err error) bool { + if err != nil { + // I think that we should instead rely on the http status (404) + // until jenkins-x go-scm is updated t return that in the error this works for github and gitlab + return strings.Contains(err.Error(), ErrNotFound.Error()) + } + return false +} diff --git a/vendor/github.com/jenkins-x/go-scm/scm/webhook.go b/vendor/github.com/jenkins-x/go-scm/scm/webhook.go index 34b8d45af52..1ac8d7fc05b 100644 --- a/vendor/github.com/jenkins-x/go-scm/scm/webhook.go +++ b/vendor/github.com/jenkins-x/go-scm/scm/webhook.go @@ -6,36 +6,61 @@ package scm import ( "errors" + "fmt" "net/http" "time" ) +// WebhookKind is the kind of webhook event represented type WebhookKind string const ( - WebhookKindBranch WebhookKind = "branch" - WebhookKindCheckRun WebhookKind = "check_run" - WebhookKindCheckSuite WebhookKind = "check_suite" - WebhookKindDeploy WebhookKind = "deploy" - WebhookKindDeploymentStatus WebhookKind = "deployment_status" - WebhookKindFork WebhookKind = "fork" - WebhookKindInstallation WebhookKind = "installation" + // WebhookKindBranch is for branch events + WebhookKindBranch WebhookKind = "branch" + // WebhookKindCheckRun is for check run events + WebhookKindCheckRun WebhookKind = "check_run" + // WebhookKindCheckSuite is for check suite events + WebhookKindCheckSuite WebhookKind = "check_suite" + // WebhookKindDeploy is for deploy events + WebhookKindDeploy WebhookKind = "deploy" + // WebhookKindDeploymentStatus is for deployment status events + WebhookKindDeploymentStatus WebhookKind = "deployment_status" + // WebhookKindFork is for fork events + WebhookKindFork WebhookKind = "fork" + // WebhookKindInstallation is for app installation events + WebhookKindInstallation WebhookKind = "installation" + // WebhookKindInstallationRepository is for app isntallation in a repository events WebhookKindInstallationRepository WebhookKind = "installation_repository" - WebhookKindIssue WebhookKind = "issue" - WebhookKindIssueComment WebhookKind = "issue_comment" - WebhookKindLabel WebhookKind = "label" - WebhookKindPing WebhookKind = "ping" - WebhookKindPullRequest WebhookKind = "pull_request" - WebhookKindPullRequestComment WebhookKind = "pull_request_comment" - WebhookKindPush WebhookKind = "push" - WebhookKindRelease WebhookKind = "release" - WebhookKindRepository WebhookKind = "repository" - WebhookKindReview WebhookKind = "review" - WebhookKindReviewCommentHook WebhookKind = "review_comment" - WebhookKindStar WebhookKind = "star" - WebhookKindStatus WebhookKind = "status" - WebhookKindTag WebhookKind = "tag" - WebhookKindWatch WebhookKind = "watch" + // WebhookKindIssue is for issue events + WebhookKindIssue WebhookKind = "issue" + // WebhookKindIssueComment is for issue comment events + WebhookKindIssueComment WebhookKind = "issue_comment" + // WebhookKindLabel is for label events + WebhookKindLabel WebhookKind = "label" + // WebhookKindPing is for ping events + WebhookKindPing WebhookKind = "ping" + // WebhookKindPullRequest is for pull request events + WebhookKindPullRequest WebhookKind = "pull_request" + // WebhookKindPullRequestComment is for pull request comment events + WebhookKindPullRequestComment WebhookKind = "pull_request_comment" + // WebhookKindPush is for push events + WebhookKindPush WebhookKind = "push" + // WebhookKindRelease is for release events + WebhookKindRelease WebhookKind = "release" + // WebhookKindRepository is for repository events + WebhookKindRepository WebhookKind = "repository" + // WebhookKindReview is for review events + WebhookKindReview WebhookKind = "review" + // WebhookKindReviewCommentHook is for review comment events + WebhookKindReviewCommentHook WebhookKind = "review_comment" + // WebhookKindStar is for star events + WebhookKindStar WebhookKind = "star" + // WebhookKindStatus is for status events + WebhookKindStatus WebhookKind = "status" + // WebhookKindTag is for tag events + WebhookKindTag WebhookKind = "tag" + // WebhookKindWatch is for watch events + WebhookKindWatch WebhookKind = "watch" ) var ( @@ -124,15 +149,30 @@ type ( Installation *InstallationRef } - // DeploymentStatusHook represents a check suite event - DeploymentStatusHook struct { + // DeployHook represents a deployment event. + // This is currently a GitHub-specific event type. + DeployHook struct { + Deployment Deployment Action Action + Ref Reference Repo Repository Sender User Label Label Installation *InstallationRef } + // DeploymentStatusHook represents a deployment status event. + // This is currently a GitHub-specific event type. + DeploymentStatusHook struct { + Deployment Deployment + DeploymentStatus DeploymentStatus + Action Action + Repo Repository + Sender User + Label Label + Installation *InstallationRef + } + // ForkHook represents a fork event ForkHook struct { Repo Repository @@ -167,6 +207,7 @@ type ( Issue Issue Comment Comment Sender User + GUID string Installation *InstallationRef } @@ -207,6 +248,7 @@ type ( ReleaseHook struct { Action Action Repo Repository + Release Release Sender User Label Label Installation *InstallationRef @@ -236,16 +278,19 @@ type ( Link string } + // PullRequestHookBranchFrom represents the branch or ref a PR is from PullRequestHookBranchFrom struct { From string } + // PullRequestHookBranch represents a branch in a PR PullRequestHookBranch struct { Ref PullRequestHookBranchFrom Sha PullRequestHookBranchFrom Repo Repository } + // PullRequestHookChanges represents the changes in a PR PullRequestHookChanges struct { Base PullRequestHookBranch } @@ -271,6 +316,7 @@ type ( PullRequest PullRequest Comment Comment Sender User + GUID string Installation *InstallationRef } @@ -284,20 +330,6 @@ type ( Installation *InstallationRef } - // DeployHook represents a deployment event. This is - // currently a GitHub-specific event type. - DeployHook struct { - Data interface{} - Desc string - Ref Reference - Repo Repository - Sender User - Target string - TargetURL string - Task string - Installation *InstallationRef - } - // WatchHook represents a watch event. This is currently GitHub-specific. WatchHook struct { Action string @@ -314,6 +346,31 @@ type ( Sender User } + // WebhookWrapper lets us parse any webhook + WebhookWrapper struct { + PingHook *PingHook `json:",omitempty"` + PushHook *PushHook `json:",omitempty"` + BranchHook *BranchHook `json:",omitempty"` + CheckRunHook *CheckRunHook `json:",omitempty"` + CheckSuiteHook *CheckSuiteHook `json:",omitempty"` + DeployHook *DeployHook `json:",omitempty"` + DeploymentStatusHook *DeploymentStatusHook `json:",omitempty"` + ForkHook *ForkHook `json:",omitempty"` + TagHook *TagHook `json:",omitempty"` + IssueHook *IssueHook `json:",omitempty"` + IssueCommentHook *IssueCommentHook `json:",omitempty"` + InstallationHook *InstallationHook `json:",omitempty"` + InstallationRepositoryHook *InstallationRepositoryHook `json:",omitempty"` + LabelHook *LabelHook `json:",omitempty"` + ReleaseHook *ReleaseHook `json:",omitempty"` + RepositoryHook *RepositoryHook `json:",omitempty"` + PullRequestHook *PullRequestHook `json:",omitempty"` + PullRequestCommentHook *PullRequestCommentHook `json:",omitempty"` + ReviewCommentHook *ReviewCommentHook `json:",omitempty"` + WatchHook *WatchHook `json:",omitempty"` + StarHook *StarHook `json:",omitempty"` + } + // SecretFunc provides the Webhook parser with the // secret key used to validate webhook authenticity. SecretFunc func(webhook Webhook) (string, error) @@ -326,58 +383,161 @@ type ( } ) -// Kind() returns the kind of webhook - -func (h *PingHook) Kind() WebhookKind { return WebhookKindPing } -func (h *PushHook) Kind() WebhookKind { return WebhookKindPush } -func (h *BranchHook) Kind() WebhookKind { return WebhookKindBranch } -func (h *DeployHook) Kind() WebhookKind { return WebhookKindDeploy } -func (h *TagHook) Kind() WebhookKind { return WebhookKindTag } -func (h *IssueHook) Kind() WebhookKind { return WebhookKindIssue } -func (h *IssueCommentHook) Kind() WebhookKind { return WebhookKindIssueComment } -func (h *PullRequestHook) Kind() WebhookKind { return WebhookKindPullRequest } -func (h *PullRequestCommentHook) Kind() WebhookKind { return WebhookKindPullRequestComment } -func (h *ReviewHook) Kind() WebhookKind { return WebhookKindReview } -func (h *ReviewCommentHook) Kind() WebhookKind { return WebhookKindReviewCommentHook } -func (h *InstallationHook) Kind() WebhookKind { return WebhookKindInstallation } -func (h *LabelHook) Kind() WebhookKind { return WebhookKindLabel } -func (h *StatusHook) Kind() WebhookKind { return WebhookKindStatus } -func (h *CheckRunHook) Kind() WebhookKind { return WebhookKindCheckRun } -func (h *CheckSuiteHook) Kind() WebhookKind { return WebhookKindCheckSuite } -func (h *DeploymentStatusHook) Kind() WebhookKind { return WebhookKindDeploymentStatus } -func (h *ReleaseHook) Kind() WebhookKind { return WebhookKindRelease } -func (h *RepositoryHook) Kind() WebhookKind { return WebhookKindRepository } -func (h *ForkHook) Kind() WebhookKind { return WebhookKindFork } +// Kind returns the kind of webhook +func (h *PingHook) Kind() WebhookKind { return WebhookKindPing } + +// Kind returns the kind of webhook +func (h *PushHook) Kind() WebhookKind { return WebhookKindPush } + +// Kind returns the kind of webhook +func (h *BranchHook) Kind() WebhookKind { return WebhookKindBranch } + +// Kind returns the kind of webhook +func (h *DeployHook) Kind() WebhookKind { return WebhookKindDeploy } + +// Kind returns the kind of webhook +func (h *TagHook) Kind() WebhookKind { return WebhookKindTag } + +// Kind returns the kind of webhook +func (h *IssueHook) Kind() WebhookKind { return WebhookKindIssue } + +// Kind returns the kind of webhook +func (h *IssueCommentHook) Kind() WebhookKind { return WebhookKindIssueComment } + +// Kind returns the kind of webhook +func (h *PullRequestHook) Kind() WebhookKind { return WebhookKindPullRequest } + +// Kind returns the kind of webhook +func (h *PullRequestCommentHook) Kind() WebhookKind { return WebhookKindPullRequestComment } + +// Kind returns the kind of webhook +func (h *ReviewHook) Kind() WebhookKind { return WebhookKindReview } + +// Kind returns the kind of webhook +func (h *ReviewCommentHook) Kind() WebhookKind { return WebhookKindReviewCommentHook } + +// Kind returns the kind of webhook +func (h *InstallationHook) Kind() WebhookKind { return WebhookKindInstallation } + +// Kind returns the kind of webhook +func (h *LabelHook) Kind() WebhookKind { return WebhookKindLabel } + +// Kind returns the kind of webhook +func (h *StatusHook) Kind() WebhookKind { return WebhookKindStatus } + +// Kind returns the kind of webhook +func (h *CheckRunHook) Kind() WebhookKind { return WebhookKindCheckRun } + +// Kind returns the kind of webhook +func (h *CheckSuiteHook) Kind() WebhookKind { return WebhookKindCheckSuite } + +// Kind returns the kind of webhook +func (h *DeploymentStatusHook) Kind() WebhookKind { return WebhookKindDeploymentStatus } + +// Kind returns the kind of webhook +func (h *ReleaseHook) Kind() WebhookKind { return WebhookKindRelease } + +// Kind returns the kind of webhook +func (h *RepositoryHook) Kind() WebhookKind { return WebhookKindRepository } + +// Kind returns the kind of webhook +func (h *ForkHook) Kind() WebhookKind { return WebhookKindFork } + +// Kind returns the kind of webhook func (h *InstallationRepositoryHook) Kind() WebhookKind { return WebhookKindInstallationRepository } -func (h *WatchHook) Kind() WebhookKind { return WebhookKindWatch } -func (h *StarHook) Kind() WebhookKind { return WebhookKindStar } -// Repository() defines the repository webhook and provides -// a convenient way to get the associated repository without +// Kind returns the kind of webhook +func (h *WatchHook) Kind() WebhookKind { return WebhookKindWatch } + +// Kind returns the kind of webhook +func (h *StarHook) Kind() WebhookKind { return WebhookKindStar } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *PingHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *PushHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *BranchHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *DeployHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *TagHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *IssueHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without // having to cast the type. +func (h *IssueCommentHook) Repository() Repository { return h.Repo } -func (h *PingHook) Repository() Repository { return h.Repo } -func (h *PushHook) Repository() Repository { return h.Repo } -func (h *BranchHook) Repository() Repository { return h.Repo } -func (h *DeployHook) Repository() Repository { return h.Repo } -func (h *TagHook) Repository() Repository { return h.Repo } -func (h *IssueHook) Repository() Repository { return h.Repo } -func (h *IssueCommentHook) Repository() Repository { return h.Repo } -func (h *PullRequestHook) Repository() Repository { return h.Repo } +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *PullRequestHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. func (h *PullRequestCommentHook) Repository() Repository { return h.Repo } -func (h *ReviewCommentHook) Repository() Repository { return h.Repo } -func (h *ReviewHook) Repository() Repository { return h.Repo } -func (h *LabelHook) Repository() Repository { return h.Repo } -func (h *StatusHook) Repository() Repository { return h.Repo } -func (h *CheckRunHook) Repository() Repository { return h.Repo } -func (h *CheckSuiteHook) Repository() Repository { return h.Repo } -func (h *DeploymentStatusHook) Repository() Repository { return h.Repo } -func (h *ReleaseHook) Repository() Repository { return h.Repo } -func (h *RepositoryHook) Repository() Repository { return h.Repo } -func (h *ForkHook) Repository() Repository { return h.Repo } -func (h *WatchHook) Repository() Repository { return h.Repo } -func (h *StarHook) Repository() Repository { return h.Repo } +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *ReviewCommentHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *ReviewHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *LabelHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *StatusHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *CheckRunHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *CheckSuiteHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *DeploymentStatusHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *ReleaseHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *RepositoryHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *ForkHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *WatchHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. +func (h *StarHook) Repository() Repository { return h.Repo } + +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. func (h *InstallationHook) Repository() Repository { if len(h.Repos) > 0 { return *h.Repos[0] @@ -385,6 +545,8 @@ func (h *InstallationHook) Repository() Repository { return Repository{} } +// Repository defines the repository webhook and provides a convenient way to get the associated repository without +// having to cast the type. func (h *InstallationRepositoryHook) Repository() Repository { if len(h.ReposAdded) > 0 { return *h.ReposAdded[0] @@ -392,30 +554,92 @@ func (h *InstallationRepositoryHook) Repository() Repository { return Repository{} } -// GetInstallationRef() returns the installation reference if the webhook is invoked on a +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *PingHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *PushHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *BranchHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *DeployHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *TagHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *IssueHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *IssueCommentHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *PullRequestHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a // GitHub App -func (h *PingHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *PushHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *BranchHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *DeployHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *TagHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *IssueHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *IssueCommentHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *PullRequestHook) GetInstallationRef() *InstallationRef { return h.Installation } func (h *PullRequestCommentHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *ReviewHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *ReviewCommentHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *LabelHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *StatusHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *CheckRunHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *CheckSuiteHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *DeploymentStatusHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *ReleaseHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *RepositoryHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *ForkHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *WatchHook) GetInstallationRef() *InstallationRef { return h.Installation } -func (h *StarHook) GetInstallationRef() *InstallationRef { return nil } +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *ReviewHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *ReviewCommentHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *LabelHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *StatusHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *CheckRunHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *CheckSuiteHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *DeploymentStatusHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *ReleaseHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *RepositoryHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *ForkHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *WatchHook) GetInstallationRef() *InstallationRef { return h.Installation } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App +func (h *StarHook) GetInstallationRef() *InstallationRef { return nil } + +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App func (h *InstallationHook) GetInstallationRef() *InstallationRef { if h.Installation == nil { return nil @@ -425,6 +649,8 @@ func (h *InstallationHook) GetInstallationRef() *InstallationRef { } } +// GetInstallationRef returns the installation reference if the webhook is invoked on a +// GitHub App func (h *InstallationRepositoryHook) GetInstallationRef() *InstallationRef { if h.Installation == nil { return nil @@ -433,3 +659,71 @@ func (h *InstallationRepositoryHook) GetInstallationRef() *InstallationRef { ID: h.Installation.ID, } } + +// ToWebhook converts the webhook wrapper to a webhook +func (h *WebhookWrapper) ToWebhook() (Webhook, error) { + if h == nil { + return nil, fmt.Errorf("no webhook supplied") + } + if h.PingHook != nil { + return h.PingHook, nil + } + if h.PushHook != nil { + return h.PushHook, nil + } + if h.BranchHook != nil { + return h.BranchHook, nil + } + if h.CheckRunHook != nil { + return h.CheckRunHook, nil + } + if h.CheckSuiteHook != nil { + return h.CheckSuiteHook, nil + } + if h.DeployHook != nil { + return h.DeployHook, nil + } + if h.DeploymentStatusHook != nil { + return h.DeploymentStatusHook, nil + } + if h.ForkHook != nil { + return h.ForkHook, nil + } + if h.TagHook != nil { + return h.TagHook, nil + } + if h.IssueHook != nil { + return h.IssueHook, nil + } + if h.IssueCommentHook != nil { + return h.IssueCommentHook, nil + } + if h.InstallationHook != nil { + return h.InstallationHook, nil + } + if h.InstallationRepositoryHook != nil { + return h.InstallationRepositoryHook, nil + } + if h.LabelHook != nil { + return h.LabelHook, nil + } + if h.RepositoryHook != nil { + return h.RepositoryHook, nil + } + if h.PullRequestHook != nil { + return h.PullRequestHook, nil + } + if h.PullRequestCommentHook != nil { + return h.PullRequestCommentHook, nil + } + if h.ReviewCommentHook != nil { + return h.ReviewCommentHook, nil + } + if h.WatchHook != nil { + return h.WatchHook, nil + } + if h.StarHook != nil { + return h.StarHook, nil + } + return nil, fmt.Errorf("unsupported webhook") +} diff --git a/vendor/github.com/mitchellh/copystructure/.travis.yml b/vendor/github.com/mitchellh/copystructure/.travis.yml new file mode 100644 index 00000000000..d7b9589ab11 --- /dev/null +++ b/vendor/github.com/mitchellh/copystructure/.travis.yml @@ -0,0 +1,12 @@ +language: go + +go: + - 1.7 + - tip + +script: + - go test + +matrix: + allow_failures: + - go: tip diff --git a/vendor/github.com/mitchellh/copystructure/LICENSE b/vendor/github.com/mitchellh/copystructure/LICENSE new file mode 100644 index 00000000000..22985159044 --- /dev/null +++ b/vendor/github.com/mitchellh/copystructure/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Mitchell Hashimoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/mitchellh/copystructure/README.md b/vendor/github.com/mitchellh/copystructure/README.md new file mode 100644 index 00000000000..bcb8c8d2cb9 --- /dev/null +++ b/vendor/github.com/mitchellh/copystructure/README.md @@ -0,0 +1,21 @@ +# copystructure + +copystructure is a Go library for deep copying values in Go. + +This allows you to copy Go values that may contain reference values +such as maps, slices, or pointers, and copy their data as well instead +of just their references. + +## Installation + +Standard `go get`: + +``` +$ go get github.com/mitchellh/copystructure +``` + +## Usage & Example + +For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/copystructure). + +The `Copy` function has examples associated with it there. diff --git a/vendor/github.com/mitchellh/copystructure/copier_time.go b/vendor/github.com/mitchellh/copystructure/copier_time.go new file mode 100644 index 00000000000..db6a6aa1a1f --- /dev/null +++ b/vendor/github.com/mitchellh/copystructure/copier_time.go @@ -0,0 +1,15 @@ +package copystructure + +import ( + "reflect" + "time" +) + +func init() { + Copiers[reflect.TypeOf(time.Time{})] = timeCopier +} + +func timeCopier(v interface{}) (interface{}, error) { + // Just... copy it. + return v.(time.Time), nil +} diff --git a/vendor/github.com/mitchellh/copystructure/copystructure.go b/vendor/github.com/mitchellh/copystructure/copystructure.go new file mode 100644 index 00000000000..140435255e1 --- /dev/null +++ b/vendor/github.com/mitchellh/copystructure/copystructure.go @@ -0,0 +1,548 @@ +package copystructure + +import ( + "errors" + "reflect" + "sync" + + "github.com/mitchellh/reflectwalk" +) + +// Copy returns a deep copy of v. +func Copy(v interface{}) (interface{}, error) { + return Config{}.Copy(v) +} + +// CopierFunc is a function that knows how to deep copy a specific type. +// Register these globally with the Copiers variable. +type CopierFunc func(interface{}) (interface{}, error) + +// Copiers is a map of types that behave specially when they are copied. +// If a type is found in this map while deep copying, this function +// will be called to copy it instead of attempting to copy all fields. +// +// The key should be the type, obtained using: reflect.TypeOf(value with type). +// +// It is unsafe to write to this map after Copies have started. If you +// are writing to this map while also copying, wrap all modifications to +// this map as well as to Copy in a mutex. +var Copiers map[reflect.Type]CopierFunc = make(map[reflect.Type]CopierFunc) + +// Must is a helper that wraps a call to a function returning +// (interface{}, error) and panics if the error is non-nil. It is intended +// for use in variable initializations and should only be used when a copy +// error should be a crashing case. +func Must(v interface{}, err error) interface{} { + if err != nil { + panic("copy error: " + err.Error()) + } + + return v +} + +var errPointerRequired = errors.New("Copy argument must be a pointer when Lock is true") + +type Config struct { + // Lock any types that are a sync.Locker and are not a mutex while copying. + // If there is an RLocker method, use that to get the sync.Locker. + Lock bool + + // Copiers is a map of types associated with a CopierFunc. Use the global + // Copiers map if this is nil. + Copiers map[reflect.Type]CopierFunc +} + +func (c Config) Copy(v interface{}) (interface{}, error) { + if c.Lock && reflect.ValueOf(v).Kind() != reflect.Ptr { + return nil, errPointerRequired + } + + w := new(walker) + if c.Lock { + w.useLocks = true + } + + if c.Copiers == nil { + c.Copiers = Copiers + } + + err := reflectwalk.Walk(v, w) + if err != nil { + return nil, err + } + + // Get the result. If the result is nil, then we want to turn it + // into a typed nil if we can. + result := w.Result + if result == nil { + val := reflect.ValueOf(v) + result = reflect.Indirect(reflect.New(val.Type())).Interface() + } + + return result, nil +} + +// Return the key used to index interfaces types we've seen. Store the number +// of pointers in the upper 32bits, and the depth in the lower 32bits. This is +// easy to calculate, easy to match a key with our current depth, and we don't +// need to deal with initializing and cleaning up nested maps or slices. +func ifaceKey(pointers, depth int) uint64 { + return uint64(pointers)<<32 | uint64(depth) +} + +type walker struct { + Result interface{} + + depth int + ignoreDepth int + vals []reflect.Value + cs []reflect.Value + + // This stores the number of pointers we've walked over, indexed by depth. + ps []int + + // If an interface is indirected by a pointer, we need to know the type of + // interface to create when creating the new value. Store the interface + // types here, indexed by both the walk depth and the number of pointers + // already seen at that depth. Use ifaceKey to calculate the proper uint64 + // value. + ifaceTypes map[uint64]reflect.Type + + // any locks we've taken, indexed by depth + locks []sync.Locker + // take locks while walking the structure + useLocks bool +} + +func (w *walker) Enter(l reflectwalk.Location) error { + w.depth++ + + // ensure we have enough elements to index via w.depth + for w.depth >= len(w.locks) { + w.locks = append(w.locks, nil) + } + + for len(w.ps) < w.depth+1 { + w.ps = append(w.ps, 0) + } + + return nil +} + +func (w *walker) Exit(l reflectwalk.Location) error { + locker := w.locks[w.depth] + w.locks[w.depth] = nil + if locker != nil { + defer locker.Unlock() + } + + // clear out pointers and interfaces as we exit the stack + w.ps[w.depth] = 0 + + for k := range w.ifaceTypes { + mask := uint64(^uint32(0)) + if k&mask == uint64(w.depth) { + delete(w.ifaceTypes, k) + } + } + + w.depth-- + if w.ignoreDepth > w.depth { + w.ignoreDepth = 0 + } + + if w.ignoring() { + return nil + } + + switch l { + case reflectwalk.Array: + fallthrough + case reflectwalk.Map: + fallthrough + case reflectwalk.Slice: + w.replacePointerMaybe() + + // Pop map off our container + w.cs = w.cs[:len(w.cs)-1] + case reflectwalk.MapValue: + // Pop off the key and value + mv := w.valPop() + mk := w.valPop() + m := w.cs[len(w.cs)-1] + + // If mv is the zero value, SetMapIndex deletes the key form the map, + // or in this case never adds it. We need to create a properly typed + // zero value so that this key can be set. + if !mv.IsValid() { + mv = reflect.Zero(m.Elem().Type().Elem()) + } + m.Elem().SetMapIndex(mk, mv) + case reflectwalk.ArrayElem: + // Pop off the value and the index and set it on the array + v := w.valPop() + i := w.valPop().Interface().(int) + if v.IsValid() { + a := w.cs[len(w.cs)-1] + ae := a.Elem().Index(i) // storing array as pointer on stack - so need Elem() call + if ae.CanSet() { + ae.Set(v) + } + } + case reflectwalk.SliceElem: + // Pop off the value and the index and set it on the slice + v := w.valPop() + i := w.valPop().Interface().(int) + if v.IsValid() { + s := w.cs[len(w.cs)-1] + se := s.Elem().Index(i) + if se.CanSet() { + se.Set(v) + } + } + case reflectwalk.Struct: + w.replacePointerMaybe() + + // Remove the struct from the container stack + w.cs = w.cs[:len(w.cs)-1] + case reflectwalk.StructField: + // Pop off the value and the field + v := w.valPop() + f := w.valPop().Interface().(reflect.StructField) + if v.IsValid() { + s := w.cs[len(w.cs)-1] + sf := reflect.Indirect(s).FieldByName(f.Name) + + if sf.CanSet() { + sf.Set(v) + } + } + case reflectwalk.WalkLoc: + // Clear out the slices for GC + w.cs = nil + w.vals = nil + } + + return nil +} + +func (w *walker) Map(m reflect.Value) error { + if w.ignoring() { + return nil + } + w.lock(m) + + // Create the map. If the map itself is nil, then just make a nil map + var newMap reflect.Value + if m.IsNil() { + newMap = reflect.New(m.Type()) + } else { + newMap = wrapPtr(reflect.MakeMap(m.Type())) + } + + w.cs = append(w.cs, newMap) + w.valPush(newMap) + return nil +} + +func (w *walker) MapElem(m, k, v reflect.Value) error { + return nil +} + +func (w *walker) PointerEnter(v bool) error { + if v { + w.ps[w.depth]++ + } + return nil +} + +func (w *walker) PointerExit(v bool) error { + if v { + w.ps[w.depth]-- + } + return nil +} + +func (w *walker) Interface(v reflect.Value) error { + if !v.IsValid() { + return nil + } + if w.ifaceTypes == nil { + w.ifaceTypes = make(map[uint64]reflect.Type) + } + + w.ifaceTypes[ifaceKey(w.ps[w.depth], w.depth)] = v.Type() + return nil +} + +func (w *walker) Primitive(v reflect.Value) error { + if w.ignoring() { + return nil + } + w.lock(v) + + // IsValid verifies the v is non-zero and CanInterface verifies + // that we're allowed to read this value (unexported fields). + var newV reflect.Value + if v.IsValid() && v.CanInterface() { + newV = reflect.New(v.Type()) + newV.Elem().Set(v) + } + + w.valPush(newV) + w.replacePointerMaybe() + return nil +} + +func (w *walker) Slice(s reflect.Value) error { + if w.ignoring() { + return nil + } + w.lock(s) + + var newS reflect.Value + if s.IsNil() { + newS = reflect.New(s.Type()) + } else { + newS = wrapPtr(reflect.MakeSlice(s.Type(), s.Len(), s.Cap())) + } + + w.cs = append(w.cs, newS) + w.valPush(newS) + return nil +} + +func (w *walker) SliceElem(i int, elem reflect.Value) error { + if w.ignoring() { + return nil + } + + // We don't write the slice here because elem might still be + // arbitrarily complex. Just record the index and continue on. + w.valPush(reflect.ValueOf(i)) + + return nil +} + +func (w *walker) Array(a reflect.Value) error { + if w.ignoring() { + return nil + } + w.lock(a) + + newA := reflect.New(a.Type()) + + w.cs = append(w.cs, newA) + w.valPush(newA) + return nil +} + +func (w *walker) ArrayElem(i int, elem reflect.Value) error { + if w.ignoring() { + return nil + } + + // We don't write the array here because elem might still be + // arbitrarily complex. Just record the index and continue on. + w.valPush(reflect.ValueOf(i)) + + return nil +} + +func (w *walker) Struct(s reflect.Value) error { + if w.ignoring() { + return nil + } + w.lock(s) + + var v reflect.Value + if c, ok := Copiers[s.Type()]; ok { + // We have a Copier for this struct, so we use that copier to + // get the copy, and we ignore anything deeper than this. + w.ignoreDepth = w.depth + + dup, err := c(s.Interface()) + if err != nil { + return err + } + + // We need to put a pointer to the value on the value stack, + // so allocate a new pointer and set it. + v = reflect.New(s.Type()) + reflect.Indirect(v).Set(reflect.ValueOf(dup)) + } else { + // No copier, we copy ourselves and allow reflectwalk to guide + // us deeper into the structure for copying. + v = reflect.New(s.Type()) + } + + // Push the value onto the value stack for setting the struct field, + // and add the struct itself to the containers stack in case we walk + // deeper so that its own fields can be modified. + w.valPush(v) + w.cs = append(w.cs, v) + + return nil +} + +func (w *walker) StructField(f reflect.StructField, v reflect.Value) error { + if w.ignoring() { + return nil + } + + // If PkgPath is non-empty, this is a private (unexported) field. + // We do not set this unexported since the Go runtime doesn't allow us. + if f.PkgPath != "" { + return reflectwalk.SkipEntry + } + + // Push the field onto the stack, we'll handle it when we exit + // the struct field in Exit... + w.valPush(reflect.ValueOf(f)) + return nil +} + +// ignore causes the walker to ignore any more values until we exit this on +func (w *walker) ignore() { + w.ignoreDepth = w.depth +} + +func (w *walker) ignoring() bool { + return w.ignoreDepth > 0 && w.depth >= w.ignoreDepth +} + +func (w *walker) pointerPeek() bool { + return w.ps[w.depth] > 0 +} + +func (w *walker) valPop() reflect.Value { + result := w.vals[len(w.vals)-1] + w.vals = w.vals[:len(w.vals)-1] + + // If we're out of values, that means we popped everything off. In + // this case, we reset the result so the next pushed value becomes + // the result. + if len(w.vals) == 0 { + w.Result = nil + } + + return result +} + +func (w *walker) valPush(v reflect.Value) { + w.vals = append(w.vals, v) + + // If we haven't set the result yet, then this is the result since + // it is the first (outermost) value we're seeing. + if w.Result == nil && v.IsValid() { + w.Result = v.Interface() + } +} + +func (w *walker) replacePointerMaybe() { + // Determine the last pointer value. If it is NOT a pointer, then + // we need to push that onto the stack. + if !w.pointerPeek() { + w.valPush(reflect.Indirect(w.valPop())) + return + } + + v := w.valPop() + + // If the expected type is a pointer to an interface of any depth, + // such as *interface{}, **interface{}, etc., then we need to convert + // the value "v" from *CONCRETE to *interface{} so types match for + // Set. + // + // Example if v is type *Foo where Foo is a struct, v would become + // *interface{} instead. This only happens if we have an interface expectation + // at this depth. + // + // For more info, see GH-16 + if iType, ok := w.ifaceTypes[ifaceKey(w.ps[w.depth], w.depth)]; ok && iType.Kind() == reflect.Interface { + y := reflect.New(iType) // Create *interface{} + y.Elem().Set(reflect.Indirect(v)) // Assign "Foo" to interface{} (dereferenced) + v = y // v is now typed *interface{} (where *v = Foo) + } + + for i := 1; i < w.ps[w.depth]; i++ { + if iType, ok := w.ifaceTypes[ifaceKey(w.ps[w.depth]-i, w.depth)]; ok { + iface := reflect.New(iType).Elem() + iface.Set(v) + v = iface + } + + p := reflect.New(v.Type()) + p.Elem().Set(v) + v = p + } + + w.valPush(v) +} + +// if this value is a Locker, lock it and add it to the locks slice +func (w *walker) lock(v reflect.Value) { + if !w.useLocks { + return + } + + if !v.IsValid() || !v.CanInterface() { + return + } + + type rlocker interface { + RLocker() sync.Locker + } + + var locker sync.Locker + + // We can't call Interface() on a value directly, since that requires + // a copy. This is OK, since the pointer to a value which is a sync.Locker + // is also a sync.Locker. + if v.Kind() == reflect.Ptr { + switch l := v.Interface().(type) { + case rlocker: + // don't lock a mutex directly + if _, ok := l.(*sync.RWMutex); !ok { + locker = l.RLocker() + } + case sync.Locker: + locker = l + } + } else if v.CanAddr() { + switch l := v.Addr().Interface().(type) { + case rlocker: + // don't lock a mutex directly + if _, ok := l.(*sync.RWMutex); !ok { + locker = l.RLocker() + } + case sync.Locker: + locker = l + } + } + + // still no callable locker + if locker == nil { + return + } + + // don't lock a mutex directly + switch locker.(type) { + case *sync.Mutex, *sync.RWMutex: + return + } + + locker.Lock() + w.locks[w.depth] = locker +} + +// wrapPtr is a helper that takes v and always make it *v. copystructure +// stores things internally as pointers until the last moment before unwrapping +func wrapPtr(v reflect.Value) reflect.Value { + if !v.IsValid() { + return v + } + vPtr := reflect.New(v.Type()) + vPtr.Elem().Set(v) + return vPtr +} diff --git a/vendor/github.com/mitchellh/copystructure/go.mod b/vendor/github.com/mitchellh/copystructure/go.mod new file mode 100644 index 00000000000..d01864309b4 --- /dev/null +++ b/vendor/github.com/mitchellh/copystructure/go.mod @@ -0,0 +1,3 @@ +module github.com/mitchellh/copystructure + +require github.com/mitchellh/reflectwalk v1.0.0 diff --git a/vendor/github.com/mitchellh/copystructure/go.sum b/vendor/github.com/mitchellh/copystructure/go.sum new file mode 100644 index 00000000000..be572456190 --- /dev/null +++ b/vendor/github.com/mitchellh/copystructure/go.sum @@ -0,0 +1,2 @@ +github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= diff --git a/vendor/github.com/mitchellh/reflectwalk/.travis.yml b/vendor/github.com/mitchellh/reflectwalk/.travis.yml new file mode 100644 index 00000000000..4f2ee4d9733 --- /dev/null +++ b/vendor/github.com/mitchellh/reflectwalk/.travis.yml @@ -0,0 +1 @@ +language: go diff --git a/vendor/github.com/mitchellh/reflectwalk/LICENSE b/vendor/github.com/mitchellh/reflectwalk/LICENSE new file mode 100644 index 00000000000..f9c841a51e0 --- /dev/null +++ b/vendor/github.com/mitchellh/reflectwalk/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013 Mitchell Hashimoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/mitchellh/reflectwalk/README.md b/vendor/github.com/mitchellh/reflectwalk/README.md new file mode 100644 index 00000000000..ac82cd2e159 --- /dev/null +++ b/vendor/github.com/mitchellh/reflectwalk/README.md @@ -0,0 +1,6 @@ +# reflectwalk + +reflectwalk is a Go library for "walking" a value in Go using reflection, +in the same way a directory tree can be "walked" on the filesystem. Walking +a complex structure can allow you to do manipulations on unknown structures +such as those decoded from JSON. diff --git a/vendor/github.com/mitchellh/reflectwalk/go.mod b/vendor/github.com/mitchellh/reflectwalk/go.mod new file mode 100644 index 00000000000..52bb7c469e9 --- /dev/null +++ b/vendor/github.com/mitchellh/reflectwalk/go.mod @@ -0,0 +1 @@ +module github.com/mitchellh/reflectwalk diff --git a/vendor/github.com/mitchellh/reflectwalk/location.go b/vendor/github.com/mitchellh/reflectwalk/location.go new file mode 100644 index 00000000000..6a7f176117f --- /dev/null +++ b/vendor/github.com/mitchellh/reflectwalk/location.go @@ -0,0 +1,19 @@ +package reflectwalk + +//go:generate stringer -type=Location location.go + +type Location uint + +const ( + None Location = iota + Map + MapKey + MapValue + Slice + SliceElem + Array + ArrayElem + Struct + StructField + WalkLoc +) diff --git a/vendor/github.com/mitchellh/reflectwalk/location_string.go b/vendor/github.com/mitchellh/reflectwalk/location_string.go new file mode 100644 index 00000000000..70760cf4c70 --- /dev/null +++ b/vendor/github.com/mitchellh/reflectwalk/location_string.go @@ -0,0 +1,16 @@ +// Code generated by "stringer -type=Location location.go"; DO NOT EDIT. + +package reflectwalk + +import "fmt" + +const _Location_name = "NoneMapMapKeyMapValueSliceSliceElemArrayArrayElemStructStructFieldWalkLoc" + +var _Location_index = [...]uint8{0, 4, 7, 13, 21, 26, 35, 40, 49, 55, 66, 73} + +func (i Location) String() string { + if i >= Location(len(_Location_index)-1) { + return fmt.Sprintf("Location(%d)", i) + } + return _Location_name[_Location_index[i]:_Location_index[i+1]] +} diff --git a/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go b/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go new file mode 100644 index 00000000000..d7ab7b6d782 --- /dev/null +++ b/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go @@ -0,0 +1,401 @@ +// reflectwalk is a package that allows you to "walk" complex structures +// similar to how you may "walk" a filesystem: visiting every element one +// by one and calling callback functions allowing you to handle and manipulate +// those elements. +package reflectwalk + +import ( + "errors" + "reflect" +) + +// PrimitiveWalker implementations are able to handle primitive values +// within complex structures. Primitive values are numbers, strings, +// booleans, funcs, chans. +// +// These primitive values are often members of more complex +// structures (slices, maps, etc.) that are walkable by other interfaces. +type PrimitiveWalker interface { + Primitive(reflect.Value) error +} + +// InterfaceWalker implementations are able to handle interface values as they +// are encountered during the walk. +type InterfaceWalker interface { + Interface(reflect.Value) error +} + +// MapWalker implementations are able to handle individual elements +// found within a map structure. +type MapWalker interface { + Map(m reflect.Value) error + MapElem(m, k, v reflect.Value) error +} + +// SliceWalker implementations are able to handle slice elements found +// within complex structures. +type SliceWalker interface { + Slice(reflect.Value) error + SliceElem(int, reflect.Value) error +} + +// ArrayWalker implementations are able to handle array elements found +// within complex structures. +type ArrayWalker interface { + Array(reflect.Value) error + ArrayElem(int, reflect.Value) error +} + +// StructWalker is an interface that has methods that are called for +// structs when a Walk is done. +type StructWalker interface { + Struct(reflect.Value) error + StructField(reflect.StructField, reflect.Value) error +} + +// EnterExitWalker implementations are notified before and after +// they walk deeper into complex structures (into struct fields, +// into slice elements, etc.) +type EnterExitWalker interface { + Enter(Location) error + Exit(Location) error +} + +// PointerWalker implementations are notified when the value they're +// walking is a pointer or not. Pointer is called for _every_ value whether +// it is a pointer or not. +type PointerWalker interface { + PointerEnter(bool) error + PointerExit(bool) error +} + +// SkipEntry can be returned from walk functions to skip walking +// the value of this field. This is only valid in the following functions: +// +// - Struct: skips all fields from being walked +// - StructField: skips walking the struct value +// +var SkipEntry = errors.New("skip this entry") + +// Walk takes an arbitrary value and an interface and traverses the +// value, calling callbacks on the interface if they are supported. +// The interface should implement one or more of the walker interfaces +// in this package, such as PrimitiveWalker, StructWalker, etc. +func Walk(data, walker interface{}) (err error) { + v := reflect.ValueOf(data) + ew, ok := walker.(EnterExitWalker) + if ok { + err = ew.Enter(WalkLoc) + } + + if err == nil { + err = walk(v, walker) + } + + if ok && err == nil { + err = ew.Exit(WalkLoc) + } + + return +} + +func walk(v reflect.Value, w interface{}) (err error) { + // Determine if we're receiving a pointer and if so notify the walker. + // The logic here is convoluted but very important (tests will fail if + // almost any part is changed). I will try to explain here. + // + // First, we check if the value is an interface, if so, we really need + // to check the interface's VALUE to see whether it is a pointer. + // + // Check whether the value is then a pointer. If so, then set pointer + // to true to notify the user. + // + // If we still have a pointer or an interface after the indirections, then + // we unwrap another level + // + // At this time, we also set "v" to be the dereferenced value. This is + // because once we've unwrapped the pointer we want to use that value. + pointer := false + pointerV := v + + for { + if pointerV.Kind() == reflect.Interface { + if iw, ok := w.(InterfaceWalker); ok { + if err = iw.Interface(pointerV); err != nil { + return + } + } + + pointerV = pointerV.Elem() + } + + if pointerV.Kind() == reflect.Ptr { + pointer = true + v = reflect.Indirect(pointerV) + } + if pw, ok := w.(PointerWalker); ok { + if err = pw.PointerEnter(pointer); err != nil { + return + } + + defer func(pointer bool) { + if err != nil { + return + } + + err = pw.PointerExit(pointer) + }(pointer) + } + + if pointer { + pointerV = v + } + pointer = false + + // If we still have a pointer or interface we have to indirect another level. + switch pointerV.Kind() { + case reflect.Ptr, reflect.Interface: + continue + } + break + } + + // We preserve the original value here because if it is an interface + // type, we want to pass that directly into the walkPrimitive, so that + // we can set it. + originalV := v + if v.Kind() == reflect.Interface { + v = v.Elem() + } + + k := v.Kind() + if k >= reflect.Int && k <= reflect.Complex128 { + k = reflect.Int + } + + switch k { + // Primitives + case reflect.Bool, reflect.Chan, reflect.Func, reflect.Int, reflect.String, reflect.Invalid: + err = walkPrimitive(originalV, w) + return + case reflect.Map: + err = walkMap(v, w) + return + case reflect.Slice: + err = walkSlice(v, w) + return + case reflect.Struct: + err = walkStruct(v, w) + return + case reflect.Array: + err = walkArray(v, w) + return + default: + panic("unsupported type: " + k.String()) + } +} + +func walkMap(v reflect.Value, w interface{}) error { + ew, ewok := w.(EnterExitWalker) + if ewok { + ew.Enter(Map) + } + + if mw, ok := w.(MapWalker); ok { + if err := mw.Map(v); err != nil { + return err + } + } + + for _, k := range v.MapKeys() { + kv := v.MapIndex(k) + + if mw, ok := w.(MapWalker); ok { + if err := mw.MapElem(v, k, kv); err != nil { + return err + } + } + + ew, ok := w.(EnterExitWalker) + if ok { + ew.Enter(MapKey) + } + + if err := walk(k, w); err != nil { + return err + } + + if ok { + ew.Exit(MapKey) + ew.Enter(MapValue) + } + + if err := walk(kv, w); err != nil { + return err + } + + if ok { + ew.Exit(MapValue) + } + } + + if ewok { + ew.Exit(Map) + } + + return nil +} + +func walkPrimitive(v reflect.Value, w interface{}) error { + if pw, ok := w.(PrimitiveWalker); ok { + return pw.Primitive(v) + } + + return nil +} + +func walkSlice(v reflect.Value, w interface{}) (err error) { + ew, ok := w.(EnterExitWalker) + if ok { + ew.Enter(Slice) + } + + if sw, ok := w.(SliceWalker); ok { + if err := sw.Slice(v); err != nil { + return err + } + } + + for i := 0; i < v.Len(); i++ { + elem := v.Index(i) + + if sw, ok := w.(SliceWalker); ok { + if err := sw.SliceElem(i, elem); err != nil { + return err + } + } + + ew, ok := w.(EnterExitWalker) + if ok { + ew.Enter(SliceElem) + } + + if err := walk(elem, w); err != nil { + return err + } + + if ok { + ew.Exit(SliceElem) + } + } + + ew, ok = w.(EnterExitWalker) + if ok { + ew.Exit(Slice) + } + + return nil +} + +func walkArray(v reflect.Value, w interface{}) (err error) { + ew, ok := w.(EnterExitWalker) + if ok { + ew.Enter(Array) + } + + if aw, ok := w.(ArrayWalker); ok { + if err := aw.Array(v); err != nil { + return err + } + } + + for i := 0; i < v.Len(); i++ { + elem := v.Index(i) + + if aw, ok := w.(ArrayWalker); ok { + if err := aw.ArrayElem(i, elem); err != nil { + return err + } + } + + ew, ok := w.(EnterExitWalker) + if ok { + ew.Enter(ArrayElem) + } + + if err := walk(elem, w); err != nil { + return err + } + + if ok { + ew.Exit(ArrayElem) + } + } + + ew, ok = w.(EnterExitWalker) + if ok { + ew.Exit(Array) + } + + return nil +} + +func walkStruct(v reflect.Value, w interface{}) (err error) { + ew, ewok := w.(EnterExitWalker) + if ewok { + ew.Enter(Struct) + } + + skip := false + if sw, ok := w.(StructWalker); ok { + err = sw.Struct(v) + if err == SkipEntry { + skip = true + err = nil + } + if err != nil { + return + } + } + + if !skip { + vt := v.Type() + for i := 0; i < vt.NumField(); i++ { + sf := vt.Field(i) + f := v.FieldByIndex([]int{i}) + + if sw, ok := w.(StructWalker); ok { + err = sw.StructField(sf, f) + + // SkipEntry just pretends this field doesn't even exist + if err == SkipEntry { + continue + } + + if err != nil { + return + } + } + + ew, ok := w.(EnterExitWalker) + if ok { + ew.Enter(StructField) + } + + err = walk(f, w) + if err != nil { + return + } + + if ok { + ew.Exit(StructField) + } + } + } + + if ewok { + ew.Exit(Struct) + } + + return nil +} diff --git a/vendor/github.com/pmezard/go-difflib/LICENSE b/vendor/github.com/pmezard/go-difflib/LICENSE new file mode 100644 index 00000000000..c67dad612a3 --- /dev/null +++ b/vendor/github.com/pmezard/go-difflib/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2013, Patrick Mezard +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + The names of its contributors may not be used to endorse or promote +products derived from this software without specific prior written +permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/pmezard/go-difflib/difflib/difflib.go b/vendor/github.com/pmezard/go-difflib/difflib/difflib.go new file mode 100644 index 00000000000..003e99fadb4 --- /dev/null +++ b/vendor/github.com/pmezard/go-difflib/difflib/difflib.go @@ -0,0 +1,772 @@ +// Package difflib is a partial port of Python difflib module. +// +// It provides tools to compare sequences of strings and generate textual diffs. +// +// The following class and functions have been ported: +// +// - SequenceMatcher +// +// - unified_diff +// +// - context_diff +// +// Getting unified diffs was the main goal of the port. Keep in mind this code +// is mostly suitable to output text differences in a human friendly way, there +// are no guarantees generated diffs are consumable by patch(1). +package difflib + +import ( + "bufio" + "bytes" + "fmt" + "io" + "strings" +) + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} + +func calculateRatio(matches, length int) float64 { + if length > 0 { + return 2.0 * float64(matches) / float64(length) + } + return 1.0 +} + +type Match struct { + A int + B int + Size int +} + +type OpCode struct { + Tag byte + I1 int + I2 int + J1 int + J2 int +} + +// SequenceMatcher compares sequence of strings. The basic +// algorithm predates, and is a little fancier than, an algorithm +// published in the late 1980's by Ratcliff and Obershelp under the +// hyperbolic name "gestalt pattern matching". The basic idea is to find +// the longest contiguous matching subsequence that contains no "junk" +// elements (R-O doesn't address junk). The same idea is then applied +// recursively to the pieces of the sequences to the left and to the right +// of the matching subsequence. This does not yield minimal edit +// sequences, but does tend to yield matches that "look right" to people. +// +// SequenceMatcher tries to compute a "human-friendly diff" between two +// sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the +// longest *contiguous* & junk-free matching subsequence. That's what +// catches peoples' eyes. The Windows(tm) windiff has another interesting +// notion, pairing up elements that appear uniquely in each sequence. +// That, and the method here, appear to yield more intuitive difference +// reports than does diff. This method appears to be the least vulnerable +// to synching up on blocks of "junk lines", though (like blank lines in +// ordinary text files, or maybe "

" lines in HTML files). That may be +// because this is the only method of the 3 that has a *concept* of +// "junk" . +// +// Timing: Basic R-O is cubic time worst case and quadratic time expected +// case. SequenceMatcher is quadratic time for the worst case and has +// expected-case behavior dependent in a complicated way on how many +// elements the sequences have in common; best case time is linear. +type SequenceMatcher struct { + a []string + b []string + b2j map[string][]int + IsJunk func(string) bool + autoJunk bool + bJunk map[string]struct{} + matchingBlocks []Match + fullBCount map[string]int + bPopular map[string]struct{} + opCodes []OpCode +} + +func NewMatcher(a, b []string) *SequenceMatcher { + m := SequenceMatcher{autoJunk: true} + m.SetSeqs(a, b) + return &m +} + +func NewMatcherWithJunk(a, b []string, autoJunk bool, + isJunk func(string) bool) *SequenceMatcher { + + m := SequenceMatcher{IsJunk: isJunk, autoJunk: autoJunk} + m.SetSeqs(a, b) + return &m +} + +// Set two sequences to be compared. +func (m *SequenceMatcher) SetSeqs(a, b []string) { + m.SetSeq1(a) + m.SetSeq2(b) +} + +// Set the first sequence to be compared. The second sequence to be compared is +// not changed. +// +// SequenceMatcher computes and caches detailed information about the second +// sequence, so if you want to compare one sequence S against many sequences, +// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other +// sequences. +// +// See also SetSeqs() and SetSeq2(). +func (m *SequenceMatcher) SetSeq1(a []string) { + if &a == &m.a { + return + } + m.a = a + m.matchingBlocks = nil + m.opCodes = nil +} + +// Set the second sequence to be compared. The first sequence to be compared is +// not changed. +func (m *SequenceMatcher) SetSeq2(b []string) { + if &b == &m.b { + return + } + m.b = b + m.matchingBlocks = nil + m.opCodes = nil + m.fullBCount = nil + m.chainB() +} + +func (m *SequenceMatcher) chainB() { + // Populate line -> index mapping + b2j := map[string][]int{} + for i, s := range m.b { + indices := b2j[s] + indices = append(indices, i) + b2j[s] = indices + } + + // Purge junk elements + m.bJunk = map[string]struct{}{} + if m.IsJunk != nil { + junk := m.bJunk + for s, _ := range b2j { + if m.IsJunk(s) { + junk[s] = struct{}{} + } + } + for s, _ := range junk { + delete(b2j, s) + } + } + + // Purge remaining popular elements + popular := map[string]struct{}{} + n := len(m.b) + if m.autoJunk && n >= 200 { + ntest := n/100 + 1 + for s, indices := range b2j { + if len(indices) > ntest { + popular[s] = struct{}{} + } + } + for s, _ := range popular { + delete(b2j, s) + } + } + m.bPopular = popular + m.b2j = b2j +} + +func (m *SequenceMatcher) isBJunk(s string) bool { + _, ok := m.bJunk[s] + return ok +} + +// Find longest matching block in a[alo:ahi] and b[blo:bhi]. +// +// If IsJunk is not defined: +// +// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where +// alo <= i <= i+k <= ahi +// blo <= j <= j+k <= bhi +// and for all (i',j',k') meeting those conditions, +// k >= k' +// i <= i' +// and if i == i', j <= j' +// +// In other words, of all maximal matching blocks, return one that +// starts earliest in a, and of all those maximal matching blocks that +// start earliest in a, return the one that starts earliest in b. +// +// If IsJunk is defined, first the longest matching block is +// determined as above, but with the additional restriction that no +// junk element appears in the block. Then that block is extended as +// far as possible by matching (only) junk elements on both sides. So +// the resulting block never matches on junk except as identical junk +// happens to be adjacent to an "interesting" match. +// +// If no blocks match, return (alo, blo, 0). +func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match { + // CAUTION: stripping common prefix or suffix would be incorrect. + // E.g., + // ab + // acab + // Longest matching block is "ab", but if common prefix is + // stripped, it's "a" (tied with "b"). UNIX(tm) diff does so + // strip, so ends up claiming that ab is changed to acab by + // inserting "ca" in the middle. That's minimal but unintuitive: + // "it's obvious" that someone inserted "ac" at the front. + // Windiff ends up at the same place as diff, but by pairing up + // the unique 'b's and then matching the first two 'a's. + besti, bestj, bestsize := alo, blo, 0 + + // find longest junk-free match + // during an iteration of the loop, j2len[j] = length of longest + // junk-free match ending with a[i-1] and b[j] + j2len := map[int]int{} + for i := alo; i != ahi; i++ { + // look at all instances of a[i] in b; note that because + // b2j has no junk keys, the loop is skipped if a[i] is junk + newj2len := map[int]int{} + for _, j := range m.b2j[m.a[i]] { + // a[i] matches b[j] + if j < blo { + continue + } + if j >= bhi { + break + } + k := j2len[j-1] + 1 + newj2len[j] = k + if k > bestsize { + besti, bestj, bestsize = i-k+1, j-k+1, k + } + } + j2len = newj2len + } + + // Extend the best by non-junk elements on each end. In particular, + // "popular" non-junk elements aren't in b2j, which greatly speeds + // the inner loop above, but also means "the best" match so far + // doesn't contain any junk *or* popular non-junk elements. + for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) && + m.a[besti-1] == m.b[bestj-1] { + besti, bestj, bestsize = besti-1, bestj-1, bestsize+1 + } + for besti+bestsize < ahi && bestj+bestsize < bhi && + !m.isBJunk(m.b[bestj+bestsize]) && + m.a[besti+bestsize] == m.b[bestj+bestsize] { + bestsize += 1 + } + + // Now that we have a wholly interesting match (albeit possibly + // empty!), we may as well suck up the matching junk on each + // side of it too. Can't think of a good reason not to, and it + // saves post-processing the (possibly considerable) expense of + // figuring out what to do with it. In the case of an empty + // interesting match, this is clearly the right thing to do, + // because no other kind of match is possible in the regions. + for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) && + m.a[besti-1] == m.b[bestj-1] { + besti, bestj, bestsize = besti-1, bestj-1, bestsize+1 + } + for besti+bestsize < ahi && bestj+bestsize < bhi && + m.isBJunk(m.b[bestj+bestsize]) && + m.a[besti+bestsize] == m.b[bestj+bestsize] { + bestsize += 1 + } + + return Match{A: besti, B: bestj, Size: bestsize} +} + +// Return list of triples describing matching subsequences. +// +// Each triple is of the form (i, j, n), and means that +// a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in +// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are +// adjacent triples in the list, and the second is not the last triple in the +// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe +// adjacent equal blocks. +// +// The last triple is a dummy, (len(a), len(b), 0), and is the only +// triple with n==0. +func (m *SequenceMatcher) GetMatchingBlocks() []Match { + if m.matchingBlocks != nil { + return m.matchingBlocks + } + + var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match + matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match { + match := m.findLongestMatch(alo, ahi, blo, bhi) + i, j, k := match.A, match.B, match.Size + if match.Size > 0 { + if alo < i && blo < j { + matched = matchBlocks(alo, i, blo, j, matched) + } + matched = append(matched, match) + if i+k < ahi && j+k < bhi { + matched = matchBlocks(i+k, ahi, j+k, bhi, matched) + } + } + return matched + } + matched := matchBlocks(0, len(m.a), 0, len(m.b), nil) + + // It's possible that we have adjacent equal blocks in the + // matching_blocks list now. + nonAdjacent := []Match{} + i1, j1, k1 := 0, 0, 0 + for _, b := range matched { + // Is this block adjacent to i1, j1, k1? + i2, j2, k2 := b.A, b.B, b.Size + if i1+k1 == i2 && j1+k1 == j2 { + // Yes, so collapse them -- this just increases the length of + // the first block by the length of the second, and the first + // block so lengthened remains the block to compare against. + k1 += k2 + } else { + // Not adjacent. Remember the first block (k1==0 means it's + // the dummy we started with), and make the second block the + // new block to compare against. + if k1 > 0 { + nonAdjacent = append(nonAdjacent, Match{i1, j1, k1}) + } + i1, j1, k1 = i2, j2, k2 + } + } + if k1 > 0 { + nonAdjacent = append(nonAdjacent, Match{i1, j1, k1}) + } + + nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0}) + m.matchingBlocks = nonAdjacent + return m.matchingBlocks +} + +// Return list of 5-tuples describing how to turn a into b. +// +// Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple +// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the +// tuple preceding it, and likewise for j1 == the previous j2. +// +// The tags are characters, with these meanings: +// +// 'r' (replace): a[i1:i2] should be replaced by b[j1:j2] +// +// 'd' (delete): a[i1:i2] should be deleted, j1==j2 in this case. +// +// 'i' (insert): b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case. +// +// 'e' (equal): a[i1:i2] == b[j1:j2] +func (m *SequenceMatcher) GetOpCodes() []OpCode { + if m.opCodes != nil { + return m.opCodes + } + i, j := 0, 0 + matching := m.GetMatchingBlocks() + opCodes := make([]OpCode, 0, len(matching)) + for _, m := range matching { + // invariant: we've pumped out correct diffs to change + // a[:i] into b[:j], and the next matching block is + // a[ai:ai+size] == b[bj:bj+size]. So we need to pump + // out a diff to change a[i:ai] into b[j:bj], pump out + // the matching block, and move (i,j) beyond the match + ai, bj, size := m.A, m.B, m.Size + tag := byte(0) + if i < ai && j < bj { + tag = 'r' + } else if i < ai { + tag = 'd' + } else if j < bj { + tag = 'i' + } + if tag > 0 { + opCodes = append(opCodes, OpCode{tag, i, ai, j, bj}) + } + i, j = ai+size, bj+size + // the list of matching blocks is terminated by a + // sentinel with size 0 + if size > 0 { + opCodes = append(opCodes, OpCode{'e', ai, i, bj, j}) + } + } + m.opCodes = opCodes + return m.opCodes +} + +// Isolate change clusters by eliminating ranges with no changes. +// +// Return a generator of groups with up to n lines of context. +// Each group is in the same format as returned by GetOpCodes(). +func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode { + if n < 0 { + n = 3 + } + codes := m.GetOpCodes() + if len(codes) == 0 { + codes = []OpCode{OpCode{'e', 0, 1, 0, 1}} + } + // Fixup leading and trailing groups if they show no changes. + if codes[0].Tag == 'e' { + c := codes[0] + i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 + codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2} + } + if codes[len(codes)-1].Tag == 'e' { + c := codes[len(codes)-1] + i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 + codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)} + } + nn := n + n + groups := [][]OpCode{} + group := []OpCode{} + for _, c := range codes { + i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 + // End the current group and start a new one whenever + // there is a large range with no changes. + if c.Tag == 'e' && i2-i1 > nn { + group = append(group, OpCode{c.Tag, i1, min(i2, i1+n), + j1, min(j2, j1+n)}) + groups = append(groups, group) + group = []OpCode{} + i1, j1 = max(i1, i2-n), max(j1, j2-n) + } + group = append(group, OpCode{c.Tag, i1, i2, j1, j2}) + } + if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') { + groups = append(groups, group) + } + return groups +} + +// Return a measure of the sequences' similarity (float in [0,1]). +// +// Where T is the total number of elements in both sequences, and +// M is the number of matches, this is 2.0*M / T. +// Note that this is 1 if the sequences are identical, and 0 if +// they have nothing in common. +// +// .Ratio() is expensive to compute if you haven't already computed +// .GetMatchingBlocks() or .GetOpCodes(), in which case you may +// want to try .QuickRatio() or .RealQuickRation() first to get an +// upper bound. +func (m *SequenceMatcher) Ratio() float64 { + matches := 0 + for _, m := range m.GetMatchingBlocks() { + matches += m.Size + } + return calculateRatio(matches, len(m.a)+len(m.b)) +} + +// Return an upper bound on ratio() relatively quickly. +// +// This isn't defined beyond that it is an upper bound on .Ratio(), and +// is faster to compute. +func (m *SequenceMatcher) QuickRatio() float64 { + // viewing a and b as multisets, set matches to the cardinality + // of their intersection; this counts the number of matches + // without regard to order, so is clearly an upper bound + if m.fullBCount == nil { + m.fullBCount = map[string]int{} + for _, s := range m.b { + m.fullBCount[s] = m.fullBCount[s] + 1 + } + } + + // avail[x] is the number of times x appears in 'b' less the + // number of times we've seen it in 'a' so far ... kinda + avail := map[string]int{} + matches := 0 + for _, s := range m.a { + n, ok := avail[s] + if !ok { + n = m.fullBCount[s] + } + avail[s] = n - 1 + if n > 0 { + matches += 1 + } + } + return calculateRatio(matches, len(m.a)+len(m.b)) +} + +// Return an upper bound on ratio() very quickly. +// +// This isn't defined beyond that it is an upper bound on .Ratio(), and +// is faster to compute than either .Ratio() or .QuickRatio(). +func (m *SequenceMatcher) RealQuickRatio() float64 { + la, lb := len(m.a), len(m.b) + return calculateRatio(min(la, lb), la+lb) +} + +// Convert range to the "ed" format +func formatRangeUnified(start, stop int) string { + // Per the diff spec at http://www.unix.org/single_unix_specification/ + beginning := start + 1 // lines start numbering with one + length := stop - start + if length == 1 { + return fmt.Sprintf("%d", beginning) + } + if length == 0 { + beginning -= 1 // empty ranges begin at line just before the range + } + return fmt.Sprintf("%d,%d", beginning, length) +} + +// Unified diff parameters +type UnifiedDiff struct { + A []string // First sequence lines + FromFile string // First file name + FromDate string // First file time + B []string // Second sequence lines + ToFile string // Second file name + ToDate string // Second file time + Eol string // Headers end of line, defaults to LF + Context int // Number of context lines +} + +// Compare two sequences of lines; generate the delta as a unified diff. +// +// Unified diffs are a compact way of showing line changes and a few +// lines of context. The number of context lines is set by 'n' which +// defaults to three. +// +// By default, the diff control lines (those with ---, +++, or @@) are +// created with a trailing newline. This is helpful so that inputs +// created from file.readlines() result in diffs that are suitable for +// file.writelines() since both the inputs and outputs have trailing +// newlines. +// +// For inputs that do not have trailing newlines, set the lineterm +// argument to "" so that the output will be uniformly newline free. +// +// The unidiff format normally has a header for filenames and modification +// times. Any or all of these may be specified using strings for +// 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'. +// The modification times are normally expressed in the ISO 8601 format. +func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error { + buf := bufio.NewWriter(writer) + defer buf.Flush() + wf := func(format string, args ...interface{}) error { + _, err := buf.WriteString(fmt.Sprintf(format, args...)) + return err + } + ws := func(s string) error { + _, err := buf.WriteString(s) + return err + } + + if len(diff.Eol) == 0 { + diff.Eol = "\n" + } + + started := false + m := NewMatcher(diff.A, diff.B) + for _, g := range m.GetGroupedOpCodes(diff.Context) { + if !started { + started = true + fromDate := "" + if len(diff.FromDate) > 0 { + fromDate = "\t" + diff.FromDate + } + toDate := "" + if len(diff.ToDate) > 0 { + toDate = "\t" + diff.ToDate + } + if diff.FromFile != "" || diff.ToFile != "" { + err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol) + if err != nil { + return err + } + err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol) + if err != nil { + return err + } + } + } + first, last := g[0], g[len(g)-1] + range1 := formatRangeUnified(first.I1, last.I2) + range2 := formatRangeUnified(first.J1, last.J2) + if err := wf("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil { + return err + } + for _, c := range g { + i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 + if c.Tag == 'e' { + for _, line := range diff.A[i1:i2] { + if err := ws(" " + line); err != nil { + return err + } + } + continue + } + if c.Tag == 'r' || c.Tag == 'd' { + for _, line := range diff.A[i1:i2] { + if err := ws("-" + line); err != nil { + return err + } + } + } + if c.Tag == 'r' || c.Tag == 'i' { + for _, line := range diff.B[j1:j2] { + if err := ws("+" + line); err != nil { + return err + } + } + } + } + } + return nil +} + +// Like WriteUnifiedDiff but returns the diff a string. +func GetUnifiedDiffString(diff UnifiedDiff) (string, error) { + w := &bytes.Buffer{} + err := WriteUnifiedDiff(w, diff) + return string(w.Bytes()), err +} + +// Convert range to the "ed" format. +func formatRangeContext(start, stop int) string { + // Per the diff spec at http://www.unix.org/single_unix_specification/ + beginning := start + 1 // lines start numbering with one + length := stop - start + if length == 0 { + beginning -= 1 // empty ranges begin at line just before the range + } + if length <= 1 { + return fmt.Sprintf("%d", beginning) + } + return fmt.Sprintf("%d,%d", beginning, beginning+length-1) +} + +type ContextDiff UnifiedDiff + +// Compare two sequences of lines; generate the delta as a context diff. +// +// Context diffs are a compact way of showing line changes and a few +// lines of context. The number of context lines is set by diff.Context +// which defaults to three. +// +// By default, the diff control lines (those with *** or ---) are +// created with a trailing newline. +// +// For inputs that do not have trailing newlines, set the diff.Eol +// argument to "" so that the output will be uniformly newline free. +// +// The context diff format normally has a header for filenames and +// modification times. Any or all of these may be specified using +// strings for diff.FromFile, diff.ToFile, diff.FromDate, diff.ToDate. +// The modification times are normally expressed in the ISO 8601 format. +// If not specified, the strings default to blanks. +func WriteContextDiff(writer io.Writer, diff ContextDiff) error { + buf := bufio.NewWriter(writer) + defer buf.Flush() + var diffErr error + wf := func(format string, args ...interface{}) { + _, err := buf.WriteString(fmt.Sprintf(format, args...)) + if diffErr == nil && err != nil { + diffErr = err + } + } + ws := func(s string) { + _, err := buf.WriteString(s) + if diffErr == nil && err != nil { + diffErr = err + } + } + + if len(diff.Eol) == 0 { + diff.Eol = "\n" + } + + prefix := map[byte]string{ + 'i': "+ ", + 'd': "- ", + 'r': "! ", + 'e': " ", + } + + started := false + m := NewMatcher(diff.A, diff.B) + for _, g := range m.GetGroupedOpCodes(diff.Context) { + if !started { + started = true + fromDate := "" + if len(diff.FromDate) > 0 { + fromDate = "\t" + diff.FromDate + } + toDate := "" + if len(diff.ToDate) > 0 { + toDate = "\t" + diff.ToDate + } + if diff.FromFile != "" || diff.ToFile != "" { + wf("*** %s%s%s", diff.FromFile, fromDate, diff.Eol) + wf("--- %s%s%s", diff.ToFile, toDate, diff.Eol) + } + } + + first, last := g[0], g[len(g)-1] + ws("***************" + diff.Eol) + + range1 := formatRangeContext(first.I1, last.I2) + wf("*** %s ****%s", range1, diff.Eol) + for _, c := range g { + if c.Tag == 'r' || c.Tag == 'd' { + for _, cc := range g { + if cc.Tag == 'i' { + continue + } + for _, line := range diff.A[cc.I1:cc.I2] { + ws(prefix[cc.Tag] + line) + } + } + break + } + } + + range2 := formatRangeContext(first.J1, last.J2) + wf("--- %s ----%s", range2, diff.Eol) + for _, c := range g { + if c.Tag == 'r' || c.Tag == 'i' { + for _, cc := range g { + if cc.Tag == 'd' { + continue + } + for _, line := range diff.B[cc.J1:cc.J2] { + ws(prefix[cc.Tag] + line) + } + } + break + } + } + } + return diffErr +} + +// Like WriteContextDiff but returns the diff a string. +func GetContextDiffString(diff ContextDiff) (string, error) { + w := &bytes.Buffer{} + err := WriteContextDiff(w, diff) + return string(w.Bytes()), err +} + +// Split a string on "\n" while preserving them. The output can be used +// as input for UnifiedDiff and ContextDiff structures. +func SplitLines(s string) []string { + lines := strings.SplitAfter(s, "\n") + lines[len(lines)-1] += "\n" + return lines +} diff --git a/vendor/github.com/stretchr/testify/LICENSE b/vendor/github.com/stretchr/testify/LICENSE new file mode 100644 index 00000000000..4b0421cf9ee --- /dev/null +++ b/vendor/github.com/stretchr/testify/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare.go b/vendor/github.com/stretchr/testify/assert/assertion_compare.go new file mode 100644 index 00000000000..41649d26792 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_compare.go @@ -0,0 +1,394 @@ +package assert + +import ( + "fmt" + "reflect" +) + +type CompareType int + +const ( + compareLess CompareType = iota - 1 + compareEqual + compareGreater +) + +var ( + intType = reflect.TypeOf(int(1)) + int8Type = reflect.TypeOf(int8(1)) + int16Type = reflect.TypeOf(int16(1)) + int32Type = reflect.TypeOf(int32(1)) + int64Type = reflect.TypeOf(int64(1)) + + uintType = reflect.TypeOf(uint(1)) + uint8Type = reflect.TypeOf(uint8(1)) + uint16Type = reflect.TypeOf(uint16(1)) + uint32Type = reflect.TypeOf(uint32(1)) + uint64Type = reflect.TypeOf(uint64(1)) + + float32Type = reflect.TypeOf(float32(1)) + float64Type = reflect.TypeOf(float64(1)) + + stringType = reflect.TypeOf("") +) + +func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { + obj1Value := reflect.ValueOf(obj1) + obj2Value := reflect.ValueOf(obj2) + + // throughout this switch we try and avoid calling .Convert() if possible, + // as this has a pretty big performance impact + switch kind { + case reflect.Int: + { + intobj1, ok := obj1.(int) + if !ok { + intobj1 = obj1Value.Convert(intType).Interface().(int) + } + intobj2, ok := obj2.(int) + if !ok { + intobj2 = obj2Value.Convert(intType).Interface().(int) + } + if intobj1 > intobj2 { + return compareGreater, true + } + if intobj1 == intobj2 { + return compareEqual, true + } + if intobj1 < intobj2 { + return compareLess, true + } + } + case reflect.Int8: + { + int8obj1, ok := obj1.(int8) + if !ok { + int8obj1 = obj1Value.Convert(int8Type).Interface().(int8) + } + int8obj2, ok := obj2.(int8) + if !ok { + int8obj2 = obj2Value.Convert(int8Type).Interface().(int8) + } + if int8obj1 > int8obj2 { + return compareGreater, true + } + if int8obj1 == int8obj2 { + return compareEqual, true + } + if int8obj1 < int8obj2 { + return compareLess, true + } + } + case reflect.Int16: + { + int16obj1, ok := obj1.(int16) + if !ok { + int16obj1 = obj1Value.Convert(int16Type).Interface().(int16) + } + int16obj2, ok := obj2.(int16) + if !ok { + int16obj2 = obj2Value.Convert(int16Type).Interface().(int16) + } + if int16obj1 > int16obj2 { + return compareGreater, true + } + if int16obj1 == int16obj2 { + return compareEqual, true + } + if int16obj1 < int16obj2 { + return compareLess, true + } + } + case reflect.Int32: + { + int32obj1, ok := obj1.(int32) + if !ok { + int32obj1 = obj1Value.Convert(int32Type).Interface().(int32) + } + int32obj2, ok := obj2.(int32) + if !ok { + int32obj2 = obj2Value.Convert(int32Type).Interface().(int32) + } + if int32obj1 > int32obj2 { + return compareGreater, true + } + if int32obj1 == int32obj2 { + return compareEqual, true + } + if int32obj1 < int32obj2 { + return compareLess, true + } + } + case reflect.Int64: + { + int64obj1, ok := obj1.(int64) + if !ok { + int64obj1 = obj1Value.Convert(int64Type).Interface().(int64) + } + int64obj2, ok := obj2.(int64) + if !ok { + int64obj2 = obj2Value.Convert(int64Type).Interface().(int64) + } + if int64obj1 > int64obj2 { + return compareGreater, true + } + if int64obj1 == int64obj2 { + return compareEqual, true + } + if int64obj1 < int64obj2 { + return compareLess, true + } + } + case reflect.Uint: + { + uintobj1, ok := obj1.(uint) + if !ok { + uintobj1 = obj1Value.Convert(uintType).Interface().(uint) + } + uintobj2, ok := obj2.(uint) + if !ok { + uintobj2 = obj2Value.Convert(uintType).Interface().(uint) + } + if uintobj1 > uintobj2 { + return compareGreater, true + } + if uintobj1 == uintobj2 { + return compareEqual, true + } + if uintobj1 < uintobj2 { + return compareLess, true + } + } + case reflect.Uint8: + { + uint8obj1, ok := obj1.(uint8) + if !ok { + uint8obj1 = obj1Value.Convert(uint8Type).Interface().(uint8) + } + uint8obj2, ok := obj2.(uint8) + if !ok { + uint8obj2 = obj2Value.Convert(uint8Type).Interface().(uint8) + } + if uint8obj1 > uint8obj2 { + return compareGreater, true + } + if uint8obj1 == uint8obj2 { + return compareEqual, true + } + if uint8obj1 < uint8obj2 { + return compareLess, true + } + } + case reflect.Uint16: + { + uint16obj1, ok := obj1.(uint16) + if !ok { + uint16obj1 = obj1Value.Convert(uint16Type).Interface().(uint16) + } + uint16obj2, ok := obj2.(uint16) + if !ok { + uint16obj2 = obj2Value.Convert(uint16Type).Interface().(uint16) + } + if uint16obj1 > uint16obj2 { + return compareGreater, true + } + if uint16obj1 == uint16obj2 { + return compareEqual, true + } + if uint16obj1 < uint16obj2 { + return compareLess, true + } + } + case reflect.Uint32: + { + uint32obj1, ok := obj1.(uint32) + if !ok { + uint32obj1 = obj1Value.Convert(uint32Type).Interface().(uint32) + } + uint32obj2, ok := obj2.(uint32) + if !ok { + uint32obj2 = obj2Value.Convert(uint32Type).Interface().(uint32) + } + if uint32obj1 > uint32obj2 { + return compareGreater, true + } + if uint32obj1 == uint32obj2 { + return compareEqual, true + } + if uint32obj1 < uint32obj2 { + return compareLess, true + } + } + case reflect.Uint64: + { + uint64obj1, ok := obj1.(uint64) + if !ok { + uint64obj1 = obj1Value.Convert(uint64Type).Interface().(uint64) + } + uint64obj2, ok := obj2.(uint64) + if !ok { + uint64obj2 = obj2Value.Convert(uint64Type).Interface().(uint64) + } + if uint64obj1 > uint64obj2 { + return compareGreater, true + } + if uint64obj1 == uint64obj2 { + return compareEqual, true + } + if uint64obj1 < uint64obj2 { + return compareLess, true + } + } + case reflect.Float32: + { + float32obj1, ok := obj1.(float32) + if !ok { + float32obj1 = obj1Value.Convert(float32Type).Interface().(float32) + } + float32obj2, ok := obj2.(float32) + if !ok { + float32obj2 = obj2Value.Convert(float32Type).Interface().(float32) + } + if float32obj1 > float32obj2 { + return compareGreater, true + } + if float32obj1 == float32obj2 { + return compareEqual, true + } + if float32obj1 < float32obj2 { + return compareLess, true + } + } + case reflect.Float64: + { + float64obj1, ok := obj1.(float64) + if !ok { + float64obj1 = obj1Value.Convert(float64Type).Interface().(float64) + } + float64obj2, ok := obj2.(float64) + if !ok { + float64obj2 = obj2Value.Convert(float64Type).Interface().(float64) + } + if float64obj1 > float64obj2 { + return compareGreater, true + } + if float64obj1 == float64obj2 { + return compareEqual, true + } + if float64obj1 < float64obj2 { + return compareLess, true + } + } + case reflect.String: + { + stringobj1, ok := obj1.(string) + if !ok { + stringobj1 = obj1Value.Convert(stringType).Interface().(string) + } + stringobj2, ok := obj2.(string) + if !ok { + stringobj2 = obj2Value.Convert(stringType).Interface().(string) + } + if stringobj1 > stringobj2 { + return compareGreater, true + } + if stringobj1 == stringobj2 { + return compareEqual, true + } + if stringobj1 < stringobj2 { + return compareLess, true + } + } + } + + return compareEqual, false +} + +// Greater asserts that the first element is greater than the second +// +// assert.Greater(t, 2, 1) +// assert.Greater(t, float64(2), float64(1)) +// assert.Greater(t, "b", "a") +func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + return compareTwoValues(t, e1, e2, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs) +} + +// GreaterOrEqual asserts that the first element is greater than or equal to the second +// +// assert.GreaterOrEqual(t, 2, 1) +// assert.GreaterOrEqual(t, 2, 2) +// assert.GreaterOrEqual(t, "b", "a") +// assert.GreaterOrEqual(t, "b", "b") +func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + return compareTwoValues(t, e1, e2, []CompareType{compareGreater, compareEqual}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs) +} + +// Less asserts that the first element is less than the second +// +// assert.Less(t, 1, 2) +// assert.Less(t, float64(1), float64(2)) +// assert.Less(t, "a", "b") +func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + return compareTwoValues(t, e1, e2, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs) +} + +// LessOrEqual asserts that the first element is less than or equal to the second +// +// assert.LessOrEqual(t, 1, 2) +// assert.LessOrEqual(t, 2, 2) +// assert.LessOrEqual(t, "a", "b") +// assert.LessOrEqual(t, "b", "b") +func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + return compareTwoValues(t, e1, e2, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs) +} + +// Positive asserts that the specified element is positive +// +// assert.Positive(t, 1) +// assert.Positive(t, 1.23) +func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { + zero := reflect.Zero(reflect.TypeOf(e)) + return compareTwoValues(t, e, zero.Interface(), []CompareType{compareGreater}, "\"%v\" is not positive", msgAndArgs) +} + +// Negative asserts that the specified element is negative +// +// assert.Negative(t, -1) +// assert.Negative(t, -1.23) +func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { + zero := reflect.Zero(reflect.TypeOf(e)) + return compareTwoValues(t, e, zero.Interface(), []CompareType{compareLess}, "\"%v\" is not negative", msgAndArgs) +} + +func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + e1Kind := reflect.ValueOf(e1).Kind() + e2Kind := reflect.ValueOf(e2).Kind() + if e1Kind != e2Kind { + return Fail(t, "Elements should be the same type", msgAndArgs...) + } + + compareResult, isComparable := compare(e1, e2, e1Kind) + if !isComparable { + return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...) + } + + if !containsValue(allowedComparesResults, compareResult) { + return Fail(t, fmt.Sprintf(failMessage, e1, e2), msgAndArgs...) + } + + return true +} + +func containsValue(values []CompareType, value CompareType) bool { + for _, v := range values { + if v == value { + return true + } + } + + return false +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go b/vendor/github.com/stretchr/testify/assert/assertion_format.go new file mode 100644 index 00000000000..4dfd1229a86 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go @@ -0,0 +1,741 @@ +/* +* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen +* THIS FILE MUST NOT BE EDITED BY HAND + */ + +package assert + +import ( + http "net/http" + url "net/url" + time "time" +) + +// Conditionf uses a Comparison to assert a complex condition. +func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Condition(t, comp, append([]interface{}{msg}, args...)...) +} + +// Containsf asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted") +// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted") +// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted") +func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Contains(t, s, contains, append([]interface{}{msg}, args...)...) +} + +// DirExistsf checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. +func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return DirExists(t, path, append([]interface{}{msg}, args...)...) +} + +// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") +func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return ElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...) +} + +// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// assert.Emptyf(t, obj, "error message %s", "formatted") +func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Empty(t, object, append([]interface{}{msg}, args...)...) +} + +// Equalf asserts that two objects are equal. +// +// assert.Equalf(t, 123, 123, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Equal(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") +func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...) +} + +// EqualValuesf asserts that two objects are equal or convertable to the same types +// and equal. +// +// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") +func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// Errorf asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if assert.Errorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } +func Errorf(t TestingT, err error, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Error(t, err, append([]interface{}{msg}, args...)...) +} + +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return ErrorAs(t, err, target, append([]interface{}{msg}, args...)...) +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return ErrorIs(t, err, target, append([]interface{}{msg}, args...)...) +} + +// Eventuallyf asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Eventually(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...) +} + +// Exactlyf asserts that two objects are equal in value and type. +// +// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") +func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Exactly(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// Failf reports a failure through +func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Fail(t, failureMessage, append([]interface{}{msg}, args...)...) +} + +// FailNowf fails test +func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return FailNow(t, failureMessage, append([]interface{}{msg}, args...)...) +} + +// Falsef asserts that the specified value is false. +// +// assert.Falsef(t, myBool, "error message %s", "formatted") +func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return False(t, value, append([]interface{}{msg}, args...)...) +} + +// FileExistsf checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. +func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return FileExists(t, path, append([]interface{}{msg}, args...)...) +} + +// Greaterf asserts that the first element is greater than the second +// +// assert.Greaterf(t, 2, 1, "error message %s", "formatted") +// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") +// assert.Greaterf(t, "b", "a", "error message %s", "formatted") +func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Greater(t, e1, e2, append([]interface{}{msg}, args...)...) +} + +// GreaterOrEqualf asserts that the first element is greater than or equal to the second +// +// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted") +func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return GreaterOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...) +} + +// HTTPBodyContainsf asserts that a specified handler returns a +// body that contains a string. +// +// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return HTTPBodyContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...) +} + +// HTTPBodyNotContainsf asserts that a specified handler returns a +// body that does not contain a string. +// +// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return HTTPBodyNotContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...) +} + +// HTTPErrorf asserts that a specified handler returns an error status code. +// +// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return HTTPError(t, handler, method, url, values, append([]interface{}{msg}, args...)...) +} + +// HTTPRedirectf asserts that a specified handler returns a redirect status code. +// +// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return HTTPRedirect(t, handler, method, url, values, append([]interface{}{msg}, args...)...) +} + +// HTTPStatusCodef asserts that a specified handler returns a specified status code. +// +// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return HTTPStatusCode(t, handler, method, url, values, statuscode, append([]interface{}{msg}, args...)...) +} + +// HTTPSuccessf asserts that a specified handler returns a success status code. +// +// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return HTTPSuccess(t, handler, method, url, values, append([]interface{}{msg}, args...)...) +} + +// Implementsf asserts that an object is implemented by the specified interface. +// +// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Implements(t, interfaceObject, object, append([]interface{}{msg}, args...)...) +} + +// InDeltaf asserts that the two numerals are within delta of each other. +// +// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return InDelta(t, expected, actual, delta, append([]interface{}{msg}, args...)...) +} + +// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return InDeltaMapValues(t, expected, actual, delta, append([]interface{}{msg}, args...)...) +} + +// InDeltaSlicef is the same as InDelta, except it compares two slices. +func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return InDeltaSlice(t, expected, actual, delta, append([]interface{}{msg}, args...)...) +} + +// InEpsilonf asserts that expected and actual have a relative error less than epsilon +func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return InEpsilon(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...) +} + +// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. +func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return InEpsilonSlice(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...) +} + +// IsDecreasingf asserts that the collection is decreasing +// +// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsDecreasing(t, object, append([]interface{}{msg}, args...)...) +} + +// IsIncreasingf asserts that the collection is increasing +// +// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsIncreasing(t, object, append([]interface{}{msg}, args...)...) +} + +// IsNonDecreasingf asserts that the collection is not decreasing +// +// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsNonDecreasing(t, object, append([]interface{}{msg}, args...)...) +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsNonIncreasing(t, object, append([]interface{}{msg}, args...)...) +} + +// IsTypef asserts that the specified objects are of the same type. +func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsType(t, expectedType, object, append([]interface{}{msg}, args...)...) +} + +// JSONEqf asserts that two JSON strings are equivalent. +// +// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// Lenf asserts that the specified object has specific length. +// Lenf also fails if the object has a type that len() not accept. +// +// assert.Lenf(t, mySlice, 3, "error message %s", "formatted") +func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Len(t, object, length, append([]interface{}{msg}, args...)...) +} + +// Lessf asserts that the first element is less than the second +// +// assert.Lessf(t, 1, 2, "error message %s", "formatted") +// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted") +// assert.Lessf(t, "a", "b", "error message %s", "formatted") +func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Less(t, e1, e2, append([]interface{}{msg}, args...)...) +} + +// LessOrEqualf asserts that the first element is less than or equal to the second +// +// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted") +// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted") +func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return LessOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...) +} + +// Negativef asserts that the specified element is negative +// +// assert.Negativef(t, -1, "error message %s", "formatted") +// assert.Negativef(t, -1.23, "error message %s", "formatted") +func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Negative(t, e, append([]interface{}{msg}, args...)...) +} + +// Neverf asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Never(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...) +} + +// Nilf asserts that the specified object is nil. +// +// assert.Nilf(t, err, "error message %s", "formatted") +func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Nil(t, object, append([]interface{}{msg}, args...)...) +} + +// NoDirExistsf checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NoDirExists(t, path, append([]interface{}{msg}, args...)...) +} + +// NoErrorf asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if assert.NoErrorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } +func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NoError(t, err, append([]interface{}{msg}, args...)...) +} + +// NoFileExistsf checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NoFileExists(t, path, append([]interface{}{msg}, args...)...) +} + +// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted") +func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotContains(t, s, contains, append([]interface{}{msg}, args...)...) +} + +// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if assert.NotEmptyf(t, obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } +func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotEmpty(t, object, append([]interface{}{msg}, args...)...) +} + +// NotEqualf asserts that the specified values are NOT equal. +// +// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// NotEqualValuesf asserts that two objects are not equal even when converted to the same type +// +// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") +func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotEqualValues(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotErrorIs(t, err, target, append([]interface{}{msg}, args...)...) +} + +// NotNilf asserts that the specified object is not nil. +// +// assert.NotNilf(t, err, "error message %s", "formatted") +func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotNil(t, object, append([]interface{}{msg}, args...)...) +} + +// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") +func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotPanics(t, f, append([]interface{}{msg}, args...)...) +} + +// NotRegexpf asserts that a specified regexp does not match a string. +// +// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") +func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...) +} + +// NotSamef asserts that two pointers do not reference the same object. +// +// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotSame(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// NotSubsetf asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") +func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotSubset(t, list, subset, append([]interface{}{msg}, args...)...) +} + +// NotZerof asserts that i is not the zero value for its type. +func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotZero(t, i, append([]interface{}{msg}, args...)...) +} + +// Panicsf asserts that the code inside the specified PanicTestFunc panics. +// +// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") +func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Panics(t, f, append([]interface{}{msg}, args...)...) +} + +// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return PanicsWithError(t, errString, f, append([]interface{}{msg}, args...)...) +} + +// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return PanicsWithValue(t, expected, f, append([]interface{}{msg}, args...)...) +} + +// Positivef asserts that the specified element is positive +// +// assert.Positivef(t, 1, "error message %s", "formatted") +// assert.Positivef(t, 1.23, "error message %s", "formatted") +func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Positive(t, e, append([]interface{}{msg}, args...)...) +} + +// Regexpf asserts that a specified regexp matches a string. +// +// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") +func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Regexp(t, rx, str, append([]interface{}{msg}, args...)...) +} + +// Samef asserts that two pointers reference the same object. +// +// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Same(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// Subsetf asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") +func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Subset(t, list, subset, append([]interface{}{msg}, args...)...) +} + +// Truef asserts that the specified value is true. +// +// assert.Truef(t, myBool, "error message %s", "formatted") +func Truef(t TestingT, value bool, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return True(t, value, append([]interface{}{msg}, args...)...) +} + +// WithinDurationf asserts that the two times are within duration delta of each other. +// +// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...) +} + +// YAMLEqf asserts that two YAML strings are equivalent. +func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// Zerof asserts that i is the zero value for its type. +func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Zero(t, i, append([]interface{}{msg}, args...)...) +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl b/vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl new file mode 100644 index 00000000000..d2bb0b81778 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl @@ -0,0 +1,5 @@ +{{.CommentFormat}} +func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool { + if h, ok := t.(tHelper); ok { h.Helper() } + return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}}) +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go new file mode 100644 index 00000000000..25337a6f07e --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go @@ -0,0 +1,1470 @@ +/* +* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen +* THIS FILE MUST NOT BE EDITED BY HAND + */ + +package assert + +import ( + http "net/http" + url "net/url" + time "time" +) + +// Condition uses a Comparison to assert a complex condition. +func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Condition(a.t, comp, msgAndArgs...) +} + +// Conditionf uses a Comparison to assert a complex condition. +func (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Conditionf(a.t, comp, msg, args...) +} + +// Contains asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// a.Contains("Hello World", "World") +// a.Contains(["Hello", "World"], "World") +// a.Contains({"Hello": "World"}, "Hello") +func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Contains(a.t, s, contains, msgAndArgs...) +} + +// Containsf asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// a.Containsf("Hello World", "World", "error message %s", "formatted") +// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted") +// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") +func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Containsf(a.t, s, contains, msg, args...) +} + +// DirExists checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. +func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return DirExists(a.t, path, msgAndArgs...) +} + +// DirExistsf checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. +func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return DirExistsf(a.t, path, msg, args...) +} + +// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2]) +func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ElementsMatch(a.t, listA, listB, msgAndArgs...) +} + +// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") +func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ElementsMatchf(a.t, listA, listB, msg, args...) +} + +// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// a.Empty(obj) +func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Empty(a.t, object, msgAndArgs...) +} + +// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// a.Emptyf(obj, "error message %s", "formatted") +func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Emptyf(a.t, object, msg, args...) +} + +// Equal asserts that two objects are equal. +// +// a.Equal(123, 123) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Equal(a.t, expected, actual, msgAndArgs...) +} + +// EqualError asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// a.EqualError(err, expectedErrorString) +func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return EqualError(a.t, theError, errString, msgAndArgs...) +} + +// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") +func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return EqualErrorf(a.t, theError, errString, msg, args...) +} + +// EqualValues asserts that two objects are equal or convertable to the same types +// and equal. +// +// a.EqualValues(uint32(123), int32(123)) +func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return EqualValues(a.t, expected, actual, msgAndArgs...) +} + +// EqualValuesf asserts that two objects are equal or convertable to the same types +// and equal. +// +// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") +func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return EqualValuesf(a.t, expected, actual, msg, args...) +} + +// Equalf asserts that two objects are equal. +// +// a.Equalf(123, 123, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Equalf(a.t, expected, actual, msg, args...) +} + +// Error asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if a.Error(err) { +// assert.Equal(t, expectedError, err) +// } +func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Error(a.t, err, msgAndArgs...) +} + +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorAs(a.t, err, target, msgAndArgs...) +} + +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorAsf(a.t, err, target, msg, args...) +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorIs(a.t, err, target, msgAndArgs...) +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorIsf(a.t, err, target, msg, args...) +} + +// Errorf asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if a.Errorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } +func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Errorf(a.t, err, msg, args...) +} + +// Eventually asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) +func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Eventually(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// Eventuallyf asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Eventuallyf(a.t, condition, waitFor, tick, msg, args...) +} + +// Exactly asserts that two objects are equal in value and type. +// +// a.Exactly(int32(123), int64(123)) +func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Exactly(a.t, expected, actual, msgAndArgs...) +} + +// Exactlyf asserts that two objects are equal in value and type. +// +// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") +func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Exactlyf(a.t, expected, actual, msg, args...) +} + +// Fail reports a failure through +func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Fail(a.t, failureMessage, msgAndArgs...) +} + +// FailNow fails test +func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return FailNow(a.t, failureMessage, msgAndArgs...) +} + +// FailNowf fails test +func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return FailNowf(a.t, failureMessage, msg, args...) +} + +// Failf reports a failure through +func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Failf(a.t, failureMessage, msg, args...) +} + +// False asserts that the specified value is false. +// +// a.False(myBool) +func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return False(a.t, value, msgAndArgs...) +} + +// Falsef asserts that the specified value is false. +// +// a.Falsef(myBool, "error message %s", "formatted") +func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Falsef(a.t, value, msg, args...) +} + +// FileExists checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. +func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return FileExists(a.t, path, msgAndArgs...) +} + +// FileExistsf checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. +func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return FileExistsf(a.t, path, msg, args...) +} + +// Greater asserts that the first element is greater than the second +// +// a.Greater(2, 1) +// a.Greater(float64(2), float64(1)) +// a.Greater("b", "a") +func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Greater(a.t, e1, e2, msgAndArgs...) +} + +// GreaterOrEqual asserts that the first element is greater than or equal to the second +// +// a.GreaterOrEqual(2, 1) +// a.GreaterOrEqual(2, 2) +// a.GreaterOrEqual("b", "a") +// a.GreaterOrEqual("b", "b") +func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return GreaterOrEqual(a.t, e1, e2, msgAndArgs...) +} + +// GreaterOrEqualf asserts that the first element is greater than or equal to the second +// +// a.GreaterOrEqualf(2, 1, "error message %s", "formatted") +// a.GreaterOrEqualf(2, 2, "error message %s", "formatted") +// a.GreaterOrEqualf("b", "a", "error message %s", "formatted") +// a.GreaterOrEqualf("b", "b", "error message %s", "formatted") +func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return GreaterOrEqualf(a.t, e1, e2, msg, args...) +} + +// Greaterf asserts that the first element is greater than the second +// +// a.Greaterf(2, 1, "error message %s", "formatted") +// a.Greaterf(float64(2), float64(1), "error message %s", "formatted") +// a.Greaterf("b", "a", "error message %s", "formatted") +func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Greaterf(a.t, e1, e2, msg, args...) +} + +// HTTPBodyContains asserts that a specified handler returns a +// body that contains a string. +// +// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...) +} + +// HTTPBodyContainsf asserts that a specified handler returns a +// body that contains a string. +// +// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...) +} + +// HTTPBodyNotContains asserts that a specified handler returns a +// body that does not contain a string. +// +// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...) +} + +// HTTPBodyNotContainsf asserts that a specified handler returns a +// body that does not contain a string. +// +// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...) +} + +// HTTPError asserts that a specified handler returns an error status code. +// +// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPError(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPErrorf asserts that a specified handler returns an error status code. +// +// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPErrorf(a.t, handler, method, url, values, msg, args...) +} + +// HTTPRedirect asserts that a specified handler returns a redirect status code. +// +// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPRedirectf asserts that a specified handler returns a redirect status code. +// +// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPRedirectf(a.t, handler, method, url, values, msg, args...) +} + +// HTTPStatusCode asserts that a specified handler returns a specified status code. +// +// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...) +} + +// HTTPStatusCodef asserts that a specified handler returns a specified status code. +// +// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPStatusCodef(a.t, handler, method, url, values, statuscode, msg, args...) +} + +// HTTPSuccess asserts that a specified handler returns a success status code. +// +// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPSuccessf asserts that a specified handler returns a success status code. +// +// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPSuccessf(a.t, handler, method, url, values, msg, args...) +} + +// Implements asserts that an object is implemented by the specified interface. +// +// a.Implements((*MyInterface)(nil), new(MyObject)) +func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Implements(a.t, interfaceObject, object, msgAndArgs...) +} + +// Implementsf asserts that an object is implemented by the specified interface. +// +// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Implementsf(a.t, interfaceObject, object, msg, args...) +} + +// InDelta asserts that the two numerals are within delta of each other. +// +// a.InDelta(math.Pi, 22/7.0, 0.01) +func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InDelta(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...) +} + +// InDeltaSlice is the same as InDelta, except it compares two slices. +func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaSlicef is the same as InDelta, except it compares two slices. +func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InDeltaSlicef(a.t, expected, actual, delta, msg, args...) +} + +// InDeltaf asserts that the two numerals are within delta of each other. +// +// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InDeltaf(a.t, expected, actual, delta, msg, args...) +} + +// InEpsilon asserts that expected and actual have a relative error less than epsilon +func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) +} + +// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. +func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...) +} + +// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. +func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...) +} + +// InEpsilonf asserts that expected and actual have a relative error less than epsilon +func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InEpsilonf(a.t, expected, actual, epsilon, msg, args...) +} + +// IsDecreasing asserts that the collection is decreasing +// +// a.IsDecreasing([]int{2, 1, 0}) +// a.IsDecreasing([]float{2, 1}) +// a.IsDecreasing([]string{"b", "a"}) +func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsDecreasing(a.t, object, msgAndArgs...) +} + +// IsDecreasingf asserts that the collection is decreasing +// +// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") +// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsDecreasingf(a.t, object, msg, args...) +} + +// IsIncreasing asserts that the collection is increasing +// +// a.IsIncreasing([]int{1, 2, 3}) +// a.IsIncreasing([]float{1, 2}) +// a.IsIncreasing([]string{"a", "b"}) +func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsIncreasing(a.t, object, msgAndArgs...) +} + +// IsIncreasingf asserts that the collection is increasing +// +// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") +// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsIncreasingf(a.t, object, msg, args...) +} + +// IsNonDecreasing asserts that the collection is not decreasing +// +// a.IsNonDecreasing([]int{1, 1, 2}) +// a.IsNonDecreasing([]float{1, 2}) +// a.IsNonDecreasing([]string{"a", "b"}) +func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsNonDecreasing(a.t, object, msgAndArgs...) +} + +// IsNonDecreasingf asserts that the collection is not decreasing +// +// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsNonDecreasingf(a.t, object, msg, args...) +} + +// IsNonIncreasing asserts that the collection is not increasing +// +// a.IsNonIncreasing([]int{2, 1, 1}) +// a.IsNonIncreasing([]float{2, 1}) +// a.IsNonIncreasing([]string{"b", "a"}) +func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsNonIncreasing(a.t, object, msgAndArgs...) +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsNonIncreasingf(a.t, object, msg, args...) +} + +// IsType asserts that the specified objects are of the same type. +func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsType(a.t, expectedType, object, msgAndArgs...) +} + +// IsTypef asserts that the specified objects are of the same type. +func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsTypef(a.t, expectedType, object, msg, args...) +} + +// JSONEq asserts that two JSON strings are equivalent. +// +// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return JSONEq(a.t, expected, actual, msgAndArgs...) +} + +// JSONEqf asserts that two JSON strings are equivalent. +// +// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return JSONEqf(a.t, expected, actual, msg, args...) +} + +// Len asserts that the specified object has specific length. +// Len also fails if the object has a type that len() not accept. +// +// a.Len(mySlice, 3) +func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Len(a.t, object, length, msgAndArgs...) +} + +// Lenf asserts that the specified object has specific length. +// Lenf also fails if the object has a type that len() not accept. +// +// a.Lenf(mySlice, 3, "error message %s", "formatted") +func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Lenf(a.t, object, length, msg, args...) +} + +// Less asserts that the first element is less than the second +// +// a.Less(1, 2) +// a.Less(float64(1), float64(2)) +// a.Less("a", "b") +func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Less(a.t, e1, e2, msgAndArgs...) +} + +// LessOrEqual asserts that the first element is less than or equal to the second +// +// a.LessOrEqual(1, 2) +// a.LessOrEqual(2, 2) +// a.LessOrEqual("a", "b") +// a.LessOrEqual("b", "b") +func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return LessOrEqual(a.t, e1, e2, msgAndArgs...) +} + +// LessOrEqualf asserts that the first element is less than or equal to the second +// +// a.LessOrEqualf(1, 2, "error message %s", "formatted") +// a.LessOrEqualf(2, 2, "error message %s", "formatted") +// a.LessOrEqualf("a", "b", "error message %s", "formatted") +// a.LessOrEqualf("b", "b", "error message %s", "formatted") +func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return LessOrEqualf(a.t, e1, e2, msg, args...) +} + +// Lessf asserts that the first element is less than the second +// +// a.Lessf(1, 2, "error message %s", "formatted") +// a.Lessf(float64(1), float64(2), "error message %s", "formatted") +// a.Lessf("a", "b", "error message %s", "formatted") +func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Lessf(a.t, e1, e2, msg, args...) +} + +// Negative asserts that the specified element is negative +// +// a.Negative(-1) +// a.Negative(-1.23) +func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Negative(a.t, e, msgAndArgs...) +} + +// Negativef asserts that the specified element is negative +// +// a.Negativef(-1, "error message %s", "formatted") +// a.Negativef(-1.23, "error message %s", "formatted") +func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Negativef(a.t, e, msg, args...) +} + +// Never asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) +func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Never(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// Neverf asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Neverf(a.t, condition, waitFor, tick, msg, args...) +} + +// Nil asserts that the specified object is nil. +// +// a.Nil(err) +func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Nil(a.t, object, msgAndArgs...) +} + +// Nilf asserts that the specified object is nil. +// +// a.Nilf(err, "error message %s", "formatted") +func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Nilf(a.t, object, msg, args...) +} + +// NoDirExists checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NoDirExists(a.t, path, msgAndArgs...) +} + +// NoDirExistsf checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NoDirExistsf(a.t, path, msg, args...) +} + +// NoError asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if a.NoError(err) { +// assert.Equal(t, expectedObj, actualObj) +// } +func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NoError(a.t, err, msgAndArgs...) +} + +// NoErrorf asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if a.NoErrorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } +func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NoErrorf(a.t, err, msg, args...) +} + +// NoFileExists checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NoFileExists(a.t, path, msgAndArgs...) +} + +// NoFileExistsf checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NoFileExistsf(a.t, path, msg, args...) +} + +// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// a.NotContains("Hello World", "Earth") +// a.NotContains(["Hello", "World"], "Earth") +// a.NotContains({"Hello": "World"}, "Earth") +func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotContains(a.t, s, contains, msgAndArgs...) +} + +// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted") +// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") +// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") +func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotContainsf(a.t, s, contains, msg, args...) +} + +// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if a.NotEmpty(obj) { +// assert.Equal(t, "two", obj[1]) +// } +func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotEmpty(a.t, object, msgAndArgs...) +} + +// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if a.NotEmptyf(obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } +func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotEmptyf(a.t, object, msg, args...) +} + +// NotEqual asserts that the specified values are NOT equal. +// +// a.NotEqual(obj1, obj2) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotEqual(a.t, expected, actual, msgAndArgs...) +} + +// NotEqualValues asserts that two objects are not equal even when converted to the same type +// +// a.NotEqualValues(obj1, obj2) +func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotEqualValues(a.t, expected, actual, msgAndArgs...) +} + +// NotEqualValuesf asserts that two objects are not equal even when converted to the same type +// +// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") +func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotEqualValuesf(a.t, expected, actual, msg, args...) +} + +// NotEqualf asserts that the specified values are NOT equal. +// +// a.NotEqualf(obj1, obj2, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotEqualf(a.t, expected, actual, msg, args...) +} + +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotErrorIs(a.t, err, target, msgAndArgs...) +} + +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotErrorIsf(a.t, err, target, msg, args...) +} + +// NotNil asserts that the specified object is not nil. +// +// a.NotNil(err) +func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotNil(a.t, object, msgAndArgs...) +} + +// NotNilf asserts that the specified object is not nil. +// +// a.NotNilf(err, "error message %s", "formatted") +func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotNilf(a.t, object, msg, args...) +} + +// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// a.NotPanics(func(){ RemainCalm() }) +func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotPanics(a.t, f, msgAndArgs...) +} + +// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") +func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotPanicsf(a.t, f, msg, args...) +} + +// NotRegexp asserts that a specified regexp does not match a string. +// +// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") +// a.NotRegexp("^start", "it's not starting") +func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotRegexp(a.t, rx, str, msgAndArgs...) +} + +// NotRegexpf asserts that a specified regexp does not match a string. +// +// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") +func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotRegexpf(a.t, rx, str, msg, args...) +} + +// NotSame asserts that two pointers do not reference the same object. +// +// a.NotSame(ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotSame(a.t, expected, actual, msgAndArgs...) +} + +// NotSamef asserts that two pointers do not reference the same object. +// +// a.NotSamef(ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotSamef(a.t, expected, actual, msg, args...) +} + +// NotSubset asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") +func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotSubset(a.t, list, subset, msgAndArgs...) +} + +// NotSubsetf asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") +func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotSubsetf(a.t, list, subset, msg, args...) +} + +// NotZero asserts that i is not the zero value for its type. +func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotZero(a.t, i, msgAndArgs...) +} + +// NotZerof asserts that i is not the zero value for its type. +func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotZerof(a.t, i, msg, args...) +} + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// a.Panics(func(){ GoCrazy() }) +func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Panics(a.t, f, msgAndArgs...) +} + +// PanicsWithError asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// a.PanicsWithError("crazy error", func(){ GoCrazy() }) +func (a *Assertions) PanicsWithError(errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return PanicsWithError(a.t, errString, f, msgAndArgs...) +} + +// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) PanicsWithErrorf(errString string, f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return PanicsWithErrorf(a.t, errString, f, msg, args...) +} + +// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// a.PanicsWithValue("crazy error", func(){ GoCrazy() }) +func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return PanicsWithValue(a.t, expected, f, msgAndArgs...) +} + +// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return PanicsWithValuef(a.t, expected, f, msg, args...) +} + +// Panicsf asserts that the code inside the specified PanicTestFunc panics. +// +// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Panicsf(a.t, f, msg, args...) +} + +// Positive asserts that the specified element is positive +// +// a.Positive(1) +// a.Positive(1.23) +func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Positive(a.t, e, msgAndArgs...) +} + +// Positivef asserts that the specified element is positive +// +// a.Positivef(1, "error message %s", "formatted") +// a.Positivef(1.23, "error message %s", "formatted") +func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Positivef(a.t, e, msg, args...) +} + +// Regexp asserts that a specified regexp matches a string. +// +// a.Regexp(regexp.MustCompile("start"), "it's starting") +// a.Regexp("start...$", "it's not starting") +func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Regexp(a.t, rx, str, msgAndArgs...) +} + +// Regexpf asserts that a specified regexp matches a string. +// +// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") +func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Regexpf(a.t, rx, str, msg, args...) +} + +// Same asserts that two pointers reference the same object. +// +// a.Same(ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Same(a.t, expected, actual, msgAndArgs...) +} + +// Samef asserts that two pointers reference the same object. +// +// a.Samef(ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Samef(a.t, expected, actual, msg, args...) +} + +// Subset asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Subset(a.t, list, subset, msgAndArgs...) +} + +// Subsetf asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") +func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Subsetf(a.t, list, subset, msg, args...) +} + +// True asserts that the specified value is true. +// +// a.True(myBool) +func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return True(a.t, value, msgAndArgs...) +} + +// Truef asserts that the specified value is true. +// +// a.Truef(myBool, "error message %s", "formatted") +func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Truef(a.t, value, msg, args...) +} + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// a.WithinDuration(time.Now(), time.Now(), 10*time.Second) +func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return WithinDuration(a.t, expected, actual, delta, msgAndArgs...) +} + +// WithinDurationf asserts that the two times are within duration delta of each other. +// +// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return WithinDurationf(a.t, expected, actual, delta, msg, args...) +} + +// YAMLEq asserts that two YAML strings are equivalent. +func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return YAMLEq(a.t, expected, actual, msgAndArgs...) +} + +// YAMLEqf asserts that two YAML strings are equivalent. +func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return YAMLEqf(a.t, expected, actual, msg, args...) +} + +// Zero asserts that i is the zero value for its type. +func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Zero(a.t, i, msgAndArgs...) +} + +// Zerof asserts that i is the zero value for its type. +func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Zerof(a.t, i, msg, args...) +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl b/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl new file mode 100644 index 00000000000..188bb9e1743 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl @@ -0,0 +1,5 @@ +{{.CommentWithoutT "a"}} +func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool { + if h, ok := a.t.(tHelper); ok { h.Helper() } + return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_order.go b/vendor/github.com/stretchr/testify/assert/assertion_order.go new file mode 100644 index 00000000000..1c3b47182a7 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_order.go @@ -0,0 +1,81 @@ +package assert + +import ( + "fmt" + "reflect" +) + +// isOrdered checks that collection contains orderable elements. +func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool { + objKind := reflect.TypeOf(object).Kind() + if objKind != reflect.Slice && objKind != reflect.Array { + return false + } + + objValue := reflect.ValueOf(object) + objLen := objValue.Len() + + if objLen <= 1 { + return true + } + + value := objValue.Index(0) + valueInterface := value.Interface() + firstValueKind := value.Kind() + + for i := 1; i < objLen; i++ { + prevValue := value + prevValueInterface := valueInterface + + value = objValue.Index(i) + valueInterface = value.Interface() + + compareResult, isComparable := compare(prevValueInterface, valueInterface, firstValueKind) + + if !isComparable { + return Fail(t, fmt.Sprintf("Can not compare type \"%s\" and \"%s\"", reflect.TypeOf(value), reflect.TypeOf(prevValue)), msgAndArgs...) + } + + if !containsValue(allowedComparesResults, compareResult) { + return Fail(t, fmt.Sprintf(failMessage, prevValue, value), msgAndArgs...) + } + } + + return true +} + +// IsIncreasing asserts that the collection is increasing +// +// assert.IsIncreasing(t, []int{1, 2, 3}) +// assert.IsIncreasing(t, []float{1, 2}) +// assert.IsIncreasing(t, []string{"a", "b"}) +func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs) +} + +// IsNonIncreasing asserts that the collection is not increasing +// +// assert.IsNonIncreasing(t, []int{2, 1, 1}) +// assert.IsNonIncreasing(t, []float{2, 1}) +// assert.IsNonIncreasing(t, []string{"b", "a"}) +func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs) +} + +// IsDecreasing asserts that the collection is decreasing +// +// assert.IsDecreasing(t, []int{2, 1, 0}) +// assert.IsDecreasing(t, []float{2, 1}) +// assert.IsDecreasing(t, []string{"b", "a"}) +func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs) +} + +// IsNonDecreasing asserts that the collection is not decreasing +// +// assert.IsNonDecreasing(t, []int{1, 1, 2}) +// assert.IsNonDecreasing(t, []float{1, 2}) +// assert.IsNonDecreasing(t, []string{"a", "b"}) +func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs) +} diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go new file mode 100644 index 00000000000..bcac4401f57 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertions.go @@ -0,0 +1,1774 @@ +package assert + +import ( + "bufio" + "bytes" + "encoding/json" + "errors" + "fmt" + "math" + "os" + "reflect" + "regexp" + "runtime" + "runtime/debug" + "strings" + "time" + "unicode" + "unicode/utf8" + + "github.com/davecgh/go-spew/spew" + "github.com/pmezard/go-difflib/difflib" + yaml "gopkg.in/yaml.v3" +) + +//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl" + +// TestingT is an interface wrapper around *testing.T +type TestingT interface { + Errorf(format string, args ...interface{}) +} + +// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful +// for table driven tests. +type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) bool + +// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful +// for table driven tests. +type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) bool + +// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful +// for table driven tests. +type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool + +// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful +// for table driven tests. +type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool + +// Comparison is a custom function that returns true on success and false on failure +type Comparison func() (success bool) + +/* + Helper functions +*/ + +// ObjectsAreEqual determines if two objects are considered equal. +// +// This function does no assertion of any kind. +func ObjectsAreEqual(expected, actual interface{}) bool { + if expected == nil || actual == nil { + return expected == actual + } + + exp, ok := expected.([]byte) + if !ok { + return reflect.DeepEqual(expected, actual) + } + + act, ok := actual.([]byte) + if !ok { + return false + } + if exp == nil || act == nil { + return exp == nil && act == nil + } + return bytes.Equal(exp, act) +} + +// ObjectsAreEqualValues gets whether two objects are equal, or if their +// values are equal. +func ObjectsAreEqualValues(expected, actual interface{}) bool { + if ObjectsAreEqual(expected, actual) { + return true + } + + actualType := reflect.TypeOf(actual) + if actualType == nil { + return false + } + expectedValue := reflect.ValueOf(expected) + if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) { + // Attempt comparison after type conversion + return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual) + } + + return false +} + +/* CallerInfo is necessary because the assert functions use the testing object +internally, causing it to print the file:line of the assert method, rather than where +the problem actually occurred in calling code.*/ + +// CallerInfo returns an array of strings containing the file and line number +// of each stack frame leading from the current test to the assert call that +// failed. +func CallerInfo() []string { + + var pc uintptr + var ok bool + var file string + var line int + var name string + + callers := []string{} + for i := 0; ; i++ { + pc, file, line, ok = runtime.Caller(i) + if !ok { + // The breaks below failed to terminate the loop, and we ran off the + // end of the call stack. + break + } + + // This is a huge edge case, but it will panic if this is the case, see #180 + if file == "" { + break + } + + f := runtime.FuncForPC(pc) + if f == nil { + break + } + name = f.Name() + + // testing.tRunner is the standard library function that calls + // tests. Subtests are called directly by tRunner, without going through + // the Test/Benchmark/Example function that contains the t.Run calls, so + // with subtests we should break when we hit tRunner, without adding it + // to the list of callers. + if name == "testing.tRunner" { + break + } + + parts := strings.Split(file, "/") + file = parts[len(parts)-1] + if len(parts) > 1 { + dir := parts[len(parts)-2] + if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" { + callers = append(callers, fmt.Sprintf("%s:%d", file, line)) + } + } + + // Drop the package + segments := strings.Split(name, ".") + name = segments[len(segments)-1] + if isTest(name, "Test") || + isTest(name, "Benchmark") || + isTest(name, "Example") { + break + } + } + + return callers +} + +// Stolen from the `go test` tool. +// isTest tells whether name looks like a test (or benchmark, according to prefix). +// It is a Test (say) if there is a character after Test that is not a lower-case letter. +// We don't want TesticularCancer. +func isTest(name, prefix string) bool { + if !strings.HasPrefix(name, prefix) { + return false + } + if len(name) == len(prefix) { // "Test" is ok + return true + } + r, _ := utf8.DecodeRuneInString(name[len(prefix):]) + return !unicode.IsLower(r) +} + +func messageFromMsgAndArgs(msgAndArgs ...interface{}) string { + if len(msgAndArgs) == 0 || msgAndArgs == nil { + return "" + } + if len(msgAndArgs) == 1 { + msg := msgAndArgs[0] + if msgAsStr, ok := msg.(string); ok { + return msgAsStr + } + return fmt.Sprintf("%+v", msg) + } + if len(msgAndArgs) > 1 { + return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...) + } + return "" +} + +// Aligns the provided message so that all lines after the first line start at the same location as the first line. +// Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab). +// The longestLabelLen parameter specifies the length of the longest label in the output (required becaues this is the +// basis on which the alignment occurs). +func indentMessageLines(message string, longestLabelLen int) string { + outBuf := new(bytes.Buffer) + + for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ { + // no need to align first line because it starts at the correct location (after the label) + if i != 0 { + // append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab + outBuf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t") + } + outBuf.WriteString(scanner.Text()) + } + + return outBuf.String() +} + +type failNower interface { + FailNow() +} + +// FailNow fails test +func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + Fail(t, failureMessage, msgAndArgs...) + + // We cannot extend TestingT with FailNow() and + // maintain backwards compatibility, so we fallback + // to panicking when FailNow is not available in + // TestingT. + // See issue #263 + + if t, ok := t.(failNower); ok { + t.FailNow() + } else { + panic("test failed and t is missing `FailNow()`") + } + return false +} + +// Fail reports a failure through +func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + content := []labeledContent{ + {"Error Trace", strings.Join(CallerInfo(), "\n\t\t\t")}, + {"Error", failureMessage}, + } + + // Add test name if the Go version supports it + if n, ok := t.(interface { + Name() string + }); ok { + content = append(content, labeledContent{"Test", n.Name()}) + } + + message := messageFromMsgAndArgs(msgAndArgs...) + if len(message) > 0 { + content = append(content, labeledContent{"Messages", message}) + } + + t.Errorf("\n%s", ""+labeledOutput(content...)) + + return false +} + +type labeledContent struct { + label string + content string +} + +// labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner: +// +// \t{{label}}:{{align_spaces}}\t{{content}}\n +// +// The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label. +// If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this +// alignment is achieved, "\t{{content}}\n" is added for the output. +// +// If the content of the labeledOutput contains line breaks, the subsequent lines are aligned so that they start at the same location as the first line. +func labeledOutput(content ...labeledContent) string { + longestLabel := 0 + for _, v := range content { + if len(v.label) > longestLabel { + longestLabel = len(v.label) + } + } + var output string + for _, v := range content { + output += "\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n" + } + return output +} + +// Implements asserts that an object is implemented by the specified interface. +// +// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) +func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + interfaceType := reflect.TypeOf(interfaceObject).Elem() + + if object == nil { + return Fail(t, fmt.Sprintf("Cannot check if nil implements %v", interfaceType), msgAndArgs...) + } + if !reflect.TypeOf(object).Implements(interfaceType) { + return Fail(t, fmt.Sprintf("%T must implement %v", object, interfaceType), msgAndArgs...) + } + + return true +} + +// IsType asserts that the specified objects are of the same type. +func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) { + return Fail(t, fmt.Sprintf("Object expected to be of type %v, but was %v", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...) + } + + return true +} + +// Equal asserts that two objects are equal. +// +// assert.Equal(t, 123, 123) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if err := validateEqualArgs(expected, actual); err != nil { + return Fail(t, fmt.Sprintf("Invalid operation: %#v == %#v (%s)", + expected, actual, err), msgAndArgs...) + } + + if !ObjectsAreEqual(expected, actual) { + diff := diff(expected, actual) + expected, actual = formatUnequalValues(expected, actual) + return Fail(t, fmt.Sprintf("Not equal: \n"+ + "expected: %s\n"+ + "actual : %s%s", expected, actual, diff), msgAndArgs...) + } + + return true + +} + +// validateEqualArgs checks whether provided arguments can be safely used in the +// Equal/NotEqual functions. +func validateEqualArgs(expected, actual interface{}) error { + if expected == nil && actual == nil { + return nil + } + + if isFunction(expected) || isFunction(actual) { + return errors.New("cannot take func type as argument") + } + return nil +} + +// Same asserts that two pointers reference the same object. +// +// assert.Same(t, ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if !samePointers(expected, actual) { + return Fail(t, fmt.Sprintf("Not same: \n"+ + "expected: %p %#v\n"+ + "actual : %p %#v", expected, expected, actual, actual), msgAndArgs...) + } + + return true +} + +// NotSame asserts that two pointers do not reference the same object. +// +// assert.NotSame(t, ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if samePointers(expected, actual) { + return Fail(t, fmt.Sprintf( + "Expected and actual point to the same object: %p %#v", + expected, expected), msgAndArgs...) + } + return true +} + +// samePointers compares two generic interface objects and returns whether +// they point to the same object +func samePointers(first, second interface{}) bool { + firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second) + if firstPtr.Kind() != reflect.Ptr || secondPtr.Kind() != reflect.Ptr { + return false + } + + firstType, secondType := reflect.TypeOf(first), reflect.TypeOf(second) + if firstType != secondType { + return false + } + + // compare pointer addresses + return first == second +} + +// formatUnequalValues takes two values of arbitrary types and returns string +// representations appropriate to be presented to the user. +// +// If the values are not of like type, the returned strings will be prefixed +// with the type name, and the value will be enclosed in parenthesis similar +// to a type conversion in the Go grammar. +func formatUnequalValues(expected, actual interface{}) (e string, a string) { + if reflect.TypeOf(expected) != reflect.TypeOf(actual) { + return fmt.Sprintf("%T(%s)", expected, truncatingFormat(expected)), + fmt.Sprintf("%T(%s)", actual, truncatingFormat(actual)) + } + switch expected.(type) { + case time.Duration: + return fmt.Sprintf("%v", expected), fmt.Sprintf("%v", actual) + } + return truncatingFormat(expected), truncatingFormat(actual) +} + +// truncatingFormat formats the data and truncates it if it's too long. +// +// This helps keep formatted error messages lines from exceeding the +// bufio.MaxScanTokenSize max line length that the go testing framework imposes. +func truncatingFormat(data interface{}) string { + value := fmt.Sprintf("%#v", data) + max := bufio.MaxScanTokenSize - 100 // Give us some space the type info too if needed. + if len(value) > max { + value = value[0:max] + "<... truncated>" + } + return value +} + +// EqualValues asserts that two objects are equal or convertable to the same types +// and equal. +// +// assert.EqualValues(t, uint32(123), int32(123)) +func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if !ObjectsAreEqualValues(expected, actual) { + diff := diff(expected, actual) + expected, actual = formatUnequalValues(expected, actual) + return Fail(t, fmt.Sprintf("Not equal: \n"+ + "expected: %s\n"+ + "actual : %s%s", expected, actual, diff), msgAndArgs...) + } + + return true + +} + +// Exactly asserts that two objects are equal in value and type. +// +// assert.Exactly(t, int32(123), int64(123)) +func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + aType := reflect.TypeOf(expected) + bType := reflect.TypeOf(actual) + + if aType != bType { + return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...) + } + + return Equal(t, expected, actual, msgAndArgs...) + +} + +// NotNil asserts that the specified object is not nil. +// +// assert.NotNil(t, err) +func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + if !isNil(object) { + return true + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Fail(t, "Expected value not to be nil.", msgAndArgs...) +} + +// containsKind checks if a specified kind in the slice of kinds. +func containsKind(kinds []reflect.Kind, kind reflect.Kind) bool { + for i := 0; i < len(kinds); i++ { + if kind == kinds[i] { + return true + } + } + + return false +} + +// isNil checks if a specified object is nil or not, without Failing. +func isNil(object interface{}) bool { + if object == nil { + return true + } + + value := reflect.ValueOf(object) + kind := value.Kind() + isNilableKind := containsKind( + []reflect.Kind{ + reflect.Chan, reflect.Func, + reflect.Interface, reflect.Map, + reflect.Ptr, reflect.Slice}, + kind) + + if isNilableKind && value.IsNil() { + return true + } + + return false +} + +// Nil asserts that the specified object is nil. +// +// assert.Nil(t, err) +func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + if isNil(object) { + return true + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...) +} + +// isEmpty gets whether the specified object is considered empty or not. +func isEmpty(object interface{}) bool { + + // get nil case out of the way + if object == nil { + return true + } + + objValue := reflect.ValueOf(object) + + switch objValue.Kind() { + // collection types are empty when they have no element + case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: + return objValue.Len() == 0 + // pointers are empty if nil or if the value they point to is empty + case reflect.Ptr: + if objValue.IsNil() { + return true + } + deref := objValue.Elem().Interface() + return isEmpty(deref) + // for all other types, compare against the zero value + default: + zero := reflect.Zero(objValue.Type()) + return reflect.DeepEqual(object, zero.Interface()) + } +} + +// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// assert.Empty(t, obj) +func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + pass := isEmpty(object) + if !pass { + if h, ok := t.(tHelper); ok { + h.Helper() + } + Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...) + } + + return pass + +} + +// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if assert.NotEmpty(t, obj) { +// assert.Equal(t, "two", obj[1]) +// } +func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + pass := !isEmpty(object) + if !pass { + if h, ok := t.(tHelper); ok { + h.Helper() + } + Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...) + } + + return pass + +} + +// getLen try to get length of object. +// return (false, 0) if impossible. +func getLen(x interface{}) (ok bool, length int) { + v := reflect.ValueOf(x) + defer func() { + if e := recover(); e != nil { + ok = false + } + }() + return true, v.Len() +} + +// Len asserts that the specified object has specific length. +// Len also fails if the object has a type that len() not accept. +// +// assert.Len(t, mySlice, 3) +func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + ok, l := getLen(object) + if !ok { + return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...) + } + + if l != length { + return Fail(t, fmt.Sprintf("\"%s\" should have %d item(s), but has %d", object, length, l), msgAndArgs...) + } + return true +} + +// True asserts that the specified value is true. +// +// assert.True(t, myBool) +func True(t TestingT, value bool, msgAndArgs ...interface{}) bool { + if !value { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Fail(t, "Should be true", msgAndArgs...) + } + + return true + +} + +// False asserts that the specified value is false. +// +// assert.False(t, myBool) +func False(t TestingT, value bool, msgAndArgs ...interface{}) bool { + if value { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Fail(t, "Should be false", msgAndArgs...) + } + + return true + +} + +// NotEqual asserts that the specified values are NOT equal. +// +// assert.NotEqual(t, obj1, obj2) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if err := validateEqualArgs(expected, actual); err != nil { + return Fail(t, fmt.Sprintf("Invalid operation: %#v != %#v (%s)", + expected, actual, err), msgAndArgs...) + } + + if ObjectsAreEqual(expected, actual) { + return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...) + } + + return true + +} + +// NotEqualValues asserts that two objects are not equal even when converted to the same type +// +// assert.NotEqualValues(t, obj1, obj2) +func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if ObjectsAreEqualValues(expected, actual) { + return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...) + } + + return true +} + +// containsElement try loop over the list check if the list includes the element. +// return (false, false) if impossible. +// return (true, false) if element was not found. +// return (true, true) if element was found. +func includeElement(list interface{}, element interface{}) (ok, found bool) { + + listValue := reflect.ValueOf(list) + listKind := reflect.TypeOf(list).Kind() + defer func() { + if e := recover(); e != nil { + ok = false + found = false + } + }() + + if listKind == reflect.String { + elementValue := reflect.ValueOf(element) + return true, strings.Contains(listValue.String(), elementValue.String()) + } + + if listKind == reflect.Map { + mapKeys := listValue.MapKeys() + for i := 0; i < len(mapKeys); i++ { + if ObjectsAreEqual(mapKeys[i].Interface(), element) { + return true, true + } + } + return true, false + } + + for i := 0; i < listValue.Len(); i++ { + if ObjectsAreEqual(listValue.Index(i).Interface(), element) { + return true, true + } + } + return true, false + +} + +// Contains asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// assert.Contains(t, "Hello World", "World") +// assert.Contains(t, ["Hello", "World"], "World") +// assert.Contains(t, {"Hello": "World"}, "Hello") +func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + ok, found := includeElement(s, contains) + if !ok { + return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...) + } + if !found { + return Fail(t, fmt.Sprintf("%#v does not contain %#v", s, contains), msgAndArgs...) + } + + return true + +} + +// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// assert.NotContains(t, "Hello World", "Earth") +// assert.NotContains(t, ["Hello", "World"], "Earth") +// assert.NotContains(t, {"Hello": "World"}, "Earth") +func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + ok, found := includeElement(s, contains) + if !ok { + return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...) + } + if found { + return Fail(t, fmt.Sprintf("\"%s\" should not contain \"%s\"", s, contains), msgAndArgs...) + } + + return true + +} + +// Subset asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if subset == nil { + return true // we consider nil to be equal to the nil set + } + + subsetValue := reflect.ValueOf(subset) + defer func() { + if e := recover(); e != nil { + ok = false + } + }() + + listKind := reflect.TypeOf(list).Kind() + subsetKind := reflect.TypeOf(subset).Kind() + + if listKind != reflect.Array && listKind != reflect.Slice { + return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) + } + + if subsetKind != reflect.Array && subsetKind != reflect.Slice { + return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) + } + + for i := 0; i < subsetValue.Len(); i++ { + element := subsetValue.Index(i).Interface() + ok, found := includeElement(list, element) + if !ok { + return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) + } + if !found { + return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", list, element), msgAndArgs...) + } + } + + return true +} + +// NotSubset asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") +func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if subset == nil { + return Fail(t, fmt.Sprintf("nil is the empty set which is a subset of every set"), msgAndArgs...) + } + + subsetValue := reflect.ValueOf(subset) + defer func() { + if e := recover(); e != nil { + ok = false + } + }() + + listKind := reflect.TypeOf(list).Kind() + subsetKind := reflect.TypeOf(subset).Kind() + + if listKind != reflect.Array && listKind != reflect.Slice { + return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) + } + + if subsetKind != reflect.Array && subsetKind != reflect.Slice { + return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) + } + + for i := 0; i < subsetValue.Len(); i++ { + element := subsetValue.Index(i).Interface() + ok, found := includeElement(list, element) + if !ok { + return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) + } + if !found { + return true + } + } + + return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...) +} + +// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2]) +func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if isEmpty(listA) && isEmpty(listB) { + return true + } + + if !isList(t, listA, msgAndArgs...) || !isList(t, listB, msgAndArgs...) { + return false + } + + extraA, extraB := diffLists(listA, listB) + + if len(extraA) == 0 && len(extraB) == 0 { + return true + } + + return Fail(t, formatListDiff(listA, listB, extraA, extraB), msgAndArgs...) +} + +// isList checks that the provided value is array or slice. +func isList(t TestingT, list interface{}, msgAndArgs ...interface{}) (ok bool) { + kind := reflect.TypeOf(list).Kind() + if kind != reflect.Array && kind != reflect.Slice { + return Fail(t, fmt.Sprintf("%q has an unsupported type %s, expecting array or slice", list, kind), + msgAndArgs...) + } + return true +} + +// diffLists diffs two arrays/slices and returns slices of elements that are only in A and only in B. +// If some element is present multiple times, each instance is counted separately (e.g. if something is 2x in A and +// 5x in B, it will be 0x in extraA and 3x in extraB). The order of items in both lists is ignored. +func diffLists(listA, listB interface{}) (extraA, extraB []interface{}) { + aValue := reflect.ValueOf(listA) + bValue := reflect.ValueOf(listB) + + aLen := aValue.Len() + bLen := bValue.Len() + + // Mark indexes in bValue that we already used + visited := make([]bool, bLen) + for i := 0; i < aLen; i++ { + element := aValue.Index(i).Interface() + found := false + for j := 0; j < bLen; j++ { + if visited[j] { + continue + } + if ObjectsAreEqual(bValue.Index(j).Interface(), element) { + visited[j] = true + found = true + break + } + } + if !found { + extraA = append(extraA, element) + } + } + + for j := 0; j < bLen; j++ { + if visited[j] { + continue + } + extraB = append(extraB, bValue.Index(j).Interface()) + } + + return +} + +func formatListDiff(listA, listB interface{}, extraA, extraB []interface{}) string { + var msg bytes.Buffer + + msg.WriteString("elements differ") + if len(extraA) > 0 { + msg.WriteString("\n\nextra elements in list A:\n") + msg.WriteString(spewConfig.Sdump(extraA)) + } + if len(extraB) > 0 { + msg.WriteString("\n\nextra elements in list B:\n") + msg.WriteString(spewConfig.Sdump(extraB)) + } + msg.WriteString("\n\nlistA:\n") + msg.WriteString(spewConfig.Sdump(listA)) + msg.WriteString("\n\nlistB:\n") + msg.WriteString(spewConfig.Sdump(listB)) + + return msg.String() +} + +// Condition uses a Comparison to assert a complex condition. +func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + result := comp() + if !result { + Fail(t, "Condition failed!", msgAndArgs...) + } + return result +} + +// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics +// methods, and represents a simple func that takes no arguments, and returns nothing. +type PanicTestFunc func() + +// didPanic returns true if the function passed to it panics. Otherwise, it returns false. +func didPanic(f PanicTestFunc) (bool, interface{}, string) { + + didPanic := false + var message interface{} + var stack string + func() { + + defer func() { + if message = recover(); message != nil { + didPanic = true + stack = string(debug.Stack()) + } + }() + + // call the target function + f() + + }() + + return didPanic, message, stack + +} + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// assert.Panics(t, func(){ GoCrazy() }) +func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if funcDidPanic, panicValue, _ := didPanic(f); !funcDidPanic { + return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) + } + + return true +} + +// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) +func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + funcDidPanic, panicValue, panickedStack := didPanic(f) + if !funcDidPanic { + return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) + } + if panicValue != expected { + return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, expected, panicValue, panickedStack), msgAndArgs...) + } + + return true +} + +// PanicsWithError asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) +func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + funcDidPanic, panicValue, panickedStack := didPanic(f) + if !funcDidPanic { + return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) + } + panicErr, ok := panicValue.(error) + if !ok || panicErr.Error() != errString { + return Fail(t, fmt.Sprintf("func %#v should panic with error message:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, errString, panicValue, panickedStack), msgAndArgs...) + } + + return true +} + +// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// assert.NotPanics(t, func(){ RemainCalm() }) +func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if funcDidPanic, panicValue, panickedStack := didPanic(f); funcDidPanic { + return Fail(t, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v\n\tPanic stack:\t%s", f, panicValue, panickedStack), msgAndArgs...) + } + + return true +} + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) +func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + dt := expected.Sub(actual) + if dt < -delta || dt > delta { + return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...) + } + + return true +} + +func toFloat(x interface{}) (float64, bool) { + var xf float64 + xok := true + + switch xn := x.(type) { + case uint: + xf = float64(xn) + case uint8: + xf = float64(xn) + case uint16: + xf = float64(xn) + case uint32: + xf = float64(xn) + case uint64: + xf = float64(xn) + case int: + xf = float64(xn) + case int8: + xf = float64(xn) + case int16: + xf = float64(xn) + case int32: + xf = float64(xn) + case int64: + xf = float64(xn) + case float32: + xf = float64(xn) + case float64: + xf = xn + case time.Duration: + xf = float64(xn) + default: + xok = false + } + + return xf, xok +} + +// InDelta asserts that the two numerals are within delta of each other. +// +// assert.InDelta(t, math.Pi, 22/7.0, 0.01) +func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + af, aok := toFloat(expected) + bf, bok := toFloat(actual) + + if !aok || !bok { + return Fail(t, fmt.Sprintf("Parameters must be numerical"), msgAndArgs...) + } + + if math.IsNaN(af) { + return Fail(t, fmt.Sprintf("Expected must not be NaN"), msgAndArgs...) + } + + if math.IsNaN(bf) { + return Fail(t, fmt.Sprintf("Expected %v with delta %v, but was NaN", expected, delta), msgAndArgs...) + } + + dt := af - bf + if dt < -delta || dt > delta { + return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...) + } + + return true +} + +// InDeltaSlice is the same as InDelta, except it compares two slices. +func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if expected == nil || actual == nil || + reflect.TypeOf(actual).Kind() != reflect.Slice || + reflect.TypeOf(expected).Kind() != reflect.Slice { + return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...) + } + + actualSlice := reflect.ValueOf(actual) + expectedSlice := reflect.ValueOf(expected) + + for i := 0; i < actualSlice.Len(); i++ { + result := InDelta(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta, msgAndArgs...) + if !result { + return result + } + } + + return true +} + +// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if expected == nil || actual == nil || + reflect.TypeOf(actual).Kind() != reflect.Map || + reflect.TypeOf(expected).Kind() != reflect.Map { + return Fail(t, "Arguments must be maps", msgAndArgs...) + } + + expectedMap := reflect.ValueOf(expected) + actualMap := reflect.ValueOf(actual) + + if expectedMap.Len() != actualMap.Len() { + return Fail(t, "Arguments must have the same number of keys", msgAndArgs...) + } + + for _, k := range expectedMap.MapKeys() { + ev := expectedMap.MapIndex(k) + av := actualMap.MapIndex(k) + + if !ev.IsValid() { + return Fail(t, fmt.Sprintf("missing key %q in expected map", k), msgAndArgs...) + } + + if !av.IsValid() { + return Fail(t, fmt.Sprintf("missing key %q in actual map", k), msgAndArgs...) + } + + if !InDelta( + t, + ev.Interface(), + av.Interface(), + delta, + msgAndArgs..., + ) { + return false + } + } + + return true +} + +func calcRelativeError(expected, actual interface{}) (float64, error) { + af, aok := toFloat(expected) + if !aok { + return 0, fmt.Errorf("expected value %q cannot be converted to float", expected) + } + if math.IsNaN(af) { + return 0, errors.New("expected value must not be NaN") + } + if af == 0 { + return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error") + } + bf, bok := toFloat(actual) + if !bok { + return 0, fmt.Errorf("actual value %q cannot be converted to float", actual) + } + if math.IsNaN(bf) { + return 0, errors.New("actual value must not be NaN") + } + + return math.Abs(af-bf) / math.Abs(af), nil +} + +// InEpsilon asserts that expected and actual have a relative error less than epsilon +func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if math.IsNaN(epsilon) { + return Fail(t, "epsilon must not be NaN") + } + actualEpsilon, err := calcRelativeError(expected, actual) + if err != nil { + return Fail(t, err.Error(), msgAndArgs...) + } + if actualEpsilon > epsilon { + return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+ + " < %#v (actual)", epsilon, actualEpsilon), msgAndArgs...) + } + + return true +} + +// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. +func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if expected == nil || actual == nil || + reflect.TypeOf(actual).Kind() != reflect.Slice || + reflect.TypeOf(expected).Kind() != reflect.Slice { + return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...) + } + + actualSlice := reflect.ValueOf(actual) + expectedSlice := reflect.ValueOf(expected) + + for i := 0; i < actualSlice.Len(); i++ { + result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), epsilon) + if !result { + return result + } + } + + return true +} + +/* + Errors +*/ + +// NoError asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if assert.NoError(t, err) { +// assert.Equal(t, expectedObj, actualObj) +// } +func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { + if err != nil { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...) + } + + return true +} + +// Error asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if assert.Error(t, err) { +// assert.Equal(t, expectedError, err) +// } +func Error(t TestingT, err error, msgAndArgs ...interface{}) bool { + if err == nil { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Fail(t, "An error is expected but got nil.", msgAndArgs...) + } + + return true +} + +// EqualError asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// assert.EqualError(t, err, expectedErrorString) +func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if !Error(t, theError, msgAndArgs...) { + return false + } + expected := errString + actual := theError.Error() + // don't need to use deep equals here, we know they are both strings + if expected != actual { + return Fail(t, fmt.Sprintf("Error message not equal:\n"+ + "expected: %q\n"+ + "actual : %q", expected, actual), msgAndArgs...) + } + return true +} + +// matchRegexp return true if a specified regexp matches a string. +func matchRegexp(rx interface{}, str interface{}) bool { + + var r *regexp.Regexp + if rr, ok := rx.(*regexp.Regexp); ok { + r = rr + } else { + r = regexp.MustCompile(fmt.Sprint(rx)) + } + + return (r.FindStringIndex(fmt.Sprint(str)) != nil) + +} + +// Regexp asserts that a specified regexp matches a string. +// +// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") +// assert.Regexp(t, "start...$", "it's not starting") +func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + match := matchRegexp(rx, str) + + if !match { + Fail(t, fmt.Sprintf("Expect \"%v\" to match \"%v\"", str, rx), msgAndArgs...) + } + + return match +} + +// NotRegexp asserts that a specified regexp does not match a string. +// +// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") +// assert.NotRegexp(t, "^start", "it's not starting") +func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + match := matchRegexp(rx, str) + + if match { + Fail(t, fmt.Sprintf("Expect \"%v\" to NOT match \"%v\"", str, rx), msgAndArgs...) + } + + return !match + +} + +// Zero asserts that i is the zero value for its type. +func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { + return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...) + } + return true +} + +// NotZero asserts that i is not the zero value for its type. +func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { + return Fail(t, fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...) + } + return true +} + +// FileExists checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. +func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + info, err := os.Lstat(path) + if err != nil { + if os.IsNotExist(err) { + return Fail(t, fmt.Sprintf("unable to find file %q", path), msgAndArgs...) + } + return Fail(t, fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...) + } + if info.IsDir() { + return Fail(t, fmt.Sprintf("%q is a directory", path), msgAndArgs...) + } + return true +} + +// NoFileExists checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + info, err := os.Lstat(path) + if err != nil { + return true + } + if info.IsDir() { + return true + } + return Fail(t, fmt.Sprintf("file %q exists", path), msgAndArgs...) +} + +// DirExists checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. +func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + info, err := os.Lstat(path) + if err != nil { + if os.IsNotExist(err) { + return Fail(t, fmt.Sprintf("unable to find file %q", path), msgAndArgs...) + } + return Fail(t, fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...) + } + if !info.IsDir() { + return Fail(t, fmt.Sprintf("%q is a file", path), msgAndArgs...) + } + return true +} + +// NoDirExists checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + info, err := os.Lstat(path) + if err != nil { + if os.IsNotExist(err) { + return true + } + return true + } + if !info.IsDir() { + return true + } + return Fail(t, fmt.Sprintf("directory %q exists", path), msgAndArgs...) +} + +// JSONEq asserts that two JSON strings are equivalent. +// +// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + var expectedJSONAsInterface, actualJSONAsInterface interface{} + + if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil { + return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", expected, err.Error()), msgAndArgs...) + } + + if err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil { + return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", actual, err.Error()), msgAndArgs...) + } + + return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...) +} + +// YAMLEq asserts that two YAML strings are equivalent. +func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + var expectedYAMLAsInterface, actualYAMLAsInterface interface{} + + if err := yaml.Unmarshal([]byte(expected), &expectedYAMLAsInterface); err != nil { + return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid yaml.\nYAML parsing error: '%s'", expected, err.Error()), msgAndArgs...) + } + + if err := yaml.Unmarshal([]byte(actual), &actualYAMLAsInterface); err != nil { + return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid yaml.\nYAML error: '%s'", actual, err.Error()), msgAndArgs...) + } + + return Equal(t, expectedYAMLAsInterface, actualYAMLAsInterface, msgAndArgs...) +} + +func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) { + t := reflect.TypeOf(v) + k := t.Kind() + + if k == reflect.Ptr { + t = t.Elem() + k = t.Kind() + } + return t, k +} + +// diff returns a diff of both values as long as both are of the same type and +// are a struct, map, slice, array or string. Otherwise it returns an empty string. +func diff(expected interface{}, actual interface{}) string { + if expected == nil || actual == nil { + return "" + } + + et, ek := typeAndKind(expected) + at, _ := typeAndKind(actual) + + if et != at { + return "" + } + + if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array && ek != reflect.String { + return "" + } + + var e, a string + if et != reflect.TypeOf("") { + e = spewConfig.Sdump(expected) + a = spewConfig.Sdump(actual) + } else { + e = reflect.ValueOf(expected).String() + a = reflect.ValueOf(actual).String() + } + + diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ + A: difflib.SplitLines(e), + B: difflib.SplitLines(a), + FromFile: "Expected", + FromDate: "", + ToFile: "Actual", + ToDate: "", + Context: 1, + }) + + return "\n\nDiff:\n" + diff +} + +func isFunction(arg interface{}) bool { + if arg == nil { + return false + } + return reflect.TypeOf(arg).Kind() == reflect.Func +} + +var spewConfig = spew.ConfigState{ + Indent: " ", + DisablePointerAddresses: true, + DisableCapacities: true, + SortKeys: true, + DisableMethods: true, + MaxDepth: 10, +} + +type tHelper interface { + Helper() +} + +// Eventually asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) +func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + ch := make(chan bool, 1) + + timer := time.NewTimer(waitFor) + defer timer.Stop() + + ticker := time.NewTicker(tick) + defer ticker.Stop() + + for tick := ticker.C; ; { + select { + case <-timer.C: + return Fail(t, "Condition never satisfied", msgAndArgs...) + case <-tick: + tick = nil + go func() { ch <- condition() }() + case v := <-ch: + if v { + return true + } + tick = ticker.C + } + } +} + +// Never asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) +func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + ch := make(chan bool, 1) + + timer := time.NewTimer(waitFor) + defer timer.Stop() + + ticker := time.NewTicker(tick) + defer ticker.Stop() + + for tick := ticker.C; ; { + select { + case <-timer.C: + return true + case <-tick: + tick = nil + go func() { ch <- condition() }() + case v := <-ch: + if v { + return Fail(t, "Condition satisfied", msgAndArgs...) + } + tick = ticker.C + } + } +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if errors.Is(err, target) { + return true + } + + var expectedText string + if target != nil { + expectedText = target.Error() + } + + chain := buildErrorChainString(err) + + return Fail(t, fmt.Sprintf("Target error should be in err chain:\n"+ + "expected: %q\n"+ + "in chain: %s", expectedText, chain, + ), msgAndArgs...) +} + +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if !errors.Is(err, target) { + return true + } + + var expectedText string + if target != nil { + expectedText = target.Error() + } + + chain := buildErrorChainString(err) + + return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+ + "found: %q\n"+ + "in chain: %s", expectedText, chain, + ), msgAndArgs...) +} + +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if errors.As(err, target) { + return true + } + + chain := buildErrorChainString(err) + + return Fail(t, fmt.Sprintf("Should be in error chain:\n"+ + "expected: %q\n"+ + "in chain: %s", target, chain, + ), msgAndArgs...) +} + +func buildErrorChainString(err error) string { + if err == nil { + return "" + } + + e := errors.Unwrap(err) + chain := fmt.Sprintf("%q", err.Error()) + for e != nil { + chain += fmt.Sprintf("\n\t%q", e.Error()) + e = errors.Unwrap(e) + } + return chain +} diff --git a/vendor/github.com/stretchr/testify/assert/doc.go b/vendor/github.com/stretchr/testify/assert/doc.go new file mode 100644 index 00000000000..c9dccc4d6cd --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/doc.go @@ -0,0 +1,45 @@ +// Package assert provides a set of comprehensive testing tools for use with the normal Go testing system. +// +// Example Usage +// +// The following is a complete example using assert in a standard test function: +// import ( +// "testing" +// "github.com/stretchr/testify/assert" +// ) +// +// func TestSomething(t *testing.T) { +// +// var a string = "Hello" +// var b string = "Hello" +// +// assert.Equal(t, a, b, "The two words should be the same.") +// +// } +// +// if you assert many times, use the format below: +// +// import ( +// "testing" +// "github.com/stretchr/testify/assert" +// ) +// +// func TestSomething(t *testing.T) { +// assert := assert.New(t) +// +// var a string = "Hello" +// var b string = "Hello" +// +// assert.Equal(a, b, "The two words should be the same.") +// } +// +// Assertions +// +// Assertions allow you to easily write test code, and are global funcs in the `assert` package. +// All assertion functions take, as the first argument, the `*testing.T` object provided by the +// testing framework. This allows the assertion funcs to write the failings and other details to +// the correct place. +// +// Every assertion function also takes an optional string message as the final argument, +// allowing custom error messages to be appended to the message the assertion method outputs. +package assert diff --git a/vendor/github.com/stretchr/testify/assert/errors.go b/vendor/github.com/stretchr/testify/assert/errors.go new file mode 100644 index 00000000000..ac9dc9d1d61 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/errors.go @@ -0,0 +1,10 @@ +package assert + +import ( + "errors" +) + +// AnError is an error instance useful for testing. If the code does not care +// about error specifics, and only needs to return the error for example, this +// error should be used to make the test code more readable. +var AnError = errors.New("assert.AnError general error for testing") diff --git a/vendor/github.com/stretchr/testify/assert/forward_assertions.go b/vendor/github.com/stretchr/testify/assert/forward_assertions.go new file mode 100644 index 00000000000..df189d2348f --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/forward_assertions.go @@ -0,0 +1,16 @@ +package assert + +// Assertions provides assertion methods around the +// TestingT interface. +type Assertions struct { + t TestingT +} + +// New makes a new Assertions object for the specified TestingT. +func New(t TestingT) *Assertions { + return &Assertions{ + t: t, + } +} + +//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs" diff --git a/vendor/github.com/stretchr/testify/assert/http_assertions.go b/vendor/github.com/stretchr/testify/assert/http_assertions.go new file mode 100644 index 00000000000..4ed341dd289 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/http_assertions.go @@ -0,0 +1,162 @@ +package assert + +import ( + "fmt" + "net/http" + "net/http/httptest" + "net/url" + "strings" +) + +// httpCode is a helper that returns HTTP code of the response. It returns -1 and +// an error if building a new request fails. +func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) { + w := httptest.NewRecorder() + req, err := http.NewRequest(method, url, nil) + if err != nil { + return -1, err + } + req.URL.RawQuery = values.Encode() + handler(w, req) + return w.Code, nil +} + +// HTTPSuccess asserts that a specified handler returns a success status code. +// +// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + code, err := httpCode(handler, method, url, values) + if err != nil { + Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) + } + + isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent + if !isSuccessCode { + Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code)) + } + + return isSuccessCode +} + +// HTTPRedirect asserts that a specified handler returns a redirect status code. +// +// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + code, err := httpCode(handler, method, url, values) + if err != nil { + Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) + } + + isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect + if !isRedirectCode { + Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code)) + } + + return isRedirectCode +} + +// HTTPError asserts that a specified handler returns an error status code. +// +// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + code, err := httpCode(handler, method, url, values) + if err != nil { + Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) + } + + isErrorCode := code >= http.StatusBadRequest + if !isErrorCode { + Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code)) + } + + return isErrorCode +} + +// HTTPStatusCode asserts that a specified handler returns a specified status code. +// +// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + code, err := httpCode(handler, method, url, values) + if err != nil { + Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) + } + + successful := code == statuscode + if !successful { + Fail(t, fmt.Sprintf("Expected HTTP status code %d for %q but received %d", statuscode, url+"?"+values.Encode(), code)) + } + + return successful +} + +// HTTPBody is a helper that returns HTTP body of the response. It returns +// empty string if building a new request fails. +func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string { + w := httptest.NewRecorder() + req, err := http.NewRequest(method, url+"?"+values.Encode(), nil) + if err != nil { + return "" + } + handler(w, req) + return w.Body.String() +} + +// HTTPBodyContains asserts that a specified handler returns a +// body that contains a string. +// +// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + body := HTTPBody(handler, method, url, values) + + contains := strings.Contains(body, fmt.Sprint(str)) + if !contains { + Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) + } + + return contains +} + +// HTTPBodyNotContains asserts that a specified handler returns a +// body that does not contain a string. +// +// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + body := HTTPBody(handler, method, url, values) + + contains := strings.Contains(body, fmt.Sprint(str)) + if contains { + Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) + } + + return !contains +} diff --git a/vendor/github.com/stretchr/testify/require/doc.go b/vendor/github.com/stretchr/testify/require/doc.go new file mode 100644 index 00000000000..169de39221c --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/doc.go @@ -0,0 +1,28 @@ +// Package require implements the same assertions as the `assert` package but +// stops test execution when a test fails. +// +// Example Usage +// +// The following is a complete example using require in a standard test function: +// import ( +// "testing" +// "github.com/stretchr/testify/require" +// ) +// +// func TestSomething(t *testing.T) { +// +// var a string = "Hello" +// var b string = "Hello" +// +// require.Equal(t, a, b, "The two words should be the same.") +// +// } +// +// Assertions +// +// The `require` package have same global functions as in the `assert` package, +// but instead of returning a boolean result they call `t.FailNow()`. +// +// Every assertion function also takes an optional string message as the final argument, +// allowing custom error messages to be appended to the message the assertion method outputs. +package require diff --git a/vendor/github.com/stretchr/testify/require/forward_requirements.go b/vendor/github.com/stretchr/testify/require/forward_requirements.go new file mode 100644 index 00000000000..1dcb2338c4c --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/forward_requirements.go @@ -0,0 +1,16 @@ +package require + +// Assertions provides assertion methods around the +// TestingT interface. +type Assertions struct { + t TestingT +} + +// New makes a new Assertions object for the specified TestingT. +func New(t TestingT) *Assertions { + return &Assertions{ + t: t, + } +} + +//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require_forward.go.tmpl -include-format-funcs" diff --git a/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/stretchr/testify/require/require.go new file mode 100644 index 00000000000..51820df2e67 --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/require.go @@ -0,0 +1,1879 @@ +/* +* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen +* THIS FILE MUST NOT BE EDITED BY HAND + */ + +package require + +import ( + assert "github.com/stretchr/testify/assert" + http "net/http" + url "net/url" + time "time" +) + +// Condition uses a Comparison to assert a complex condition. +func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Condition(t, comp, msgAndArgs...) { + return + } + t.FailNow() +} + +// Conditionf uses a Comparison to assert a complex condition. +func Conditionf(t TestingT, comp assert.Comparison, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Conditionf(t, comp, msg, args...) { + return + } + t.FailNow() +} + +// Contains asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// assert.Contains(t, "Hello World", "World") +// assert.Contains(t, ["Hello", "World"], "World") +// assert.Contains(t, {"Hello": "World"}, "Hello") +func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Contains(t, s, contains, msgAndArgs...) { + return + } + t.FailNow() +} + +// Containsf asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted") +// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted") +// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted") +func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Containsf(t, s, contains, msg, args...) { + return + } + t.FailNow() +} + +// DirExists checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. +func DirExists(t TestingT, path string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.DirExists(t, path, msgAndArgs...) { + return + } + t.FailNow() +} + +// DirExistsf checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. +func DirExistsf(t TestingT, path string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.DirExistsf(t, path, msg, args...) { + return + } + t.FailNow() +} + +// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2]) +func ElementsMatch(t TestingT, listA interface{}, listB interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ElementsMatch(t, listA, listB, msgAndArgs...) { + return + } + t.FailNow() +} + +// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") +func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ElementsMatchf(t, listA, listB, msg, args...) { + return + } + t.FailNow() +} + +// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// assert.Empty(t, obj) +func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Empty(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// assert.Emptyf(t, obj, "error message %s", "formatted") +func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Emptyf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// Equal asserts that two objects are equal. +// +// assert.Equal(t, 123, 123) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Equal(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// EqualError asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// assert.EqualError(t, err, expectedErrorString) +func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.EqualError(t, theError, errString, msgAndArgs...) { + return + } + t.FailNow() +} + +// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") +func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.EqualErrorf(t, theError, errString, msg, args...) { + return + } + t.FailNow() +} + +// EqualValues asserts that two objects are equal or convertable to the same types +// and equal. +// +// assert.EqualValues(t, uint32(123), int32(123)) +func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.EqualValues(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// EqualValuesf asserts that two objects are equal or convertable to the same types +// and equal. +// +// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") +func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.EqualValuesf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Equalf asserts that two objects are equal. +// +// assert.Equalf(t, 123, 123, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Equalf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Error asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if assert.Error(t, err) { +// assert.Equal(t, expectedError, err) +// } +func Error(t TestingT, err error, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Error(t, err, msgAndArgs...) { + return + } + t.FailNow() +} + +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorAs(t, err, target, msgAndArgs...) { + return + } + t.FailNow() +} + +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorAsf(t, err, target, msg, args...) { + return + } + t.FailNow() +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorIs(t, err, target, msgAndArgs...) { + return + } + t.FailNow() +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorIsf(t, err, target, msg, args...) { + return + } + t.FailNow() +} + +// Errorf asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if assert.Errorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } +func Errorf(t TestingT, err error, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Errorf(t, err, msg, args...) { + return + } + t.FailNow() +} + +// Eventually asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) +func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Eventually(t, condition, waitFor, tick, msgAndArgs...) { + return + } + t.FailNow() +} + +// Eventuallyf asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Eventuallyf(t, condition, waitFor, tick, msg, args...) { + return + } + t.FailNow() +} + +// Exactly asserts that two objects are equal in value and type. +// +// assert.Exactly(t, int32(123), int64(123)) +func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Exactly(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// Exactlyf asserts that two objects are equal in value and type. +// +// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") +func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Exactlyf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Fail reports a failure through +func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Fail(t, failureMessage, msgAndArgs...) { + return + } + t.FailNow() +} + +// FailNow fails test +func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.FailNow(t, failureMessage, msgAndArgs...) { + return + } + t.FailNow() +} + +// FailNowf fails test +func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.FailNowf(t, failureMessage, msg, args...) { + return + } + t.FailNow() +} + +// Failf reports a failure through +func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Failf(t, failureMessage, msg, args...) { + return + } + t.FailNow() +} + +// False asserts that the specified value is false. +// +// assert.False(t, myBool) +func False(t TestingT, value bool, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.False(t, value, msgAndArgs...) { + return + } + t.FailNow() +} + +// Falsef asserts that the specified value is false. +// +// assert.Falsef(t, myBool, "error message %s", "formatted") +func Falsef(t TestingT, value bool, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Falsef(t, value, msg, args...) { + return + } + t.FailNow() +} + +// FileExists checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. +func FileExists(t TestingT, path string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.FileExists(t, path, msgAndArgs...) { + return + } + t.FailNow() +} + +// FileExistsf checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. +func FileExistsf(t TestingT, path string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.FileExistsf(t, path, msg, args...) { + return + } + t.FailNow() +} + +// Greater asserts that the first element is greater than the second +// +// assert.Greater(t, 2, 1) +// assert.Greater(t, float64(2), float64(1)) +// assert.Greater(t, "b", "a") +func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Greater(t, e1, e2, msgAndArgs...) { + return + } + t.FailNow() +} + +// GreaterOrEqual asserts that the first element is greater than or equal to the second +// +// assert.GreaterOrEqual(t, 2, 1) +// assert.GreaterOrEqual(t, 2, 2) +// assert.GreaterOrEqual(t, "b", "a") +// assert.GreaterOrEqual(t, "b", "b") +func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.GreaterOrEqual(t, e1, e2, msgAndArgs...) { + return + } + t.FailNow() +} + +// GreaterOrEqualf asserts that the first element is greater than or equal to the second +// +// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted") +func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.GreaterOrEqualf(t, e1, e2, msg, args...) { + return + } + t.FailNow() +} + +// Greaterf asserts that the first element is greater than the second +// +// assert.Greaterf(t, 2, 1, "error message %s", "formatted") +// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") +// assert.Greaterf(t, "b", "a", "error message %s", "formatted") +func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Greaterf(t, e1, e2, msg, args...) { + return + } + t.FailNow() +} + +// HTTPBodyContains asserts that a specified handler returns a +// body that contains a string. +// +// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPBodyContains(t, handler, method, url, values, str, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPBodyContainsf asserts that a specified handler returns a +// body that contains a string. +// +// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPBodyContainsf(t, handler, method, url, values, str, msg, args...) { + return + } + t.FailNow() +} + +// HTTPBodyNotContains asserts that a specified handler returns a +// body that does not contain a string. +// +// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPBodyNotContains(t, handler, method, url, values, str, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPBodyNotContainsf asserts that a specified handler returns a +// body that does not contain a string. +// +// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPBodyNotContainsf(t, handler, method, url, values, str, msg, args...) { + return + } + t.FailNow() +} + +// HTTPError asserts that a specified handler returns an error status code. +// +// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPError(t, handler, method, url, values, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPErrorf asserts that a specified handler returns an error status code. +// +// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPErrorf(t, handler, method, url, values, msg, args...) { + return + } + t.FailNow() +} + +// HTTPRedirect asserts that a specified handler returns a redirect status code. +// +// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPRedirect(t, handler, method, url, values, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPRedirectf asserts that a specified handler returns a redirect status code. +// +// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPRedirectf(t, handler, method, url, values, msg, args...) { + return + } + t.FailNow() +} + +// HTTPStatusCode asserts that a specified handler returns a specified status code. +// +// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPStatusCode(t, handler, method, url, values, statuscode, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPStatusCodef asserts that a specified handler returns a specified status code. +// +// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPStatusCodef(t, handler, method, url, values, statuscode, msg, args...) { + return + } + t.FailNow() +} + +// HTTPSuccess asserts that a specified handler returns a success status code. +// +// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPSuccess(t, handler, method, url, values, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPSuccessf asserts that a specified handler returns a success status code. +// +// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPSuccessf(t, handler, method, url, values, msg, args...) { + return + } + t.FailNow() +} + +// Implements asserts that an object is implemented by the specified interface. +// +// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) +func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Implements(t, interfaceObject, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// Implementsf asserts that an object is implemented by the specified interface. +// +// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Implementsf(t, interfaceObject, object, msg, args...) { + return + } + t.FailNow() +} + +// InDelta asserts that the two numerals are within delta of each other. +// +// assert.InDelta(t, math.Pi, 22/7.0, 0.01) +func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDelta(t, expected, actual, delta, msgAndArgs...) { + return + } + t.FailNow() +} + +// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func InDeltaMapValues(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDeltaMapValues(t, expected, actual, delta, msgAndArgs...) { + return + } + t.FailNow() +} + +// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDeltaMapValuesf(t, expected, actual, delta, msg, args...) { + return + } + t.FailNow() +} + +// InDeltaSlice is the same as InDelta, except it compares two slices. +func InDeltaSlice(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) { + return + } + t.FailNow() +} + +// InDeltaSlicef is the same as InDelta, except it compares two slices. +func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDeltaSlicef(t, expected, actual, delta, msg, args...) { + return + } + t.FailNow() +} + +// InDeltaf asserts that the two numerals are within delta of each other. +// +// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDeltaf(t, expected, actual, delta, msg, args...) { + return + } + t.FailNow() +} + +// InEpsilon asserts that expected and actual have a relative error less than epsilon +func InEpsilon(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) { + return + } + t.FailNow() +} + +// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. +func InEpsilonSlice(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InEpsilonSlice(t, expected, actual, epsilon, msgAndArgs...) { + return + } + t.FailNow() +} + +// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. +func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InEpsilonSlicef(t, expected, actual, epsilon, msg, args...) { + return + } + t.FailNow() +} + +// InEpsilonf asserts that expected and actual have a relative error less than epsilon +func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InEpsilonf(t, expected, actual, epsilon, msg, args...) { + return + } + t.FailNow() +} + +// IsDecreasing asserts that the collection is decreasing +// +// assert.IsDecreasing(t, []int{2, 1, 0}) +// assert.IsDecreasing(t, []float{2, 1}) +// assert.IsDecreasing(t, []string{"b", "a"}) +func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsDecreasing(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsDecreasingf asserts that the collection is decreasing +// +// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsDecreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// IsIncreasing asserts that the collection is increasing +// +// assert.IsIncreasing(t, []int{1, 2, 3}) +// assert.IsIncreasing(t, []float{1, 2}) +// assert.IsIncreasing(t, []string{"a", "b"}) +func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsIncreasing(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsIncreasingf asserts that the collection is increasing +// +// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsIncreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// IsNonDecreasing asserts that the collection is not decreasing +// +// assert.IsNonDecreasing(t, []int{1, 1, 2}) +// assert.IsNonDecreasing(t, []float{1, 2}) +// assert.IsNonDecreasing(t, []string{"a", "b"}) +func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonDecreasing(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsNonDecreasingf asserts that the collection is not decreasing +// +// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonDecreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// IsNonIncreasing asserts that the collection is not increasing +// +// assert.IsNonIncreasing(t, []int{2, 1, 1}) +// assert.IsNonIncreasing(t, []float{2, 1}) +// assert.IsNonIncreasing(t, []string{"b", "a"}) +func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonIncreasing(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonIncreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// IsType asserts that the specified objects are of the same type. +func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsType(t, expectedType, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsTypef asserts that the specified objects are of the same type. +func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsTypef(t, expectedType, object, msg, args...) { + return + } + t.FailNow() +} + +// JSONEq asserts that two JSON strings are equivalent. +// +// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.JSONEq(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// JSONEqf asserts that two JSON strings are equivalent. +// +// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.JSONEqf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Len asserts that the specified object has specific length. +// Len also fails if the object has a type that len() not accept. +// +// assert.Len(t, mySlice, 3) +func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Len(t, object, length, msgAndArgs...) { + return + } + t.FailNow() +} + +// Lenf asserts that the specified object has specific length. +// Lenf also fails if the object has a type that len() not accept. +// +// assert.Lenf(t, mySlice, 3, "error message %s", "formatted") +func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Lenf(t, object, length, msg, args...) { + return + } + t.FailNow() +} + +// Less asserts that the first element is less than the second +// +// assert.Less(t, 1, 2) +// assert.Less(t, float64(1), float64(2)) +// assert.Less(t, "a", "b") +func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Less(t, e1, e2, msgAndArgs...) { + return + } + t.FailNow() +} + +// LessOrEqual asserts that the first element is less than or equal to the second +// +// assert.LessOrEqual(t, 1, 2) +// assert.LessOrEqual(t, 2, 2) +// assert.LessOrEqual(t, "a", "b") +// assert.LessOrEqual(t, "b", "b") +func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.LessOrEqual(t, e1, e2, msgAndArgs...) { + return + } + t.FailNow() +} + +// LessOrEqualf asserts that the first element is less than or equal to the second +// +// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted") +// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted") +func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.LessOrEqualf(t, e1, e2, msg, args...) { + return + } + t.FailNow() +} + +// Lessf asserts that the first element is less than the second +// +// assert.Lessf(t, 1, 2, "error message %s", "formatted") +// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted") +// assert.Lessf(t, "a", "b", "error message %s", "formatted") +func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Lessf(t, e1, e2, msg, args...) { + return + } + t.FailNow() +} + +// Negative asserts that the specified element is negative +// +// assert.Negative(t, -1) +// assert.Negative(t, -1.23) +func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Negative(t, e, msgAndArgs...) { + return + } + t.FailNow() +} + +// Negativef asserts that the specified element is negative +// +// assert.Negativef(t, -1, "error message %s", "formatted") +// assert.Negativef(t, -1.23, "error message %s", "formatted") +func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Negativef(t, e, msg, args...) { + return + } + t.FailNow() +} + +// Never asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) +func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Never(t, condition, waitFor, tick, msgAndArgs...) { + return + } + t.FailNow() +} + +// Neverf asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Neverf(t, condition, waitFor, tick, msg, args...) { + return + } + t.FailNow() +} + +// Nil asserts that the specified object is nil. +// +// assert.Nil(t, err) +func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Nil(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// Nilf asserts that the specified object is nil. +// +// assert.Nilf(t, err, "error message %s", "formatted") +func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Nilf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// NoDirExists checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoDirExists(t, path, msgAndArgs...) { + return + } + t.FailNow() +} + +// NoDirExistsf checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoDirExistsf(t, path, msg, args...) { + return + } + t.FailNow() +} + +// NoError asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if assert.NoError(t, err) { +// assert.Equal(t, expectedObj, actualObj) +// } +func NoError(t TestingT, err error, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoError(t, err, msgAndArgs...) { + return + } + t.FailNow() +} + +// NoErrorf asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if assert.NoErrorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } +func NoErrorf(t TestingT, err error, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoErrorf(t, err, msg, args...) { + return + } + t.FailNow() +} + +// NoFileExists checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoFileExists(t, path, msgAndArgs...) { + return + } + t.FailNow() +} + +// NoFileExistsf checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoFileExistsf(t, path, msg, args...) { + return + } + t.FailNow() +} + +// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// assert.NotContains(t, "Hello World", "Earth") +// assert.NotContains(t, ["Hello", "World"], "Earth") +// assert.NotContains(t, {"Hello": "World"}, "Earth") +func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotContains(t, s, contains, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted") +func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotContainsf(t, s, contains, msg, args...) { + return + } + t.FailNow() +} + +// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if assert.NotEmpty(t, obj) { +// assert.Equal(t, "two", obj[1]) +// } +func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEmpty(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if assert.NotEmptyf(t, obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } +func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEmptyf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// NotEqual asserts that the specified values are NOT equal. +// +// assert.NotEqual(t, obj1, obj2) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEqual(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotEqualValues asserts that two objects are not equal even when converted to the same type +// +// assert.NotEqualValues(t, obj1, obj2) +func NotEqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEqualValues(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotEqualValuesf asserts that two objects are not equal even when converted to the same type +// +// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") +func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEqualValuesf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// NotEqualf asserts that the specified values are NOT equal. +// +// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEqualf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotErrorIs(t, err, target, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotErrorIsf(t, err, target, msg, args...) { + return + } + t.FailNow() +} + +// NotNil asserts that the specified object is not nil. +// +// assert.NotNil(t, err) +func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotNil(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotNilf asserts that the specified object is not nil. +// +// assert.NotNilf(t, err, "error message %s", "formatted") +func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotNilf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// assert.NotPanics(t, func(){ RemainCalm() }) +func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotPanics(t, f, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") +func NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotPanicsf(t, f, msg, args...) { + return + } + t.FailNow() +} + +// NotRegexp asserts that a specified regexp does not match a string. +// +// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") +// assert.NotRegexp(t, "^start", "it's not starting") +func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotRegexp(t, rx, str, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotRegexpf asserts that a specified regexp does not match a string. +// +// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") +func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotRegexpf(t, rx, str, msg, args...) { + return + } + t.FailNow() +} + +// NotSame asserts that two pointers do not reference the same object. +// +// assert.NotSame(t, ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func NotSame(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotSame(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotSamef asserts that two pointers do not reference the same object. +// +// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotSamef(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// NotSubset asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") +func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotSubset(t, list, subset, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotSubsetf asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") +func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotSubsetf(t, list, subset, msg, args...) { + return + } + t.FailNow() +} + +// NotZero asserts that i is not the zero value for its type. +func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotZero(t, i, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotZerof asserts that i is not the zero value for its type. +func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotZerof(t, i, msg, args...) { + return + } + t.FailNow() +} + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// assert.Panics(t, func(){ GoCrazy() }) +func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Panics(t, f, msgAndArgs...) { + return + } + t.FailNow() +} + +// PanicsWithError asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) +func PanicsWithError(t TestingT, errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.PanicsWithError(t, errString, f, msgAndArgs...) { + return + } + t.FailNow() +} + +// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func PanicsWithErrorf(t TestingT, errString string, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.PanicsWithErrorf(t, errString, f, msg, args...) { + return + } + t.FailNow() +} + +// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) +func PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.PanicsWithValue(t, expected, f, msgAndArgs...) { + return + } + t.FailNow() +} + +// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.PanicsWithValuef(t, expected, f, msg, args...) { + return + } + t.FailNow() +} + +// Panicsf asserts that the code inside the specified PanicTestFunc panics. +// +// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") +func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Panicsf(t, f, msg, args...) { + return + } + t.FailNow() +} + +// Positive asserts that the specified element is positive +// +// assert.Positive(t, 1) +// assert.Positive(t, 1.23) +func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Positive(t, e, msgAndArgs...) { + return + } + t.FailNow() +} + +// Positivef asserts that the specified element is positive +// +// assert.Positivef(t, 1, "error message %s", "formatted") +// assert.Positivef(t, 1.23, "error message %s", "formatted") +func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Positivef(t, e, msg, args...) { + return + } + t.FailNow() +} + +// Regexp asserts that a specified regexp matches a string. +// +// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") +// assert.Regexp(t, "start...$", "it's not starting") +func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Regexp(t, rx, str, msgAndArgs...) { + return + } + t.FailNow() +} + +// Regexpf asserts that a specified regexp matches a string. +// +// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") +func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Regexpf(t, rx, str, msg, args...) { + return + } + t.FailNow() +} + +// Same asserts that two pointers reference the same object. +// +// assert.Same(t, ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func Same(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Same(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// Samef asserts that two pointers reference the same object. +// +// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Samef(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Subset asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Subset(t, list, subset, msgAndArgs...) { + return + } + t.FailNow() +} + +// Subsetf asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") +func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Subsetf(t, list, subset, msg, args...) { + return + } + t.FailNow() +} + +// True asserts that the specified value is true. +// +// assert.True(t, myBool) +func True(t TestingT, value bool, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.True(t, value, msgAndArgs...) { + return + } + t.FailNow() +} + +// Truef asserts that the specified value is true. +// +// assert.Truef(t, myBool, "error message %s", "formatted") +func Truef(t TestingT, value bool, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Truef(t, value, msg, args...) { + return + } + t.FailNow() +} + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) +func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) { + return + } + t.FailNow() +} + +// WithinDurationf asserts that the two times are within duration delta of each other. +// +// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.WithinDurationf(t, expected, actual, delta, msg, args...) { + return + } + t.FailNow() +} + +// YAMLEq asserts that two YAML strings are equivalent. +func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.YAMLEq(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// YAMLEqf asserts that two YAML strings are equivalent. +func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.YAMLEqf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Zero asserts that i is the zero value for its type. +func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Zero(t, i, msgAndArgs...) { + return + } + t.FailNow() +} + +// Zerof asserts that i is the zero value for its type. +func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Zerof(t, i, msg, args...) { + return + } + t.FailNow() +} diff --git a/vendor/github.com/stretchr/testify/require/require.go.tmpl b/vendor/github.com/stretchr/testify/require/require.go.tmpl new file mode 100644 index 00000000000..55e42ddebdc --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/require.go.tmpl @@ -0,0 +1,6 @@ +{{.Comment}} +func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { + if h, ok := t.(tHelper); ok { h.Helper() } + if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return } + t.FailNow() +} diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/stretchr/testify/require/require_forward.go new file mode 100644 index 00000000000..ed54a9d83f3 --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/require_forward.go @@ -0,0 +1,1471 @@ +/* +* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen +* THIS FILE MUST NOT BE EDITED BY HAND + */ + +package require + +import ( + assert "github.com/stretchr/testify/assert" + http "net/http" + url "net/url" + time "time" +) + +// Condition uses a Comparison to assert a complex condition. +func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Condition(a.t, comp, msgAndArgs...) +} + +// Conditionf uses a Comparison to assert a complex condition. +func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Conditionf(a.t, comp, msg, args...) +} + +// Contains asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// a.Contains("Hello World", "World") +// a.Contains(["Hello", "World"], "World") +// a.Contains({"Hello": "World"}, "Hello") +func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Contains(a.t, s, contains, msgAndArgs...) +} + +// Containsf asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// a.Containsf("Hello World", "World", "error message %s", "formatted") +// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted") +// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") +func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Containsf(a.t, s, contains, msg, args...) +} + +// DirExists checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. +func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + DirExists(a.t, path, msgAndArgs...) +} + +// DirExistsf checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. +func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + DirExistsf(a.t, path, msg, args...) +} + +// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2]) +func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ElementsMatch(a.t, listA, listB, msgAndArgs...) +} + +// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") +func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ElementsMatchf(a.t, listA, listB, msg, args...) +} + +// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// a.Empty(obj) +func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Empty(a.t, object, msgAndArgs...) +} + +// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// a.Emptyf(obj, "error message %s", "formatted") +func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Emptyf(a.t, object, msg, args...) +} + +// Equal asserts that two objects are equal. +// +// a.Equal(123, 123) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Equal(a.t, expected, actual, msgAndArgs...) +} + +// EqualError asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// a.EqualError(err, expectedErrorString) +func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + EqualError(a.t, theError, errString, msgAndArgs...) +} + +// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") +func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + EqualErrorf(a.t, theError, errString, msg, args...) +} + +// EqualValues asserts that two objects are equal or convertable to the same types +// and equal. +// +// a.EqualValues(uint32(123), int32(123)) +func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + EqualValues(a.t, expected, actual, msgAndArgs...) +} + +// EqualValuesf asserts that two objects are equal or convertable to the same types +// and equal. +// +// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") +func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + EqualValuesf(a.t, expected, actual, msg, args...) +} + +// Equalf asserts that two objects are equal. +// +// a.Equalf(123, 123, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Equalf(a.t, expected, actual, msg, args...) +} + +// Error asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if a.Error(err) { +// assert.Equal(t, expectedError, err) +// } +func (a *Assertions) Error(err error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Error(a.t, err, msgAndArgs...) +} + +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorAs(a.t, err, target, msgAndArgs...) +} + +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorAsf(a.t, err, target, msg, args...) +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorIs(a.t, err, target, msgAndArgs...) +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorIsf(a.t, err, target, msg, args...) +} + +// Errorf asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if a.Errorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } +func (a *Assertions) Errorf(err error, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Errorf(a.t, err, msg, args...) +} + +// Eventually asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) +func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Eventually(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// Eventuallyf asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Eventuallyf(a.t, condition, waitFor, tick, msg, args...) +} + +// Exactly asserts that two objects are equal in value and type. +// +// a.Exactly(int32(123), int64(123)) +func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Exactly(a.t, expected, actual, msgAndArgs...) +} + +// Exactlyf asserts that two objects are equal in value and type. +// +// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") +func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Exactlyf(a.t, expected, actual, msg, args...) +} + +// Fail reports a failure through +func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Fail(a.t, failureMessage, msgAndArgs...) +} + +// FailNow fails test +func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + FailNow(a.t, failureMessage, msgAndArgs...) +} + +// FailNowf fails test +func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + FailNowf(a.t, failureMessage, msg, args...) +} + +// Failf reports a failure through +func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Failf(a.t, failureMessage, msg, args...) +} + +// False asserts that the specified value is false. +// +// a.False(myBool) +func (a *Assertions) False(value bool, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + False(a.t, value, msgAndArgs...) +} + +// Falsef asserts that the specified value is false. +// +// a.Falsef(myBool, "error message %s", "formatted") +func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Falsef(a.t, value, msg, args...) +} + +// FileExists checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. +func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + FileExists(a.t, path, msgAndArgs...) +} + +// FileExistsf checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. +func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + FileExistsf(a.t, path, msg, args...) +} + +// Greater asserts that the first element is greater than the second +// +// a.Greater(2, 1) +// a.Greater(float64(2), float64(1)) +// a.Greater("b", "a") +func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Greater(a.t, e1, e2, msgAndArgs...) +} + +// GreaterOrEqual asserts that the first element is greater than or equal to the second +// +// a.GreaterOrEqual(2, 1) +// a.GreaterOrEqual(2, 2) +// a.GreaterOrEqual("b", "a") +// a.GreaterOrEqual("b", "b") +func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + GreaterOrEqual(a.t, e1, e2, msgAndArgs...) +} + +// GreaterOrEqualf asserts that the first element is greater than or equal to the second +// +// a.GreaterOrEqualf(2, 1, "error message %s", "formatted") +// a.GreaterOrEqualf(2, 2, "error message %s", "formatted") +// a.GreaterOrEqualf("b", "a", "error message %s", "formatted") +// a.GreaterOrEqualf("b", "b", "error message %s", "formatted") +func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + GreaterOrEqualf(a.t, e1, e2, msg, args...) +} + +// Greaterf asserts that the first element is greater than the second +// +// a.Greaterf(2, 1, "error message %s", "formatted") +// a.Greaterf(float64(2), float64(1), "error message %s", "formatted") +// a.Greaterf("b", "a", "error message %s", "formatted") +func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Greaterf(a.t, e1, e2, msg, args...) +} + +// HTTPBodyContains asserts that a specified handler returns a +// body that contains a string. +// +// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...) +} + +// HTTPBodyContainsf asserts that a specified handler returns a +// body that contains a string. +// +// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...) +} + +// HTTPBodyNotContains asserts that a specified handler returns a +// body that does not contain a string. +// +// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...) +} + +// HTTPBodyNotContainsf asserts that a specified handler returns a +// body that does not contain a string. +// +// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...) +} + +// HTTPError asserts that a specified handler returns an error status code. +// +// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPError(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPErrorf asserts that a specified handler returns an error status code. +// +// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPErrorf(a.t, handler, method, url, values, msg, args...) +} + +// HTTPRedirect asserts that a specified handler returns a redirect status code. +// +// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPRedirectf asserts that a specified handler returns a redirect status code. +// +// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPRedirectf(a.t, handler, method, url, values, msg, args...) +} + +// HTTPStatusCode asserts that a specified handler returns a specified status code. +// +// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...) +} + +// HTTPStatusCodef asserts that a specified handler returns a specified status code. +// +// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPStatusCodef(a.t, handler, method, url, values, statuscode, msg, args...) +} + +// HTTPSuccess asserts that a specified handler returns a success status code. +// +// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPSuccessf asserts that a specified handler returns a success status code. +// +// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPSuccessf(a.t, handler, method, url, values, msg, args...) +} + +// Implements asserts that an object is implemented by the specified interface. +// +// a.Implements((*MyInterface)(nil), new(MyObject)) +func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Implements(a.t, interfaceObject, object, msgAndArgs...) +} + +// Implementsf asserts that an object is implemented by the specified interface. +// +// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Implementsf(a.t, interfaceObject, object, msg, args...) +} + +// InDelta asserts that the two numerals are within delta of each other. +// +// a.InDelta(math.Pi, 22/7.0, 0.01) +func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDelta(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...) +} + +// InDeltaSlice is the same as InDelta, except it compares two slices. +func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaSlicef is the same as InDelta, except it compares two slices. +func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDeltaSlicef(a.t, expected, actual, delta, msg, args...) +} + +// InDeltaf asserts that the two numerals are within delta of each other. +// +// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDeltaf(a.t, expected, actual, delta, msg, args...) +} + +// InEpsilon asserts that expected and actual have a relative error less than epsilon +func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) +} + +// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. +func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...) +} + +// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. +func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...) +} + +// InEpsilonf asserts that expected and actual have a relative error less than epsilon +func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InEpsilonf(a.t, expected, actual, epsilon, msg, args...) +} + +// IsDecreasing asserts that the collection is decreasing +// +// a.IsDecreasing([]int{2, 1, 0}) +// a.IsDecreasing([]float{2, 1}) +// a.IsDecreasing([]string{"b", "a"}) +func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsDecreasing(a.t, object, msgAndArgs...) +} + +// IsDecreasingf asserts that the collection is decreasing +// +// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") +// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsDecreasingf(a.t, object, msg, args...) +} + +// IsIncreasing asserts that the collection is increasing +// +// a.IsIncreasing([]int{1, 2, 3}) +// a.IsIncreasing([]float{1, 2}) +// a.IsIncreasing([]string{"a", "b"}) +func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsIncreasing(a.t, object, msgAndArgs...) +} + +// IsIncreasingf asserts that the collection is increasing +// +// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") +// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsIncreasingf(a.t, object, msg, args...) +} + +// IsNonDecreasing asserts that the collection is not decreasing +// +// a.IsNonDecreasing([]int{1, 1, 2}) +// a.IsNonDecreasing([]float{1, 2}) +// a.IsNonDecreasing([]string{"a", "b"}) +func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonDecreasing(a.t, object, msgAndArgs...) +} + +// IsNonDecreasingf asserts that the collection is not decreasing +// +// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonDecreasingf(a.t, object, msg, args...) +} + +// IsNonIncreasing asserts that the collection is not increasing +// +// a.IsNonIncreasing([]int{2, 1, 1}) +// a.IsNonIncreasing([]float{2, 1}) +// a.IsNonIncreasing([]string{"b", "a"}) +func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonIncreasing(a.t, object, msgAndArgs...) +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonIncreasingf(a.t, object, msg, args...) +} + +// IsType asserts that the specified objects are of the same type. +func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsType(a.t, expectedType, object, msgAndArgs...) +} + +// IsTypef asserts that the specified objects are of the same type. +func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsTypef(a.t, expectedType, object, msg, args...) +} + +// JSONEq asserts that two JSON strings are equivalent. +// +// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + JSONEq(a.t, expected, actual, msgAndArgs...) +} + +// JSONEqf asserts that two JSON strings are equivalent. +// +// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + JSONEqf(a.t, expected, actual, msg, args...) +} + +// Len asserts that the specified object has specific length. +// Len also fails if the object has a type that len() not accept. +// +// a.Len(mySlice, 3) +func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Len(a.t, object, length, msgAndArgs...) +} + +// Lenf asserts that the specified object has specific length. +// Lenf also fails if the object has a type that len() not accept. +// +// a.Lenf(mySlice, 3, "error message %s", "formatted") +func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Lenf(a.t, object, length, msg, args...) +} + +// Less asserts that the first element is less than the second +// +// a.Less(1, 2) +// a.Less(float64(1), float64(2)) +// a.Less("a", "b") +func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Less(a.t, e1, e2, msgAndArgs...) +} + +// LessOrEqual asserts that the first element is less than or equal to the second +// +// a.LessOrEqual(1, 2) +// a.LessOrEqual(2, 2) +// a.LessOrEqual("a", "b") +// a.LessOrEqual("b", "b") +func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + LessOrEqual(a.t, e1, e2, msgAndArgs...) +} + +// LessOrEqualf asserts that the first element is less than or equal to the second +// +// a.LessOrEqualf(1, 2, "error message %s", "formatted") +// a.LessOrEqualf(2, 2, "error message %s", "formatted") +// a.LessOrEqualf("a", "b", "error message %s", "formatted") +// a.LessOrEqualf("b", "b", "error message %s", "formatted") +func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + LessOrEqualf(a.t, e1, e2, msg, args...) +} + +// Lessf asserts that the first element is less than the second +// +// a.Lessf(1, 2, "error message %s", "formatted") +// a.Lessf(float64(1), float64(2), "error message %s", "formatted") +// a.Lessf("a", "b", "error message %s", "formatted") +func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Lessf(a.t, e1, e2, msg, args...) +} + +// Negative asserts that the specified element is negative +// +// a.Negative(-1) +// a.Negative(-1.23) +func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Negative(a.t, e, msgAndArgs...) +} + +// Negativef asserts that the specified element is negative +// +// a.Negativef(-1, "error message %s", "formatted") +// a.Negativef(-1.23, "error message %s", "formatted") +func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Negativef(a.t, e, msg, args...) +} + +// Never asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) +func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Never(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// Neverf asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Neverf(a.t, condition, waitFor, tick, msg, args...) +} + +// Nil asserts that the specified object is nil. +// +// a.Nil(err) +func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Nil(a.t, object, msgAndArgs...) +} + +// Nilf asserts that the specified object is nil. +// +// a.Nilf(err, "error message %s", "formatted") +func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Nilf(a.t, object, msg, args...) +} + +// NoDirExists checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoDirExists(a.t, path, msgAndArgs...) +} + +// NoDirExistsf checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoDirExistsf(a.t, path, msg, args...) +} + +// NoError asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if a.NoError(err) { +// assert.Equal(t, expectedObj, actualObj) +// } +func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoError(a.t, err, msgAndArgs...) +} + +// NoErrorf asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if a.NoErrorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } +func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoErrorf(a.t, err, msg, args...) +} + +// NoFileExists checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoFileExists(a.t, path, msgAndArgs...) +} + +// NoFileExistsf checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoFileExistsf(a.t, path, msg, args...) +} + +// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// a.NotContains("Hello World", "Earth") +// a.NotContains(["Hello", "World"], "Earth") +// a.NotContains({"Hello": "World"}, "Earth") +func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotContains(a.t, s, contains, msgAndArgs...) +} + +// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted") +// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") +// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") +func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotContainsf(a.t, s, contains, msg, args...) +} + +// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if a.NotEmpty(obj) { +// assert.Equal(t, "two", obj[1]) +// } +func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEmpty(a.t, object, msgAndArgs...) +} + +// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if a.NotEmptyf(obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } +func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEmptyf(a.t, object, msg, args...) +} + +// NotEqual asserts that the specified values are NOT equal. +// +// a.NotEqual(obj1, obj2) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEqual(a.t, expected, actual, msgAndArgs...) +} + +// NotEqualValues asserts that two objects are not equal even when converted to the same type +// +// a.NotEqualValues(obj1, obj2) +func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEqualValues(a.t, expected, actual, msgAndArgs...) +} + +// NotEqualValuesf asserts that two objects are not equal even when converted to the same type +// +// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") +func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEqualValuesf(a.t, expected, actual, msg, args...) +} + +// NotEqualf asserts that the specified values are NOT equal. +// +// a.NotEqualf(obj1, obj2, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEqualf(a.t, expected, actual, msg, args...) +} + +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotErrorIs(a.t, err, target, msgAndArgs...) +} + +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotErrorIsf(a.t, err, target, msg, args...) +} + +// NotNil asserts that the specified object is not nil. +// +// a.NotNil(err) +func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotNil(a.t, object, msgAndArgs...) +} + +// NotNilf asserts that the specified object is not nil. +// +// a.NotNilf(err, "error message %s", "formatted") +func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotNilf(a.t, object, msg, args...) +} + +// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// a.NotPanics(func(){ RemainCalm() }) +func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotPanics(a.t, f, msgAndArgs...) +} + +// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") +func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotPanicsf(a.t, f, msg, args...) +} + +// NotRegexp asserts that a specified regexp does not match a string. +// +// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") +// a.NotRegexp("^start", "it's not starting") +func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotRegexp(a.t, rx, str, msgAndArgs...) +} + +// NotRegexpf asserts that a specified regexp does not match a string. +// +// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") +func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotRegexpf(a.t, rx, str, msg, args...) +} + +// NotSame asserts that two pointers do not reference the same object. +// +// a.NotSame(ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotSame(a.t, expected, actual, msgAndArgs...) +} + +// NotSamef asserts that two pointers do not reference the same object. +// +// a.NotSamef(ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotSamef(a.t, expected, actual, msg, args...) +} + +// NotSubset asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") +func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotSubset(a.t, list, subset, msgAndArgs...) +} + +// NotSubsetf asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") +func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotSubsetf(a.t, list, subset, msg, args...) +} + +// NotZero asserts that i is not the zero value for its type. +func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotZero(a.t, i, msgAndArgs...) +} + +// NotZerof asserts that i is not the zero value for its type. +func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotZerof(a.t, i, msg, args...) +} + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// a.Panics(func(){ GoCrazy() }) +func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Panics(a.t, f, msgAndArgs...) +} + +// PanicsWithError asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// a.PanicsWithError("crazy error", func(){ GoCrazy() }) +func (a *Assertions) PanicsWithError(errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + PanicsWithError(a.t, errString, f, msgAndArgs...) +} + +// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) PanicsWithErrorf(errString string, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + PanicsWithErrorf(a.t, errString, f, msg, args...) +} + +// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// a.PanicsWithValue("crazy error", func(){ GoCrazy() }) +func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + PanicsWithValue(a.t, expected, f, msgAndArgs...) +} + +// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + PanicsWithValuef(a.t, expected, f, msg, args...) +} + +// Panicsf asserts that the code inside the specified PanicTestFunc panics. +// +// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Panicsf(a.t, f, msg, args...) +} + +// Positive asserts that the specified element is positive +// +// a.Positive(1) +// a.Positive(1.23) +func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Positive(a.t, e, msgAndArgs...) +} + +// Positivef asserts that the specified element is positive +// +// a.Positivef(1, "error message %s", "formatted") +// a.Positivef(1.23, "error message %s", "formatted") +func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Positivef(a.t, e, msg, args...) +} + +// Regexp asserts that a specified regexp matches a string. +// +// a.Regexp(regexp.MustCompile("start"), "it's starting") +// a.Regexp("start...$", "it's not starting") +func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Regexp(a.t, rx, str, msgAndArgs...) +} + +// Regexpf asserts that a specified regexp matches a string. +// +// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") +func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Regexpf(a.t, rx, str, msg, args...) +} + +// Same asserts that two pointers reference the same object. +// +// a.Same(ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Same(a.t, expected, actual, msgAndArgs...) +} + +// Samef asserts that two pointers reference the same object. +// +// a.Samef(ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Samef(a.t, expected, actual, msg, args...) +} + +// Subset asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Subset(a.t, list, subset, msgAndArgs...) +} + +// Subsetf asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") +func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Subsetf(a.t, list, subset, msg, args...) +} + +// True asserts that the specified value is true. +// +// a.True(myBool) +func (a *Assertions) True(value bool, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + True(a.t, value, msgAndArgs...) +} + +// Truef asserts that the specified value is true. +// +// a.Truef(myBool, "error message %s", "formatted") +func (a *Assertions) Truef(value bool, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Truef(a.t, value, msg, args...) +} + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// a.WithinDuration(time.Now(), time.Now(), 10*time.Second) +func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + WithinDuration(a.t, expected, actual, delta, msgAndArgs...) +} + +// WithinDurationf asserts that the two times are within duration delta of each other. +// +// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + WithinDurationf(a.t, expected, actual, delta, msg, args...) +} + +// YAMLEq asserts that two YAML strings are equivalent. +func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + YAMLEq(a.t, expected, actual, msgAndArgs...) +} + +// YAMLEqf asserts that two YAML strings are equivalent. +func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + YAMLEqf(a.t, expected, actual, msg, args...) +} + +// Zero asserts that i is the zero value for its type. +func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Zero(a.t, i, msgAndArgs...) +} + +// Zerof asserts that i is the zero value for its type. +func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Zerof(a.t, i, msg, args...) +} diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl new file mode 100644 index 00000000000..54124df1d3b --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl @@ -0,0 +1,5 @@ +{{.CommentWithoutT "a"}} +func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { + if h, ok := a.t.(tHelper); ok { h.Helper() } + {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) +} diff --git a/vendor/github.com/stretchr/testify/require/requirements.go b/vendor/github.com/stretchr/testify/require/requirements.go new file mode 100644 index 00000000000..91772dfeb91 --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/requirements.go @@ -0,0 +1,29 @@ +package require + +// TestingT is an interface wrapper around *testing.T +type TestingT interface { + Errorf(format string, args ...interface{}) + FailNow() +} + +type tHelper interface { + Helper() +} + +// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful +// for table driven tests. +type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) + +// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful +// for table driven tests. +type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) + +// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful +// for table driven tests. +type BoolAssertionFunc func(TestingT, bool, ...interface{}) + +// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful +// for table driven tests. +type ErrorAssertionFunc func(TestingT, error, ...interface{}) + +//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs" diff --git a/vendor/modules.txt b/vendor/modules.txt index 75fa22867c3..96a936dcc46 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -103,14 +103,14 @@ github.com/containerd/stargz-snapshotter/estargz github.com/containerd/stargz-snapshotter/estargz/errorutil # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew -# github.com/docker/cli v20.10.2+incompatible +# github.com/docker/cli v20.10.8+incompatible github.com/docker/cli/cli/config github.com/docker/cli/cli/config/configfile github.com/docker/cli/cli/config/credentials github.com/docker/cli/cli/config/types # github.com/docker/distribution v2.7.1+incompatible github.com/docker/distribution/registry/client/auth/challenge -# github.com/docker/docker v20.10.2+incompatible +# github.com/docker/docker v20.10.8+incompatible github.com/docker/docker/pkg/homedir # github.com/docker/docker-credential-helpers v0.6.3 github.com/docker/docker-credential-helpers/client @@ -215,7 +215,7 @@ github.com/hashicorp/golang-lru github.com/hashicorp/golang-lru/simplelru # github.com/imdario/mergo v0.3.9 github.com/imdario/mergo -# github.com/jenkins-x/go-scm v1.5.117 +# github.com/jenkins-x/go-scm v1.10.10 github.com/jenkins-x/go-scm/pkg/hmac github.com/jenkins-x/go-scm/scm github.com/jenkins-x/go-scm/scm/driver/fake @@ -239,8 +239,12 @@ github.com/mailru/easyjson/jlexer github.com/mailru/easyjson/jwriter # github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 github.com/matttproud/golang_protobuf_extensions/pbutil +# github.com/mitchellh/copystructure v1.0.0 +github.com/mitchellh/copystructure # github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-homedir +# github.com/mitchellh/reflectwalk v1.0.0 +github.com/mitchellh/reflectwalk # github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd github.com/modern-go/concurrent # github.com/modern-go/reflect2 v1.0.1 @@ -254,6 +258,8 @@ github.com/opencontainers/image-spec/specs-go/v1 github.com/openzipkin/zipkin-go/model # github.com/pkg/errors v0.9.1 github.com/pkg/errors +# github.com/pmezard/go-difflib v1.0.0 +github.com/pmezard/go-difflib/difflib # github.com/prometheus/client_golang v1.11.0 github.com/prometheus/client_golang/prometheus github.com/prometheus/client_golang/prometheus/internal @@ -281,6 +287,9 @@ github.com/shurcooL/graphql/internal/jsonutil github.com/sirupsen/logrus # github.com/spf13/pflag v1.0.5 github.com/spf13/pflag +# github.com/stretchr/testify v1.7.0 +github.com/stretchr/testify/assert +github.com/stretchr/testify/require # github.com/tektoncd/plumbing v0.0.0-20210514044347-f8a9689d5bd5 github.com/tektoncd/plumbing github.com/tektoncd/plumbing/scripts