diff --git a/.drone.yml.bak b/.drone.yml.bak new file mode 100644 index 000000000..f723ac8f8 --- /dev/null +++ b/.drone.yml.bak @@ -0,0 +1,56 @@ +--- +kind: pipeline +type: vm +name: default + +pool: + use: ubuntu + +steps: +- name: vet + image: golang:1.22 + commands: + - go vet ./... + volumes: + - name: gopath + path: /go + depends_on: + - clone + +- name: test + image: golang:1.22 + commands: + - go test -cover ./... + volumes: + - name: gopath + path: /go + depends_on: + - vet + +- name: check go.mod is up to date + image: golang:1.22 + commands: + - cp go.mod go.mod.bak + - go mod tidy + - diff go.mod go.mod.bak || (echo "go.mod is not up to date" && exit 1) + volumes: + - name: gopath + path: /go + depends_on: + - vet + +- name: golangci-lint + image: golangci/golangci-lint:v1.48-alpine + commands: + - golangci-lint run --timeout 500s --new-from-rev=HEAD~ + volumes: + - name: gopath + path: /go + depends_on: + - clone + +volumes: +- name: gopath + temp: {} + +... diff --git a/.golangci.json b/.golangci.json new file mode 100644 index 000000000..dc836dacc --- /dev/null +++ b/.golangci.json @@ -0,0 +1,51 @@ +{ + "linters": { + "disable-all": true, + "enable": [ + "govet", + "revive", + "goimports", + "misspell", + "ineffassign", + "gofmt" + ] + }, + "linters-settings": { + "govet": { + "check-shadowing": false + }, + "gofmt": { + "simplify": false + } + }, + "run": { + "skip-dirs": [ + "vendor", + "tests", + "pkg/client", + "pkg/generated" + ], + "tests": false, + "timeout": "10m" + }, + "issues": { + "exclude-rules": [ + { + "linters": "govet", + "text": "^(nilness|structtag)" + }, + { + "linters": "revive", + "text": "should have comment" + }, + { + "linters": "revive", + "text": "should be of the form" + }, + { + "linters": "typecheck", + "text": "imported but not used as apierrors" + } + ] + } +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e0bc4f5c..d63a81137 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,314 @@ # Changelog +## [Unreleased](https://github.com/drone/go-scm/tree/HEAD) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.34.3...HEAD) + +**Closed issues:** + +- Cron Jobs don't run with Gitea-scm [\#292](https://github.com/drone/go-scm/issues/292) + +**Merged pull requests:** + +- feat: change as per new contract of webhook in harness code [\#294](https://github.com/drone/go-scm/pull/294) ([abhinav-harness](https://github.com/abhinav-harness)) +- Stash pr commits pagination [\#293](https://github.com/drone/go-scm/pull/293) ([raghavharness](https://github.com/raghavharness)) +- Added support for branch names containing '&' and '\#' for GetFile Operations. [\#291](https://github.com/drone/go-scm/pull/291) ([senjucanon2](https://github.com/senjucanon2)) + +## [v1.34.3](https://github.com/drone/go-scm/tree/v1.34.3) (2023-12-20) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.34.2...v1.34.3) + +**Merged pull requests:** + +- feat: add pr link as coming from new webhook [\#290](https://github.com/drone/go-scm/pull/290) ([abhinav-harness](https://github.com/abhinav-harness)) + +## [v1.34.2](https://github.com/drone/go-scm/tree/v1.34.2) (2023-12-20) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.34.1...v1.34.2) + +**Merged pull requests:** + +- feat: support more events in webhook parse in go-scm for gitness [\#289](https://github.com/drone/go-scm/pull/289) ([abhinav-harness](https://github.com/abhinav-harness)) +- fix: ref should be branch name for harness code [\#288](https://github.com/drone/go-scm/pull/288) ([abhinav-harness](https://github.com/abhinav-harness)) + +## [v1.34.1](https://github.com/drone/go-scm/tree/v1.34.1) (2023-12-08) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.34.0...v1.34.1) + +**Fixed bugs:** + +- fix: use opts for harness list commits [\#286](https://github.com/drone/go-scm/pull/286) ([abhinav-harness](https://github.com/abhinav-harness)) + +**Merged pull requests:** + +- \(maint\) v1.34.1 release prep [\#287](https://github.com/drone/go-scm/pull/287) ([tphoney](https://github.com/tphoney)) + +## [v1.34.0](https://github.com/drone/go-scm/tree/v1.34.0) (2023-12-07) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.33.0...v1.34.0) + +**Implemented enhancements:** + +- feat: add support for branch update for gitness [\#283](https://github.com/drone/go-scm/pull/283) ([abhinav-harness](https://github.com/abhinav-harness)) + +**Merged pull requests:** + +- \(maint\) v1.34.0 prep [\#284](https://github.com/drone/go-scm/pull/284) ([tphoney](https://github.com/tphoney)) + +## [v1.33.0](https://github.com/drone/go-scm/tree/v1.33.0) (2023-10-27) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.32.3...v1.33.0) + +**Implemented enhancements:** + +- feat: Add pr\_comment webhook for harness [\#280](https://github.com/drone/go-scm/pull/280) ([abhinav-harness](https://github.com/abhinav-harness)) + +**Merged pull requests:** + +- \(maint\) prep 1.33.0 [\#281](https://github.com/drone/go-scm/pull/281) ([tphoney](https://github.com/tphoney)) + +## [v1.32.3](https://github.com/drone/go-scm/tree/v1.32.3) (2023-10-11) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.32.2...v1.32.3) + +**Fixed bugs:** + +- fix: ref should have pullreq instead of pull for gitness [\#279](https://github.com/drone/go-scm/pull/279) ([abhinav-harness](https://github.com/abhinav-harness)) +- fix: ref should have pullreq instead of pull for gitness [\#278](https://github.com/drone/go-scm/pull/278) ([abhinav-harness](https://github.com/abhinav-harness)) + +## [v1.32.2](https://github.com/drone/go-scm/tree/v1.32.2) (2023-10-03) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.32.1...v1.32.2) + +**Implemented enhancements:** + +- feat: Harness list commits api update as per new spec [\#277](https://github.com/drone/go-scm/pull/277) ([abhinav-harness](https://github.com/abhinav-harness)) + +## [v1.32.1](https://github.com/drone/go-scm/tree/v1.32.1) (2023-09-27) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.32.0...v1.32.1) + +**Fixed bugs:** + +- fix: Gitness get content missing query param [\#275](https://github.com/drone/go-scm/pull/275) ([abhinav-harness](https://github.com/abhinav-harness)) + +**Merged pull requests:** + +- \(maint\) prep for 1.32.1 [\#276](https://github.com/drone/go-scm/pull/276) ([tphoney](https://github.com/tphoney)) +- \(maint\) clean integration testing for stash [\#273](https://github.com/drone/go-scm/pull/273) ([tphoney](https://github.com/tphoney)) + +## [v1.32.0](https://github.com/drone/go-scm/tree/v1.32.0) (2023-09-12) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.31.2...v1.32.0) + +**Implemented enhancements:** + +- \[feat\]: \[CDS-75848\]: Add new action type for github provider [\#270](https://github.com/drone/go-scm/pull/270) ([rathodmeetsatish](https://github.com/rathodmeetsatish)) + +**Merged pull requests:** + +- \(maint\) release prep for 1.32.0 [\#272](https://github.com/drone/go-scm/pull/272) ([tphoney](https://github.com/tphoney)) + +## [v1.31.2](https://github.com/drone/go-scm/tree/v1.31.2) (2023-08-31) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.31.1...v1.31.2) + +**Fixed bugs:** + +- fix: \[CODE-727\]: change branch in source and target for harness provider [\#264](https://github.com/drone/go-scm/pull/264) ([abhinav-harness](https://github.com/abhinav-harness)) + +## [v1.31.1](https://github.com/drone/go-scm/tree/v1.31.1) (2023-08-29) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.31.0...v1.31.1) + +**Fixed bugs:** + +- Fix diff api response conversion for harness compareChange [\#269](https://github.com/drone/go-scm/pull/269) ([shubham149](https://github.com/shubham149)) +- Fix api name for fetching diff in harness driver [\#268](https://github.com/drone/go-scm/pull/268) ([shubham149](https://github.com/shubham149)) +- Fix compare change api result for harness [\#267](https://github.com/drone/go-scm/pull/267) ([shubham149](https://github.com/shubham149)) + +## [v1.31.0](https://github.com/drone/go-scm/tree/v1.31.0) (2023-08-15) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.30.0...v1.31.0) + +**Implemented enhancements:** + +- \[IAC-941\]: PR comment creation for BitBucket [\#265](https://github.com/drone/go-scm/pull/265) ([scottyw-harness](https://github.com/scottyw-harness)) +- Implemented FindMembership method in organization service for gitea driver [\#263](https://github.com/drone/go-scm/pull/263) ([cod3rboy](https://github.com/cod3rboy)) + +**Closed issues:** + +- \(missing feature\) add support to check organization membership in gitea driver [\#262](https://github.com/drone/go-scm/issues/262) + +**Merged pull requests:** + +- \(maint\) v1.31.0 release prep [\#266](https://github.com/drone/go-scm/pull/266) ([tphoney](https://github.com/tphoney)) + +## [v1.30.0](https://github.com/drone/go-scm/tree/v1.30.0) (2023-07-19) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.29.1...v1.30.0) + +**Implemented enhancements:** + +- \[feat\]: \[CDS-73572\]: Support List Repo Live Search for all git providers [\#261](https://github.com/drone/go-scm/pull/261) ([adivishy1](https://github.com/adivishy1)) +- \[feat\]: \[CDS-73030\]: Support for text based branch filtration [\#260](https://github.com/drone/go-scm/pull/260) ([adivishy1](https://github.com/adivishy1)) +- feat: \[CDS-69341\]: add find user email api for github in go-scm [\#256](https://github.com/drone/go-scm/pull/256) ([shalini-agr](https://github.com/shalini-agr)) + +**Fixed bugs:** + +- fix: \[CDS-67745\]: fix find user email api for bitbucket in go-scm [\#255](https://github.com/drone/go-scm/pull/255) ([shalini-agr](https://github.com/shalini-agr)) +- fix: \[CI-6978\] fixed gitlab webhook parse [\#253](https://github.com/drone/go-scm/pull/253) ([devkimittal](https://github.com/devkimittal)) +- Add required header for bitbucket server in commit API use-case to handle csrf failures [\#252](https://github.com/drone/go-scm/pull/252) ([mohitg0795](https://github.com/mohitg0795)) + +**Merged pull requests:** + +- \(maint\) stash/bitbucket on prem v5 add push webhook test [\#257](https://github.com/drone/go-scm/pull/257) ([tphoney](https://github.com/tphoney)) + +## [v1.29.1](https://github.com/drone/go-scm/tree/v1.29.1) (2023-02-16) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.29.0...v1.29.1) + +**Fixed bugs:** + +- \(fix\) - azure content list queryparam incorrect [\#249](https://github.com/drone/go-scm/pull/249) ([eoinmcafee00](https://github.com/eoinmcafee00)) + +## [v1.29.0](https://github.com/drone/go-scm/tree/v1.29.0) (2023-02-15) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.28.1...v1.29.0) + +**Implemented enhancements:** + +- \(feat\) harness, add finduser [\#250](https://github.com/drone/go-scm/pull/250) ([tphoney](https://github.com/tphoney)) +- \(feat\) harness, fix create branch, PR calls [\#247](https://github.com/drone/go-scm/pull/247) ([tphoney](https://github.com/tphoney)) +- \(feat\) harness, add user and compare branches [\#246](https://github.com/drone/go-scm/pull/246) ([tphoney](https://github.com/tphoney)) +- \(feat\) harness, add list commits / branches [\#245](https://github.com/drone/go-scm/pull/245) ([tphoney](https://github.com/tphoney)) +- \(feat\) harness, add webhook parsing [\#244](https://github.com/drone/go-scm/pull/244) ([tphoney](https://github.com/tphoney)) +- fetch branch for bitbucket onprem [\#242](https://github.com/drone/go-scm/pull/242) ([devkimittal](https://github.com/devkimittal)) +- \(feat\) harness, add repo list [\#241](https://github.com/drone/go-scm/pull/241) ([tphoney](https://github.com/tphoney)) +- Harness move [\#237](https://github.com/drone/go-scm/pull/237) ([tphoney](https://github.com/tphoney)) + +**Fixed bugs:** + +- \(fix\) harness, webhook fixes [\#248](https://github.com/drone/go-scm/pull/248) ([tphoney](https://github.com/tphoney)) +- fix: \[PIE-7927\]: Fix header value typo issue for BB OnPrem CSRF header [\#236](https://github.com/drone/go-scm/pull/236) ([mohitg0795](https://github.com/mohitg0795)) + +**Merged pull requests:** + +- \(maint\) prep for 1.29.0 [\#251](https://github.com/drone/go-scm/pull/251) ([tphoney](https://github.com/tphoney)) + +## [v1.28.1](https://github.com/drone/go-scm/tree/v1.28.1) (2023-01-27) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.28.0...v1.28.1) + +**Fixed bugs:** + +- feat: \[PIE-7927\]: added header to avoid/bypass csrf check [\#234](https://github.com/drone/go-scm/pull/234) ([mohitg0795](https://github.com/mohitg0795)) + +**Closed issues:** + +- Gogs commit fails to deserialize commitDetails in some cases [\#231](https://github.com/drone/go-scm/issues/231) + +**Merged pull requests:** + +- \(maint\) prep 1.28.1 release [\#235](https://github.com/drone/go-scm/pull/235) ([tphoney](https://github.com/tphoney)) + +## [v1.28.0](https://github.com/drone/go-scm/tree/v1.28.0) (2022-11-22) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.27.0...v1.28.0) + +**Implemented enhancements:** + +- Add Actor UUID to push and branch create events for Bitbucket [\#230](https://github.com/drone/go-scm/pull/230) ([rutvijmehta-harness](https://github.com/rutvijmehta-harness)) +- Add support for Github release webhook [\#229](https://github.com/drone/go-scm/pull/229) ([vcalasansh](https://github.com/vcalasansh)) +- Add Actor UUID to Sender for all webhooks responses for Bitbucket [\#227](https://github.com/drone/go-scm/pull/227) ([rutvijmehta-harness](https://github.com/rutvijmehta-harness)) +- added date info for commits in push hook [\#223](https://github.com/drone/go-scm/pull/223) ([raghavharness](https://github.com/raghavharness)) +- Added support for branch in list commits bb onprem API [\#215](https://github.com/drone/go-scm/pull/215) ([mohitg0795](https://github.com/mohitg0795)) +- \[PL-26239\]: added api to list installation for github app [\#213](https://github.com/drone/go-scm/pull/213) ([bhavya181](https://github.com/bhavya181)) + +**Fixed bugs:** + +- fixbug: gitee convert repository [\#226](https://github.com/drone/go-scm/pull/226) ([kit101](https://github.com/kit101)) +- Bitbucket sha fix for merged pr [\#225](https://github.com/drone/go-scm/pull/225) ([raghavharness](https://github.com/raghavharness)) +- decoding projectName for azure repo [\#224](https://github.com/drone/go-scm/pull/224) ([raghavharness](https://github.com/raghavharness)) +- added omitempty annotation for secret [\#221](https://github.com/drone/go-scm/pull/221) ([raghavharness](https://github.com/raghavharness)) +- \[PL-26239\]: fix for list response [\#218](https://github.com/drone/go-scm/pull/218) ([bhavya181](https://github.com/bhavya181)) + +**Closed issues:** + +- gitlab: force\_remove\_source\_branch type is inconsistent [\#228](https://github.com/drone/go-scm/issues/228) +- gitee: When the name and path are inconsistent, got 404 error [\#217](https://github.com/drone/go-scm/issues/217) +- file naming conventions [\#208](https://github.com/drone/go-scm/issues/208) +- Support for Azure Devops git repos? [\#53](https://github.com/drone/go-scm/issues/53) + +**Merged pull requests:** + +- \(maint\) release prep for 1.28.0 [\#232](https://github.com/drone/go-scm/pull/232) ([tphoney](https://github.com/tphoney)) +- \(maint\) fixing naming and add more go best practice [\#211](https://github.com/drone/go-scm/pull/211) ([tphoney](https://github.com/tphoney)) + +## [v1.27.0](https://github.com/drone/go-scm/tree/v1.27.0) (2022-07-19) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.26.0...v1.27.0) + +**Merged pull requests:** + +- Update scm version 1.27.0 [\#206](https://github.com/drone/go-scm/pull/206) ([raghavharness](https://github.com/raghavharness)) +- Using resource version 2.0 for Azure [\#205](https://github.com/drone/go-scm/pull/205) ([raghavharness](https://github.com/raghavharness)) + +## [v1.26.0](https://github.com/drone/go-scm/tree/v1.26.0) (2022-07-01) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.25.0...v1.26.0) + +**Implemented enhancements:** + +- Support parsing PR comment events for Bitbucket Cloud [\#202](https://github.com/drone/go-scm/pull/202) ([rutvijmehta-harness](https://github.com/rutvijmehta-harness)) +- added issue comment hook support for Azure [\#200](https://github.com/drone/go-scm/pull/200) ([raghavharness](https://github.com/raghavharness)) + +**Fixed bugs:** + +- \[CI-4623\] - Azure webhook parseAPI changes [\#198](https://github.com/drone/go-scm/pull/198) ([raghavharness](https://github.com/raghavharness)) + +**Merged pull requests:** + +- Fixed formatting in README.md [\#199](https://github.com/drone/go-scm/pull/199) ([hemanthmantri](https://github.com/hemanthmantri)) + +## [v1.25.0](https://github.com/drone/go-scm/tree/v1.25.0) (2022-06-16) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.24.0...v1.25.0) + +**Implemented enhancements:** + +- Support parsing Gitlab Note Hook event [\#194](https://github.com/drone/go-scm/pull/194) ([rutvijmehta-harness](https://github.com/rutvijmehta-harness)) + +**Fixed bugs:** + +- \[PL-25889\]: fix list branches Azure API [\#195](https://github.com/drone/go-scm/pull/195) ([bhavya181](https://github.com/bhavya181)) +- Return project specific hooks only in ListHooks API for Azure. [\#192](https://github.com/drone/go-scm/pull/192) ([raghavharness](https://github.com/raghavharness)) + +**Merged pull requests:** + +- Update scm version 1.25.0 [\#197](https://github.com/drone/go-scm/pull/197) ([rutvijmehta-harness](https://github.com/rutvijmehta-harness)) + +## [v1.24.0](https://github.com/drone/go-scm/tree/v1.24.0) (2022-06-07) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.23.0...v1.24.0) + +**Implemented enhancements:** + +- Added PR find and listCommit API support for Azure [\#188](https://github.com/drone/go-scm/pull/188) ([raghavharness](https://github.com/raghavharness)) + +**Fixed bugs:** + +- remove redundant slash from list commits api [\#190](https://github.com/drone/go-scm/pull/190) ([aman-harness](https://github.com/aman-harness)) +- Using target commit instead of source in base info for azure [\#189](https://github.com/drone/go-scm/pull/189) ([raghavharness](https://github.com/raghavharness)) + +**Closed issues:** + +- gitee client pagination bug [\#187](https://github.com/drone/go-scm/issues/187) + +**Merged pull requests:** + +- release\_prep\_v1.24.0 [\#191](https://github.com/drone/go-scm/pull/191) ([tphoney](https://github.com/tphoney)) + ## [v1.23.0](https://github.com/drone/go-scm/tree/v1.23.0) (2022-05-23) [Full Changelog](https://github.com/drone/go-scm/compare/v1.22.0...v1.23.0) @@ -13,6 +322,10 @@ - Remove the null value de-reference issue when the bitbucket server url is nil [\#183](https://github.com/drone/go-scm/pull/183) ([DeepakPatankar](https://github.com/DeepakPatankar)) - \[PL-24913\]: Handle the error raised while creating a multipart input [\#181](https://github.com/drone/go-scm/pull/181) ([DeepakPatankar](https://github.com/DeepakPatankar)) +**Merged pull requests:** + +- Upgrade the scm version [\#185](https://github.com/drone/go-scm/pull/185) ([DeepakPatankar](https://github.com/DeepakPatankar)) + ## [v1.22.0](https://github.com/drone/go-scm/tree/v1.22.0) (2022-05-10) [Full Changelog](https://github.com/drone/go-scm/compare/v1.21.1...v1.22.0) diff --git a/README.md b/README.md index 7ada651d4..a95de0461 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,7 @@ comment, _, err := client.Issues.CreateComment(ctx, "octocat/Hello-World", 1, in Here are some useful links to providers API documentation: -- [Azure DevOps](https://docs.microsoft.com/en-us/rest/api/azure/devops/git/?view=azure-devops-rest-6.0)) +- [Azure DevOps](https://docs.microsoft.com/en-us/rest/api/azure/devops/git/?view=azure-devops-rest-6.0) - [Bitbucket cloud API](https://developer.atlassian.com/cloud/bitbucket/rest/intro/) - [Bitbucket server/Stash API](https://docs.atlassian.com/bitbucket-server/rest/5.16.0/bitbucket-rest.html) - [Gitea API](https://gitea.com/api/swagger/#/) diff --git a/go.sum b/go.sum index 00f0342cb..6d69376b6 100644 --- a/go.sum +++ b/go.sum @@ -1,17 +1,6 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/h2non/gock v1.0.9 h1:17gCehSo8ZOgEsFKpQgqHiR7VLyjxdAG3lkhVvO9QZU= github.com/h2non/gock v1.0.9/go.mod h1:CZMcB0Lg5IWnr9bF79pPMg9WeV6WumxQiUJ1UvdO1iE= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/scm/client.go b/scm/client.go index 112d1d7ca..fba635ba6 100644 --- a/scm/client.go +++ b/scm/client.go @@ -68,6 +68,26 @@ type ( Reset int64 } + // BranchListOptions specifies optional branch search term and pagination + // parameters. + BranchListOptions struct { + SearchTerm string + PageListOptions ListOptions + } + + // RepoListOptions specifies optional repo search term and pagination + // parameters. + RepoListOptions struct { + ListOptions + RepoSearchTerm + } + + // RepoSearchTerm specifies searchable parameters. + RepoSearchTerm struct { + RepoName string + User string + } + // ListOptions specifies optional pagination // parameters. ListOptions struct { diff --git a/scm/const.go b/scm/const.go index b7e8bf7ff..17a4c9896 100644 --- a/scm/const.go +++ b/scm/const.go @@ -40,8 +40,14 @@ const ( // pull requests ActionSync ActionMerge + ActionReviewReady // issue comment ActionEdit + // release + ActionPublish + ActionUnpublish + ActionPrerelease + ActionRelease ) // String returns the string representation of Action. @@ -67,6 +73,16 @@ func (a Action) String() (s string) { return "synchronized" case ActionMerge: return "merged" + case ActionPublish: + return "published" + case ActionUnpublish: + return "unpublished" + case ActionPrerelease: + return "prereleased" + case ActionRelease: + return "released" + case ActionReviewReady: + return "review_ready" default: return } @@ -104,6 +120,18 @@ func (a *Action) UnmarshalJSON(data []byte) error { *a = ActionSync case "merged": *a = ActionMerge + case "edited": + *a = ActionEdit + case "published": + *a = ActionPublish + case "unpublished": + *a = ActionUnpublish + case "prereleased": + *a = ActionPrerelease + case "released": + *a = ActionRelease + case "review_ready": + *a = ActionReviewReady } return nil } @@ -123,6 +151,7 @@ const ( DriverCoding DriverGitee DriverAzure + DriverHarness ) // String returns the string representation of Driver. @@ -146,6 +175,8 @@ func (d Driver) String() (s string) { return "gitee" case DriverAzure: return "azure" + case DriverHarness: + return "harness" default: return "unknown" } @@ -255,4 +286,66 @@ func (v Visibility) String() (s string) { } } +// Status defines an enum for execution status +type ExecutionStatus int + +const ( + StatusUnknown ExecutionStatus = iota + StatusPending + StatusRunning + StatusSuccess + StatusFailed + StatusCanceled +) + +// String returns the string representation of ExecutionStatus. +func (k ExecutionStatus) String() string { + switch k { + case StatusSuccess: + return "success" + case StatusPending: + return "pending" + case StatusRunning: + return "running" + case StatusFailed: + return "failed" + case StatusCanceled: + return "canceled" + case StatusUnknown: + return "Unknown" + default: + return "unsupported" + } +} + +// MarshalJSON returns the JSON-encoded Action. +func (k ExecutionStatus) MarshalJSON() ([]byte, error) { + return json.Marshal(k.String()) +} + +// UnmarshalJSON unmarshales the JSON-encoded ExecutionStatus. +func (k *ExecutionStatus) UnmarshalJSON(data []byte) error { + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + switch s { + case StatusSuccess.String(): + *k = StatusSuccess + case StatusPending.String(): + *k = StatusPending + case StatusPending.String(): + *k = StatusPending + case StatusRunning.String(): + *k = StatusRunning + case StatusFailed.String(): + *k = StatusFailed + case StatusCanceled.String(): + *k = StatusCanceled + default: + *k = StatusUnknown + } + return nil +} + const SearchTimeFormat = "2006-01-02T15:04:05Z" diff --git a/scm/content.go b/scm/content.go index 4f5e4a0e9..2d5cb6fde 100644 --- a/scm/content.go +++ b/scm/content.go @@ -40,13 +40,13 @@ type ( // Find returns the repository file content by path. Find(ctx context.Context, repo, path, ref string) (*Content, *Response, error) - // Create creates a new repositroy file. + // Create creates a new repository file. Create(ctx context.Context, repo, path string, params *ContentParams) (*Response, error) // Update updates a repository file. Update(ctx context.Context, repo, path string, params *ContentParams) (*Response, error) - // Delete deletes a reository file. + // Delete deletes a repository file. Delete(ctx context.Context, repo, path string, params *ContentParams) (*Response, error) // List returns a list of contents in a repository directory by path. It is diff --git a/scm/driver/azure/azure.go b/scm/driver/azure/azure.go index 1832e568d..e762a6db1 100644 --- a/scm/driver/azure/azure.go +++ b/scm/driver/azure/azure.go @@ -122,8 +122,5 @@ func ProjectRequiredError() error { } func SanitizeBranchName(name string) string { - if strings.Contains(name, "/") { - return name - } return "refs/heads/" + name } diff --git a/scm/driver/azure/azure_test.go b/scm/driver/azure/azure_test.go index 0a4334374..c3cc56732 100644 --- a/scm/driver/azure/azure_test.go +++ b/scm/driver/azure/azure_test.go @@ -54,11 +54,11 @@ func TestSanitizeBranchName(t *testing.T) { "refs/heads/master", }, { - "refs/heads/master", + "feature/main-patch", args{ - "refs/heads/master", + "feature/main-patch", }, - "refs/heads/master", + "refs/heads/feature/main-patch", }, } for _, tt := range tests { diff --git a/scm/driver/azure/content.go b/scm/driver/azure/content.go index 18cd0402a..a31258d8a 100644 --- a/scm/driver/azure/content.go +++ b/scm/driver/azure/content.go @@ -8,6 +8,8 @@ import ( "context" "encoding/base64" "fmt" + "net/url" + "strings" "github.com/drone/go-scm/scm" ) @@ -19,10 +21,11 @@ type contentService struct { func (s *contentService) Find(ctx context.Context, repo, path, ref string) (*scm.Content, *scm.Response, error) { // https://docs.microsoft.com/en-us/rest/api/azure/devops/git/items/get?view=azure-devops-rest-6.0 if s.client.project == "" { - return nil, nil, ProjectRequiredError() - } + return nil, nil, ProjectRequiredError() + } + urlEncodedRef := url.QueryEscape(ref) endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/items?path=%s&includeContent=true&$format=json", s.client.owner, s.client.project, repo, path) - endpoint += generateURIFromRef(ref) + endpoint += generateURIFromRef(urlEncodedRef) endpoint += "&api-version=6.0" out := new(content) res, err := s.client.do(ctx, "GET", endpoint, nil, out) @@ -37,8 +40,8 @@ func (s *contentService) Find(ctx context.Context, repo, path, ref string) (*scm func (s *contentService) Create(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { if s.client.project == "" { - return nil, ProjectRequiredError() - } + return nil, ProjectRequiredError() + } endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/pushes?api-version=6.0", s.client.owner, s.client.project, repo) ref := refUpdate{ Name: SanitizeBranchName(params.Branch), @@ -66,8 +69,8 @@ func (s *contentService) Create(ctx context.Context, repo, path string, params * func (s *contentService) Update(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { if s.client.project == "" { - return nil, ProjectRequiredError() - } + return nil, ProjectRequiredError() + } endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/pushes?api-version=6.0", s.client.owner, s.client.project, repo) ref := refUpdate{ Name: SanitizeBranchName(params.Branch), @@ -95,8 +98,8 @@ func (s *contentService) Update(ctx context.Context, repo, path string, params * func (s *contentService) Delete(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { if s.client.project == "" { - return nil, ProjectRequiredError() - } + return nil, ProjectRequiredError() + } endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/pushes?api-version=6.0", s.client.owner, s.client.project, repo) ref := refUpdate{ Name: SanitizeBranchName(params.Branch), @@ -122,9 +125,9 @@ func (s *contentService) Delete(ctx context.Context, repo, path string, params * func (s *contentService) List(ctx context.Context, repo, path, ref string, _ scm.ListOptions) ([]*scm.ContentInfo, *scm.Response, error) { // https://docs.microsoft.com/en-us/rest/api/azure/devops/git/items/list?view=azure-devops-rest-6.0 if s.client.project == "" { - return nil, nil, ProjectRequiredError() - } - endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/items?path=%s&recursionLevel=Full&$format=json", s.client.owner, s.client.project, repo, path) + return nil, nil, ProjectRequiredError() + } + endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/items?scopePath=%s&recursionLevel=Full&$format=json", s.client.owner, s.client.project, repo, path) endpoint += generateURIFromRef(ref) out := new(contentList) res, err := s.client.do(ctx, "GET", endpoint, nil, &out) @@ -205,6 +208,8 @@ func generateURIFromRef(ref string) (uri string) { if ref != "" { if len(ref) == 40 { return fmt.Sprintf("&versionDescriptor.versionType=commit&versionDescriptor.version=%s", ref) + } else if strings.HasPrefix(ref, "refs/tags/") { + return fmt.Sprintf("&versionDescriptor.versionType=tag&versionDescriptor.version=%s", scm.TrimRef(ref)) } else { return fmt.Sprintf("&versionDescriptor.versionType=branch&versionDescriptor.version=%s", ref) } diff --git a/scm/driver/azure/content_test.go b/scm/driver/azure/content_test.go index e674ccdaf..ad857ccd9 100644 --- a/scm/driver/azure/content_test.go +++ b/scm/driver/azure/content_test.go @@ -17,6 +17,7 @@ func TestContentFind(t *testing.T) { gock.New("https:/dev.azure.com/"). Get("/ORG/PROJ/_apis/git/repositories/REPOID/items"). MatchParam("path", "README"). + MatchParam("versionDescriptor.version", "b1&b2"). Reply(200). Type("application/json"). File("testdata/content.json") @@ -26,7 +27,7 @@ func TestContentFind(t *testing.T) { context.Background(), "REPOID", "README", - "", + "b1&b2", ) if err != nil { t.Error(err) diff --git a/scm/driver/azure/git.go b/scm/driver/azure/git.go index e61ec6236..dae86f58b 100644 --- a/scm/driver/azure/git.go +++ b/scm/driver/azure/git.go @@ -16,11 +16,11 @@ type gitService struct { client *wrapper } -func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.CreateBranch) (*scm.Response, error) { +func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.ReferenceInput) (*scm.Response, error) { // https://docs.microsoft.com/en-us/rest/api/azure/devops/git/refs/update-refs?view=azure-devops-rest-6.0 if s.client.project == "" { - return nil, ProjectRequiredError() - } + return nil, ProjectRequiredError() + } endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/refs?api-version=6.0", s.client.owner, s.client.project, repo) in := make(crudBranch, 1) @@ -32,16 +32,16 @@ func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm. func (s *gitService) FindBranch(ctx context.Context, repo, name string) (*scm.Reference, *scm.Response, error) { if s.client.project == "" { - return nil, nil, ProjectRequiredError() - } + return nil, nil, ProjectRequiredError() + } return nil, nil, scm.ErrNotSupported } func (s *gitService) FindCommit(ctx context.Context, repo, ref string) (*scm.Commit, *scm.Response, error) { // https://docs.microsoft.com/en-us/rest/api/azure/devops/git/commits/get?view=azure-devops-rest-6.0#get-by-id if s.client.project == "" { - return nil, nil, ProjectRequiredError() - } + return nil, nil, ProjectRequiredError() + } endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/commits/%s?api-version=6.0", s.client.owner, s.client.project, repo, ref) out := new(gitCommit) res, err := s.client.do(ctx, "GET", endpoint, nil, out) @@ -55,9 +55,20 @@ func (s *gitService) FindTag(ctx context.Context, repo, name string) (*scm.Refer func (s *gitService) ListBranches(ctx context.Context, repo string, _ scm.ListOptions) ([]*scm.Reference, *scm.Response, error) { // https://docs.microsoft.com/en-us/rest/api/azure/devops/git/refs/list?view=azure-devops-rest-6.0 if s.client.project == "" { - return nil, nil, ProjectRequiredError() - } - endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/refs?api-version=6.0", s.client.owner, s.client.project, repo) + return nil, nil, ProjectRequiredError() + } + endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/refs?includeMyBranches=true&api-version=6.0", s.client.owner, s.client.project, repo) + out := new(branchList) + res, err := s.client.do(ctx, "GET", endpoint, nil, &out) + return convertBranchList(out.Value), res, err +} + +func (s *gitService) ListBranchesV2(ctx context.Context, repo string, opts scm.BranchListOptions) ([]*scm.Reference, *scm.Response, error) { + // https://docs.microsoft.com/en-us/rest/api/azure/devops/git/refs/list?view=azure-devops-rest-6.0 + if s.client.project == "" { + return nil, nil, ProjectRequiredError() + } + endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/refs?api-version=6.0&filterContains=%s", s.client.owner, s.client.project, repo, opts.SearchTerm) out := new(branchList) res, err := s.client.do(ctx, "GET", endpoint, nil, &out) return convertBranchList(out.Value), res, err @@ -66,8 +77,8 @@ func (s *gitService) ListBranches(ctx context.Context, repo string, _ scm.ListOp func (s *gitService) ListCommits(ctx context.Context, repo string, opts scm.CommitListOptions) ([]*scm.Commit, *scm.Response, error) { // https://docs.microsoft.com/en-us/rest/api/azure/devops/git/commits/get-commits?view=azure-devops-rest-6.0 if s.client.project == "" { - return nil, nil, ProjectRequiredError() - } + return nil, nil, ProjectRequiredError() + } endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/commits?", s.client.owner, s.client.project, repo) if opts.Ref != "" { endpoint += fmt.Sprintf("searchCriteria.itemVersion.version=%s&", opts.Ref) @@ -83,7 +94,18 @@ func (s *gitService) ListCommits(ctx context.Context, repo string, opts scm.Comm } func (s *gitService) ListTags(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Reference, *scm.Response, error) { - return nil, nil, scm.ErrNotSupported + if s.client.project == "" { + return nil, nil, ProjectRequiredError() + } + endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/refs?", s.client.owner, s.client.project, repo) + // add tags + endpoint += fmt.Sprintf("filter=tags/") + // add target + endpoint += fmt.Sprintf("&api-version=7.1-preview.1") + out := new(tags) + res, err := s.client.do(ctx, "GET", endpoint, nil, &out) + + return convertTags(out.Value), res, err } func (s *gitService) ListChanges(ctx context.Context, repo, ref string, _ scm.ListOptions) ([]*scm.Change, *scm.Response, error) { @@ -93,8 +115,8 @@ func (s *gitService) ListChanges(ctx context.Context, repo, ref string, _ scm.Li func (s *gitService) CompareChanges(ctx context.Context, repo, source, target string, _ scm.ListOptions) ([]*scm.Change, *scm.Response, error) { // https://docs.microsoft.com/en-us/rest/api/azure/devops/git/diffs/get?view=azure-devops-rest-6.0 if s.client.project == "" { - return nil, nil, ProjectRequiredError() - } + return nil, nil, ProjectRequiredError() + } endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/diffs/commits?", s.client.owner, s.client.project, repo) // add base endpoint += fmt.Sprintf("baseVersion=%s&baseVersionType=commit&", source) @@ -191,6 +213,29 @@ type compare struct { TargetCommit string `json:"targetCommit"` } +type tags struct { + Value []*tag `json:"value"` + Count int `json:"count"` +} +type tag struct { + Name string `json:"name"` + ObjectID string `json:"objectId"` + Creator struct { + DisplayName string `json:"displayName"` + URL string `json:"url"` + Links struct { + Avatar struct { + Href string `json:"href"` + } `json:"avatar"` + } `json:"_links"` + ID string `json:"id"` + UniqueName string `json:"uniqueName"` + ImageURL string `json:"imageUrl"` + Descriptor string `json:"descriptor"` + } `json:"creator"` + URL string `json:"url"` +} + func convertBranchList(from []*branch) []*scm.Reference { to := []*scm.Reference{} for _, v := range from { @@ -221,11 +266,13 @@ func convertCommit(from *gitCommit) *scm.Commit { Sha: from.CommitID, Link: from.URL, Author: scm.Signature{ + Login: from.Author.Name, Name: from.Author.Name, Email: from.Author.Email, Date: from.Author.Date, }, Committer: scm.Signature{ + Login: from.Committer.Name, Name: from.Committer.Name, Email: from.Committer.Email, Date: from.Committer.Date, @@ -256,3 +303,15 @@ func convertChange(from *file) *scm.Change { return returnVal } + +func convertTags(from []*tag) []*scm.Reference { + var to []*scm.Reference + for _, v := range from { + to = append(to, &scm.Reference{ + Name: scm.TrimRef(v.Name), + Path: scm.ExpandRef(v.Name, "refs/tags/"), + Sha: v.ObjectID, + }) + } + return to +} diff --git a/scm/driver/azure/git_test.go b/scm/driver/azure/git_test.go index 0e652eca2..4f79b78eb 100644 --- a/scm/driver/azure/git_test.go +++ b/scm/driver/azure/git_test.go @@ -53,7 +53,7 @@ func TestGitCreateBranch(t *testing.T) { Type("application/json"). File("testdata/branch_create.json") - params := &scm.CreateBranch{ + params := &scm.ReferenceInput{ Name: "test_branch", Sha: "312797ba52425353dec56871a255e2a36fc96344", } @@ -123,6 +123,32 @@ func TestGitListBranches(t *testing.T) { } } +func TestGitListBranchesV2(t *testing.T) { + defer gock.Off() + + gock.New("https:/dev.azure.com/"). + Get("/ORG/PROJ/_apis/git/repositories/REPOID/"). + Reply(200). + Type("application/json"). + File("testdata/branches_filter.json") + + client := NewDefault("ORG", "PROJ") + got, _, err := client.Git.ListBranchesV2(context.Background(), "REPOID", scm.BranchListOptions{SearchTerm: "main"}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Reference{} + raw, _ := ioutil.ReadFile("testdata/branches_filter.json.golden") + _ = json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + func TestGitCompareChanges(t *testing.T) { defer gock.Off() @@ -149,3 +175,62 @@ func TestGitCompareChanges(t *testing.T) { } } + +func TestGitListTags(t *testing.T) { + defer gock.Off() + + gock.New("https:/dev.azure.com/"). + Get("/ORG/PROJ/_apis/git/repositories/REPOID/"). + Reply(200). + Type("application/json"). + File("testdata/tags.json") + + client := NewDefault("ORG", "PROJ") + got, _, err := client.Git.ListTags(context.Background(), "REPOID", scm.ListOptions{}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Reference{} + raw, _ := ioutil.ReadFile("testdata/tags.json.golden") + _ = json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestConvertTags(t *testing.T) { + from := []*tag{ + { + Name: "refs/tags/v1.0.0", + ObjectID: "23d9c1d0d6c41f1c8e08ab98a6a79c2d5ada649d", + }, + { + Name: "refs/tags/v1.1.0", + ObjectID: "8a9db19b5e19613c18e9059d7b9fa5d6d6a3785f", + }, + } + + got := convertTags(from) + + want := []*scm.Reference{ + { + Name: "v1.0.0", + Path: "refs/tags/v1.0.0", + Sha: "23d9c1d0d6c41f1c8e08ab98a6a79c2d5ada649d", + }, + { + Name: "v1.1.0", + Path: "refs/tags/v1.1.0", + Sha: "8a9db19b5e19613c18e9059d7b9fa5d6d6a3785f", + }, + } + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} diff --git a/scm/driver/azure/integration/git_test.go b/scm/driver/azure/integration/git_test.go index ce9eefca6..aeb9f41b8 100644 --- a/scm/driver/azure/integration/git_test.go +++ b/scm/driver/azure/integration/git_test.go @@ -54,7 +54,7 @@ func TestCreateBranch(t *testing.T) { if commitErr != nil { t.Errorf("we got an error %v", commitErr) } - input := &scm.CreateBranch{ + input := &scm.ReferenceInput{ Name: "test_branch", Sha: currentCommit, } diff --git a/scm/driver/azure/integration/testSettings.go b/scm/driver/azure/integration/integration.go similarity index 100% rename from scm/driver/azure/integration/testSettings.go rename to scm/driver/azure/integration/integration.go diff --git a/scm/driver/azure/integration/pr_test.go b/scm/driver/azure/integration/pr_test.go index 941b30526..b82307340 100644 --- a/scm/driver/azure/integration/pr_test.go +++ b/scm/driver/azure/integration/pr_test.go @@ -40,3 +40,54 @@ func TestCreatePR(t *testing.T) { t.Errorf("PullRequests.Create does not have the correct title %v", outputPR.Title) } } + +func TestPullRequestFind(t *testing.T) { + if token == "" { + t.Skip("Skipping, Acceptance test") + } + client = azure.NewDefault(organization, project) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("Authorization", fmt.Sprintf("Basic %s", token)) + }, + }, + } + outputPR, response, err := client.PullRequests.Find(context.Background(), repoID, 1) + if err != nil { + t.Errorf("PullRequests.Find got an error %v", err) + } + if response.Status != http.StatusOK { + t.Errorf("PullRequests.Find did not get a 200 back %v", response.Status) + } + if outputPR.Title != "test_pr" { + t.Errorf("PullRequests.Find does not have the correct title %v", outputPR.Title) + } +} + +func TestPullRequestCommits(t *testing.T) { + if token == "" { + t.Skip("Skipping, Acceptance test") + } + client = azure.NewDefault(organization, project) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("Authorization", fmt.Sprintf("Basic %s", token)) + }, + }, + } + commits, response, err := client.PullRequests.ListCommits(context.Background(), repoID, 1, scm.ListOptions{}) + if err != nil { + t.Errorf("PullRequests.ListCommits got an error %v", err) + } + if response.Status != http.StatusOK { + t.Errorf("PullRequests.ListCommits did not get a 200 back %v", response.Status) + } + if len(commits) < 1 { + t.Errorf("PullRequests.ListCommits there should be at least 1 commit %d", len(commits)) + } + if commits[0].Sha == "" { + t.Errorf("PullRequests.ListCommits first entry did not get a sha back %v", commits[0].Sha) + } +} diff --git a/scm/driver/azure/pr.go b/scm/driver/azure/pr.go index 647332899..d2e36c48f 100644 --- a/scm/driver/azure/pr.go +++ b/scm/driver/azure/pr.go @@ -10,6 +10,7 @@ import ( "time" "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/internal/null" ) type pullService struct { @@ -17,7 +18,12 @@ type pullService struct { } func (s *pullService) Find(ctx context.Context, repo string, number int) (*scm.PullRequest, *scm.Response, error) { - return nil, nil, scm.ErrNotSupported + // https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull-requests/get-pull-request?view=azure-devops-rest-6.0 + endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/pullrequests/%d?api-version=6.0", + s.client.owner, s.client.project, repo, number) + out := new(pr) + res, err := s.client.do(ctx, "GET", endpoint, nil, out) + return convertPullRequest(out), res, err } func (s *pullService) List(ctx context.Context, repo string, opts scm.PullRequestListOptions) ([]*scm.PullRequest, *scm.Response, error) { @@ -29,7 +35,12 @@ func (s *pullService) ListChanges(ctx context.Context, repo string, number int, } func (s *pullService) ListCommits(ctx context.Context, repo string, number int, opts scm.ListOptions) ([]*scm.Commit, *scm.Response, error) { - return nil, nil, scm.ErrNotSupported + // https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull-request-commits/get-pull-request-commits?view=azure-devops-rest-6.0 + endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/pullRequests/%d/commits?api-version=6.0", + s.client.owner, s.client.project, repo, number) + out := new(commitList) + res, err := s.client.do(ctx, "GET", endpoint, nil, out) + return convertCommitList(out.Value), res, err } func (s *pullService) Merge(ctx context.Context, repo string, number int) (*scm.Response, error) { @@ -89,13 +100,15 @@ type pr struct { URL string `json:"url"` ImageURL string `json:"imageUrl"` } `json:"createdBy"` - CreationDate time.Time `json:"creationDate"` - Title string `json:"title"` - Description string `json:"description"` - SourceRefName string `json:"sourceRefName"` - TargetRefName string `json:"targetRefName"` - MergeStatus string `json:"mergeStatus"` - MergeID string `json:"mergeId"` + CreationDate time.Time `json:"creationDate"` + ClosedDate null.String `json:"closedDate"` + Title string `json:"title"` + Description string `json:"description"` + SourceRefName string `json:"sourceRefName"` + TargetRefName string `json:"targetRefName"` + MergeStatus string `json:"mergeStatus"` + IsDraft bool `json:"isDraft"` + MergeID string `json:"mergeId"` LastMergeSourceCommit struct { CommitID string `json:"commitId"` URL string `json:"url"` @@ -153,15 +166,19 @@ func convertPullRequest(from *pr) *scm.PullRequest { Title: from.Title, Body: from.Description, Sha: from.LastMergeSourceCommit.CommitID, - Source: from.SourceRefName, - Target: from.TargetRefName, + Source: scm.TrimRef(from.SourceRefName), + Target: scm.TrimRef(from.TargetRefName), Link: from.URL, + Draft: from.IsDraft, + Closed: from.ClosedDate.Valid, + Merged: from.Status == "completed", + Ref: fmt.Sprintf("refs/pull/%d/merge", from.PullRequestID), Head: scm.Reference{ Sha: from.LastMergeSourceCommit.CommitID, }, Base: scm.Reference{ - Sha: from.LastMergeSourceCommit.CommitID, + Sha: from.LastMergeTargetCommit.CommitID, }, Author: scm.User{ Login: from.CreatedBy.UniqueName, diff --git a/scm/driver/azure/pr_test.go b/scm/driver/azure/pr_test.go index afddc8da7..42b60dfe7 100644 --- a/scm/driver/azure/pr_test.go +++ b/scm/driver/azure/pr_test.go @@ -48,3 +48,55 @@ func TestPullCreate(t *testing.T) { t.Log(diff) } } + +func TestPullFind(t *testing.T) { + defer gock.Off() + + gock.New("https:/dev.azure.com/"). + Get("/ORG/PROJ/_apis/git/repositories/REPOID/pullrequests/1"). + Reply(200). + Type("application/json"). + File("testdata/pr.json") + + client := NewDefault("ORG", "PROJ") + got, _, err := client.PullRequests.Find(context.Background(), "REPOID", 1) + if err != nil { + t.Error(err) + return + } + + want := new(scm.PullRequest) + raw, _ := ioutil.ReadFile("testdata/pr.json.golden") + _ = json.Unmarshal(raw, want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestPullListCommits(t *testing.T) { + defer gock.Off() + + gock.New("https:/dev.azure.com/"). + Get("/ORG/PROJ/_apis/git/repositories/REPOID/pullRequests/1/commits"). + Reply(200). + Type("application/json"). + File("testdata/commits.json") + + client := NewDefault("ORG", "PROJ") + got, _, err := client.PullRequests.ListCommits(context.Background(), "REPOID", 1, scm.ListOptions{}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Commit{} + raw, _ := ioutil.ReadFile("testdata/commits.json.golden") + _ = json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} diff --git a/scm/driver/azure/repo.go b/scm/driver/azure/repo.go index 5b96ff625..0e815ae7c 100644 --- a/scm/driver/azure/repo.go +++ b/scm/driver/azure/repo.go @@ -7,6 +7,8 @@ package azure import ( "context" "fmt" + "net/url" + "strings" "github.com/drone/go-scm/scm" ) @@ -27,7 +29,7 @@ func (s *RepositoryService) Find(ctx context.Context, repo string) (*scm.Reposit out := new(repository) res, err := s.client.do(ctx, "GET", endpoint, nil, &out) - return convertRepository(out), res, err + return convertRepository(out, s.client.owner), res, err } // FindHook returns a repository hook. @@ -52,7 +54,19 @@ func (s *RepositoryService) List(ctx context.Context, opts scm.ListOptions) ([]* out := new(repositories) res, err := s.client.do(ctx, "GET", endpoint, nil, &out) - return convertRepositoryList(out), res, err + return convertRepositoryList(out, s.client.owner), res, err +} + +// ListV2 returns the user repository list. +func (s *RepositoryService) ListV2(ctx context.Context, opts scm.RepoListOptions) ([]*scm.Repository, *scm.Response, error) { + // Azure does not support search filters, hence calling List api without search filtering + return s.List(ctx, opts.ListOptions) +} + +// ListNamespace is of no use in azure as our client already has project information +func (s *RepositoryService) ListNamespace(ctx context.Context, _ string, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { + // Azure client already has org/proj information + return s.List(ctx, opts) } func (s *RepositoryService) List2(ctx context.Context, orgSlug string, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { @@ -69,10 +83,14 @@ func (s *RepositoryService) ListHooks(ctx context.Context, repo string, opts scm if s.client.project == "" { return nil, nil, ProjectRequiredError() } + projectID, projErr := s.getProjectIDFromProjectName(ctx, s.client.project) + if projErr != nil { + return nil, nil, fmt.Errorf("ListHooks was unable to look up the project's projectID, %s", projErr) + } endpoint := fmt.Sprintf("%s/_apis/hooks/subscriptions?api-version=6.0", s.client.owner) out := new(subscriptions) res, err := s.client.do(ctx, "GET", endpoint, nil, &out) - return convertHookList(out.Value, repo), res, err + return convertHookList(out.Value, projectID, repo), res, err } // ListStatus returns a list of commit statuses. @@ -113,6 +131,10 @@ func (s *RepositoryService) CreateHook(ctx context.Context, repo string, input * if input.SkipVerify { in.ConsumerInputs.AcceptUntrustedCerts = "enabled" } + // with version 1.0, azure provides incomplete data for issue-comment + if in.EventType == "ms.vss-code.git-pullrequest-comment-event" { + in.ResourceVersion = "2.0" + } out := new(subscription) res, err := s.client.do(ctx, "POST", endpoint, in, out) return convertHook(out), res, err @@ -146,6 +168,11 @@ func (s *RepositoryService) DeleteHook(ctx context.Context, repo, id string) (*s // helper function to return the projectID from the project name func (s *RepositoryService) getProjectIDFromProjectName(ctx context.Context, projectName string) (string, error) { // https://docs.microsoft.com/en-us/rest/api/azure/devops/core/projects/list?view=azure-devops-rest-6.0 + projectName, err := url.PathUnescape(projectName) + if err != nil { + return "", fmt.Errorf("unable to unscape project: %s", projectName) + } + endpoint := fmt.Sprintf("%s/_apis/projects?api-version=6.0", s.client.owner) type projects struct { Count int64 `json:"count"` @@ -182,10 +209,11 @@ type repository struct { ID string `json:"id"` Name string `json:"name"` Project struct { - ID string `json:"id"` - Name string `json:"name"` - State string `json:"state"` - URL string `json:"url"` + ID string `json:"id"` + Name string `json:"name"` + State string `json:"state"` + URL string `json:"url"` + Visibility string `json:"visibility"` } `json:"project"` RemoteURL string `json:"remoteUrl"` URL string `json:"url"` @@ -249,31 +277,36 @@ type subscription struct { URL string `json:"url"` } -// helper function to convert from the gogs repository list to +// helper function to convert from the azure devops repository list to // the common repository structure. -func convertRepositoryList(from *repositories) []*scm.Repository { +func convertRepositoryList(from *repositories, owner string) []*scm.Repository { to := []*scm.Repository{} for _, v := range from.Value { - to = append(to, convertRepository(v)) + to = append(to, convertRepository(v, owner)) } return to } -// helper function to convert from the gogs repository structure +// helper function to convert from the azure devops repository structure // to the common repository structure. -func convertRepository(from *repository) *scm.Repository { +func convertRepository(from *repository, owner string) *scm.Repository { + namespace := []string{owner, from.Project.Name} return &scm.Repository{ - ID: from.ID, - Name: from.Name, - Link: from.URL, - Branch: scm.TrimRef(from.DefaultBranch), + ID: from.ID, + Name: from.Name, + Namespace: strings.Join(namespace, "/"), + Link: from.URL, + Branch: scm.TrimRef(from.DefaultBranch), + Clone: from.RemoteURL, + Private: scm.ConvertPrivate(from.Project.Visibility), + Visibility: scm.ConvertVisibility(from.Project.Visibility), } } -func convertHookList(from []*subscription, repositoryFilter string) []*scm.Hook { +func convertHookList(from []*subscription, projectFilter string, repositoryFilter string) []*scm.Hook { to := []*scm.Hook{} for _, v := range from { - if repositoryFilter != "" && repositoryFilter == v.PublisherInputs.Repository { + if repositoryFilter != "" && projectFilter == v.PublisherInputs.ProjectID && repositoryFilter == v.PublisherInputs.Repository { to = append(to, convertHook(v)) } } diff --git a/scm/driver/azure/repo_test.go b/scm/driver/azure/repo_test.go index 48663e64c..f2bd509db 100644 --- a/scm/driver/azure/repo_test.go +++ b/scm/driver/azure/repo_test.go @@ -83,6 +83,43 @@ func TestRepositoryHookCreate(t *testing.T) { } } +func TestHooksList(t *testing.T) { + defer gock.Off() + + gock.New("https:/dev.azure.com/"). + Get("/ORG/_apis/projects"). + Reply(201). + Type("application/json"). + File("testdata/projects.json") + + gock.New("https:/dev.azure.com/"). + Get("/ORG/_apis/hooks/subscriptions"). + Reply(200). + Type("application/json"). + File("testdata/hooks.json") + + client := NewDefault("ORG", "test_project") + repoID := "fde2d21f-13b9-4864-a995-83329045289a" + + got, _, err := client.Repositories.ListHooks(context.Background(), repoID, scm.ListOptions{}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Hook{} + raw, _ := ioutil.ReadFile("testdata/hooks.json.golden") + jsonErr := json.Unmarshal(raw, &want) + if jsonErr != nil { + t.Error(jsonErr) + } + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + func TestRepositoryHookDelete(t *testing.T) { defer gock.Off() diff --git a/scm/driver/azure/testdata/branches_filter.json b/scm/driver/azure/testdata/branches_filter.json new file mode 100644 index 000000000..b9043edb5 --- /dev/null +++ b/scm/driver/azure/testdata/branches_filter.json @@ -0,0 +1,41 @@ +{ + "value": [ + { + "name": "refs/heads/main", + "objectId": "e0aee6aa543294d62520fb906689da6710af149c", + "creator": { + "displayName": "tp", + "url": "https://spsproduks1.vssps.visualstudio.com/A93f74f38-2b8d-42d4-a5cb-74646f46666e/_apis/Identities/3ff4a20f-306e-677e-8a01-57f35e71f109", + "_links": { + "avatar": { + "href": "https://dev.azure.com/tphoney/_apis/GraphProfile/MemberAvatars/msa.M2ZmNGEyMGYtMzA2ZS03NzdlLThhMDEtNTdmMzVlNzFmMTA5" + } + }, + "id": "3ff4a20f-306e-677e-8a01-57f35e71f109", + "uniqueName": "tp@harness.io", + "imageUrl": "https://dev.azure.com/tphoney/_api/_common/identityImage?id=3ff4a20f-306e-677e-8a01-57f35e71f109", + "descriptor": "msa.M2ZmNGEyMGYtMzA2ZS03NzdlLThhMDEtNTdmMzVlNzFmMTA5" + }, + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/refs?filter=heads%2Fmain" + }, + { + "name": "refs/heads/main-patch", + "objectId": "01768d964c03e97260af0bd8cd9e5cd1f9ac6356", + "creator": { + "displayName": "tp", + "url": "https://spsproduks1.vssps.visualstudio.com/A93f74f38-2b8d-42d4-a5cb-74646f46666e/_apis/Identities/3ff4a20f-306e-677e-8a01-57f35e71f109", + "_links": { + "avatar": { + "href": "https://dev.azure.com/tphoney/_apis/GraphProfile/MemberAvatars/msa.M2ZmNGEyMGYtMzA2ZS03NzdlLThhMDEtNTdmMzVlNzFmMTA5" + } + }, + "id": "3ff4a20f-306e-677e-8a01-57f35e71f109", + "uniqueName": "tp@harness.io", + "imageUrl": "https://dev.azure.com/tphoney/_api/_common/identityImage?id=3ff4a20f-306e-677e-8a01-57f35e71f109", + "descriptor": "msa.M2ZmNGEyMGYtMzA2ZS03NzdlLThhMDEtNTdmMzVlNzFmMTA5" + }, + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/refs?filter=heads%2Fpr_branch" + } + ], + "count": 2 +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/branches_filter.json.golden b/scm/driver/azure/testdata/branches_filter.json.golden new file mode 100644 index 000000000..df3589ce6 --- /dev/null +++ b/scm/driver/azure/testdata/branches_filter.json.golden @@ -0,0 +1,12 @@ +[ + { + "Name": "main", + "Path": "refs/heads/main", + "Sha": "e0aee6aa543294d62520fb906689da6710af149c" + }, + { + "Name": "main-patch", + "Path": "refs/heads/main-patch", + "Sha": "01768d964c03e97260af0bd8cd9e5cd1f9ac6356" + } +] \ No newline at end of file diff --git a/scm/driver/azure/testdata/commit.json.golden b/scm/driver/azure/testdata/commit.json.golden index 36b73b3cf..1659822a9 100644 --- a/scm/driver/azure/testdata/commit.json.golden +++ b/scm/driver/azure/testdata/commit.json.golden @@ -5,14 +5,14 @@ "Name": "tp", "Email": "tp@harness.io", "Date": "2022-03-15T17:08:22Z", - "Login": "", + "Login": "tp", "Avatar": "" }, "Committer": { "Name": "tp", "Email": "tp@harness.io", "Date": "2022-03-15T17:08:22Z", - "Login": "", + "Login": "tp", "Avatar": "" }, "Link": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/14897f4465d2d63508242b5cbf68aa2865f693e7" diff --git a/scm/driver/azure/testdata/commits.json.golden b/scm/driver/azure/testdata/commits.json.golden index 7f2eb4a47..a42699cf2 100644 --- a/scm/driver/azure/testdata/commits.json.golden +++ b/scm/driver/azure/testdata/commits.json.golden @@ -6,14 +6,14 @@ "Name": "tp", "Email": "tp@harness.io", "Date": "2022-03-04T12:19:58Z", - "Login": "", + "Login": "tp", "Avatar": "" }, "Committer": { "Name": "tp", "Email": "tp@harness.io", "Date": "2022-03-04T12:19:58Z", - "Login": "", + "Login": "tp", "Avatar": "" }, "Link": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/e0aee6aa543294d62520fb906689da6710af149c" @@ -25,14 +25,14 @@ "Name": "tp", "Email": "tp@harness.io", "Date": "2022-03-04T12:19:57Z", - "Login": "", + "Login": "tp", "Avatar": "" }, "Committer": { "Name": "tp", "Email": "tp@harness.io", "Date": "2022-03-04T12:19:57Z", - "Login": "", + "Login": "tp", "Avatar": "" }, "Link": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/1fe456794debece7c4125b9e283b601c974977a9" @@ -44,14 +44,14 @@ "Name": "tp", "Email": "tp@harness.io", "Date": "2022-03-04T12:19:56Z", - "Login": "", + "Login": "tp", "Avatar": "" }, "Committer": { "Name": "tp", "Email": "tp@harness.io", "Date": "2022-03-04T12:19:56Z", - "Login": "", + "Login": "tp", "Avatar": "" }, "Link": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/dc49e8e6e22bb3456366a09365ce9e72912f26b5" diff --git a/scm/driver/azure/testdata/hooks.json b/scm/driver/azure/testdata/hooks.json new file mode 100644 index 000000000..76efd534c --- /dev/null +++ b/scm/driver/azure/testdata/hooks.json @@ -0,0 +1,121 @@ +{ + "count": 2, + "value": [ + { + "id": "d455cb11-20a0-4b15-b546-7e9fb9973cc6", + "url": "https://dev.azure.com/tphoney/_apis/hooks/subscriptions/d455cb11-20a0-4b15-b546-7e9fb9973cc6", + "status": "enabled", + "publisherId": "tfs", + "eventType": "git.pullrequest.created", + "subscriber": null, + "resourceVersion": "1.0", + "eventDescription": "Repository test_repo2", + "consumerId": "webHooks", + "consumerActionId": "httpRequest", + "actionDescription": "To host www.bla.com", + "probationRetries": 1, + "createdBy": { + "displayName": "tp", + "id": "3ff4a20f-306e-677e-8a01-57f35e71f109", + "uniqueName": "tp@harness.io", + "descriptor": "msa.M2ZmNGEyMGYtMzA2ZS03NzdlLThhMDEtNTdmMzVlNzFmMTA5" + }, + "createdDate": "2022-03-25T13:28:12.39Z", + "modifiedBy": { + "displayName": "tp", + "id": "3ff4a20f-306e-677e-8a01-57f35e71f109", + "uniqueName": "tp@harness.io", + "descriptor": "msa.M2ZmNGEyMGYtMzA2ZS03NzdlLThhMDEtNTdmMzVlNzFmMTA5" + }, + "modifiedDate": "2022-03-29T10:39:13.813Z", + "lastProbationRetryDate": "2022-03-28T10:44:51.093Z", + "publisherInputs": { + "branch": "", + "projectId": "d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "pullrequestCreatedBy": "", + "pullrequestReviewersContains": "", + "repository": "fde2d21f-13b9-4864-a995-83329045289a", + "tfsSubscriptionId": "4ce8d6c4-f655-418d-8eb6-9462dd01ff39" + }, + "consumerInputs": { + "acceptUntrustedCerts": "true", + "url": "http://www.bla.com" + }, + "_links": { + "self": { + "href": "https://dev.azure.com/tphoney/_apis/hooks/subscriptions/d455cb11-20a0-4b15-b546-7e9fb9973cc6" + }, + "consumer": { + "href": "https://dev.azure.com/tphoney/_apis/hooks/consumers/webHooks" + }, + "actions": { + "href": "https://dev.azure.com/tphoney/_apis/hooks/consumers/webHooks/actions" + }, + "notifications": { + "href": "https://dev.azure.com/tphoney/_apis/hooks/subscriptions/d455cb11-20a0-4b15-b546-7e9fb9973cc6/notifications" + }, + "publisher": { + "href": "https://dev.azure.com/tphoney/_apis/hooks/publishers/tfs" + } + } + }, + { + "id": "d455cb11-20a0-4b15-b546-7e9fb9973cc7", + "url": "https://dev.azure.com/tphoney/_apis/hooks/subscriptions/d455cb11-20a0-4b15-b546-7e9fb9973cc7", + "status": "enabled", + "publisherId": "tfs", + "eventType": "git.pullrequest.merged", + "subscriber": null, + "resourceVersion": "1.0", + "eventDescription": "Repository test_repo2", + "consumerId": "webHooks", + "consumerActionId": "httpRequest", + "actionDescription": "To host www.bla.com", + "probationRetries": 1, + "createdBy": { + "displayName": "tp", + "id": "3ff4a20f-306e-677e-8a01-57f35e71f109", + "uniqueName": "tp@harness.io", + "descriptor": "msa.M2ZmNGEyMGYtMzA2ZS03NzdlLThhMDEtNTdmMzVlNzFmMTA5" + }, + "createdDate": "2022-03-25T13:28:12.39Z", + "modifiedBy": { + "displayName": "tp", + "id": "3ff4a20f-306e-677e-8a01-57f35e71f109", + "uniqueName": "tp@harness.io", + "descriptor": "msa.M2ZmNGEyMGYtMzA2ZS03NzdlLThhMDEtNTdmMzVlNzFmMTA5" + }, + "modifiedDate": "2022-03-29T10:39:13.813Z", + "lastProbationRetryDate": "2022-03-28T10:44:51.093Z", + "publisherInputs": { + "branch": "", + "projectId": "d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "pullrequestCreatedBy": "", + "pullrequestReviewersContains": "", + "repository": "fde2d21f-13b9-4864-a995-83329045289a", + "tfsSubscriptionId": "4ce8d6c4-f655-418d-8eb6-9462dd01ff39" + }, + "consumerInputs": { + "acceptUntrustedCerts": "true", + "url": "http://www.bla.com" + }, + "_links": { + "self": { + "href": "https://dev.azure.com/tphoney/_apis/hooks/subscriptions/d455cb11-20a0-4b15-b546-7e9fb9973cc7" + }, + "consumer": { + "href": "https://dev.azure.com/tphoney/_apis/hooks/consumers/webHooks" + }, + "actions": { + "href": "https://dev.azure.com/tphoney/_apis/hooks/consumers/webHooks/actions" + }, + "notifications": { + "href": "https://dev.azure.com/tphoney/_apis/hooks/subscriptions/d455cb11-20a0-4b15-b546-7e9fb9973cc7/notifications" + }, + "publisher": { + "href": "https://dev.azure.com/tphoney/_apis/hooks/publishers/tfs" + } + } + } + ] +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/hooks.json.golden b/scm/driver/azure/testdata/hooks.json.golden new file mode 100644 index 000000000..78d873eb2 --- /dev/null +++ b/scm/driver/azure/testdata/hooks.json.golden @@ -0,0 +1,22 @@ +[ + { + "ID": "d455cb11-20a0-4b15-b546-7e9fb9973cc6", + "Name": "", + "Target": "http://www.bla.com", + "Events": [ + "git.pullrequest.created" + ], + "Active": true, + "SkipVerify": true + }, + { + "ID": "d455cb11-20a0-4b15-b546-7e9fb9973cc7", + "Name": "", + "Target": "http://www.bla.com", + "Events": [ + "git.pullrequest.merged" + ], + "Active": true, + "SkipVerify": true + } +] \ No newline at end of file diff --git a/scm/driver/azure/testdata/pr.json b/scm/driver/azure/testdata/pr.json index b721e0dae..01c08b31e 100644 --- a/scm/driver/azure/testdata/pr.json +++ b/scm/driver/azure/testdata/pr.json @@ -15,7 +15,7 @@ }, "pullRequestId": 19, "codeReviewId": 19, - "status": "active", + "status": "completed", "createdBy": { "id": "3ff4a20f-306e-677e-8a01-57f35e71f109", "displayName": "tp", @@ -24,11 +24,13 @@ "imageUrl": "https://dev.azure.com/tphoney/_api/_common/identityImage?id=3ff4a20f-306e-677e-8a01-57f35e71f109" }, "creationDate": "2022-03-04T13:34:54.3177724Z", + "closedDate": "2022-06-03T06:33:42.2405472Z", "title": "test_pr", "description": "test_pr_body", "sourceRefName": "refs/heads/pr_branch", "targetRefName": "refs/heads/main", "mergeStatus": "queued", + "isDraft": false, "mergeId": "36c88bf7-3d14-437f-82aa-e38cce733261", "lastMergeSourceCommit": { "commitId": "01768d964c03e97260af0bd8cd9e5cd1f9ac6356", diff --git a/scm/driver/azure/testdata/pr.json.golden b/scm/driver/azure/testdata/pr.json.golden index 291b6f063..23330a15e 100644 --- a/scm/driver/azure/testdata/pr.json.golden +++ b/scm/driver/azure/testdata/pr.json.golden @@ -4,17 +4,19 @@ "Body": "test_pr_body", "Sha": "01768d964c03e97260af0bd8cd9e5cd1f9ac6356", "Ref": "", - "Source": "refs/heads/pr_branch", - "Target": "refs/heads/main", + "Source": "pr_branch", + "Target": "main", + "Ref": "refs/pull/19/merge", "Fork": "", "Link": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/pullRequests/19", "Diff": "", - "Closed": false, - "Merged": false, + "Draft": false, + "Closed": true, + "Merged": true, "Base": { "Name": "", "Path": "", - "Sha": "01768d964c03e97260af0bd8cd9e5cd1f9ac6356" + "Sha": "b748ab7eb49b8627214f22f631f878c4af9893b5" }, "Head": { "Name": "", diff --git a/scm/driver/azure/testdata/repo.json.golden b/scm/driver/azure/testdata/repo.json.golden index 92f3b874a..c65a2d23d 100644 --- a/scm/driver/azure/testdata/repo.json.golden +++ b/scm/driver/azure/testdata/repo.json.golden @@ -1,6 +1,10 @@ { "ID": "91f0d4cb-4c36-49a5-b28d-2d72da089c4d", "Name": "test_project", + "Namespace": "ORG/test_project", "Branch": "main", - "Link": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/91f0d4cb-4c36-49a5-b28d-2d72da089c4d" + "Link": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/91f0d4cb-4c36-49a5-b28d-2d72da089c4d", + "Clone": "https://tphoney@dev.azure.com/tphoney/test_project/_git/test_project", + "Private": true, + "Visibility": 3 } \ No newline at end of file diff --git a/scm/driver/azure/testdata/repos.json b/scm/driver/azure/testdata/repos.json index a05b6ce13..e5d7c6a23 100644 --- a/scm/driver/azure/testdata/repos.json +++ b/scm/driver/azure/testdata/repos.json @@ -30,7 +30,7 @@ "url": "https://dev.azure.com/tphoney/_apis/projects/d350c9c0-7749-4ff8-a78f-f9c1f0e56729", "state": "wellFormed", "revision": 11, - "visibility": "private", + "visibility": "public", "lastUpdateTime": "2022-02-24T15:31:27.89Z" }, "defaultBranch": "refs/heads/main", diff --git a/scm/driver/azure/testdata/repos.json.golden b/scm/driver/azure/testdata/repos.json.golden index cbe9d840d..137b73660 100644 --- a/scm/driver/azure/testdata/repos.json.golden +++ b/scm/driver/azure/testdata/repos.json.golden @@ -2,13 +2,21 @@ { "ID": "91f0d4cb-4c36-49a5-b28d-2d72da089c4d", "Name": "test_project", + "Namespace": "ORG/test_project", "Branch": "main", - "Link": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/91f0d4cb-4c36-49a5-b28d-2d72da089c4d" + "Link": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/91f0d4cb-4c36-49a5-b28d-2d72da089c4d", + "Clone": "https://tphoney@dev.azure.com/tphoney/test_project/_git/test_project", + "Private": true, + "Visibility": 3 }, { "ID": "fde2d21f-13b9-4864-a995-83329045289a", "Name": "test_repo2", + "Namespace": "ORG/test_project", "Branch": "main", - "Link": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a" + "Link": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a", + "Clone": "https://tphoney@dev.azure.com/tphoney/test_project/_git/test_repo2", + "Private": false, + "Visibility": 1 } ] \ No newline at end of file diff --git a/scm/driver/azure/testdata/tags.json b/scm/driver/azure/testdata/tags.json new file mode 100644 index 000000000..090690921 --- /dev/null +++ b/scm/driver/azure/testdata/tags.json @@ -0,0 +1,41 @@ +{ + "value": [ + { + "name": "refs/tags/v1.0.0", + "objectId": "23d9c1d0d6c41f1c8e08ab98a6a79c2d5ada649d", + "creator": { + "displayName": "Test User", + "url": "https://dev.azure.com/fabrikam/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db", + "_links": { + "avatar": { + "href": "https://dev.azure.com/fabrikam/_apis/GraphProfile/MemberAvatars/aad.YTYyNDVmMjAtMmFmOC00NGY0LTk0NTEtODEwN2NiMjc2N2Ri" + } + }, + "id": "d6245f20-2af8-44f4-9451-8107cb2767db", + "uniqueName": "test@example.com", + "imageUrl": "https://dev.azure.com/fabrikam/_api/_common/identityImage?id=d6245f20-2af8-44f4-9451-8107cb2767db", + "descriptor": "aad.YTYyNDVmMjAtMmFmOC00NGY0LTk0NTEtODEwN2NiMjc2N2Ri" + }, + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249/refs/tags/v1.0.0" + }, + { + "name": "refs/tags/v1.1.0", + "objectId": "8a9db19b5e19613c18e9059d7b9fa5d6d6a3785f", + "creator": { + "displayName": "Test User", + "url": "https://dev.azure.com/fabrikam/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db", + "_links": { + "avatar": { + "href": "https://dev.azure.com/fabrikam/_apis/GraphProfile/MemberAvatars/aad.YTYyNDVmMjAtMmFmOC00NGY0LTk0NTEtODEwN2NiMjc2N2Ri" + } + }, + "id": "d6245f20-2af8-44f4-9451-8107cb2767db", + "uniqueName": "test@example.com", + "imageUrl": "https://dev.azure.com/fabrikam/_api/_common/identityImage?id=d6245f20-2af8-44f4-9451-8107cb2767db", + "descriptor": "aad.YTYyNDVmMjAtMmFmOC00NGY0LTk0NTEtODEwN2NiMjc2N2Ri" + }, + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249/refs/tags/v1.1.0" + } + ], + "count": 2 +} diff --git a/scm/driver/azure/testdata/tags.json.golden b/scm/driver/azure/testdata/tags.json.golden new file mode 100644 index 000000000..28ef8bbf3 --- /dev/null +++ b/scm/driver/azure/testdata/tags.json.golden @@ -0,0 +1,12 @@ +[ + { + "Name": "v1.0.0", + "Path": "refs/tags/v1.0.0", + "Sha": "23d9c1d0d6c41f1c8e08ab98a6a79c2d5ada649d" + }, + { + "Name": "v1.1.0", + "Path": "refs/tags/v1.1.0", + "Sha": "8a9db19b5e19613c18e9059d7b9fa5d6d6a3785f" + } +] diff --git a/scm/driver/azure/testdata/webhooks/issue_comment.json b/scm/driver/azure/testdata/webhooks/issue_comment.json new file mode 100644 index 000000000..33cd10cad --- /dev/null +++ b/scm/driver/azure/testdata/webhooks/issue_comment.json @@ -0,0 +1,132 @@ +{ + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "notificationId": 2, + "id": "af07be1b-f3ad-44c8-a7f1-c4835f2df06b", + "eventType": "ms.vss-code.git-pullrequest-comment-event", + "publisherId": "tfs", + "message": { + "text": "Jamal Hartnett has edited a pull request comment", + "html": "Jamal Hartnett has edited a pull request comment", + "markdown": "Jamal Hartnett has [edited](https://fabrikam.visualstudio.com/DefaultCollection/_git/Fabrikam/pullrequest/1?discussionId=5) a pull request comment" + }, + "detailedMessage": { + "text": "Jamal Hartnett has edited a pull request comment\r\nThis is my comment.\r\n", + "html": "Jamal Hartnett has edited a pull request comment

This is my comment.

", + "markdown": "Jamal Hartnett has [edited](https://fabrikam.visualstudio.com/DefaultCollection/_git/Fabrikam/pullrequest/1?discussionId=5) a pull request comment\r\nThis is my comment.\r\n" + }, + "resource": { + "comment": { + "id": 2, + "parentCommentId": 1, + "author": { + "displayName": "Jamal Hartnett", + "url": "https://fabrikam.vssps.visualstudio.com/_apis/Identities/54d125f7-69f7-4191-904f-c5b96b6261c8", + "id": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "uniqueName": "fabrikamfiber4@hotmail.com", + "imageUrl": "https://fabrikam.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8" + }, + "content": "This is my comment.", + "publishedDate": "2014-06-17T16:55:46.589889Z", + "lastUpdatedDate": "2014-06-17T16:55:46.589889Z", + "lastContentUpdatedDate": "2014-06-17T16:58:33.123889Z", + "commentType": "text", + "_links": { + "self": { + "href": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1/threads/5/comments/2" + }, + "repository": { + "href": "http://joscol2/DefaultCollection/ebed510c-62eb-474b-965f-fd151ebb82e4/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079" + }, + "threads": { + "href": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1/threads/5" + } + } + }, + "pullRequest": { + "repository": { + "id": "4bc14d40-c903-45e2-872e-0462c7748079", + "name": "Fabrikam", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079", + "project": { + "id": "6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "name": "Fabrikam", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/projects/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "state": "wellFormed", + "visibility": "unchanged", + "lastUpdateTime": "0001-01-01T00:00:00" + }, + "sshUrl": "git@ssh.dev.azure.com:v3/fabrikam/DefaultCollection/Fabrikam", + "webUrl": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", + "remoteUrl": "https://fabrikam.visualstudio.com/DefaultCollection/_git/Fabrikam" + }, + "pullRequestId": 1, + "status": "active", + "createdBy": { + "displayName": "Jamal Hartnett", + "url": "https://fabrikam.vssps.visualstudio.com/_apis/Identities/54d125f7-69f7-4191-904f-c5b96b6261c8", + "id": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "uniqueName": "fabrikamfiber4@hotmail.com", + "imageUrl": "https://fabrikam.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8" + }, + "creationDate": "2014-06-17T16:55:46.589889Z", + "title": "my first pull request", + "description": " - test2\r\n", + "sourceRefName": "refs/heads/mytopic", + "targetRefName": "refs/heads/master", + "mergeStatus": "succeeded", + "mergeId": "a10bb228-6ba6-4362-abd7-49ea21333dbd", + "lastMergeSourceCommit": { + "commitId": "53d54ac915144006c2c9e90d2c7d3880920db49c", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/53d54ac915144006c2c9e90d2c7d3880920db49c" + }, + "lastMergeTargetCommit": { + "commitId": "a511f535b1ea495ee0c903badb68fbc83772c882", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/a511f535b1ea495ee0c903badb68fbc83772c882" + }, + "lastMergeCommit": { + "commitId": "eef717f69257a6333f221566c1c987dc94cc0d72", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72" + }, + "reviewers": [ + { + "reviewerUrl": null, + "vote": 0, + "displayName": "[Mobile]\\Mobile Team", + "url": "https://fabrikam.vssps.visualstudio.com/_apis/Identities/2ea2d095-48f9-4cd6-9966-62f6f574096c", + "id": "2ea2d095-48f9-4cd6-9966-62f6f574096c", + "uniqueName": "vstfs:///Classification/TeamProject/f0811a3b-8c8a-4e43-a3bf-9a049b4835bd\\Mobile Team", + "imageUrl": "https://fabrikam.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=2ea2d095-48f9-4cd6-9966-62f6f574096c", + "isContainer": true + } + ], + "commits": [ + { + "commitId": "53d54ac915144006c2c9e90d2c7d3880920db49c", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/53d54ac915144006c2c9e90d2c7d3880920db49c" + } + ], + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1", + "_links": { + "web": { + "href": "https://fabrikam.visualstudio.com/DefaultCollection/_git/Fabrikam/pullrequest/1#view=discussion" + }, + "statuses": { + "href": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1/statuses" + } + } + } + }, + "resourceVersion": "2.0", + "resourceContainers": { + "collection": { + "id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2" + }, + "account": { + "id": "f844ec47-a9db-4511-8281-8b63f4eaf94e" + }, + "project": { + "id": "be9b3917-87e6-42a4-a549-2bc06a7a878f" + } + }, + "createdDate": "2022-06-21T13:03:20.480894Z" + } \ No newline at end of file diff --git a/scm/driver/azure/testdata/webhooks/issue_comment.json.golden b/scm/driver/azure/testdata/webhooks/issue_comment.json.golden new file mode 100644 index 000000000..70b4da243 --- /dev/null +++ b/scm/driver/azure/testdata/webhooks/issue_comment.json.golden @@ -0,0 +1,88 @@ +{ + "Action": "created", + "Repo": { + "ID": "4bc14d40-c903-45e2-872e-0462c7748079", + "Namespace": "Fabrikam", + "Name": "Fabrikam", + "Perm": null, + "Branch": "mytopic", + "Archived": false, + "Private": false, + "Visibility": 0, + "Clone": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", + "CloneSSH": "git@ssh.dev.azure.com:v3/fabrikam/DefaultCollection/Fabrikam", + "Link": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Issue": { + "Number": 1, + "Title": "my first pull request", + "Body": " - test2\r\n", + "Link": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1", + "Author": { + "Login": "Jamal Hartnett", + "Name": "Jamal Hartnett", + "Email": "fabrikamfiber4@hotmail.com", + "Avatar": "https://fabrikam.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 1, + "Title": "my first pull request", + "Body": " - test2\r\n", + "Sha": "53d54ac915144006c2c9e90d2c7d3880920db49c", + "Ref": "refs/heads/mytopic", + "Source": "mytopic", + "Target": "master", + "Fork": "", + "Link": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1", + "Diff": "", + "Closed": false, + "Merged": false, + "Base": { + "Name": "", + "Path": "", + "Sha": "" + }, + "Head": { + "Name": "", + "Path": "", + "Sha": "" + }, + "Author": { + "Login": "Jamal Hartnett", + "Name": "Jamal Hartnett", + "Email": "fabrikamfiber4@hotmail.com", + "Avatar": "https://fabrikam.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Created": "2014-06-17T16:55:46.589889Z", + "Updated": "0001-01-01T00:00:00Z", + "Labels": null + }, + "Created": "2014-06-17T16:55:46.589889Z" + }, + "Comment": { + "ID": 2, + "Body": "This is my comment.", + "Author": { + "Login": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "Name": "Jamal Hartnett", + "Email": "fabrikamfiber4@hotmail.com", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Created": "2014-06-17T16:55:46.589889Z", + "Updated": "2014-06-17T16:55:46.589889Z" + }, + "Sender": { + "Login": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "Name": "Jamal Hartnett", + "Email": "fabrikamfiber4@hotmail.com", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + } +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/webhooks/issue_comment_delete.json b/scm/driver/azure/testdata/webhooks/issue_comment_delete.json new file mode 100644 index 000000000..5b154f7b3 --- /dev/null +++ b/scm/driver/azure/testdata/webhooks/issue_comment_delete.json @@ -0,0 +1,133 @@ +{ + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "notificationId": 2, + "id": "af07be1b-f3ad-44c8-a7f1-c4835f2df06b", + "eventType": "ms.vss-code.git-pullrequest-comment-event", + "publisherId": "tfs", + "message": { + "text": "Jamal Hartnett has edited a pull request comment", + "html": "Jamal Hartnett has edited a pull request comment", + "markdown": "Jamal Hartnett has [edited](https://fabrikam.visualstudio.com/DefaultCollection/_git/Fabrikam/pullrequest/1?discussionId=5) a pull request comment" + }, + "detailedMessage": { + "text": "Jamal Hartnett has edited a pull request comment\r\nThis is my comment.\r\n", + "html": "Jamal Hartnett has edited a pull request comment

This is my comment.

", + "markdown": "Jamal Hartnett has [edited](https://fabrikam.visualstudio.com/DefaultCollection/_git/Fabrikam/pullrequest/1?discussionId=5) a pull request comment\r\nThis is my comment.\r\n" + }, + "resource": { + "comment": { + "id": 2, + "parentCommentId": 1, + "author": { + "displayName": "Jamal Hartnett", + "url": "https://fabrikam.vssps.visualstudio.com/_apis/Identities/54d125f7-69f7-4191-904f-c5b96b6261c8", + "id": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "uniqueName": "fabrikamfiber4@hotmail.com", + "imageUrl": "https://fabrikam.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8" + }, + "content": "This is my comment.", + "publishedDate": "2014-06-17T16:55:46.589889Z", + "lastUpdatedDate": "2014-06-17T16:58:33.123889Z", + "lastContentUpdatedDate": "2014-06-17T16:58:33.123889Z", + "commentType": "text", + "isDeleted": true, + "_links": { + "self": { + "href": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1/threads/5/comments/2" + }, + "repository": { + "href": "http://joscol2/DefaultCollection/ebed510c-62eb-474b-965f-fd151ebb82e4/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079" + }, + "threads": { + "href": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1/threads/5" + } + } + }, + "pullRequest": { + "repository": { + "id": "4bc14d40-c903-45e2-872e-0462c7748079", + "name": "Fabrikam", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079", + "project": { + "id": "6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "name": "Fabrikam", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/projects/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "state": "wellFormed", + "visibility": "unchanged", + "lastUpdateTime": "0001-01-01T00:00:00" + }, + "sshUrl": "git@ssh.dev.azure.com:v3/fabrikam/DefaultCollection/Fabrikam", + "webUrl": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", + "remoteUrl": "https://fabrikam.visualstudio.com/DefaultCollection/_git/Fabrikam" + }, + "pullRequestId": 1, + "status": "active", + "createdBy": { + "displayName": "Jamal Hartnett", + "url": "https://fabrikam.vssps.visualstudio.com/_apis/Identities/54d125f7-69f7-4191-904f-c5b96b6261c8", + "id": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "uniqueName": "fabrikamfiber4@hotmail.com", + "imageUrl": "https://fabrikam.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8" + }, + "creationDate": "2014-06-17T16:55:46.589889Z", + "title": "my first pull request", + "description": " - test2\r\n", + "sourceRefName": "refs/heads/mytopic", + "targetRefName": "refs/heads/master", + "mergeStatus": "succeeded", + "mergeId": "a10bb228-6ba6-4362-abd7-49ea21333dbd", + "lastMergeSourceCommit": { + "commitId": "53d54ac915144006c2c9e90d2c7d3880920db49c", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/53d54ac915144006c2c9e90d2c7d3880920db49c" + }, + "lastMergeTargetCommit": { + "commitId": "a511f535b1ea495ee0c903badb68fbc83772c882", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/a511f535b1ea495ee0c903badb68fbc83772c882" + }, + "lastMergeCommit": { + "commitId": "eef717f69257a6333f221566c1c987dc94cc0d72", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72" + }, + "reviewers": [ + { + "reviewerUrl": null, + "vote": 0, + "displayName": "[Mobile]\\Mobile Team", + "url": "https://fabrikam.vssps.visualstudio.com/_apis/Identities/2ea2d095-48f9-4cd6-9966-62f6f574096c", + "id": "2ea2d095-48f9-4cd6-9966-62f6f574096c", + "uniqueName": "vstfs:///Classification/TeamProject/f0811a3b-8c8a-4e43-a3bf-9a049b4835bd\\Mobile Team", + "imageUrl": "https://fabrikam.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=2ea2d095-48f9-4cd6-9966-62f6f574096c", + "isContainer": true + } + ], + "commits": [ + { + "commitId": "53d54ac915144006c2c9e90d2c7d3880920db49c", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/53d54ac915144006c2c9e90d2c7d3880920db49c" + } + ], + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1", + "_links": { + "web": { + "href": "https://fabrikam.visualstudio.com/DefaultCollection/_git/Fabrikam/pullrequest/1#view=discussion" + }, + "statuses": { + "href": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1/statuses" + } + } + } + }, + "resourceVersion": "2.0", + "resourceContainers": { + "collection": { + "id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2" + }, + "account": { + "id": "f844ec47-a9db-4511-8281-8b63f4eaf94e" + }, + "project": { + "id": "be9b3917-87e6-42a4-a549-2bc06a7a878f" + } + }, + "createdDate": "2022-06-21T13:03:20.480894Z" + } \ No newline at end of file diff --git a/scm/driver/azure/testdata/webhooks/issue_comment_delete.json.golden b/scm/driver/azure/testdata/webhooks/issue_comment_delete.json.golden new file mode 100644 index 000000000..cd1e33741 --- /dev/null +++ b/scm/driver/azure/testdata/webhooks/issue_comment_delete.json.golden @@ -0,0 +1,88 @@ +{ + "Action": "deleted", + "Repo": { + "ID": "4bc14d40-c903-45e2-872e-0462c7748079", + "Namespace": "Fabrikam", + "Name": "Fabrikam", + "Perm": null, + "Branch": "mytopic", + "Archived": false, + "Private": false, + "Visibility": 0, + "Clone": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", + "CloneSSH": "git@ssh.dev.azure.com:v3/fabrikam/DefaultCollection/Fabrikam", + "Link": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Issue": { + "Number": 1, + "Title": "my first pull request", + "Body": " - test2\r\n", + "Link": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1", + "Author": { + "Login": "Jamal Hartnett", + "Name": "Jamal Hartnett", + "Email": "fabrikamfiber4@hotmail.com", + "Avatar": "https://fabrikam.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 1, + "Title": "my first pull request", + "Body": " - test2\r\n", + "Sha": "53d54ac915144006c2c9e90d2c7d3880920db49c", + "Ref": "refs/heads/mytopic", + "Source": "mytopic", + "Target": "master", + "Fork": "", + "Link": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1", + "Diff": "", + "Closed": false, + "Merged": false, + "Base": { + "Name": "", + "Path": "", + "Sha": "" + }, + "Head": { + "Name": "", + "Path": "", + "Sha": "" + }, + "Author": { + "Login": "Jamal Hartnett", + "Name": "Jamal Hartnett", + "Email": "fabrikamfiber4@hotmail.com", + "Avatar": "https://fabrikam.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Created": "2014-06-17T16:55:46.589889Z", + "Updated": "0001-01-01T00:00:00Z", + "Labels": null + }, + "Created": "2014-06-17T16:55:46.589889Z" + }, + "Comment": { + "ID": 2, + "Body": "This is my comment.", + "Author": { + "Login": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "Name": "Jamal Hartnett", + "Email": "fabrikamfiber4@hotmail.com", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Created": "2014-06-17T16:55:46.589889Z", + "Updated": "2014-06-17T16:58:33.123889Z" + }, + "Sender": { + "Login": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "Name": "Jamal Hartnett", + "Email": "fabrikamfiber4@hotmail.com", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + } +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/webhooks/issue_comment_edit.json b/scm/driver/azure/testdata/webhooks/issue_comment_edit.json new file mode 100644 index 000000000..971daae0d --- /dev/null +++ b/scm/driver/azure/testdata/webhooks/issue_comment_edit.json @@ -0,0 +1,132 @@ +{ + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "notificationId": 2, + "id": "af07be1b-f3ad-44c8-a7f1-c4835f2df06b", + "eventType": "ms.vss-code.git-pullrequest-comment-event", + "publisherId": "tfs", + "message": { + "text": "Jamal Hartnett has edited a pull request comment", + "html": "Jamal Hartnett has edited a pull request comment", + "markdown": "Jamal Hartnett has [edited](https://fabrikam.visualstudio.com/DefaultCollection/_git/Fabrikam/pullrequest/1?discussionId=5) a pull request comment" + }, + "detailedMessage": { + "text": "Jamal Hartnett has edited a pull request comment\r\nThis is my comment.\r\n", + "html": "Jamal Hartnett has edited a pull request comment

This is my comment.

", + "markdown": "Jamal Hartnett has [edited](https://fabrikam.visualstudio.com/DefaultCollection/_git/Fabrikam/pullrequest/1?discussionId=5) a pull request comment\r\nThis is my comment.\r\n" + }, + "resource": { + "comment": { + "id": 2, + "parentCommentId": 1, + "author": { + "displayName": "Jamal Hartnett", + "url": "https://fabrikam.vssps.visualstudio.com/_apis/Identities/54d125f7-69f7-4191-904f-c5b96b6261c8", + "id": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "uniqueName": "fabrikamfiber4@hotmail.com", + "imageUrl": "https://fabrikam.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8" + }, + "content": "This is my comment.", + "publishedDate": "2014-06-17T16:55:46.589889Z", + "lastUpdatedDate": "2014-06-17T16:58:33.123889Z", + "lastContentUpdatedDate": "2014-06-17T16:58:33.123889Z", + "commentType": "text", + "_links": { + "self": { + "href": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1/threads/5/comments/2" + }, + "repository": { + "href": "http://joscol2/DefaultCollection/ebed510c-62eb-474b-965f-fd151ebb82e4/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079" + }, + "threads": { + "href": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1/threads/5" + } + } + }, + "pullRequest": { + "repository": { + "id": "4bc14d40-c903-45e2-872e-0462c7748079", + "name": "Fabrikam", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079", + "project": { + "id": "6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "name": "Fabrikam", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/projects/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "state": "wellFormed", + "visibility": "unchanged", + "lastUpdateTime": "0001-01-01T00:00:00" + }, + "sshUrl": "git@ssh.dev.azure.com:v3/fabrikam/DefaultCollection/Fabrikam", + "webUrl": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", + "remoteUrl": "https://fabrikam.visualstudio.com/DefaultCollection/_git/Fabrikam" + }, + "pullRequestId": 1, + "status": "active", + "createdBy": { + "displayName": "Jamal Hartnett", + "url": "https://fabrikam.vssps.visualstudio.com/_apis/Identities/54d125f7-69f7-4191-904f-c5b96b6261c8", + "id": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "uniqueName": "fabrikamfiber4@hotmail.com", + "imageUrl": "https://fabrikam.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8" + }, + "creationDate": "2014-06-17T16:55:46.589889Z", + "title": "my first pull request", + "description": " - test2\r\n", + "sourceRefName": "refs/heads/mytopic", + "targetRefName": "refs/heads/master", + "mergeStatus": "succeeded", + "mergeId": "a10bb228-6ba6-4362-abd7-49ea21333dbd", + "lastMergeSourceCommit": { + "commitId": "53d54ac915144006c2c9e90d2c7d3880920db49c", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/53d54ac915144006c2c9e90d2c7d3880920db49c" + }, + "lastMergeTargetCommit": { + "commitId": "a511f535b1ea495ee0c903badb68fbc83772c882", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/a511f535b1ea495ee0c903badb68fbc83772c882" + }, + "lastMergeCommit": { + "commitId": "eef717f69257a6333f221566c1c987dc94cc0d72", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72" + }, + "reviewers": [ + { + "reviewerUrl": null, + "vote": 0, + "displayName": "[Mobile]\\Mobile Team", + "url": "https://fabrikam.vssps.visualstudio.com/_apis/Identities/2ea2d095-48f9-4cd6-9966-62f6f574096c", + "id": "2ea2d095-48f9-4cd6-9966-62f6f574096c", + "uniqueName": "vstfs:///Classification/TeamProject/f0811a3b-8c8a-4e43-a3bf-9a049b4835bd\\Mobile Team", + "imageUrl": "https://fabrikam.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=2ea2d095-48f9-4cd6-9966-62f6f574096c", + "isContainer": true + } + ], + "commits": [ + { + "commitId": "53d54ac915144006c2c9e90d2c7d3880920db49c", + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/53d54ac915144006c2c9e90d2c7d3880920db49c" + } + ], + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1", + "_links": { + "web": { + "href": "https://fabrikam.visualstudio.com/DefaultCollection/_git/Fabrikam/pullrequest/1#view=discussion" + }, + "statuses": { + "href": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1/statuses" + } + } + } + }, + "resourceVersion": "2.0", + "resourceContainers": { + "collection": { + "id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2" + }, + "account": { + "id": "f844ec47-a9db-4511-8281-8b63f4eaf94e" + }, + "project": { + "id": "be9b3917-87e6-42a4-a549-2bc06a7a878f" + } + }, + "createdDate": "2022-06-21T13:03:20.480894Z" + } \ No newline at end of file diff --git a/scm/driver/azure/testdata/webhooks/issue_comment_edit.json.golden b/scm/driver/azure/testdata/webhooks/issue_comment_edit.json.golden new file mode 100644 index 000000000..4ae2669fb --- /dev/null +++ b/scm/driver/azure/testdata/webhooks/issue_comment_edit.json.golden @@ -0,0 +1,88 @@ +{ + "Action": "edited", + "Repo": { + "ID": "4bc14d40-c903-45e2-872e-0462c7748079", + "Namespace": "Fabrikam", + "Name": "Fabrikam", + "Perm": null, + "Branch": "mytopic", + "Archived": false, + "Private": false, + "Visibility": 0, + "Clone": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", + "CloneSSH": "git@ssh.dev.azure.com:v3/fabrikam/DefaultCollection/Fabrikam", + "Link": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Issue": { + "Number": 1, + "Title": "my first pull request", + "Body": " - test2\r\n", + "Link": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1", + "Author": { + "Login": "Jamal Hartnett", + "Name": "Jamal Hartnett", + "Email": "fabrikamfiber4@hotmail.com", + "Avatar": "https://fabrikam.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 1, + "Title": "my first pull request", + "Body": " - test2\r\n", + "Sha": "53d54ac915144006c2c9e90d2c7d3880920db49c", + "Ref": "refs/heads/mytopic", + "Source": "mytopic", + "Target": "master", + "Fork": "", + "Link": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1", + "Diff": "", + "Closed": false, + "Merged": false, + "Base": { + "Name": "", + "Path": "", + "Sha": "" + }, + "Head": { + "Name": "", + "Path": "", + "Sha": "" + }, + "Author": { + "Login": "Jamal Hartnett", + "Name": "Jamal Hartnett", + "Email": "fabrikamfiber4@hotmail.com", + "Avatar": "https://fabrikam.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Created": "2014-06-17T16:55:46.589889Z", + "Updated": "0001-01-01T00:00:00Z", + "Labels": null + }, + "Created": "2014-06-17T16:55:46.589889Z" + }, + "Comment": { + "ID": 2, + "Body": "This is my comment.", + "Author": { + "Login": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "Name": "Jamal Hartnett", + "Email": "fabrikamfiber4@hotmail.com", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Created": "2014-06-17T16:55:46.589889Z", + "Updated": "2014-06-17T16:58:33.123889Z" + }, + "Sender": { + "Login": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "Name": "Jamal Hartnett", + "Email": "fabrikamfiber4@hotmail.com", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + } +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/webhooks/pr_created.json b/scm/driver/azure/testdata/webhooks/pr_created.json index 746cacec8..9b544c962 100644 --- a/scm/driver/azure/testdata/webhooks/pr_created.json +++ b/scm/driver/azure/testdata/webhooks/pr_created.json @@ -24,7 +24,8 @@ "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/projects/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", "state": "wellFormed" }, - "defaultBranch": "refs/heads/master", + "sshUrl": "git@ssh.dev.azure.com:v3/fabrikam/DefaultCollection/Fabrikam", + "webUrl": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", "remoteUrl": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam" }, "pullRequestId": 1, diff --git a/scm/driver/azure/testdata/webhooks/pr_created.json.golden b/scm/driver/azure/testdata/webhooks/pr_created.json.golden index 3ca595b6c..e081e85fa 100644 --- a/scm/driver/azure/testdata/webhooks/pr_created.json.golden +++ b/scm/driver/azure/testdata/webhooks/pr_created.json.golden @@ -1,17 +1,17 @@ { - "Action": "opened", + "Action": "created", "Repo": { "ID": "4bc14d40-c903-45e2-872e-0462c7748079", "Namespace": "Fabrikam", - "Name": "4bc14d40-c903-45e2-872e-0462c7748079", + "Name": "Fabrikam", "Perm": null, "Branch": "", "Archived": false, "Private": false, "Visibility": 0, - "Clone": "", - "CloneSSH": "", - "Link": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079", + "Clone": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", + "CloneSSH": "git@ssh.dev.azure.com:v3/fabrikam/DefaultCollection/Fabrikam", + "Link": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", "Created": "0001-01-01T00:00:00Z", "Updated": "0001-01-01T00:00:00Z" }, @@ -19,10 +19,10 @@ "Number": 1, "Title": "my first pull request", "Body": " - test2\r\n", - "Sha": "a10bb228-6ba6-4362-abd7-49ea21333dbd", + "Sha": "53d54ac915144006c2c9e90d2c7d3880920db49c", "Ref": "refs/heads/mytopic", - "Source": "refs/heads/mytopic", - "Target": "refs/heads/master", + "Source": "mytopic", + "Target": "master", "Fork": "", "Link": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1", "Diff": "", @@ -39,7 +39,7 @@ "Sha": "" }, "Author": { - "Login": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "Login": "Jamal Hartnett", "Name": "Jamal Hartnett", "Email": "fabrikamfiber4@hotmail.com", "Avatar": "https://dev.azure.com/fabrikam/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8", diff --git a/scm/driver/azure/testdata/webhooks/pr_merged.json b/scm/driver/azure/testdata/webhooks/pr_merged.json index 2cdd4a359..15537ac3e 100644 --- a/scm/driver/azure/testdata/webhooks/pr_merged.json +++ b/scm/driver/azure/testdata/webhooks/pr_merged.json @@ -24,7 +24,8 @@ "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/projects/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", "state": "wellFormed" }, - "defaultBranch": "refs/heads/master", + "sshUrl": "git@ssh.dev.azure.com:v3/fabrikam/DefaultCollection/Fabrikam", + "webUrl": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", "remoteUrl": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam" }, "pullRequestId": 1, diff --git a/scm/driver/azure/testdata/webhooks/pr_merged.json.golden b/scm/driver/azure/testdata/webhooks/pr_merged.json.golden index 0b9fcf117..844d14542 100644 --- a/scm/driver/azure/testdata/webhooks/pr_merged.json.golden +++ b/scm/driver/azure/testdata/webhooks/pr_merged.json.golden @@ -3,15 +3,15 @@ "Repo": { "ID": "4bc14d40-c903-45e2-872e-0462c7748079", "Namespace": "Fabrikam", - "Name": "4bc14d40-c903-45e2-872e-0462c7748079", + "Name": "Fabrikam", "Perm": null, "Branch": "", "Archived": false, "Private": false, "Visibility": 0, - "Clone": "", - "CloneSSH": "", - "Link": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079", + "Clone": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", + "CloneSSH": "git@ssh.dev.azure.com:v3/fabrikam/DefaultCollection/Fabrikam", + "Link": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", "Created": "0001-01-01T00:00:00Z", "Updated": "0001-01-01T00:00:00Z" }, @@ -19,15 +19,15 @@ "Number": 1, "Title": "my first pull request", "Body": " - test2\r\n", - "Sha": "a10bb228-6ba6-4362-abd7-49ea21333dbd", + "Sha": "53d54ac915144006c2c9e90d2c7d3880920db49c", "Ref": "refs/heads/mytopic", - "Source": "refs/heads/mytopic", - "Target": "refs/heads/master", + "Source": "mytopic", + "Target": "master", "Fork": "", "Link": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1", "Diff": "", "Closed": false, - "Merged": false, + "Merged": true, "Base": { "Name": "", "Path": "", @@ -39,7 +39,7 @@ "Sha": "" }, "Author": { - "Login": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "Login": "Jamal Hartnett", "Name": "Jamal Hartnett", "Email": "fabrikamfiber4@hotmail.com", "Avatar": "https://dev.azure.com/fabrikam/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8", diff --git a/scm/driver/azure/testdata/webhooks/pr_updated.json b/scm/driver/azure/testdata/webhooks/pr_updated.json index 25115a743..ac0f7f1ac 100644 --- a/scm/driver/azure/testdata/webhooks/pr_updated.json +++ b/scm/driver/azure/testdata/webhooks/pr_updated.json @@ -24,7 +24,8 @@ "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/projects/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", "state": "wellFormed" }, - "defaultBranch": "refs/heads/master", + "sshUrl": "git@ssh.dev.azure.com:v3/fabrikam/DefaultCollection/Fabrikam", + "webUrl": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", "remoteUrl": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam" }, "pullRequestId": 1, diff --git a/scm/driver/azure/testdata/webhooks/pr_updated.json.golden b/scm/driver/azure/testdata/webhooks/pr_updated.json.golden index aed341d44..ae36b5d5b 100644 --- a/scm/driver/azure/testdata/webhooks/pr_updated.json.golden +++ b/scm/driver/azure/testdata/webhooks/pr_updated.json.golden @@ -3,15 +3,15 @@ "Repo": { "ID": "4bc14d40-c903-45e2-872e-0462c7748079", "Namespace": "Fabrikam", - "Name": "4bc14d40-c903-45e2-872e-0462c7748079", + "Name": "Fabrikam", "Perm": null, "Branch": "", "Archived": false, "Private": false, "Visibility": 0, - "Clone": "", - "CloneSSH": "", - "Link": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079", + "Clone": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", + "CloneSSH": "git@ssh.dev.azure.com:v3/fabrikam/DefaultCollection/Fabrikam", + "Link": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam", "Created": "0001-01-01T00:00:00Z", "Updated": "0001-01-01T00:00:00Z" }, @@ -19,14 +19,14 @@ "Number": 1, "Title": "my first pull request", "Body": " - test2\r\n", - "Sha": "a10bb228-6ba6-4362-abd7-49ea21333dbd", + "Sha": "53d54ac915144006c2c9e90d2c7d3880920db49c", "Ref": "refs/heads/mytopic", - "Source": "refs/heads/mytopic", - "Target": "refs/heads/master", + "Source": "mytopic", + "Target": "master", "Fork": "", "Link": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1", "Diff": "", - "Closed": false, + "Closed": true, "Merged": false, "Base": { "Name": "", @@ -39,7 +39,7 @@ "Sha": "" }, "Author": { - "Login": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "Login": "Jamal Hartnett", "Name": "Jamal Hartnett", "Email": "fabrikamfiber4@hotmail.com", "Avatar": "https://dev.azure.com/fabrikam/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8", diff --git a/scm/driver/azure/testdata/webhooks/push.json.golden b/scm/driver/azure/testdata/webhooks/push.json.golden index 76073d237..59fae065b 100644 --- a/scm/driver/azure/testdata/webhooks/push.json.golden +++ b/scm/driver/azure/testdata/webhooks/push.json.golden @@ -4,14 +4,14 @@ "After": "33b55f7cb7e7e245323987634f960cf4a6e6bc74", "Repo": { "ID": "278d5cd2-584d-4b63-824a-2ba458937249", - "Namespace": "", + "Namespace": "Fabrikam-Fiber-Git", "Name": "Fabrikam-Fiber-Git", "Perm": null, - "Branch": "", + "Branch": "master", "Private": false, - "Clone": "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_apis/repos/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249", + "Clone": "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git", "CloneSSH": "", - "Link": "", + "Link": "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git", "Created": "0001-01-01T00:00:00Z", "Updated": "0001-01-01T00:00:00Z" }, @@ -37,9 +37,26 @@ } ], "Sender": { - "Login": "", - "Name": "", - "Email": "", + "Login": "00067FFED5C7AF52@Live.com", + "Name": "Jamal Hartnett", + "Email": "Windows Live ID\\fabrikamfiber4@hotmail.com", "Avatar": "" + }, + "Commit": { + "Sha": "33b55f7cb7e7e245323987634f960cf4a6e6bc74", + "Message": "", + "Author": { + "Login": "00067FFED5C7AF52@Live.com", + "Name": "Jamal Hartnett", + "Email": "Windows Live ID\\fabrikamfiber4@hotmail.com", + "Avatar": "" + }, + "Committer": { + "Login": "00067FFED5C7AF52@Live.com", + "Name": "Jamal Hartnett", + "Email": "Windows Live ID\\fabrikamfiber4@hotmail.com", + "Avatar": "" + }, + "Link": "" } } \ No newline at end of file diff --git a/scm/driver/azure/webhook.go b/scm/driver/azure/webhook.go index 94bafe10d..9e17da18f 100644 --- a/scm/driver/azure/webhook.go +++ b/scm/driver/azure/webhook.go @@ -13,6 +13,7 @@ import ( "time" "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/internal/null" ) type webhookService struct { @@ -52,7 +53,7 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo return nil, err } dst := convertCreatePullRequestHook(src) - dst.Action = scm.ActionOpen + dst.Action = scm.ActionCreate return dst, nil case "git.pullrequest.updated": // https://docs.microsoft.com/en-us/azure/devops/service-hooks/events?view=azure-devops#git.pullrequest.updated @@ -74,11 +75,30 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo dst := convertMergePullRequestHook(src) dst.Action = scm.ActionMerge return dst, nil + case "ms.vss-code.git-pullrequest-comment-event": + src := new(issueCommentPullRequestHook) + err := json.Unmarshal(data, src) + if err != nil { + return nil, err + } + dst := convertIssueCommentHook(src) + dst.Action = getIssueCommentAction(src) + return dst, nil default: return nil, scm.ErrUnknownEvent } } +func getIssueCommentAction(src *issueCommentPullRequestHook) scm.Action { + if src.Resource.Comment.IsDeleted { + return scm.ActionDelete + } else if src.Resource.Comment.PublishedDate.Equal(src.Resource.Comment.LastUpdatedDate) { + return scm.ActionCreate + } else { + return scm.ActionEdit + } +} + func convertPushHook(src *pushHook) *scm.PushHook { var commits []scm.Commit for _, c := range src.Resource.Commits { @@ -102,13 +122,39 @@ func convertPushHook(src *pushHook) *scm.PushHook { }) } dst := &scm.PushHook{ + Commit: scm.Commit{ + Sha: src.Resource.RefUpdates[0].NewObjectID, + Message: "", + Author: scm.Signature{ + Login: src.Resource.PushedBy.ID, + Name: src.Resource.PushedBy.DisplayName, + Email: src.Resource.PushedBy.UniqueName, + Avatar: src.Resource.PushedBy.ImageURL, + }, + Committer: scm.Signature{ + Login: src.Resource.PushedBy.ID, + Name: src.Resource.PushedBy.DisplayName, + Email: src.Resource.PushedBy.UniqueName, + Avatar: src.Resource.PushedBy.ImageURL, + }, + Link: "", + }, Ref: src.Resource.RefUpdates[0].Name, Before: src.Resource.RefUpdates[0].OldObjectID, After: src.Resource.RefUpdates[0].NewObjectID, + Sender: scm.User{ + Login: src.Resource.PushedBy.ID, + Name: src.Resource.PushedBy.DisplayName, + Email: src.Resource.PushedBy.UniqueName, + Avatar: src.Resource.PushedBy.ImageURL, + }, Repo: scm.Repository{ - ID: src.Resource.Repository.ID, - Name: src.Resource.Repository.Name, - Clone: src.Resource.Repository.URL, + ID: src.Resource.Repository.ID, + Branch: scm.TrimRef(src.Resource.Repository.DefaultBranch), + Name: src.Resource.Repository.Name, + Namespace: src.Resource.Repository.Project.Name, + Clone: src.Resource.Repository.RemoteURL, + Link: src.Resource.Repository.RemoteURL, }, Commits: commits, } @@ -121,13 +167,15 @@ func convertCreatePullRequestHook(src *createPullRequestHook) (returnVal *scm.Pu Number: src.Resource.PullRequestID, Title: src.Resource.Title, Body: src.Resource.Description, - Sha: src.Resource.MergeID, + Sha: src.Resource.LastMergeSourceCommit.CommitID, Ref: src.Resource.SourceRefName, - Source: src.Resource.SourceRefName, - Target: src.Resource.TargetRefName, + Source: scm.TrimRef(src.Resource.SourceRefName), + Target: scm.TrimRef(src.Resource.TargetRefName), Link: src.Resource.URL, + Closed: false, + Merged: false, Author: scm.User{ - Login: src.Resource.CreatedBy.ID, + Login: src.Resource.CreatedBy.DisplayName, Name: src.Resource.CreatedBy.DisplayName, Email: src.Resource.CreatedBy.UniqueName, Avatar: src.Resource.CreatedBy.ImageURL, @@ -136,9 +184,11 @@ func convertCreatePullRequestHook(src *createPullRequestHook) (returnVal *scm.Pu }, Repo: scm.Repository{ ID: src.Resource.Repository.ID, - Name: src.Resource.Repository.ID, - Namespace: src.Resource.Repository.Name, - Link: src.Resource.Repository.URL, + Name: src.Resource.Repository.Name, + Namespace: src.Resource.Repository.Project.Name, + Link: src.Resource.Repository.WebURL, + Clone: src.Resource.Repository.WebURL, + CloneSSH: src.Resource.Repository.SSHURL, }, Sender: scm.User{ Login: src.Resource.CreatedBy.ID, @@ -156,13 +206,15 @@ func convertUpdatePullRequestHook(src *updatePullRequestHook) (returnVal *scm.Pu Number: src.Resource.PullRequestID, Title: src.Resource.Title, Body: src.Resource.Description, - Sha: src.Resource.MergeID, + Sha: src.Resource.LastMergeSourceCommit.CommitID, Ref: src.Resource.SourceRefName, - Source: src.Resource.SourceRefName, - Target: src.Resource.TargetRefName, + Source: scm.TrimRef(src.Resource.SourceRefName), + Target: scm.TrimRef(src.Resource.TargetRefName), Link: src.Resource.URL, + Closed: src.Resource.ClosedDate.Valid, + Merged: false, Author: scm.User{ - Login: src.Resource.CreatedBy.ID, + Login: src.Resource.CreatedBy.DisplayName, Name: src.Resource.CreatedBy.DisplayName, Email: src.Resource.CreatedBy.UniqueName, Avatar: src.Resource.CreatedBy.ImageURL, @@ -171,9 +223,11 @@ func convertUpdatePullRequestHook(src *updatePullRequestHook) (returnVal *scm.Pu }, Repo: scm.Repository{ ID: src.Resource.Repository.ID, - Name: src.Resource.Repository.ID, - Namespace: src.Resource.Repository.Name, - Link: src.Resource.Repository.URL, + Name: src.Resource.Repository.Name, + Namespace: src.Resource.Repository.Project.Name, + Link: src.Resource.Repository.WebURL, + Clone: src.Resource.Repository.WebURL, + CloneSSH: src.Resource.Repository.SSHURL, }, Sender: scm.User{ Login: src.Resource.CreatedBy.ID, @@ -191,13 +245,15 @@ func convertMergePullRequestHook(src *mergePullRequestHook) (returnVal *scm.Pull Number: src.Resource.PullRequestID, Title: src.Resource.Title, Body: src.Resource.Description, - Sha: src.Resource.MergeID, + Sha: src.Resource.LastMergeSourceCommit.CommitID, Ref: src.Resource.SourceRefName, - Source: src.Resource.SourceRefName, - Target: src.Resource.TargetRefName, + Source: scm.TrimRef(src.Resource.SourceRefName), + Target: scm.TrimRef(src.Resource.TargetRefName), Link: src.Resource.URL, + Closed: false, + Merged: true, Author: scm.User{ - Login: src.Resource.CreatedBy.ID, + Login: src.Resource.CreatedBy.DisplayName, Name: src.Resource.CreatedBy.DisplayName, Email: src.Resource.CreatedBy.UniqueName, Avatar: src.Resource.CreatedBy.ImageURL, @@ -206,9 +262,11 @@ func convertMergePullRequestHook(src *mergePullRequestHook) (returnVal *scm.Pull }, Repo: scm.Repository{ ID: src.Resource.Repository.ID, - Name: src.Resource.Repository.ID, - Namespace: src.Resource.Repository.Name, - Link: src.Resource.Repository.URL, + Name: src.Resource.Repository.Name, + Namespace: src.Resource.Repository.Project.Name, + Link: src.Resource.Repository.WebURL, + Clone: src.Resource.Repository.WebURL, + CloneSSH: src.Resource.Repository.SSHURL, }, Sender: scm.User{ Login: src.Resource.CreatedBy.ID, @@ -220,6 +278,70 @@ func convertMergePullRequestHook(src *mergePullRequestHook) (returnVal *scm.Pull return returnVal } +func convertIssueCommentHook(src *issueCommentPullRequestHook) *scm.IssueCommentHook { + dst := &scm.IssueCommentHook{ + Repo: scm.Repository{ + ID: src.Resource.PullRequest.Repository.ID, + Namespace: src.Resource.PullRequest.Repository.Project.Name, + Name: src.Resource.PullRequest.Repository.Name, + Branch: scm.TrimRef(src.Resource.PullRequest.SourceRefName), + Private: false, + Clone: src.Resource.PullRequest.Repository.WebURL, + CloneSSH: src.Resource.PullRequest.Repository.SSHURL, + Link: src.Resource.PullRequest.Repository.WebURL, + }, + Issue: scm.Issue{ + Number: src.Resource.PullRequest.PullRequestID, + Title: src.Resource.PullRequest.Title, + Body: src.Resource.PullRequest.Description, + Link: src.Resource.PullRequest.URL, + Author: scm.User{ + Login: src.Resource.PullRequest.CreatedBy.DisplayName, + Name: src.Resource.PullRequest.CreatedBy.DisplayName, + Email: src.Resource.PullRequest.CreatedBy.UniqueName, + Avatar: src.Resource.PullRequest.CreatedBy.ImageURL, + }, + PullRequest: scm.PullRequest{ + Number: src.Resource.PullRequest.PullRequestID, + Title: src.Resource.PullRequest.Title, + Body: src.Resource.PullRequest.Description, + Sha: src.Resource.PullRequest.LastMergeSourceCommit.CommitID, + Ref: src.Resource.PullRequest.SourceRefName, + Source: scm.TrimRef(src.Resource.PullRequest.SourceRefName), + Target: scm.TrimRef(src.Resource.PullRequest.TargetRefName), + Link: src.Resource.PullRequest.URL, + Closed: false, + Merged: false, + Author: scm.User{ + Login: src.Resource.PullRequest.CreatedBy.DisplayName, + Name: src.Resource.PullRequest.CreatedBy.DisplayName, + Email: src.Resource.PullRequest.CreatedBy.UniqueName, + Avatar: src.Resource.PullRequest.CreatedBy.ImageURL, + }, + Created: src.Resource.PullRequest.CreationDate, + }, + Created: src.Resource.PullRequest.CreationDate, + }, + Comment: scm.Comment{ + ID: src.Resource.Comment.ID, + Body: src.Resource.Comment.Content, + Author: scm.User{ + Email: src.Resource.Comment.Author.UniqueName, + Login: src.Resource.Comment.Author.ID, + Name: src.Resource.Comment.Author.DisplayName, + }, + Created: src.Resource.Comment.PublishedDate, + Updated: src.Resource.Comment.LastUpdatedDate, + }, + Sender: scm.User{ + Email: src.Resource.Comment.Author.UniqueName, + Login: src.Resource.Comment.Author.ID, + Name: src.Resource.Comment.Author.DisplayName, + }, + } + return dst +} + type pushHook struct { CreatedDate string `json:"createdDate"` DetailedMessage struct { @@ -257,6 +379,7 @@ type pushHook struct { DisplayName string `json:"displayName"` ID string `json:"id"` UniqueName string `json:"uniqueName"` + ImageURL string `json:"imageUrl"` } `json:"pushedBy"` RefUpdates []struct { Name string `json:"name"` @@ -313,6 +436,8 @@ type createPullRequestHook struct { ID string `json:"id"` Name string `json:"name"` URL string `json:"url"` + WebURL string `json:"webUrl"` + SSHURL string `json:"sshUrl"` Project struct { ID string `json:"id"` Name string `json:"name"` @@ -393,7 +518,7 @@ type updatePullRequestHook struct { } `json:"message"` PublisherID string `json:"publisherId"` Resource struct { - ClosedDate string `json:"closedDate"` + ClosedDate null.String `json:"closedDate"` Commits []struct { CommitID string `json:"commitId"` URL string `json:"url"` @@ -434,6 +559,8 @@ type updatePullRequestHook struct { } `json:"project"` RemoteURL string `json:"remoteUrl"` URL string `json:"url"` + WebURL string `json:"webUrl"` + SSHURL string `json:"sshUrl"` } `json:"repository"` Reviewers []struct { DisplayName string `json:"displayName"` @@ -519,6 +646,8 @@ type mergePullRequestHook struct { } `json:"project"` RemoteURL string `json:"remoteUrl"` URL string `json:"url"` + WebURL string `json:"webUrl"` + SSHURL string `json:"sshUrl"` } `json:"repository"` Reviewers []struct { DisplayName string `json:"displayName"` @@ -550,3 +679,112 @@ type mergePullRequestHook struct { ResourceVersion string `json:"resourceVersion"` Scope string `json:"scope"` } + +type issueCommentPullRequestHook struct { + CreatedDate string `json:"createdDate"` + DetailedMessage struct { + HTML string `json:"html"` + Markdown string `json:"markdown"` + Text string `json:"text"` + } `json:"detailedMessage"` + EventType string `json:"eventType"` + ID string `json:"id"` + Message struct { + HTML string `json:"html"` + Markdown string `json:"markdown"` + Text string `json:"text"` + } `json:"message"` + PublisherID string `json:"publisherId"` + Resource struct { + PullRequest struct { + CreatedBy struct { + DisplayName string `json:"displayName"` + ID string `json:"id"` + ImageURL string `json:"imageUrl"` + UniqueName string `json:"uniqueName"` + URL string `json:"url"` + } `json:"createdBy"` + CreationDate time.Time `json:"creationDate"` + Description string `json:"description"` + LastMergeCommit struct { + CommitID string `json:"commitId"` + Author struct { + Date time.Time `json:"date"` + Email string `json:"email"` + Name string `json:"name"` + } `json:"author"` + URL string `json:"url"` + } `json:"lastMergeCommit"` + LastMergeSourceCommit struct { + CommitID string `json:"commitId"` + URL string `json:"url"` + } `json:"lastMergeSourceCommit"` + LastMergeTargetCommit struct { + CommitID string `json:"commitId"` + URL string `json:"url"` + } `json:"lastMergeTargetCommit"` + MergeID string `json:"mergeId"` + MergeStatus string `json:"mergeStatus"` + PullRequestID int `json:"pullRequestId"` + Repository struct { + ID string `json:"id"` + Name string `json:"name"` + Project struct { + ID string `json:"id"` + Name string `json:"name"` + State string `json:"state"` + URL string `json:"url"` + } `json:"project"` + RemoteURL string `json:"remoteUrl"` + URL string `json:"url"` + WebURL string `json:"webUrl"` + SSHURL string `json:"sshUrl"` + } `json:"repository"` + Reviewers []struct { + DisplayName string `json:"displayName"` + ID string `json:"id"` + ImageURL string `json:"imageUrl"` + IsContainer bool `json:"isContainer"` + ReviewerURL interface{} `json:"reviewerUrl"` + UniqueName string `json:"uniqueName"` + URL string `json:"url"` + Vote int64 `json:"vote"` + } `json:"reviewers"` + SourceRefName string `json:"sourceRefName"` + Status string `json:"status"` + TargetRefName string `json:"targetRefName"` + Title string `json:"title"` + URL string `json:"url"` + } `json:"pullRequest"` + Comment struct { + ID int `json:"id"` + ParentCommentId int `json:"parentCommentId"` + Content string `json:"content"` + PublishedDate time.Time `json:"publishedDate"` + LastUpdatedDate time.Time `json:"lastUpdatedDate"` + LastContentUpdatedDate time.Time `json:"lastContentUpdatedDate"` + CommentType string `json:"commentType"` + IsDeleted bool `json:"isDeleted"` + Author struct { + DisplayName string `json:"displayName"` + ID string `json:"id"` + ImageURL string `json:"imageUrl"` + UniqueName string `json:"uniqueName"` + URL string `json:"url"` + } `json:"author"` + } `json:"comment"` + } `json:"resource"` + ResourceContainers struct { + Account struct { + ID string `json:"id"` + } `json:"account"` + Collection struct { + ID string `json:"id"` + } `json:"collection"` + Project struct { + ID string `json:"id"` + } `json:"project"` + } `json:"resourceContainers"` + ResourceVersion string `json:"resourceVersion"` + Scope string `json:"scope"` +} \ No newline at end of file diff --git a/scm/driver/azure/webhook_test.go b/scm/driver/azure/webhook_test.go index 7ea03870e..d4024c2f8 100644 --- a/scm/driver/azure/webhook_test.go +++ b/scm/driver/azure/webhook_test.go @@ -47,6 +47,24 @@ func TestWebhooks(t *testing.T) { after: "testdata/webhooks/pr_merged.json.golden", obj: new(scm.PullRequestHook), }, + // issue comment create + { + before: "testdata/webhooks/issue_comment.json", + after: "testdata/webhooks/issue_comment.json.golden", + obj: new(scm.IssueCommentHook), + }, + // issue comment edit + { + before: "testdata/webhooks/issue_comment_edit.json", + after: "testdata/webhooks/issue_comment_edit.json.golden", + obj: new(scm.IssueCommentHook), + }, + // issue comment delete + { + before: "testdata/webhooks/issue_comment_delete.json", + after: "testdata/webhooks/issue_comment_delete.json.golden", + obj: new(scm.IssueCommentHook), + }, } for _, test := range tests { diff --git a/scm/driver/bitbucket/bitbucket.go b/scm/driver/bitbucket/bitbucket.go index d5afda370..f05ab670e 100644 --- a/scm/driver/bitbucket/bitbucket.go +++ b/scm/driver/bitbucket/bitbucket.go @@ -36,7 +36,7 @@ func New(uri string) (*scm.Client, error) { client.Issues = &issueService{client} client.Milestones = &milestoneService{client} client.Organizations = &organizationService{client} - client.PullRequests = &pullService{&issueService{client}} + client.PullRequests = &pullService{client} client.Repositories = &repositoryService{client} client.Releases = &releaseService{client} client.Reviews = &reviewService{client} diff --git a/scm/driver/bitbucket/content.go b/scm/driver/bitbucket/content.go index 3501de53f..3bb2960cf 100644 --- a/scm/driver/bitbucket/content.go +++ b/scm/driver/bitbucket/content.go @@ -8,6 +8,7 @@ import ( "bytes" "context" "fmt" + "net/url" "github.com/drone/go-scm/scm" ) @@ -17,7 +18,8 @@ type contentService struct { } func (s *contentService) Find(ctx context.Context, repo, path, ref string) (*scm.Content, *scm.Response, error) { - endpoint := fmt.Sprintf("/2.0/repositories/%s/src/%s/%s", repo, ref, path) + urlEncodedRef := url.QueryEscape(ref) + endpoint := fmt.Sprintf("/2.0/repositories/%s/src/%s/%s", repo, urlEncodedRef, path) out := new(bytes.Buffer) res, err := s.client.do(ctx, "GET", endpoint, nil, out) content := &scm.Content{ @@ -27,7 +29,7 @@ func (s *contentService) Find(ctx context.Context, repo, path, ref string) (*scm if err != nil { return content, res, err } - metaEndpoint := fmt.Sprintf("/2.0/repositories/%s/src/%s/%s?format=meta", repo, ref, path) + metaEndpoint := fmt.Sprintf("/2.0/repositories/%s/src/%s/%s?format=meta", repo, urlEncodedRef, path) metaOut := new(metaContent) metaRes, metaErr := s.client.do(ctx, "GET", metaEndpoint, nil, metaOut) if metaErr == nil { diff --git a/scm/driver/bitbucket/git.go b/scm/driver/bitbucket/git.go index 03093c5bc..df16afbcb 100644 --- a/scm/driver/bitbucket/git.go +++ b/scm/driver/bitbucket/git.go @@ -7,6 +7,7 @@ package bitbucket import ( "context" "fmt" + "strings" "time" "github.com/drone/go-scm/scm" @@ -16,7 +17,7 @@ type gitService struct { client *wrapper } -func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.CreateBranch) (*scm.Response, error) { +func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.ReferenceInput) (*scm.Response, error) { path := fmt.Sprintf("2.0/repositories/%s/refs/branches", repo) in := &createBranch{ Name: params.Name, @@ -44,7 +45,12 @@ func (s *gitService) FindCommit(ctx context.Context, repo, ref string) (*scm.Com ref = branch.Sha // replace ref with sha } } - path := fmt.Sprintf("2.0/repositories/%s/commit/%s", repo, ref) + var path string + if strings.Contains(ref, "/") { + path = fmt.Sprintf("2.0/repositories/%s/?at=%s", repo, ref) + } else { + path = fmt.Sprintf("2.0/repositories/%s/commit/%s", repo, ref) + } out := new(commit) res, err := s.client.do(ctx, "GET", path, nil, out) return convertCommit(out), res, err @@ -64,6 +70,13 @@ func (s *gitService) ListBranches(ctx context.Context, repo string, opts scm.Lis copyPagination(out.pagination, res) return convertBranchList(out), res, err } +func (s *gitService) ListBranchesV2(ctx context.Context, repo string, opts scm.BranchListOptions) ([]*scm.Reference, *scm.Response, error) { + path := fmt.Sprintf("2.0/repositories/%s/refs/branches?%s", repo, encodeBranchListOptions(opts)) + out := new(branches) + res, err := s.client.do(ctx, "GET", path, nil, out) + copyPagination(out.pagination, res) + return convertBranchList(out), res, err +} func (s *gitService) ListCommits(ctx context.Context, repo string, opts scm.CommitListOptions) ([]*scm.Commit, *scm.Response, error) { path := fmt.Sprintf("2.0/repositories/%s/commits/%s?%s", repo, opts.Ref, encodeCommitListOptions(opts)) @@ -74,10 +87,19 @@ func (s *gitService) ListCommits(ctx context.Context, repo string, opts scm.Comm } func (s *gitService) ListTags(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Reference, *scm.Response, error) { + // make page params only with 'pagelen' as there is a bug with 'page' param + opts.Page = 0 path := fmt.Sprintf("2.0/repositories/%s/refs/tags?%s", repo, encodeListOptions(opts)) + out := new(branches) res, err := s.client.do(ctx, "GET", path, nil, &out) + copyPagination(out.pagination, res) + + if res != nil { + res.Page.Next = 0 + } + return convertTagList(out), res, err } diff --git a/scm/driver/bitbucket/git_test.go b/scm/driver/bitbucket/git_test.go index 7e666772c..912434bf1 100644 --- a/scm/driver/bitbucket/git_test.go +++ b/scm/driver/bitbucket/git_test.go @@ -41,6 +41,32 @@ func TestGitFindCommit(t *testing.T) { } } +func TestGitFindCommitForTagSlash(t *testing.T) { + defer gock.Off() + + gock.New("https://api.bitbucket.org"). + Get("/2.0/repositories/atlassian/stash-example-plugin"). + MatchParam("at", "ab/cd"). + Reply(200). + Type("application/json"). + File("testdata/commit.json") + + client, _ := New("https://api.bitbucket.org") + got, _, err := client.Git.FindCommit(context.Background(), "atlassian/stash-example-plugin", "ab/cd") + if err != nil { + t.Error(err) + } + + want := new(scm.Commit) + raw, _ := ioutil.ReadFile("testdata/commit.json.golden") + json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + func TestGitFindCommitForBranch(t *testing.T) { defer gock.Off() @@ -81,7 +107,7 @@ func TestGitCreateBranch(t *testing.T) { Type("application/json"). File("testdata/branch_create.json") - params := &scm.CreateBranch{ + params := &scm.ReferenceInput{ Name: "yooo", Sha: "2e684d13a43afd86cb48ea36d9f40f43e791fae9", } @@ -206,19 +232,51 @@ func TestGitListBranches(t *testing.T) { t.Run("Page", testPage(res)) } +func TestGitListBranchesV2(t *testing.T) { + defer gock.Off() + + gock.New("https://api.bitbucket.org"). + Get("/2.0/repositories/atlassian/stash-example-plugin/refs"). + MatchParam("q", "name~\\\"mast\\\""). + MatchParam("page", "1"). + MatchParam("pagelen", "30"). + Reply(200). + Type("application/json"). + File("testdata/branches_filter.json") + + client, _ := New("https://api.bitbucket.org") + got, res, err := client.Git.ListBranchesV2(context.Background(), "atlassian/stash-example-plugin", scm.BranchListOptions{ + SearchTerm: "mast", + PageListOptions: scm.ListOptions{Page: 1, Size: 30}, + }) + if err != nil { + t.Error(err) + } + + want := []*scm.Reference{} + raw, _ := ioutil.ReadFile("testdata/branches_filter.json.golden") + json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + t.Run("Page", testPage(res)) +} + func TestGitListTags(t *testing.T) { defer gock.Off() gock.New("https://api.bitbucket.org"). Get("/2.0/repositories/atlassian/atlaskit/refs/tags"). - MatchParam("page", "1"). MatchParam("pagelen", "30"). Reply(200). Type("application/json"). File("testdata/tags.json") client, _ := New("https://api.bitbucket.org") - got, res, err := client.Git.ListTags(context.Background(), "atlassian/atlaskit", scm.ListOptions{Page: 1, Size: 30}) + got, _, err := client.Git.ListTags(context.Background(), "atlassian/atlaskit", scm.ListOptions{Page: 1, Size: 30}) if err != nil { t.Error(err) } @@ -232,7 +290,6 @@ func TestGitListTags(t *testing.T) { t.Log(diff) } - t.Run("Page", testPage(res)) } func TestGitListChanges(t *testing.T) { diff --git a/scm/driver/bitbucket/pr.go b/scm/driver/bitbucket/pr.go index 20dc31441..c0282f714 100644 --- a/scm/driver/bitbucket/pr.go +++ b/scm/driver/bitbucket/pr.go @@ -13,7 +13,7 @@ import ( ) type pullService struct { - *issueService + client *wrapper } func (s *pullService) Find(ctx context.Context, repo string, number int) (*scm.PullRequest, *scm.Response, error) { @@ -69,6 +69,27 @@ func (s *pullService) Create(ctx context.Context, repo string, input *scm.PullRe return convertPullRequest(out), res, err } +func (s *pullService) FindComment(ctx context.Context, repo string, index, id int) (*scm.Comment, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *pullService) ListComments(ctx context.Context, repo string, index int, opts scm.ListOptions) ([]*scm.Comment, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *pullService) CreateComment(ctx context.Context, repo string, number int, input *scm.CommentInput) (*scm.Comment, *scm.Response, error) { + path := fmt.Sprintf("2.0/repositories/%s/pullrequests/%d/comments", repo, number) + in := &prCommentInput{} + in.Content.Raw = input.Body + out := new(prComment) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertPullRequestComment(out), res, err +} + +func (s *pullService) DeleteComment(ctx context.Context, repo string, number, id int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + type reference struct { Commit struct { Hash string `json:"hash"` @@ -108,6 +129,10 @@ type pr struct { HTML string `json:"html"` Type string `json:"type"` } `json:"summary"` + MergeCommit struct { + Type string `json:"type"` + Hash string `json:"hash"` + } `json:"merge_commit"` Source reference `json:"source"` State string `json:"state"` Author user `json:"author"` @@ -149,6 +174,7 @@ func convertPullRequest(from *pr) *scm.PullRequest { Title: from.Title, Body: from.Description, Sha: from.Source.Commit.Hash, + Merge: from.MergeCommit.Hash, Source: from.Source.Branch.Name, Target: from.Destination.Branch.Name, Fork: from.Source.Repository.FullName, @@ -167,7 +193,7 @@ func convertPullRequest(from *pr) *scm.PullRequest { Sha: from.Destination.Commit.Hash, }, Author: scm.User{ - Login: from.Author.Nickname, + ID: from.Author.AccountID, Name: from.Author.DisplayName, Avatar: from.Author.Links.Avatar.Href, }, @@ -175,3 +201,18 @@ func convertPullRequest(from *pr) *scm.PullRequest { Updated: from.UpdatedOn, } } + +func convertPullRequestComment(from *prComment) *scm.Comment { + return &scm.Comment{ + ID: from.ID, + Body: from.Content.Raw, + Author: scm.User{ + ID: from.User.UUID, + Login: from.User.Nickname, + Name: from.User.DisplayName, + Avatar: from.User.Links.Avatar.Href, + }, + Created: from.CreatedOn, + Updated: from.UpdatedOn, + } +} diff --git a/scm/driver/bitbucket/pr_test.go b/scm/driver/bitbucket/pr_test.go index 00f112f75..038ec1952 100644 --- a/scm/driver/bitbucket/pr_test.go +++ b/scm/driver/bitbucket/pr_test.go @@ -175,3 +175,53 @@ func TestPullListCommits(t *testing.T) { t.Log(diff) } } + +func TestPullRequestCommentFind(t *testing.T) { + _, _, err := NewDefault().PullRequests.FindComment(context.Background(), "", 0, 0) + if err != scm.ErrNotSupported { + t.Errorf("Expect Not Supported error") + } +} + +func TestPullRequestListComments(t *testing.T) { + _, _, err := NewDefault().PullRequests.ListComments(context.Background(), "", 0, scm.ListOptions{}) + if err != scm.ErrNotSupported { + t.Errorf("Expect Not Supported error") + } +} + +func TestPullRequestCreateComment(t *testing.T) { + defer gock.Off() + + gock.New("https://api.bitbucket.org"). + Post("/2.0/repositories/atlassian/atlaskit/pullrequests/12"). + Reply(201). + Type("application/json"). + File("testdata/prcomment.json") + + input := &scm.CommentInput{ + Body: "Lovely comment", + } + + client, _ := New("https://api.bitbucket.org") + got, _, err := client.PullRequests.CreateComment(context.Background(), "atlassian/atlaskit", 12, input) + if err != nil { + t.Error(err) + } + + want := new(scm.Comment) + raw, _ := ioutil.ReadFile("testdata/prcomment.json.golden") + json.Unmarshal(raw, want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestPullRequestCommentDelete(t *testing.T) { + _, err := NewDefault().PullRequests.DeleteComment(context.Background(), "", 0, 0) + if err != scm.ErrNotSupported { + t.Errorf("Expect Not Supported error") + } +} diff --git a/scm/driver/bitbucket/repo.go b/scm/driver/bitbucket/repo.go index d06d28db1..70fa6b0ee 100644 --- a/scm/driver/bitbucket/repo.go +++ b/scm/driver/bitbucket/repo.go @@ -172,6 +172,29 @@ func (s *repositoryService) List(ctx context.Context, opts scm.ListOptions) ([]* return convertRepositoryList(out), res, err } +// ListV2 returns the user repository list based on the searchTerm passed. +func (s *repositoryService) ListV2(ctx context.Context, opts scm.RepoListOptions) ([]*scm.Repository, *scm.Response, error) { + path := fmt.Sprintf("2.0/repositories?%s", encodeRepoListOptions(opts)) + if opts.ListOptions.URL != "" { + path = opts.ListOptions.URL + } + out := new(repositories) + res, err := s.client.do(ctx, "GET", path, nil, &out) + copyPagination(out.pagination, res) + return convertRepositoryList(out), res, err +} + +func (s *repositoryService) ListNamespace(ctx context.Context, namespace string, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { + path := fmt.Sprintf("2.0/repositories/%s?%s", namespace, encodeListRoleOptions(opts)) + if opts.URL != "" { + path = opts.URL + } + out := new(repositories) + res, err := s.client.do(ctx, "GET", path, nil, &out) + copyPagination(out.pagination, res) + return convertRepositoryList(out), res, err +} + func (s *repositoryService) ListRepoLanguages(context.Context, string) (map[string]float64, *scm.Response, error) { return nil, nil, scm.ErrNotSupported } diff --git a/scm/driver/bitbucket/repo_test.go b/scm/driver/bitbucket/repo_test.go index 6493fdd16..58fc343f2 100644 --- a/scm/driver/bitbucket/repo_test.go +++ b/scm/driver/bitbucket/repo_test.go @@ -143,6 +143,37 @@ func TestRepositoryList(t *testing.T) { } } +func TestRepositoryListV2(t *testing.T) { + defer gock.Off() + + gock.New("https://api.bitbucket.org"). + Get("/2.0/repositories"). + MatchParam("q", "name~\\\"plugin1\\\""). + MatchParam("role", "member"). + Reply(200). + Type("application/json"). + File("testdata/repos_filter.json") + + got := []*scm.Repository{} + opts := scm.RepoListOptions{RepoSearchTerm: scm.RepoSearchTerm{RepoName: "plugin1"}} + client, _ := New("https://api.bitbucket.org") + + repos, _, err := client.Repositories.ListV2(context.Background(), opts) + if err != nil { + t.Error(err) + } + got = append(got, repos...) + + want := []*scm.Repository{} + raw, _ := ioutil.ReadFile("testdata/repos_filter.json.golden") + json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + func TestRepositoryList2(t *testing.T) { defer gock.Off() diff --git a/scm/driver/bitbucket/testdata/branches_filter.json b/scm/driver/bitbucket/testdata/branches_filter.json new file mode 100644 index 000000000..122655ec4 --- /dev/null +++ b/scm/driver/bitbucket/testdata/branches_filter.json @@ -0,0 +1,201 @@ +{ + "pagelen": 30, + "values": [ + { + "type": "branch", + "name": "master", + "links": { + "commits": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/commits\/master" + }, + "self": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/refs\/branches\/master" + }, + "html": { + "href": "https:\/\/bitbucket.org\/atlassian\/stash-example-plugin\/branch\/master" + } + }, + "target": { + "hash": "a6e5e7d797edf751cbd839d6bd4aef86c941eec9", + "repository": { + "links": { + "self": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin" + }, + "html": { + "href": "https:\/\/bitbucket.org\/atlassian\/stash-example-plugin" + }, + "avatar": { + "href": "https:\/\/bytebucket.org\/ravatar\/%7B7dd600e6-0d9c-4801-b967-cb4cc17359ff%7D?ts=default" + } + }, + "type": "repository", + "name": "stash-example-plugin", + "full_name": "atlassian\/stash-example-plugin", + "uuid": "{7dd600e6-0d9c-4801-b967-cb4cc17359ff}" + }, + "links": { + "self": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/commit\/a6e5e7d797edf751cbd839d6bd4aef86c941eec9" + }, + "comments": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/commit\/a6e5e7d797edf751cbd839d6bd4aef86c941eec9\/comments" + }, + "patch": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/patch\/a6e5e7d797edf751cbd839d6bd4aef86c941eec9" + }, + "html": { + "href": "https:\/\/bitbucket.org\/atlassian\/stash-example-plugin\/commits\/a6e5e7d797edf751cbd839d6bd4aef86c941eec9" + }, + "diff": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/diff\/a6e5e7d797edf751cbd839d6bd4aef86c941eec9" + }, + "approve": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/commit\/a6e5e7d797edf751cbd839d6bd4aef86c941eec9\/approve" + }, + "statuses": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/commit\/a6e5e7d797edf751cbd839d6bd4aef86c941eec9\/statuses" + } + }, + "author": { + "raw": "Adam Ahmed ", + "type": "author", + "user": { + "username": "aahmed", + "display_name": "Adam Ahmed", + "account_id": "557057:74dc5efb-ffe7-49af-b427-6abc299bb3b9", + "links": { + "self": { + "href": "https:\/\/api.bitbucket.org\/2.0\/users\/aahmed" + }, + "html": { + "href": "https:\/\/bitbucket.org\/aahmed\/" + }, + "avatar": { + "href": "https:\/\/bitbucket.org\/account\/aahmed\/avatar\/32\/" + } + }, + "type": "user", + "uuid": "{3d5de233-98d4-4138-b4af-8678fbb009ad}" + } + }, + "parents": [ + { + "hash": "5be6855032e171280a1acb860d7265c29f40487c", + "type": "commit", + "links": { + "self": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/commit\/5be6855032e171280a1acb860d7265c29f40487c" + }, + "html": { + "href": "https:\/\/bitbucket.org\/atlassian\/stash-example-plugin\/commits\/5be6855032e171280a1acb860d7265c29f40487c" + } + } + } + ], + "date": "2015-08-27T03:25:04+00:00", + "message": "Add Apache 2.0 License\n", + "type": "commit" + } + }, + { + "type": "branch", + "name": "master-patch", + "links": { + "commits": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/commits\/master" + }, + "self": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/refs\/branches\/master" + }, + "html": { + "href": "https:\/\/bitbucket.org\/atlassian\/stash-example-plugin\/branch\/master" + } + }, + "target": { + "hash": "a6e5e7d797edf751cbd839d6bd4aef86c941eec8", + "repository": { + "links": { + "self": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin" + }, + "html": { + "href": "https:\/\/bitbucket.org\/atlassian\/stash-example-plugin" + }, + "avatar": { + "href": "https:\/\/bytebucket.org\/ravatar\/%7B7dd600e6-0d9c-4801-b967-cb4cc17359ff%7D?ts=default" + } + }, + "type": "repository", + "name": "stash-example-plugin", + "full_name": "atlassian\/stash-example-plugin", + "uuid": "{7dd600e6-0d9c-4801-b967-cb4cc17359ff}" + }, + "links": { + "self": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/commit\/a6e5e7d797edf751cbd839d6bd4aef86c941eec9" + }, + "comments": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/commit\/a6e5e7d797edf751cbd839d6bd4aef86c941eec9\/comments" + }, + "patch": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/patch\/a6e5e7d797edf751cbd839d6bd4aef86c941eec9" + }, + "html": { + "href": "https:\/\/bitbucket.org\/atlassian\/stash-example-plugin\/commits\/a6e5e7d797edf751cbd839d6bd4aef86c941eec9" + }, + "diff": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/diff\/a6e5e7d797edf751cbd839d6bd4aef86c941eec9" + }, + "approve": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/commit\/a6e5e7d797edf751cbd839d6bd4aef86c941eec9\/approve" + }, + "statuses": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/commit\/a6e5e7d797edf751cbd839d6bd4aef86c941eec9\/statuses" + } + }, + "author": { + "raw": "Adam Ahmed ", + "type": "author", + "user": { + "username": "aahmed", + "display_name": "Adam Ahmed", + "account_id": "557057:74dc5efb-ffe7-49af-b427-6abc299bb3b9", + "links": { + "self": { + "href": "https:\/\/api.bitbucket.org\/2.0\/users\/aahmed" + }, + "html": { + "href": "https:\/\/bitbucket.org\/aahmed\/" + }, + "avatar": { + "href": "https:\/\/bitbucket.org\/account\/aahmed\/avatar\/32\/" + } + }, + "type": "user", + "uuid": "{3d5de233-98d4-4138-b4af-8678fbb009ad}" + } + }, + "parents": [ + { + "hash": "5be6855032e171280a1acb860d7265c29f40487c", + "type": "commit", + "links": { + "self": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin\/commit\/5be6855032e171280a1acb860d7265c29f40487c" + }, + "html": { + "href": "https:\/\/bitbucket.org\/atlassian\/stash-example-plugin\/commits\/5be6855032e171280a1acb860d7265c29f40487c" + } + } + } + ], + "date": "2015-08-27T03:25:04+00:00", + "message": "Add Apache 2.0 License\n", + "type": "commit" + } + } + ], + "page": 1, + "next": "https:\/\/bitbucket.org\/atlassian\/stash-example-plugin\/refs\/branches?pagelen=30&page=2" +} \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/branches_filter.json.golden b/scm/driver/bitbucket/testdata/branches_filter.json.golden new file mode 100644 index 000000000..79754a78f --- /dev/null +++ b/scm/driver/bitbucket/testdata/branches_filter.json.golden @@ -0,0 +1,12 @@ +[ + { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "a6e5e7d797edf751cbd839d6bd4aef86c941eec9" + }, + { + "Name": "master-patch", + "Path": "refs/heads/master-patch", + "Sha": "a6e5e7d797edf751cbd839d6bd4aef86c941eec8" + } +] \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/pr.json.golden b/scm/driver/bitbucket/testdata/pr.json.golden index 8132df37f..1ed8a643f 100644 --- a/scm/driver/bitbucket/testdata/pr.json.golden +++ b/scm/driver/bitbucket/testdata/pr.json.golden @@ -22,7 +22,7 @@ "Name": "Lachlan-Vass/ios-date-picker-component-duplicate-marc-1579222909688" }, "Author": { - "Login": "Lachlan", + "ID": "5c7c7b1a0b79db7c3e33eca2", "Name": "Lachlan Vass", "Avatar": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/5c7c7b1a0b79db7c3e33eca2/6b6b8178-0da0-4a37-b0dd-f8b5e3628eaa/128" }, diff --git a/scm/driver/bitbucket/testdata/prcomment.json b/scm/driver/bitbucket/testdata/prcomment.json new file mode 100644 index 000000000..953b2d158 --- /dev/null +++ b/scm/driver/bitbucket/testdata/prcomment.json @@ -0,0 +1,52 @@ +{ + "id": 419169807, + "created_on": "2023-08-14T11:38:53.460132+00:00", + "updated_on": "2023-08-14T11:38:53.460205+00:00", + "content": { + "type": "rendered", + "raw": "Lovely comment", + "markup": "markdown", + "html": "

Lovely comment<\/p>" + }, + "user": { + "display_name": "Brian Jacobson", + "links": { + "self": { + "href": "https:\/\/bitbucket.org\/!api\/2.0\/users\/%7B6dff94-1b8b-4f62-b37f-3069e13dfdf33e%7D" + }, + "avatar": { + "href": "http:\/\/localhost:3000\/avatars\/1" + }, + "html": { + "href": "https:\/\/bitbucket.org\/%7B6dff94-1b8b-4f62-b37f-3069e13dfdf33e%7D\/" + } + }, + "type": "user", + "uuid": "{6b408a94-1b8b-4f62-b37f-3069e13bc33e}", + "account_id": "60259ce8164527007100d945", + "nickname": "brian.jacobson" + }, + "deleted": false, + "type": "pullrequest_comment", + "links": { + "self": { + "href": "https:\/\/bitbucket.org\/!api\/2.0\/repositories\/brianharness\/test\/pullrequests\/3\/comments\/419169807" + }, + "html": { + "href": "https:\/\/bitbucket.org\/brianharness\/test\/pull-requests\/3\/_\/diff#comment-419169807" + } + }, + "pullrequest": { + "type": "pullrequest", + "id": 3, + "title": "README.md edited online with Bitbucket", + "links": { + "self": { + "href": "https:\/\/bitbucket.org\/!api\/2.0\/repositories\/brianharness\/test\/pullrequests\/3" + }, + "html": { + "href": "https:\/\/bitbucket.org\/brianharness\/test\/pull-requests\/3" + } + } + } +} \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/prcomment.json.golden b/scm/driver/bitbucket/testdata/prcomment.json.golden new file mode 100644 index 000000000..e6dea457a --- /dev/null +++ b/scm/driver/bitbucket/testdata/prcomment.json.golden @@ -0,0 +1,12 @@ +{ + "ID": 419169807, + "Body": "Lovely comment", + "Author": { + "ID": "{6b408a94-1b8b-4f62-b37f-3069e13bc33e}", + "Login": "brian.jacobson", + "Name": "Brian Jacobson", + "Avatar": "http://localhost:3000/avatars/1" + }, + "Created": "2023-08-14T11:38:53.460132+00:00", + "Updated": "2023-08-14T11:38:53.460205+00:00" +} diff --git a/scm/driver/bitbucket/testdata/prs.json.golden b/scm/driver/bitbucket/testdata/prs.json.golden index 29cafe903..90a246041 100644 --- a/scm/driver/bitbucket/testdata/prs.json.golden +++ b/scm/driver/bitbucket/testdata/prs.json.golden @@ -23,7 +23,7 @@ "Name": "Lachlan-Vass/ios-date-picker-component-duplicate-marc-1579222909688" }, "Author": { - "Login": "Lachlan", + "ID": "5c7c7b1a0b79db7c3e33eca2", "Name": "Lachlan Vass", "Avatar": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/5c7c7b1a0b79db7c3e33eca2/6b6b8178-0da0-4a37-b0dd-f8b5e3628eaa/128" }, diff --git a/scm/driver/bitbucket/testdata/repos_filter.json b/scm/driver/bitbucket/testdata/repos_filter.json new file mode 100644 index 000000000..df610e1f4 --- /dev/null +++ b/scm/driver/bitbucket/testdata/repos_filter.json @@ -0,0 +1,110 @@ +{ + "pagelen": 1, + "values": [ + { + "scm": "git", + "website": "", + "has_wiki": false, + "uuid": "{7dd600e6-0d9c-4801-b967-cb4cc17359ff}", + "links": { + "watchers": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/watchers" + }, + "branches": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/refs\/branches" + }, + "tags": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/refs\/tags" + }, + "commits": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/commits" + }, + "clone": [ + { + "href": "https:\/\/brydzewski@bitbucket.org\/atlassian\/stash-example-plugin1.git", + "name": "https" + }, + { + "href": "git@bitbucket.org:atlassian\/stash-example-plugin1.git", + "name": "ssh" + } + ], + "self": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1" + }, + "source": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/src" + }, + "html": { + "href": "https:\/\/bitbucket.org\/atlassian\/stash-example-plugin1" + }, + "avatar": { + "href": "https:\/\/bytebucket.org\/ravatar\/%7B7dd600e6-0d9c-4801-b967-cb4cc17359ff%7D?ts=default" + }, + "hooks": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/hooks" + }, + "forks": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/forks" + }, + "downloads": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/downloads" + }, + "pullrequests": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/pullrequests" + } + }, + "fork_policy": "allow_forks", + "name": "stash-example-plugin1", + "project": { + "key": "PROJ", + "type": "project", + "uuid": "{8b56daff-dbc7-4cae-a7a3-1228c526906b}", + "links": { + "self": { + "href": "https:\/\/api.bitbucket.org\/2.0\/teams\/atlassian\/projects\/PROJ" + }, + "html": { + "href": "https:\/\/bitbucket.org\/account\/user\/atlassian\/projects\/PROJ" + }, + "avatar": { + "href": "https:\/\/bitbucket.org\/account\/user\/atlassian\/projects\/PROJ\/avatar\/32" + } + }, + "name": "Project: Atlassian" + }, + "language": "", + "created_on": "2013-04-15T03:05:05.595458+00:00", + "mainbranch": { + "type": "branch", + "name": "master" + }, + "full_name": "atlassian\/stash-example-plugin1", + "has_issues": false, + "owner": { + "username": "atlassian", + "display_name": "Atlassian", + "type": "team", + "uuid": "{02b941e3-cfaa-40f9-9a58-cec53e20bdc3}", + "links": { + "self": { + "href": "https:\/\/api.bitbucket.org\/2.0\/teams\/atlassian" + }, + "html": { + "href": "https:\/\/bitbucket.org\/atlassian\/" + }, + "avatar": { + "href": "https:\/\/bitbucket.org\/account\/atlassian\/avatar\/32\/" + } + } + }, + "updated_on": "2018-04-01T16:36:35.970175+00:00", + "size": 1116345, + "type": "repository", + "slug": "stash-example-plugin1", + "is_private": true, + "description": "Examples on how to decorate various pages around Stash." + } + ], + "next": "https:\/\/api.bitbucket.org\/2.0\/repositories?pagelen=1&after=PLACEHOLDER&role=member" +} \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/repos_filter.json.golden b/scm/driver/bitbucket/testdata/repos_filter.json.golden new file mode 100644 index 000000000..cf1ace3ba --- /dev/null +++ b/scm/driver/bitbucket/testdata/repos_filter.json.golden @@ -0,0 +1,15 @@ +[ + { + "ID": "{7dd600e6-0d9c-4801-b967-cb4cc17359ff}", + "Namespace": "atlassian", + "Name": "stash-example-plugin1", + "Perm": null, + "Branch": "master", + "Private": true, + "Clone": "https://bitbucket.org/atlassian/stash-example-plugin1.git", + "CloneSSH": "git@bitbucket.org:atlassian/stash-example-plugin1.git", + "Link": "https://bitbucket.org/atlassian/stash-example-plugin1", + "Created": "2013-04-15T03:05:05.595458Z", + "Updated": "2018-04-01T16:36:35.970175Z" + } +] \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/tags.json.golden b/scm/driver/bitbucket/testdata/tags.json.golden index 8cb6251e0..0e0e95ed0 100644 --- a/scm/driver/bitbucket/testdata/tags.json.golden +++ b/scm/driver/bitbucket/testdata/tags.json.golden @@ -1,7 +1,7 @@ [ { - "Name": "@atlaskit/activity@1.0.3", - "Path": "refs/tags/@atlaskit/activity@1.0.3", + "Name": "@atlaskit\/activity@1.0.3", + "Path": "refs/tags/@atlaskit\/activity@1.0.3", "Sha": "ceb01356c3f062579bdfeb15bc53fe151b9e00f0" } ] \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/userEmail.json b/scm/driver/bitbucket/testdata/userEmail.json new file mode 100644 index 000000000..80e1c227a --- /dev/null +++ b/scm/driver/bitbucket/testdata/userEmail.json @@ -0,0 +1,8 @@ +{ + "Values": [ + { + "email": "test@harness.io", + "is_primary": true + } + ] +} \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_created.json b/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_created.json new file mode 100644 index 000000000..02c506c67 --- /dev/null +++ b/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_created.json @@ -0,0 +1,175 @@ +{ + "repository": { + "type": "repository", + "full_name": "automationtestharness/testrepo", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/testrepo" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B2b922c6d-3824-4e91-a7be-90c8b8392f84%7D?ts=default" + } + }, + "name": "testRepo", + "scm": "git", + "website": null, + "owner": { + "display_name": "Automationtestharness", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/%7B612f7b18-b167-4bff-8ee9-d43570117ff1%7D" + }, + "avatar": { + "href": "https://bitbucket.org/account/automationtestharness/avatar/" + }, + "html": { + "href": "https://bitbucket.org/%7B612f7b18-b167-4bff-8ee9-d43570117ff1%7D/" + } + }, + "type": "team", + "uuid": "{612f7b18-b167-4bff-8ee9-d43570117ff1}", + "username": "automationtestharness" + }, + "workspace": { + "type": "workspace", + "uuid": "{612f7b18-b167-4bff-8ee9-d43570117ff1}", + "name": "Automationtestharness", + "slug": "automationtestharness", + "links": { + "avatar": { + "href": "https://bitbucket.org/workspaces/automationtestharness/avatar/?ts=1740994558" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/" + }, + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/automationtestharness" + } + } + }, + "is_private": true, + "project": { + "type": "project", + "key": "TEST", + "uuid": "{af6d7f47-6ce6-48b6-9beb-d5ad6b674ba0}", + "name": "test", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/automationtestharness/projects/TEST" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/workspace/projects/TEST" + }, + "avatar": { + "href": "https://bitbucket.org/automationtestharness/workspace/projects/TEST/avatar/32?ts=1738907820" + } + } + }, + "uuid": "{2b922c6d-3824-4e91-a7be-90c8b8392f84}", + "parent": null + }, + "actor": { + "display_name": "Automationtestharness", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/%7B612f7b18-b167-4bff-8ee9-d43570117ff1%7D" + }, + "avatar": { + "href": "https://bitbucket.org/account/automationtestharness/avatar/" + }, + "html": { + "href": "https://bitbucket.org/%7B612f7b18-b167-4bff-8ee9-d43570117ff1%7D/" + } + }, + "type": "team", + "uuid": "{612f7b18-b167-4bff-8ee9-d43570117ff1}", + "username": "automationtestharness" + }, + "commit_status": { + "key": "3343801", + "type": "build", + "state": "INPROGRESS", + "name": "Pipeline #4 for main", + "refname": "main", + "commit": { + "type": "commit", + "hash": "bdf6fac0519ffd1562461eb82e018ff62efffbc9", + "date": "2025-03-24T08:48:15+00:00", + "author": { + "type": "author", + "raw": "Shivam Negi ", + "user": { + "display_name": "Shivam Negi", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7Bce7d5dfc-83c9-4878-beaf-7b91610e104a%7D" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/39b64ab2df0f61fcce00db05f94c600b?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FSN-2.png" + }, + "html": { + "href": "https://bitbucket.org/%7Bce7d5dfc-83c9-4878-beaf-7b91610e104a%7D/" + } + }, + "type": "user", + "uuid": "{ce7d5dfc-83c9-4878-beaf-7b91610e104a}", + "account_id": "601ba1bdb7bda90068ed5d1b", + "nickname": "Shivam Negi" + } + }, + "message": "Merged in Shivam-Negi/testyaml-edited-online-with-bitbucket-1742806076994 (pull request #13)\n\ntest.yaml edited online with Bitbucket\n", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/testrepo/commits/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + }, + "diff": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/diff/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + }, + "approve": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9/approve" + }, + "comments": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9/comments" + }, + "statuses": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9/statuses" + } + } + }, + "url": "https://bitbucket.org/automationtestharness/testrepo/addon/pipelines/home#!/results/4", + "repository": { + "type": "repository", + "full_name": "automationtestharness/testrepo", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/testrepo" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B2b922c6d-3824-4e91-a7be-90c8b8392f84%7D?ts=default" + } + }, + "name": "testRepo", + "uuid": "{2b922c6d-3824-4e91-a7be-90c8b8392f84}" + }, + "description": "", + "created_on": "2025-03-24T08:48:56.572438+00:00", + "updated_on": "2025-03-24T08:48:56.572450+00:00", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9/statuses/build/3343801" + }, + "commit": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + } + } + } + } \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_created.json.golden b/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_created.json.golden new file mode 100644 index 000000000..b0e6c2a38 --- /dev/null +++ b/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_created.json.golden @@ -0,0 +1,39 @@ +{ + "Repo": { + "ID": "{2b922c6d-3824-4e91-a7be-90c8b8392f84}", + "Namespace": "automationtestharness", + "Name": "testrepo", + "Clone": "https://bitbucket.org/automationtestharness/testrepo", + "CloneSSH": "", + "Branch": "main", + "Private": true + }, + "Commit": { + "Sha": "bdf6fac0519ffd1562461eb82e018ff62efffbc9", + "Message": "Merged in Shivam-Negi/testyaml-edited-online-with-bitbucket-1742806076994 (pull request #13)\n\ntest.yaml edited online with Bitbucket\n", + "Author": { + "Name": "Shivam Negi", + "Email": "shivamnegi94@gmail.com", + "Avatar": "https://secure.gravatar.com/avatar/39b64ab2df0f61fcce00db05f94c600b?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FSN-2.png" + }, + "Committer": { + "Name": "Shivam Negi", + "Email": "shivamnegi94@gmail.com", + "Avatar": "https://secure.gravatar.com/avatar/39b64ab2df0f61fcce00db05f94c600b?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FSN-2.png" + }, + "Link": "https://bitbucket.org/automationtestharness/testrepo/commits/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + }, + "Execution": { + "Number": 4, + "Status": "running", + "Created": "2025-03-24T08:48:56.572438+00:00", + "URL": "https://bitbucket.org/automationtestharness/testrepo/addon/pipelines/home#!/results/4" + }, + "Sender": { + "Login": "automationtestharness", + "Name": "Automationtestharness", + "Email": "", + "Avatar": "https://bitbucket.org/account/automationtestharness/avatar/", + "ID": "{612f7b18-b167-4bff-8ee9-d43570117ff1}" + } +} diff --git a/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_update.json b/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_update.json new file mode 100644 index 000000000..10655dd05 --- /dev/null +++ b/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_update.json @@ -0,0 +1,175 @@ +{ + "repository": { + "type": "repository", + "full_name": "automationtestharness/testrepo", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/testrepo" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B2b922c6d-3824-4e91-a7be-90c8b8392f84%7D?ts=default" + } + }, + "name": "testRepo", + "scm": "git", + "website": null, + "owner": { + "display_name": "Automationtestharness", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/%7B612f7b18-b167-4bff-8ee9-d43570117ff1%7D" + }, + "avatar": { + "href": "https://bitbucket.org/account/automationtestharness/avatar/" + }, + "html": { + "href": "https://bitbucket.org/%7B612f7b18-b167-4bff-8ee9-d43570117ff1%7D/" + } + }, + "type": "team", + "uuid": "{612f7b18-b167-4bff-8ee9-d43570117ff1}", + "username": "automationtestharness" + }, + "workspace": { + "type": "workspace", + "uuid": "{612f7b18-b167-4bff-8ee9-d43570117ff1}", + "name": "Automationtestharness", + "slug": "automationtestharness", + "links": { + "avatar": { + "href": "https://bitbucket.org/workspaces/automationtestharness/avatar/?ts=1740994558" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/" + }, + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/automationtestharness" + } + } + }, + "is_private": true, + "project": { + "type": "project", + "key": "TEST", + "uuid": "{af6d7f47-6ce6-48b6-9beb-d5ad6b674ba0}", + "name": "test", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/automationtestharness/projects/TEST" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/workspace/projects/TEST" + }, + "avatar": { + "href": "https://bitbucket.org/automationtestharness/workspace/projects/TEST/avatar/32?ts=1738907820" + } + } + }, + "uuid": "{2b922c6d-3824-4e91-a7be-90c8b8392f84}", + "parent": null + }, + "actor": { + "display_name": "Automationtestharness", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/%7B612f7b18-b167-4bff-8ee9-d43570117ff1%7D" + }, + "avatar": { + "href": "https://bitbucket.org/account/automationtestharness/avatar/" + }, + "html": { + "href": "https://bitbucket.org/%7B612f7b18-b167-4bff-8ee9-d43570117ff1%7D/" + } + }, + "type": "team", + "uuid": "{612f7b18-b167-4bff-8ee9-d43570117ff1}", + "username": "automationtestharness" + }, + "commit_status": { + "key": "3343801", + "type": "build", + "state": "SUCCESSFUL", + "name": "Pipeline #4 for main", + "refname": "main", + "commit": { + "type": "commit", + "hash": "bdf6fac0519ffd1562461eb82e018ff62efffbc9", + "date": "2025-03-24T08:48:15+00:00", + "author": { + "type": "author", + "raw": "Shivam Negi ", + "user": { + "display_name": "Shivam Negi", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7Bce7d5dfc-83c9-4878-beaf-7b91610e104a%7D" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/39b64ab2df0f61fcce00db05f94c600b?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FSN-2.png" + }, + "html": { + "href": "https://bitbucket.org/%7Bce7d5dfc-83c9-4878-beaf-7b91610e104a%7D/" + } + }, + "type": "user", + "uuid": "{ce7d5dfc-83c9-4878-beaf-7b91610e104a}", + "account_id": "601ba1bdb7bda90068ed5d1b", + "nickname": "Shivam Negi" + } + }, + "message": "Merged in Shivam-Negi/testyaml-edited-online-with-bitbucket-1742806076994 (pull request #13)\n\ntest.yaml edited online with Bitbucket\n", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/testrepo/commits/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + }, + "diff": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/diff/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + }, + "approve": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9/approve" + }, + "comments": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9/comments" + }, + "statuses": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9/statuses" + } + } + }, + "url": "https://bitbucket.org/automationtestharness/testrepo/addon/pipelines/home#!/results/4", + "repository": { + "type": "repository", + "full_name": "automationtestharness/testrepo", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/testrepo" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B2b922c6d-3824-4e91-a7be-90c8b8392f84%7D?ts=default" + } + }, + "name": "testRepo", + "uuid": "{2b922c6d-3824-4e91-a7be-90c8b8392f84}" + }, + "description": "", + "created_on": "2025-03-24T08:48:56.572438+00:00", + "updated_on": "2025-03-24T08:49:42.838984+00:00", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9/statuses/build/3343801" + }, + "commit": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + } + } + } + } \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_update.json.golden b/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_update.json.golden new file mode 100644 index 000000000..1b0b7623f --- /dev/null +++ b/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_update.json.golden @@ -0,0 +1,39 @@ +{ + "Repo": { + "ID": "{2b922c6d-3824-4e91-a7be-90c8b8392f84}", + "Namespace": "automationtestharness", + "Name": "testrepo", + "Clone": "https://bitbucket.org/automationtestharness/testrepo", + "CloneSSH": "", + "Branch": "main", + "Private": true + }, + "Commit": { + "Sha": "bdf6fac0519ffd1562461eb82e018ff62efffbc9", + "Message": "Merged in Shivam-Negi/testyaml-edited-online-with-bitbucket-1742806076994 (pull request #13)\n\ntest.yaml edited online with Bitbucket\n", + "Author": { + "Name": "Shivam Negi", + "Email": "shivamnegi94@gmail.com", + "Avatar": "https://secure.gravatar.com/avatar/39b64ab2df0f61fcce00db05f94c600b?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FSN-2.png" + }, + "Committer": { + "Name": "Shivam Negi", + "Email": "shivamnegi94@gmail.com", + "Avatar": "https://secure.gravatar.com/avatar/39b64ab2df0f61fcce00db05f94c600b?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FSN-2.png" + }, + "Link": "https://bitbucket.org/automationtestharness/testrepo/commits/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + }, + "Execution": { + "Number": 4, + "Status": "success", + "Created": "2025-03-24T08:48:56.572438+00:00", + "URL": "https://bitbucket.org/automationtestharness/testrepo/addon/pipelines/home#!/results/4" + }, + "Sender": { + "Login": "automationtestharness", + "Name": "Automationtestharness", + "Email": "", + "Avatar": "https://bitbucket.org/account/automationtestharness/avatar/", + "ID": "{612f7b18-b167-4bff-8ee9-d43570117ff1}" + } +} diff --git a/scm/driver/bitbucket/testdata/webhooks/pr_comment_created.json b/scm/driver/bitbucket/testdata/webhooks/pr_comment_created.json new file mode 100644 index 000000000..b13056f91 --- /dev/null +++ b/scm/driver/bitbucket/testdata/webhooks/pr_comment_created.json @@ -0,0 +1,331 @@ +{ + "comment": { + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/comments/311512047" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba/pull-requests/1/_/diff#comment-311512047" + } + }, + "deleted": false, + "pullrequest": { + "type": "pullrequest", + "id": 1, + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba/pull-requests/1" + } + }, + "title": "Update pom.xml" + }, + "content": { + "raw": "test comment", + "markup": "markdown", + "html": "

test comment

", + "type": "rendered" + }, + "created_on": "2022-06-23T22:10:09.939925+00:00", + "user": { + "display_name": "Rutvij Mehta", + "uuid": "{145a94da-035e-42d6-bf85-296cea8005ba}", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D" + }, + "html": { + "href": "https://bitbucket.org/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D/" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/1bf4d1258f18330b314d2737db430cb0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRM-5.png" + } + }, + "type": "user", + "nickname": "Rutvij Mehta", + "account_id": "624de6f6fd5e450070486936" + }, + "updated_on": "2022-06-23T22:10:09.939978+00:00", + "type": "pullrequest_comment", + "id": 311512047 + }, + "pullrequest": { + "rendered": { + "description": { + "raw": "Test", + "markup": "markdown", + "html": "

Test

", + "type": "rendered" + }, + "title": { + "raw": "Update pom.xml", + "markup": "markdown", + "html": "

Update pom.xml

", + "type": "rendered" + } + }, + "type": "pullrequest", + "description": "Test", + "links": { + "decline": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/decline" + }, + "diffstat": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/diffstat/rutvijmehta-harness/spring-cloud-alibaba:b9437f32dddd%0Dcfd2d864e389?from_pullrequest_id=1&topic=true" + }, + "commits": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/commits" + }, + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1" + }, + "comments": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/comments" + }, + "merge": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/merge" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba/pull-requests/1" + }, + "activity": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/activity" + }, + "request-changes": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/request-changes" + }, + "diff": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/diff/rutvijmehta-harness/spring-cloud-alibaba:b9437f32dddd%0Dcfd2d864e389?from_pullrequest_id=1&topic=true" + }, + "approve": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/approve" + }, + "statuses": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/statuses" + } + }, + "title": "Update pom.xml", + "close_source_branch": false, + "reviewers": [], + "id": 1, + "destination": { + "commit": { + "hash": "cfd2d864e389", + "type": "commit", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/commit/cfd2d864e389" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba/commits/cfd2d864e389" + } + } + }, + "repository": { + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B4402cbae-7790-453a-b29e-5fcab61a84df%7D?ts=default" + } + }, + "type": "repository", + "name": "spring-cloud-alibaba", + "full_name": "rutvijmehta-harness/spring-cloud-alibaba", + "uuid": "{4402cbae-7790-453a-b29e-5fcab61a84df}" + }, + "branch": { + "name": "2021.x" + } + }, + "created_on": "2022-06-23T19:27:25.443049+00:00", + "summary": { + "raw": "Test", + "markup": "markdown", + "html": "

Test

", + "type": "rendered" + }, + "source": { + "commit": { + "hash": "b9437f32dddd", + "type": "commit", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/commit/b9437f32dddd" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba/commits/b9437f32dddd" + } + } + }, + "repository": { + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B4402cbae-7790-453a-b29e-5fcab61a84df%7D?ts=default" + } + }, + "type": "repository", + "name": "spring-cloud-alibaba", + "full_name": "rutvijmehta-harness/spring-cloud-alibaba", + "uuid": "{4402cbae-7790-453a-b29e-5fcab61a84df}" + }, + "branch": { + "name": "tiwhitepaper-rutvij" + } + }, + "comment_count": 1, + "state": "OPEN", + "task_count": 0, + "participants": [ + { + "participated_on": "2022-06-23T22:10:09.939978+00:00", + "state": null, + "role": "PARTICIPANT", + "user": { + "display_name": "Rutvij Mehta", + "uuid": "{145a94da-035e-42d6-bf85-296cea8005ba}", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D" + }, + "html": { + "href": "https://bitbucket.org/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D/" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/1bf4d1258f18330b314d2737db430cb0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRM-5.png" + } + }, + "type": "user", + "nickname": "Rutvij Mehta", + "account_id": "624de6f6fd5e450070486936" + }, + "type": "participant", + "approved": false + } + ], + "reason": "", + "updated_on": "2022-06-23T22:10:09.939978+00:00", + "author": { + "display_name": "Rutvij Mehta", + "uuid": "{145a94da-035e-42d6-bf85-296cea8005ba}", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D" + }, + "html": { + "href": "https://bitbucket.org/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D/" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/1bf4d1258f18330b314d2737db430cb0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRM-5.png" + } + }, + "type": "user", + "nickname": "Rutvij Mehta", + "account_id": "624de6f6fd5e450070486936" + }, + "merge_commit": null, + "closed_by": null + }, + "repository": { + "scm": "git", + "website": null, + "uuid": "{4402cbae-7790-453a-b29e-5fcab61a84df}", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B4402cbae-7790-453a-b29e-5fcab61a84df%7D?ts=default" + } + }, + "project": { + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/rutvijmehta-harness/projects/TEST" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/workspace/projects/TEST" + }, + "avatar": { + "href": "https://bitbucket.org/account/user/rutvijmehta-harness/projects/TEST/avatar/32?ts=1655023274" + } + }, + "type": "project", + "name": "Test", + "key": "TEST", + "uuid": "{aa857cae-daad-4fbd-93ef-503cc3d6c3d6}" + }, + "full_name": "rutvijmehta-harness/spring-cloud-alibaba", + "owner": { + "display_name": "Rutvij Mehta", + "uuid": "{145a94da-035e-42d6-bf85-296cea8005ba}", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D" + }, + "html": { + "href": "https://bitbucket.org/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D/" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/1bf4d1258f18330b314d2737db430cb0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRM-5.png" + } + }, + "type": "user", + "nickname": "Rutvij Mehta", + "account_id": "624de6f6fd5e450070486936" + }, + "workspace": { + "slug": "rutvijmehta-harness", + "type": "workspace", + "name": "Rutvij Mehta", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/rutvijmehta-harness" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/" + }, + "avatar": { + "href": "https://bitbucket.org/workspaces/rutvijmehta-harness/avatar/?ts=1655023237" + } + }, + "uuid": "{145a94da-035e-42d6-bf85-296cea8005ba}" + }, + "type": "repository", + "is_private": false, + "name": "spring-cloud-alibaba" + }, + "actor": { + "display_name": "Rutvij Mehta", + "uuid": "{145a94da-035e-42d6-bf85-296cea8005ba}", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D" + }, + "html": { + "href": "https://bitbucket.org/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D/" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/1bf4d1258f18330b314d2737db430cb0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRM-5.png" + } + }, + "type": "user", + "nickname": "Rutvij Mehta", + "account_id": "624de6f6fd5e450070486936" + } +} \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/webhooks/pr_comment_created.json.golden b/scm/driver/bitbucket/testdata/webhooks/pr_comment_created.json.golden new file mode 100644 index 000000000..f4b06fb9d --- /dev/null +++ b/scm/driver/bitbucket/testdata/webhooks/pr_comment_created.json.golden @@ -0,0 +1,96 @@ +{ + "Action": "created", + "Repo": { + "ID": "{4402cbae-7790-453a-b29e-5fcab61a84df}", + "Namespace": "rutvijmehta-harness", + "Name": "spring-cloud-alibaba", + "Perm": null, + "Branch": "", + "Archived": false, + "Private": false, + "Visibility": 0, + "Clone": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba.git", + "CloneSSH": "git@bitbucket.org:rutvijmehta-harness/spring-cloud-alibaba.git", + "Link": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Issue": { + "Number": 1, + "Title": "Update pom.xml", + "Body": "Test", + "Link": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba/pull-requests/1", + "Labels": null, + "Closed": false, + "Locked": false, + "Author": { + "Login": "", + "Name": "Rutvij Mehta", + "Email": "", + "Avatar": "https://secure.gravatar.com/avatar/1bf4d1258f18330b314d2737db430cb0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRM-5.png", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 1, + "Title": "Update pom.xml", + "Body": "Test", + "Sha": "b9437f32dddd", + "Ref": "refs/pull-requests/1/from", + "Source": "tiwhitepaper-rutvij", + "Target": "2021.x", + "Fork": "rutvijmehta-harness/spring-cloud-alibaba", + "Link": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba/pull-requests/1", + "Diff": "", + "Closed": false, + "Merged": false, + "Base": { + "Name": "", + "Path": "", + "Sha": "" + }, + "Head": { + "Name": "", + "Path": "", + "Sha": "" + }, + "Author": { + "Login": "", + "Name": "Rutvij Mehta", + "Email": "", + "Avatar": "https://secure.gravatar.com/avatar/1bf4d1258f18330b314d2737db430cb0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRM-5.png", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Created": "2022-06-23T19:27:25.443049Z", + "Updated": "2022-06-23T22:10:09.939978Z", + "Labels": null + }, + "Created": "2022-06-23T19:27:25.443049Z", + "Updated": "2022-06-23T22:10:09.939978Z" + }, + "Comment": { + "ID": 311512047, + "Body": "test comment", + "Author": { + "ID": "{145a94da-035e-42d6-bf85-296cea8005ba}", + "Login": "", + "Name": "Rutvij Mehta", + "Email": "", + "Avatar": "https://secure.gravatar.com/avatar/1bf4d1258f18330b314d2737db430cb0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRM-5.png", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Created": "2022-06-23T22:10:09.939925Z", + "Updated": "2022-06-23T22:10:09.939978Z" + }, + "Sender": { + "ID": "{145a94da-035e-42d6-bf85-296cea8005ba}", + "Login": "", + "Name": "Rutvij Mehta", + "Email": "", + "Avatar": "https://secure.gravatar.com/avatar/1bf4d1258f18330b314d2737db430cb0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRM-5.png", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + } +} \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/webhooks/pr_comment_deleted.json b/scm/driver/bitbucket/testdata/webhooks/pr_comment_deleted.json new file mode 100644 index 000000000..23b3f0e3b --- /dev/null +++ b/scm/driver/bitbucket/testdata/webhooks/pr_comment_deleted.json @@ -0,0 +1,305 @@ +{ + "comment": { + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/comments/311512047" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba/pull-requests/1/_/diff#comment-311512047" + } + }, + "deleted": true, + "pullrequest": { + "type": "pullrequest", + "id": 1, + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba/pull-requests/1" + } + }, + "title": "Update pom.xml" + }, + "content": { + "raw": "", + "markup": "markdown", + "html": "", + "type": "rendered" + }, + "created_on": "2022-06-23T22:10:09.939925+00:00", + "user": { + "display_name": "Rutvij Mehta", + "uuid": "{145a94da-035e-42d6-bf85-296cea8005ba}", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D" + }, + "html": { + "href": "https://bitbucket.org/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D/" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/1bf4d1258f18330b314d2737db430cb0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRM-5.png" + } + }, + "type": "user", + "nickname": "Rutvij Mehta", + "account_id": "624de6f6fd5e450070486936" + }, + "updated_on": "2022-06-24T01:38:47.831843+00:00", + "type": "pullrequest_comment", + "id": 311512047 + }, + "pullrequest": { + "rendered": { + "description": { + "raw": "Test", + "markup": "markdown", + "html": "

Test

", + "type": "rendered" + }, + "title": { + "raw": "Update pom.xml", + "markup": "markdown", + "html": "

Update pom.xml

", + "type": "rendered" + } + }, + "type": "pullrequest", + "description": "Test", + "links": { + "decline": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/decline" + }, + "diffstat": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/diffstat/rutvijmehta-harness/spring-cloud-alibaba:b9437f32dddd%0Dcfd2d864e389?from_pullrequest_id=1&topic=true" + }, + "commits": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/commits" + }, + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1" + }, + "comments": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/comments" + }, + "merge": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/merge" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba/pull-requests/1" + }, + "activity": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/activity" + }, + "request-changes": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/request-changes" + }, + "diff": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/diff/rutvijmehta-harness/spring-cloud-alibaba:b9437f32dddd%0Dcfd2d864e389?from_pullrequest_id=1&topic=true" + }, + "approve": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/approve" + }, + "statuses": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/pullrequests/1/statuses" + } + }, + "title": "Update pom.xml", + "close_source_branch": false, + "reviewers": [], + "id": 1, + "destination": { + "commit": { + "hash": "cfd2d864e389", + "type": "commit", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/commit/cfd2d864e389" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba/commits/cfd2d864e389" + } + } + }, + "repository": { + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B4402cbae-7790-453a-b29e-5fcab61a84df%7D?ts=default" + } + }, + "type": "repository", + "name": "spring-cloud-alibaba", + "full_name": "rutvijmehta-harness/spring-cloud-alibaba", + "uuid": "{4402cbae-7790-453a-b29e-5fcab61a84df}" + }, + "branch": { + "name": "2021.x" + } + }, + "created_on": "2022-06-23T19:27:25.443049+00:00", + "summary": { + "raw": "Test", + "markup": "markdown", + "html": "

Test

", + "type": "rendered" + }, + "source": { + "commit": { + "hash": "b9437f32dddd", + "type": "commit", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba/commit/b9437f32dddd" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba/commits/b9437f32dddd" + } + } + }, + "repository": { + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B4402cbae-7790-453a-b29e-5fcab61a84df%7D?ts=default" + } + }, + "type": "repository", + "name": "spring-cloud-alibaba", + "full_name": "rutvijmehta-harness/spring-cloud-alibaba", + "uuid": "{4402cbae-7790-453a-b29e-5fcab61a84df}" + }, + "branch": { + "name": "tiwhitepaper-rutvij" + } + }, + "comment_count": 0, + "state": "OPEN", + "task_count": 0, + "participants": [], + "reason": "", + "updated_on": "2022-06-24T01:40:18.667126+00:00", + "author": { + "display_name": "Rutvij Mehta", + "uuid": "{145a94da-035e-42d6-bf85-296cea8005ba}", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D" + }, + "html": { + "href": "https://bitbucket.org/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D/" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/1bf4d1258f18330b314d2737db430cb0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRM-5.png" + } + }, + "type": "user", + "nickname": "Rutvij Mehta", + "account_id": "624de6f6fd5e450070486936" + }, + "merge_commit": null, + "closed_by": null + }, + "repository": { + "scm": "git", + "website": null, + "uuid": "{4402cbae-7790-453a-b29e-5fcab61a84df}", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/rutvijmehta-harness/spring-cloud-alibaba" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B4402cbae-7790-453a-b29e-5fcab61a84df%7D?ts=default" + } + }, + "project": { + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/rutvijmehta-harness/projects/TEST" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/workspace/projects/TEST" + }, + "avatar": { + "href": "https://bitbucket.org/account/user/rutvijmehta-harness/projects/TEST/avatar/32?ts=1655023274" + } + }, + "type": "project", + "name": "Test", + "key": "TEST", + "uuid": "{aa857cae-daad-4fbd-93ef-503cc3d6c3d6}" + }, + "full_name": "rutvijmehta-harness/spring-cloud-alibaba", + "owner": { + "display_name": "Rutvij Mehta", + "uuid": "{145a94da-035e-42d6-bf85-296cea8005ba}", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D" + }, + "html": { + "href": "https://bitbucket.org/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D/" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/1bf4d1258f18330b314d2737db430cb0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRM-5.png" + } + }, + "type": "user", + "nickname": "Rutvij Mehta", + "account_id": "624de6f6fd5e450070486936" + }, + "workspace": { + "slug": "rutvijmehta-harness", + "type": "workspace", + "name": "Rutvij Mehta", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/rutvijmehta-harness" + }, + "html": { + "href": "https://bitbucket.org/rutvijmehta-harness/" + }, + "avatar": { + "href": "https://bitbucket.org/workspaces/rutvijmehta-harness/avatar/?ts=1655023237" + } + }, + "uuid": "{145a94da-035e-42d6-bf85-296cea8005ba}" + }, + "type": "repository", + "is_private": false, + "name": "spring-cloud-alibaba" + }, + "actor": { + "display_name": "Rutvij Mehta", + "uuid": "{145a94da-035e-42d6-bf85-296cea8005ba}", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D" + }, + "html": { + "href": "https://bitbucket.org/%7B145a94da-035e-42d6-bf85-296cea8005ba%7D/" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/1bf4d1258f18330b314d2737db430cb0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRM-5.png" + } + }, + "type": "user", + "nickname": "Rutvij Mehta", + "account_id": "624de6f6fd5e450070486936" + } +} \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/webhooks/pr_comment_deleted.json.golden b/scm/driver/bitbucket/testdata/webhooks/pr_comment_deleted.json.golden new file mode 100644 index 000000000..7190b1ff7 --- /dev/null +++ b/scm/driver/bitbucket/testdata/webhooks/pr_comment_deleted.json.golden @@ -0,0 +1,96 @@ +{ + "Action": "deleted", + "Repo": { + "ID": "{4402cbae-7790-453a-b29e-5fcab61a84df}", + "Namespace": "rutvijmehta-harness", + "Name": "spring-cloud-alibaba", + "Perm": null, + "Branch": "", + "Archived": false, + "Private": false, + "Visibility": 0, + "Clone": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba.git", + "CloneSSH": "git@bitbucket.org:rutvijmehta-harness/spring-cloud-alibaba.git", + "Link": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Issue": { + "Number": 1, + "Title": "Update pom.xml", + "Body": "Test", + "Link": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba/pull-requests/1", + "Labels": null, + "Closed": false, + "Locked": false, + "Author": { + "Login": "", + "Name": "Rutvij Mehta", + "Email": "", + "Avatar": "https://secure.gravatar.com/avatar/1bf4d1258f18330b314d2737db430cb0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRM-5.png", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 1, + "Title": "Update pom.xml", + "Body": "Test", + "Sha": "b9437f32dddd", + "Ref": "refs/pull-requests/1/from", + "Source": "tiwhitepaper-rutvij", + "Target": "2021.x", + "Fork": "rutvijmehta-harness/spring-cloud-alibaba", + "Link": "https://bitbucket.org/rutvijmehta-harness/spring-cloud-alibaba/pull-requests/1", + "Diff": "", + "Closed": false, + "Merged": false, + "Base": { + "Name": "", + "Path": "", + "Sha": "" + }, + "Head": { + "Name": "", + "Path": "", + "Sha": "" + }, + "Author": { + "Login": "", + "Name": "Rutvij Mehta", + "Email": "", + "Avatar": "https://secure.gravatar.com/avatar/1bf4d1258f18330b314d2737db430cb0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRM-5.png", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Created": "2022-06-23T19:27:25.443049Z", + "Updated": "2022-06-24T01:40:18.667126Z", + "Labels": null + }, + "Created": "2022-06-23T19:27:25.443049Z", + "Updated": "2022-06-24T01:40:18.667126Z" + }, + "Comment": { + "ID": 311512047, + "Body": "", + "Author": { + "ID": "{145a94da-035e-42d6-bf85-296cea8005ba}", + "Login": "", + "Name": "Rutvij Mehta", + "Email": "", + "Avatar": "https://secure.gravatar.com/avatar/1bf4d1258f18330b314d2737db430cb0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRM-5.png", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Created": "2022-06-23T22:10:09.939925Z", + "Updated": "2022-06-24T01:38:47.831843Z" + }, + "Sender": { + "ID": "{145a94da-035e-42d6-bf85-296cea8005ba}", + "Login": "", + "Name": "Rutvij Mehta", + "Email": "", + "Avatar": "https://secure.gravatar.com/avatar/1bf4d1258f18330b314d2737db430cb0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRM-5.png", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + } +} \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/webhooks/pr_created.json.golden b/scm/driver/bitbucket/testdata/webhooks/pr_created.json.golden index 00825c69a..f1901d6d9 100644 --- a/scm/driver/bitbucket/testdata/webhooks/pr_created.json.golden +++ b/scm/driver/bitbucket/testdata/webhooks/pr_created.json.golden @@ -35,6 +35,7 @@ "Updated": "2018-07-02T21:51:39.532546Z" }, "Sender": { + "ID": "{87bb15eb-47c1-49b3-9f16-ca824a2979a4}", "Login": "brydzewski", "Name": "Brad Rydzewski", "Email": "", diff --git a/scm/driver/bitbucket/testdata/webhooks/pr_declined.json.golden b/scm/driver/bitbucket/testdata/webhooks/pr_declined.json.golden index 395a0bc80..081cf4aff 100644 --- a/scm/driver/bitbucket/testdata/webhooks/pr_declined.json.golden +++ b/scm/driver/bitbucket/testdata/webhooks/pr_declined.json.golden @@ -35,6 +35,7 @@ "Updated": "2018-07-03T01:44:00.030575Z" }, "Sender": { + "ID": "{87bb15eb-47c1-49b3-9f16-ca824a2979a4}", "Login": "brydzewski", "Name": "Brad Rydzewski", "Email": "", diff --git a/scm/driver/bitbucket/testdata/webhooks/pr_fulfilled.json.golden b/scm/driver/bitbucket/testdata/webhooks/pr_fulfilled.json.golden index 1cc60a2f0..642fe2a9f 100644 --- a/scm/driver/bitbucket/testdata/webhooks/pr_fulfilled.json.golden +++ b/scm/driver/bitbucket/testdata/webhooks/pr_fulfilled.json.golden @@ -18,6 +18,7 @@ "Title": "Awesome new feature", "Body": "made some changes", "Sha": "0704fc5beccc", + "Merge": "4f8f6de9d0ff", "Ref": "refs/pull-requests/1/from", "Source": "develop", "Target": "master", @@ -35,6 +36,7 @@ "Updated": "2018-07-03T01:28:05.903251Z" }, "Sender": { + "ID": "{87bb15eb-47c1-49b3-9f16-ca824a2979a4}", "Login": "brydzewski", "Name": "Brad Rydzewski", "Email": "", diff --git a/scm/driver/bitbucket/testdata/webhooks/pr_updated.json.golden b/scm/driver/bitbucket/testdata/webhooks/pr_updated.json.golden index b5a933fbb..3c4a45ea4 100644 --- a/scm/driver/bitbucket/testdata/webhooks/pr_updated.json.golden +++ b/scm/driver/bitbucket/testdata/webhooks/pr_updated.json.golden @@ -35,6 +35,7 @@ "Updated": "2018-07-02T21:54:34.210775Z" }, "Sender": { + "ID": "{87bb15eb-47c1-49b3-9f16-ca824a2979a4}", "Login": "brydzewski", "Name": "Brad Rydzewski", "Email": "", diff --git a/scm/driver/bitbucket/testdata/webhooks/push.json.golden b/scm/driver/bitbucket/testdata/webhooks/push.json.golden index 5c76ff577..7d6e576b5 100644 --- a/scm/driver/bitbucket/testdata/webhooks/push.json.golden +++ b/scm/driver/bitbucket/testdata/webhooks/push.json.golden @@ -56,6 +56,7 @@ } ], "Sender": { + "ID": "{87bb15eb-47c1-49b3-9f16-ca824a2979a4}", "Login": "brydzewski", "Name": "Brad Rydzewski", "Email": "", diff --git a/scm/driver/bitbucket/testdata/webhooks/push_branch_create.json.golden b/scm/driver/bitbucket/testdata/webhooks/push_branch_create.json.golden index 068c597b5..d835008c1 100644 --- a/scm/driver/bitbucket/testdata/webhooks/push_branch_create.json.golden +++ b/scm/driver/bitbucket/testdata/webhooks/push_branch_create.json.golden @@ -18,6 +18,7 @@ }, "Action": "created", "Sender": { + "ID": "{87bb15eb-47c1-49b3-9f16-ca824a2979a4}", "Login": "brydzewski", "Name": "Brad Rydzewski", "Email": "", diff --git a/scm/driver/bitbucket/testdata/webhooks/push_branch_delete.json.golden b/scm/driver/bitbucket/testdata/webhooks/push_branch_delete.json.golden index 34a12d028..9c5ed6dce 100644 --- a/scm/driver/bitbucket/testdata/webhooks/push_branch_delete.json.golden +++ b/scm/driver/bitbucket/testdata/webhooks/push_branch_delete.json.golden @@ -18,6 +18,7 @@ }, "Action": "deleted", "Sender": { + "ID": "{87bb15eb-47c1-49b3-9f16-ca824a2979a4}", "Login": "brydzewski", "Name": "Brad Rydzewski", "Email": "", diff --git a/scm/driver/bitbucket/testdata/webhooks/push_tag_create.json.golden b/scm/driver/bitbucket/testdata/webhooks/push_tag_create.json.golden index 0f965056d..906d992ed 100644 --- a/scm/driver/bitbucket/testdata/webhooks/push_tag_create.json.golden +++ b/scm/driver/bitbucket/testdata/webhooks/push_tag_create.json.golden @@ -18,6 +18,7 @@ }, "Action": "created", "Sender": { + "ID": "{87bb15eb-47c1-49b3-9f16-ca824a2979a4}", "Login": "brydzewski", "Name": "Brad Rydzewski", "Email": "", diff --git a/scm/driver/bitbucket/testdata/webhooks/push_tag_delete.json.golden b/scm/driver/bitbucket/testdata/webhooks/push_tag_delete.json.golden index 5fe074bcb..479ffec02 100644 --- a/scm/driver/bitbucket/testdata/webhooks/push_tag_delete.json.golden +++ b/scm/driver/bitbucket/testdata/webhooks/push_tag_delete.json.golden @@ -18,6 +18,7 @@ }, "Action": "deleted", "Sender": { + "ID": "{87bb15eb-47c1-49b3-9f16-ca824a2979a4}", "Login": "brydzewski", "Name": "Brad Rydzewski", "Email": "", diff --git a/scm/driver/bitbucket/user.go b/scm/driver/bitbucket/user.go index 949d88b65..718811fb8 100644 --- a/scm/driver/bitbucket/user.go +++ b/scm/driver/bitbucket/user.go @@ -6,7 +6,6 @@ package bitbucket import ( "context" - "errors" "fmt" "github.com/drone/go-scm/scm" @@ -31,23 +30,23 @@ func (s *userService) FindLogin(ctx context.Context, login string) (*scm.User, * func (s *userService) FindEmail(ctx context.Context) (string, *scm.Response, error) { out := new(emails) - res, err := s.client.do(ctx, "GET", "2.0/user/emails", nil, out) - if err != nil { - return "", res, err - } - - for _, emailObj := range out.Values { - if emailObj.IsPrimary { - return emailObj.Email, res, nil - } - } - return "", res, errors.New("no primary email found") + res, err := s.client.do(ctx, "GET", "2.0/user/emails", nil, &out) + return convertEmailList(out), res, err } func (s *userService) ListEmail(context.Context, scm.ListOptions) ([]*scm.Email, *scm.Response, error) { return nil, nil, scm.ErrNotSupported } +func convertEmailList(from *emails) string { + for _, v := range from.Values { + if v.IsPrimary == true { + return v.Email + } + } + return "" +} + type user struct { // The `username` field is no longer available after 29 April 2019 in // accordance with GDPR regulations. See: @@ -65,12 +64,13 @@ type user struct { UUID string `json:"uuid"` } +type email struct { + Email string `json:"email"` + IsPrimary bool `json:"is_primary"` +} + type emails struct { - Values []struct { - IsPrimary bool `json:"is_primary"` - IsConfirmed bool `json:"is_confirmed"` - Email string `json:"email"` - } `json:"values"` + Values []*email `json:"values"` } func convertUser(from *user) *scm.User { diff --git a/scm/driver/bitbucket/user_test.go b/scm/driver/bitbucket/user_test.go index 3e2d82c68..4e6b3c9f4 100644 --- a/scm/driver/bitbucket/user_test.go +++ b/scm/driver/bitbucket/user_test.go @@ -67,18 +67,24 @@ func TestUserLoginFind(t *testing.T) { } func TestUserFindEmail(t *testing.T) { + defer gock.Off() + gock.New("https://api.bitbucket.org"). - Get("2.0/user/emails"). + Get("/2.0/user/emails"). Reply(200). Type("application/json"). - File("testdata/email.json") + File("testdata/userEmail.json") client, _ := New("https://api.bitbucket.org") got, _, err := client.Users.FindEmail(context.Background()) if err != nil { - t.Errorf("Unexpected error") + t.Error(err) } - if got != "primary@example.com" { + + want := "test@harness.io" + + if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") + t.Log(diff) } } diff --git a/scm/driver/bitbucket/util.go b/scm/driver/bitbucket/util.go index 03c5eaae4..e43ea71cf 100644 --- a/scm/driver/bitbucket/util.go +++ b/scm/driver/bitbucket/util.go @@ -8,6 +8,7 @@ import ( "net/url" "regexp" "strconv" + "strings" "github.com/drone/go-scm/scm" ) @@ -24,6 +25,26 @@ func extractEmail(gitauthor string) (author string) { return } +func encodeBranchListOptions(opts scm.BranchListOptions) string { + params := url.Values{} + if opts.SearchTerm != "" { + var sb strings.Builder + sb.WriteString("name~\"") + sb.WriteString(opts.SearchTerm) + sb.WriteString("\"") + params.Set("q", sb.String()) + } + if opts.PageListOptions != (scm.ListOptions{}) { + if opts.PageListOptions.Page != 0 { + params.Set("page", strconv.Itoa(opts.PageListOptions.Page)) + } + if opts.PageListOptions.Size != 0 { + params.Set("pagelen", strconv.Itoa(opts.PageListOptions.Size)) + } + } + return params.Encode() +} + func encodeListOptions(opts scm.ListOptions) string { params := url.Values{} if opts.Page != 0 { @@ -47,6 +68,27 @@ func encodeListRoleOptions(opts scm.ListOptions) string { return params.Encode() } +func encodeRepoListOptions(opts scm.RepoListOptions) string { + params := url.Values{} + if opts.RepoSearchTerm.RepoName != "" { + var sb strings.Builder + sb.WriteString("name~\"") + sb.WriteString(opts.RepoSearchTerm.RepoName) + sb.WriteString("\"") + params.Set("q", sb.String()) + } + if opts.ListOptions != (scm.ListOptions{}) { + if opts.ListOptions.Page != 0 { + params.Set("page", strconv.Itoa(opts.ListOptions.Page)) + } + if opts.ListOptions.Size != 0 { + params.Set("pagelen", strconv.Itoa(opts.ListOptions.Size)) + } + } + params.Set("role", "member") + return params.Encode() +} + func encodeCommitListOptions(opts scm.CommitListOptions) string { params := url.Values{} if opts.Page != 0 { diff --git a/scm/driver/bitbucket/webhook.go b/scm/driver/bitbucket/webhook.go index 0b3780d10..bfd491edc 100644 --- a/scm/driver/bitbucket/webhook.go +++ b/scm/driver/bitbucket/webhook.go @@ -11,6 +11,8 @@ import ( "io" "io/ioutil" "net/http" + "regexp" + "strconv" "time" "github.com/drone/go-scm/scm" @@ -53,6 +55,25 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo if hook != nil { hook.(*scm.PullRequestHook).Action = scm.ActionClose } + case "pullrequest:comment_created": + hook, err = s.parsePullRequestCommentHook(data) + if hook != nil { + hook.(*scm.IssueCommentHook).Action = scm.ActionCreate + } + case "pullrequest:comment_updated": + // Bitbucket PR Comment Update is unreliable and does not send events + // most of the time https://github.com/iterative/cml/issues/817 + hook, err = s.parsePullRequestCommentHook(data) + if hook != nil { + hook.(*scm.IssueCommentHook).Action = scm.ActionEdit + } + case "pullrequest:comment_deleted": + hook, err = s.parsePullRequestCommentHook(data) + if hook != nil { + hook.(*scm.IssueCommentHook).Action = scm.ActionDelete + } + case "repo:commit_status_updated", "repo:commit_status_created": + hook, err = s.parsePipelineHook(data) } if err != nil { return nil, err @@ -78,6 +99,12 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo return hook, nil } +func (s *webhookService) parsePullRequestCommentHook(data []byte) (scm.Webhook, error) { + dst := new(prCommentHook) + err := json.Unmarshal(data, dst) + return convertPrCommentHook(dst), err +} + func (s *webhookService) parsePushHook(data []byte) (scm.Webhook, error) { dst := new(pushHook) err := json.Unmarshal(data, dst) @@ -115,6 +142,15 @@ func (s *webhookService) parsePullRequestHook(data []byte) (*scm.PullRequestHook } } +func (s *webhookService) parsePipelineHook(data []byte) (*scm.PipelineHook, error) { + dst := new(pipelineHook) + err := json.Unmarshal(data, dst) + if err != nil { + return nil, err + } + return convertBitbucketHook(dst), err +} + // // native data structures // @@ -381,6 +417,278 @@ type ( } `json:"links"` UUID string `json:"uuid"` } + + prCommentInput struct { + Content struct { + Raw string `json:"raw"` + } `json:"content"` + } + + prComment struct { + Links struct { + Self link `json:"self"` + HTML link `json:"html"` + } `json:"links"` + Deleted bool `json:"deleted"` + PullRequest struct { + Type string `json:"type"` + ID int `json:"id"` + Links struct { + Self link `json:"self"` + HTML link `json:"html"` + } `json:"links"` + Title string `json:"title"` + } + Content struct { + Raw string `json:"raw"` + Markup string `json:"markup"` + Html string `json:"html"` + Type string `json:"type"` + } + CreatedOn time.Time `json:"created_on"` + User prCommentHookUser `json:"user"` + UpdatedOn time.Time `json:"updated_on"` + Type string `json:"type"` + ID int `json:"id"` + } + + prCommentHookRepo struct { + Scm string `json:"scm"` + Website string `json:"website"` + UUID string `json:"uuid"` + Links struct { + Self link `json:"self"` + HTML link `json:"html"` + Avatar link `json:"avatar"` + } `json:"links"` + Project struct { + Links struct { + Self link `json:"self"` + HTML link `json:"html"` + Avatar link `json:"avatar"` + } `json:"links"` + Type string `json:"type"` + Name string `json:"name"` + Key string `json:"key"` + UUID string `json:"uuid"` + } `json:"project"` + FullName string `json:"full_name"` + Owner prCommentHookUser `json:"owner"` + Workspace struct { + Slug string `json:"slugg"` + Type string `json:"type"` + Name string `json:"name"` + Links struct { + Self link `json:"self"` + HTML link `json:"html"` + Avatar link `json:"avatar"` + } `json:"links"` + UUID string `json:"uuid"` + } `json:"workspace"` + Type string `json:"type"` + IsPrivate bool `json:"is_private"` + Name string `json:"name"` + } + + prCommentHookUser struct { + Username string `json:"username"` + DisplayName string `json:"display_name"` + UUID string `json:"uuid"` + Links struct { + Self link `json:"self"` + HTML link `json:"html"` + Avatar link `json:"avatar"` + } `json:"links"` + Type string `json:"type"` + Nickname string `json:"nickname"` + AccountID string `json:"account_id"` + } + + prCommentHookPullRequest struct { + Rendered struct { + Description struct { + Raw string `json:"raw"` + Markup string `json:"markup"` + Html string `json:"html"` + Type string `json:"type"` + } `json:"description"` + Title struct { + Raw string `json:"raw"` + Markup string `json:"markup"` + Html string `json:"html"` + Type string `json:"type"` + } `json:"title"` + } `json:"rendered"` + Type string `json:"type"` + Description string `json:"description"` + Links struct { + Decline link `json:"decline"` + Diffstat link `json:"diffstat"` + Commits link `json:"commits"` + Self link `json:"self"` + Comments link `json:"comments"` + Merge link `json:"merge"` + Html link `json:"html"` + Activity link `json:"activity"` + RequestChanges link `json:"request-changes"` + Diff link `json:"diff"` + Approve link `json:"approve"` + Statuses link `json:"statuses"` + } `json:"links"` + Title string `json:"title"` + CloseSourceBranch bool `json:"close_source_branch"` + Reviewers []interface{} `json:"reviewers"` + ID int `json:"id"` + Destination struct { + Commit struct { + Hash string `json:"hash"` + Type string `json:"type"` + Links struct { + Self link `json:"self"` + HTML link `json:"html"` + } `json:"links"` + } + Repository struct { + Links struct { + Self link `json:"self"` + HTML link `json:"html"` + Avatar link `json:"avatar"` + } `json:"links"` + Type string `json:"type"` + Name string `json:"name"` + FullName string `json:"full_name"` + UUID string `json:"uuid"` + } `json:"repository"` + Branch struct { + Name string `json:"name"` + } `json:"branch"` + } `json:"destination"` + CreatedOn time.Time `json:"created_on"` + Summary struct { + Raw string `json:"raw"` + Markup string `json:"markup"` + Html string `json:"html"` + Type string `json:"type"` + } `json:"summary"` + Source struct { + Commit struct { + Hash string `json:"hash"` + Type string `json:"type"` + Links struct { + Self link `json:"self"` + HTML link `json:"html"` + } `json:"links"` + } + Repository struct { + Links struct { + Self link `json:"self"` + HTML link `json:"html"` + Avatar link `json:"avatar"` + } `json:"links"` + Type string `json:"type"` + Name string `json:"name"` + FullName string `json:"full_name"` + UUID string `json:"uuid"` + } `json:"repository"` + Branch struct { + Name string `json:"name"` + } `json:"branch"` + } `json:"source"` + CommentCount int `json:"comment_count"` + State string `json:"state"` + TaskCount int `json:"task_count"` + Participants []interface{} `json:"participants"` + Reason string `json:"reason"` + UpdatedOn time.Time `json:"updated_on"` + Author prCommentHookUser `json:"author"` + MergeCommit interface{} `json:"merge_commit"` + ClosedBy interface{} `json:"closed_by"` + } + + prCommentHook struct { + Comment prComment `json:"comment"` + PullRequest prCommentHookPullRequest `json:"pullRequest"` + Repository prCommentHookRepo `json:"repository"` + Actor prCommentHookUser `json:"actor"` + } + + pipelineHook struct { + Repository webhookRepository `json:"repository"` + Actor actor `json:"actor"` + CommitStatus struct { + Key string `json:"key"` + Type string `json:"type"` + State string `json:"state"` + Name string `json:"name"` + RefName string `json:"refname"` + Commit struct { + Type string `json:"type"` + Hash string `json:"hash"` + Date time.Time `json:"date"` + Author author `json:"author"` + Message string `json:"message"` + Links struct { + Self href `json:"self"` + HTML href `json:"html"` + Avatar href `json:"avatar"` + } `json:"links"` + } `json:"commit"` + URL string `json:"url"` + Repository info `json:"repository"` + Description string `json:"description"` + CreatedOn time.Time `json:"created_on"` + UpdatedOn time.Time `json:"updated_on"` + Links struct { + Self href `json:"self"` + Commit href `json:"commit"` + } `json:"links"` + } `json:"commit_status"` + } + + href struct { + Href string `json:"href"` + } + + actor struct { + DisplayName string `json:"display_name"` + Links struct { + Self href `json:"self"` + HTML href `json:"html"` + Avatar href `json:"avatar"` + } `json:"links"` + Type string `json:"type"` + UUID string `json:"uuid"` + Username string `json:"username"` + } + + author struct { + Type string `json:"type"` + Raw string `json:"raw"` + User struct { + DisplayName string `json:"display_name"` + Links struct { + Self href `json:"self"` + HTML href `json:"html"` + Avatar href `json:"avatar"` + } `json:"links"` + Type string `json:"type"` + UUID string `json:"uuid"` + AccountID string `json:"account_id"` + Nickname string `json:"nickname"` + } `json:"user"` + } + + info struct { + Type string `json:"type"` + FullName string `json:"full_name"` + Links struct { + Self href `json:"self"` + HTML href `json:"html"` + Avatar href `json:"avatar"` + } `json:"links"` + Name string `json:"name"` + UUID string `json:"uuid"` + } ) // @@ -446,6 +754,7 @@ func convertPushHook(src *pushHook) *scm.PushHook { Link: src.Repository.Links.HTML.Href, }, Sender: scm.User{ + ID: src.Actor.UUID, Login: src.Actor.Username, Name: src.Actor.DisplayName, Avatar: src.Actor.Links.Avatar.Href, @@ -478,6 +787,7 @@ func convertBranchCreateHook(src *pushHook) *scm.BranchHook { Link: src.Repository.Links.HTML.Href, }, Sender: scm.User{ + ID: src.Actor.UUID, Login: src.Actor.Username, Name: src.Actor.DisplayName, Avatar: src.Actor.Links.Avatar.Href, @@ -505,6 +815,7 @@ func convertBranchDeleteHook(src *pushHook) *scm.BranchHook { Link: src.Repository.Links.HTML.Href, }, Sender: scm.User{ + ID: src.Actor.UUID, Login: src.Actor.Username, Name: src.Actor.DisplayName, Avatar: src.Actor.Links.Avatar.Href, @@ -532,6 +843,7 @@ func convertTagCreateHook(src *pushHook) *scm.TagHook { Link: src.Repository.Links.HTML.Href, }, Sender: scm.User{ + ID: src.Actor.UUID, Login: src.Actor.Username, Name: src.Actor.DisplayName, Avatar: src.Actor.Links.Avatar.Href, @@ -559,6 +871,7 @@ func convertTagDeleteHook(src *pushHook) *scm.TagHook { Link: src.Repository.Links.HTML.Href, }, Sender: scm.User{ + ID: src.Actor.UUID, Login: src.Actor.Username, Name: src.Actor.DisplayName, Avatar: src.Actor.Links.Avatar.Href, @@ -579,6 +892,7 @@ func convertPullRequestHook(src *webhook) *scm.PullRequestHook { Title: src.PullRequest.Title, Body: src.PullRequest.Description, Sha: src.PullRequest.Source.Commit.Hash, + Merge: src.PullRequest.MergeCommit.Hash, Ref: fmt.Sprintf("refs/pull-requests/%d/from", src.PullRequest.ID), Source: src.PullRequest.Source.Branch.Name, Target: src.PullRequest.Destination.Branch.Name, @@ -604,9 +918,136 @@ func convertPullRequestHook(src *webhook) *scm.PullRequestHook { Link: src.Repository.Links.HTML.Href, }, Sender: scm.User{ + ID: src.Actor.UUID, Login: src.Actor.Username, Name: src.Actor.DisplayName, Avatar: src.Actor.Links.Avatar.Href, }, } } + +func convertPrCommentHook(src *prCommentHook) *scm.IssueCommentHook { + namespace, _ := scm.Split(src.Repository.FullName) + dst := scm.IssueCommentHook{ + Repo: scm.Repository{ + ID: src.Repository.UUID, + Namespace: namespace, + Name: src.Repository.Name, + Clone: fmt.Sprintf("https://bitbucket.org/%s.git", src.Repository.FullName), + CloneSSH: fmt.Sprintf("git@bitbucket.org:%s.git", src.Repository.FullName), + Link: src.Repository.Links.HTML.Href, + Private: src.Repository.IsPrivate, + }, + Issue: scm.Issue{ + Number: src.PullRequest.ID, + Title: src.PullRequest.Title, + Body: src.PullRequest.Description, + Link: src.PullRequest.Links.Html.Href, + Author: scm.User{ + Login: src.PullRequest.Author.Username, + Name: src.PullRequest.Author.DisplayName, + Avatar: src.PullRequest.Author.Links.Avatar.Href, + }, + PullRequest: scm.PullRequest{ + Number: src.PullRequest.ID, + Title: src.PullRequest.Title, + Body: src.PullRequest.Description, + Sha: src.PullRequest.Source.Commit.Hash, + // Bitbucket does not support PR Refs: https://jira.atlassian.com/browse/BCLOUD-5814 + Ref: fmt.Sprintf("refs/pull-requests/%d/from", src.PullRequest.ID), + Source: src.PullRequest.Source.Branch.Name, + Target: src.PullRequest.Destination.Branch.Name, + Fork: src.PullRequest.Source.Repository.FullName, + Link: src.PullRequest.Links.Html.Href, + Closed: src.PullRequest.State != "OPEN", + Merged: src.PullRequest.State == "MERGED", + Author: scm.User{ + Login: src.PullRequest.Author.Username, + Name: src.PullRequest.Author.DisplayName, + Avatar: src.PullRequest.Author.Links.Avatar.Href, + }, + Created: src.PullRequest.CreatedOn, + Updated: src.PullRequest.UpdatedOn, + }, + Created: src.PullRequest.CreatedOn, + Updated: src.PullRequest.UpdatedOn, + }, + Comment: scm.Comment{ + ID: src.Comment.ID, + Body: src.Comment.Content.Raw, + Author: scm.User{ + ID: src.Comment.User.UUID, + Login: src.Comment.User.Username, + Name: src.Comment.User.DisplayName, + Avatar: src.Comment.User.Links.Avatar.Href, + }, + Created: src.Comment.CreatedOn, + Updated: src.Comment.UpdatedOn, + }, + Sender: scm.User{ + ID: src.Actor.UUID, + Login: src.Actor.Username, + Name: src.Actor.DisplayName, + Avatar: src.Actor.Links.Avatar.Href, + }, + } + return &dst +} + +func convertBitbucketHook(src *pipelineHook) *scm.PipelineHook { + if src.CommitStatus.Type == "" || src.CommitStatus.Type != "build" { + return nil + } + namespace, name := scm.Split(src.Repository.FullName) + + return &scm.PipelineHook{ + Repo: scm.Repository{ + ID: src.Repository.UUID, + Namespace: namespace, + Name: name, + Clone: src.Repository.Links.HTML.Href, // Assuming HTML link as Clone URL + Branch: src.CommitStatus.RefName, + Private: src.Repository.IsPrivate, + }, + Commit: scm.Commit{ + Sha: src.CommitStatus.Commit.Hash, + Message: src.CommitStatus.Commit.Message, + Author: scm.Signature{ + Name: src.CommitStatus.Commit.Author.User.DisplayName, + Email: extractEmail(src.CommitStatus.Commit.Author.Raw), + Avatar: src.CommitStatus.Commit.Author.User.Links.Avatar.Href, + }, + Committer: scm.Signature{ + Name: src.CommitStatus.Commit.Author.User.DisplayName, + Email: extractEmail(src.CommitStatus.Commit.Author.Raw), + Avatar: src.CommitStatus.Commit.Author.User.Links.Avatar.Href, + }, + Link: src.CommitStatus.Commit.Links.HTML.Href, + }, + Execution: scm.Execution{ + Number: extractExecutionId(src.CommitStatus.URL), + Status: scm.ConvertExecutionStatus(src.CommitStatus.State), + Created: src.CommitStatus.CreatedOn, + URL: src.CommitStatus.URL, + }, + Sender: scm.User{ + Login: src.Actor.Username, + Name: src.Actor.DisplayName, + Avatar: src.Actor.Links.Avatar.Href, + ID: src.Actor.UUID, + }, + PullRequest: scm.PullRequest{}, + } +} + +func extractExecutionId(url string) int { + re := regexp.MustCompile(`/results/(\d+)`) + match := re.FindStringSubmatch(url) + if len(match) > 1 { + id, err := strconv.Atoi(match[1]) + if err == nil { + return id + } + } + return -1 +} diff --git a/scm/driver/bitbucket/webhook_test.go b/scm/driver/bitbucket/webhook_test.go index f8ecaccd7..65efed852 100644 --- a/scm/driver/bitbucket/webhook_test.go +++ b/scm/driver/bitbucket/webhook_test.go @@ -132,6 +132,34 @@ func TestWebhooks(t *testing.T) { // after: "samples/pr_unlabeled.json.golden", // obj: new(scm.PullRequestHook), // }, + { + sig: "71295b197fa25f4356d2fb9965df3f2379d903d7", + event: "pullrequest:comment_created", + before: "testdata/webhooks/pr_comment_created.json", + after: "testdata/webhooks/pr_comment_created.json.golden", + obj: new(scm.IssueCommentHook), + }, + { + sig: "71295b197fa25f4356d2fb9965df3f2379d903d7", + event: "pullrequest:comment_deleted", + before: "testdata/webhooks/pr_comment_deleted.json", + after: "testdata/webhooks/pr_comment_deleted.json.golden", + obj: new(scm.IssueCommentHook), + }, + { + sig: "71295b197fa25f4356d2fb9965df3f2379d903d7", + event: "repo:commit_status_created", + before: "testdata/webhooks/pipeline_hook_created.json", + after: "testdata/webhooks/pipeline_hook_created.json.golden", + obj: new(scm.PipelineHook), + }, + { + sig: "71295b197fa25f4356d2fb9965df3f2379d903d7", + event: "repo:commit_status_updated", + before: "testdata/webhooks/pipeline_hook_update.json", + after: "testdata/webhooks/pipeline_hook_update.json.golden", + obj: new(scm.PipelineHook), + }, } for _, test := range tests { diff --git a/scm/driver/gitea/git.go b/scm/driver/gitea/git.go index 8382b8cad..aaa58134f 100644 --- a/scm/driver/gitea/git.go +++ b/scm/driver/gitea/git.go @@ -17,7 +17,7 @@ type gitService struct { client *wrapper } -func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.CreateBranch) (*scm.Response, error) { +func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.ReferenceInput) (*scm.Response, error) { return nil, scm.ErrNotSupported } @@ -59,6 +59,12 @@ func (s *gitService) ListBranches(ctx context.Context, repo string, opts scm.Lis return convertBranchList(out), res, err } +func (s *gitService) ListBranchesV2(ctx context.Context, repo string, opts scm.BranchListOptions) ([]*scm.Reference, *scm.Response, error) { + // Gitea doesnt provide support listing based on searchTerm + // Hence calling the ListBranches + return s.ListBranches(ctx, repo, opts.PageListOptions) +} + func (s *gitService) ListCommits(ctx context.Context, repo string, _ scm.CommitListOptions) ([]*scm.Commit, *scm.Response, error) { path := fmt.Sprintf("api/v1/repos/%s/commits", repo) out := []*commitInfo{} diff --git a/scm/driver/gitea/org.go b/scm/driver/gitea/org.go index 103031dca..b8fe15471 100644 --- a/scm/driver/gitea/org.go +++ b/scm/driver/gitea/org.go @@ -23,7 +23,13 @@ func (s *organizationService) Find(ctx context.Context, name string) (*scm.Organ } func (s *organizationService) FindMembership(ctx context.Context, name, username string) (*scm.Membership, *scm.Response, error) { - return nil, nil, scm.ErrNotSupported + membership := new(membership) + membership.Active = s.checkMembership(ctx, name, username) + out := new(permissions) + path := fmt.Sprintf("api/v1/users/%s/orgs/%s/permissions", username, name) + res, err := s.client.do(ctx, "GET", path, nil, out) + membership.Permissions = out + return convertMembership(membership), res, err } func (s *organizationService) ListMemberships(ctx context.Context, orgNameList []string, username string, opts scm.ListOptions) ([]*scm.Membership, *scm.Response, error) { @@ -37,6 +43,18 @@ func (s *organizationService) List(ctx context.Context, opts scm.ListOptions) ([ return convertOrgList(out), res, err } +type permissions struct { + IsOwner bool `json:"is_owner"` + IsAdmin bool `json:"is_admin"` + CanWrite bool `json:"can_write"` + CanRead bool `json:"can_read"` + CanCreateRepository bool `json:"can_create_repository"` +} +type membership struct { + Permissions *permissions + Active bool +} + // // native data structures // @@ -64,3 +82,27 @@ func convertOrg(from *org) *scm.Organization { Avatar: from.Avatar, } } + +func (s *organizationService) checkMembership(ctx context.Context, name, username string) bool { + path := fmt.Sprintf("api/v1/orgs/%s/members/%s", name, username) + res, err := s.client.do(ctx, "GET", path, nil, nil) + if err != nil { + return false + } + return res.Status == 204 +} + +func convertMembership(from *membership) *scm.Membership { + to := new(scm.Membership) + to.Active = from.Active + isAdmin := from.Permissions.IsAdmin + isMember := from.Permissions.CanRead || from.Permissions.CanWrite || from.Permissions.CanCreateRepository + if isAdmin { + to.Role = scm.RoleAdmin + } else if isMember { + to.Role = scm.RoleMember + } else { + to.Role = scm.RoleUndefined + } + return to +} diff --git a/scm/driver/gitea/org_test.go b/scm/driver/gitea/org_test.go index 90a0a193c..ceaba401b 100644 --- a/scm/driver/gitea/org_test.go +++ b/scm/driver/gitea/org_test.go @@ -42,10 +42,31 @@ func TestOrgFind(t *testing.T) { } func TestOrganizationFindMembership(t *testing.T) { + defer gock.Off() + + gock.New("https://try.gitea.io"). + Get("/api/v1/orgs/gogits/members/jcitizen"). + Reply(204) + + gock.New("https://try.gitea.io"). + Get("/api/v1/users/jcitizen/orgs/gogits/permissions"). + Reply(200). + Type("application/json"). + File("testdata/permissions.json") + client, _ := New("https://try.gitea.io") - _, _, err := client.Organizations.FindMembership(context.Background(), "gogits", "jcitizen") - if err != scm.ErrNotSupported { - t.Errorf("Expect Not Supported error") + got, _, err := client.Organizations.FindMembership(context.Background(), "gogits", "jcitizen") + if err != nil { + t.Error(err) + } + + want := new(scm.Membership) + raw, _ := ioutil.ReadFile("testdata/membership.json.golden") + json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) } } diff --git a/scm/driver/gitea/repo.go b/scm/driver/gitea/repo.go index 04a630591..e5cdcb09f 100644 --- a/scm/driver/gitea/repo.go +++ b/scm/driver/gitea/repo.go @@ -46,6 +46,18 @@ func (s *repositoryService) List(ctx context.Context, opts scm.ListOptions) ([]* return convertRepositoryList(out), res, err } +func (s *repositoryService) ListV2(ctx context.Context, opts scm.RepoListOptions) ([]*scm.Repository, *scm.Response, error) { + // gitea does not support search filters, hence calling List api without search filtering + return s.List(ctx, opts.ListOptions) +} + +func (s *repositoryService) ListNamespace(ctx context.Context, namespace string, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { + path := fmt.Sprintf("api/v1/orgs/%s/repos?%s", namespace, encodeListOptions(opts)) + out := []*repository{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertRepositoryList(out), res, err +} + func (s *repositoryService) List2(ctx context.Context, orgSlug string, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { return nil, nil, scm.ErrNotSupported } diff --git a/scm/driver/gitea/testdata/membership.json.golden b/scm/driver/gitea/testdata/membership.json.golden new file mode 100644 index 000000000..96ec5685e --- /dev/null +++ b/scm/driver/gitea/testdata/membership.json.golden @@ -0,0 +1,4 @@ +{ + "Active": true, + "Role": 2 +} \ No newline at end of file diff --git a/scm/driver/gitea/testdata/permissions.json b/scm/driver/gitea/testdata/permissions.json new file mode 100644 index 000000000..77e2cff85 --- /dev/null +++ b/scm/driver/gitea/testdata/permissions.json @@ -0,0 +1,7 @@ +{ + "is_owner": true, + "is_admin": true, + "can_write": true, + "can_read": true, + "can_create_repository": true +} diff --git a/scm/driver/gitee/git.go b/scm/driver/gitee/git.go index 6b2933b67..b3377a43c 100644 --- a/scm/driver/gitee/git.go +++ b/scm/driver/gitee/git.go @@ -16,7 +16,7 @@ type gitService struct { client *wrapper } -func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.CreateBranch) (*scm.Response, error) { +func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.ReferenceInput) (*scm.Response, error) { path := fmt.Sprintf("repos/%s/branches", repo) in := &branchCreate{ Refs: params.Sha, @@ -60,6 +60,12 @@ func (s *gitService) ListBranches(ctx context.Context, repo string, _ scm.ListOp return convertBranchList(out), res, err } +func (s *gitService) ListBranchesV2(ctx context.Context, repo string, opts scm.BranchListOptions) ([]*scm.Reference, *scm.Response, error) { + // Gitee doesnt provide support listing based on searchTerm + // Hence calling the ListBranches + return s.ListBranches(ctx, repo, opts.PageListOptions) +} + func (s *gitService) ListCommits(ctx context.Context, repo string, opts scm.CommitListOptions) ([]*scm.Commit, *scm.Response, error) { path := fmt.Sprintf("repos/%s/commits?%s", repo, encodeCommitListOptions(opts)) out := []*commit{} diff --git a/scm/driver/gitee/git_test.go b/scm/driver/gitee/git_test.go index b62cd951c..bdceb7634 100644 --- a/scm/driver/gitee/git_test.go +++ b/scm/driver/gitee/git_test.go @@ -26,7 +26,7 @@ func TestGitCreateBranch(t *testing.T) { SetHeaders(mockHeaders) client := NewDefault() - input := scm.CreateBranch{ + input := scm.ReferenceInput{ Name: "create-by-api", Sha: "b72a4c4a2d838d96a545a42d41d7776ae5566f4a", } diff --git a/scm/driver/gitee/repo.go b/scm/driver/gitee/repo.go index d656d2e73..453947879 100644 --- a/scm/driver/gitee/repo.go +++ b/scm/driver/gitee/repo.go @@ -45,6 +45,14 @@ func (s *RepositoryService) List(ctx context.Context, opts scm.ListOptions) ([]* res, err := s.client.do(ctx, "GET", path, nil, &out) return convertRepositoryList(out), res, err } +func (s *RepositoryService) ListV2(ctx context.Context, opts scm.RepoListOptions) ([]*scm.Repository, *scm.Response, error) { + // gitee does not support search filters, hence calling List api without search filtering + return s.List(ctx, opts.ListOptions) +} + +func (s *RepositoryService) ListNamespace(ctx context.Context, namespace string, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} func (s *RepositoryService) List2(ctx context.Context, orgSlug string, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { return nil, nil, scm.ErrNotSupported @@ -167,7 +175,7 @@ func convertRepositoryList(from []*repository) []*scm.Repository { func convertRepository(from *repository) *scm.Repository { return &scm.Repository{ ID: strconv.Itoa(from.ID), - Name: from.Name, + Name: from.Path, Namespace: from.Namespace.Path, Perm: &scm.Perm{ Push: from.Permission.Push, diff --git a/scm/driver/github/content.go b/scm/driver/github/content.go index 709cf705f..19c734e6a 100644 --- a/scm/driver/github/content.go +++ b/scm/driver/github/content.go @@ -8,6 +8,7 @@ import ( "context" "encoding/base64" "fmt" + "net/url" "github.com/drone/go-scm/scm" ) @@ -17,7 +18,8 @@ type contentService struct { } func (s *contentService) Find(ctx context.Context, repo, path, ref string) (*scm.Content, *scm.Response, error) { - endpoint := fmt.Sprintf("repos/%s/contents/%s?ref=%s", repo, path, ref) + urlEncodedRef := url.QueryEscape(ref) + endpoint := fmt.Sprintf("repos/%s/contents/%s?ref=%s", repo, path, urlEncodedRef) out := new(content) res, err := s.client.do(ctx, "GET", endpoint, nil, out) raw, _ := base64.StdEncoding.DecodeString(out.Content) diff --git a/scm/driver/github/content_test.go b/scm/driver/github/content_test.go index 06923bf74..c1e8d4110 100644 --- a/scm/driver/github/content_test.go +++ b/scm/driver/github/content_test.go @@ -47,6 +47,35 @@ func TestContentFind(t *testing.T) { t.Log(diff) } + gock.New("https://api.github.com"). + Get("/repos/octocat/hello-world/contents/README"). + MatchParam("ref", "b1&b2"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/content.json") + + client = NewDefault() + got, res, err = client.Contents.Find( + context.Background(), + "octocat/hello-world", + "README", + "b1&b2", + ) + if err != nil { + t.Error(err) + return + } + + want = new(scm.Content) + raw, _ = ioutil.ReadFile("testdata/content.json.golden") + _ = json.Unmarshal(raw, want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + t.Run("Request", testRequest(res)) t.Run("Rate", testRate(res)) } diff --git a/scm/driver/github/git.go b/scm/driver/github/git.go index 0ef94db44..11edba432 100644 --- a/scm/driver/github/git.go +++ b/scm/driver/github/git.go @@ -16,7 +16,7 @@ type gitService struct { client *wrapper } -func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.CreateBranch) (*scm.Response, error) { +func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.ReferenceInput) (*scm.Response, error) { path := fmt.Sprintf("repos/%s/git/refs", repo) in := &createBranch{ Ref: scm.ExpandRef(params.Name, "refs/heads"), @@ -53,6 +53,12 @@ func (s *gitService) ListBranches(ctx context.Context, repo string, opts scm.Lis return convertBranchList(out), res, err } +func (s *gitService) ListBranchesV2(ctx context.Context, repo string, opts scm.BranchListOptions) ([]*scm.Reference, *scm.Response, error) { + // Github doesnt provide support listing based on searchTerm + // Hence calling the ListBranches + return s.ListBranches(ctx, repo, opts.PageListOptions) +} + func (s *gitService) ListCommits(ctx context.Context, repo string, opts scm.CommitListOptions) ([]*scm.Commit, *scm.Response, error) { path := fmt.Sprintf("repos/%s/commits?%s", repo, encodeCommitListOptions(opts)) out := []*commit{} @@ -61,10 +67,10 @@ func (s *gitService) ListCommits(ctx context.Context, repo string, opts scm.Comm } func (s *gitService) ListTags(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Reference, *scm.Response, error) { - path := fmt.Sprintf("repos/%s/tags?%s", repo, encodeListOptions(opts)) - out := []*branch{} + path := fmt.Sprintf("repos/%s/git/refs/tags?%s", repo, encodeListOptions(opts)) + out := []*ref{} res, err := s.client.do(ctx, "GET", path, nil, &out) - return convertTagList(out), res, err + return convertRefList(out), res, err } func (s *gitService) ListChanges(ctx context.Context, repo, ref string, _ scm.ListOptions) ([]*scm.Change, *scm.Response, error) { @@ -185,10 +191,10 @@ func convertRef(from *ref) *scm.Reference { } } -func convertTagList(from []*branch) []*scm.Reference { +func convertRefList(from []*ref) []*scm.Reference { to := []*scm.Reference{} for _, v := range from { - to = append(to, convertTag(v)) + to = append(to, convertRef(v)) } return to } diff --git a/scm/driver/github/git_test.go b/scm/driver/github/git_test.go index 65c2562c9..8d1ff4c5c 100644 --- a/scm/driver/github/git_test.go +++ b/scm/driver/github/git_test.go @@ -116,7 +116,7 @@ func TestGitCreateBranch(t *testing.T) { SetHeaders(mockHeaders). File("testdata/branch_create.json") - params := &scm.CreateBranch{ + params := &scm.ReferenceInput{ Name: "Hello", Sha: "312797ba52425353dec56871a255e2a36fc96344", } @@ -211,7 +211,7 @@ func TestGitListTags(t *testing.T) { defer gock.Off() gock.New("https://api.github.com"). - Get("/repos/octocat/hello-world/tags"). + Get("/repos/octocat/hello-world/git/refs/tags"). MatchParam("page", "1"). MatchParam("per_page", "30"). Reply(200). diff --git a/scm/driver/github/pr.go b/scm/driver/github/pr.go index 2dc083b4c..52e980937 100644 --- a/scm/driver/github/pr.go +++ b/scm/driver/github/pr.go @@ -39,7 +39,7 @@ func (s *pullService) ListChanges(ctx context.Context, repo string, number int, } func (s *pullService) ListCommits(ctx context.Context, repo string, number int, opts scm.ListOptions) ([]*scm.Commit, *scm.Response, error) { - path := fmt.Sprintf("/repos/%s/pulls/%d/commits?%s", repo, number, encodeListOptions(opts)) + path := fmt.Sprintf("repos/%s/pulls/%d/commits?%s", repo, number, encodeListOptions(opts)) out := []*commit{} res, err := s.client.do(ctx, "GET", path, nil, &out) return convertCommitList(out), res, err @@ -76,6 +76,7 @@ type pr struct { State string `json:"state"` Title string `json:"title"` Body string `json:"body"` + Draft bool `json:"draft"` DiffURL string `json:"diff_url"` HTMLURL string `json:"html_url"` User struct { @@ -154,6 +155,7 @@ func convertPullRequest(from *pr) *scm.PullRequest { Fork: from.Head.Repo.FullName, Link: from.HTMLURL, Diff: from.DiffURL, + Draft: from.Draft, Closed: from.State != "open", Merged: from.MergedAt.String != "", Head: scm.Reference{ diff --git a/scm/driver/github/repo.go b/scm/driver/github/repo.go index 58e6d03bd..d32867d50 100644 --- a/scm/driver/github/repo.go +++ b/scm/driver/github/repo.go @@ -40,6 +40,10 @@ type repository struct { } `json:"permissions"` } +type searchRepositoryList struct { + Repositories []*repository `json:"items"` +} + type repositoryList2 struct { Repositories []*repository `json:"repositories"` } @@ -57,6 +61,11 @@ type hook struct { } `json:"config"` } +type repositoryList struct { + TotalCount int `json:"total_count"` + Repositories []*repository `json:"repositories"` +} + // RepositoryService implements the repository service for // the GitHub driver. type RepositoryService struct { @@ -109,6 +118,30 @@ func (s *RepositoryService) List(ctx context.Context, opts scm.ListOptions) ([]* return convertRepositoryList(out), res, err } +// ListV2 returns the user repository list based on the searchTerm passed. +func (s *RepositoryService) ListV2(ctx context.Context, opts scm.RepoListOptions) ([]*scm.Repository, *scm.Response, error) { + path := fmt.Sprintf("search/repositories?%s", encodeRepoListOptions(opts)) + out := new(searchRepositoryList) + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertRepositoryList(out.Repositories), res, err +} + +// ListNamespace returns the orgs' repository list. +func (s *RepositoryService) ListNamespace(ctx context.Context, namespace string, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { + path := fmt.Sprintf("orgs/%s/repos?%s", namespace, encodeListOptions(opts)) + out := []*repository{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertRepositoryList(out), res, err +} + +// List returns the github app installation repository list. +func (s *RepositoryService) ListByInstallation(ctx context.Context, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { + path := fmt.Sprintf("installation/repositories?%s", encodeListOptions(opts)) + out := new(repositoryList) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertRepositoryList(out.Repositories), res, err +} + func (s *RepositoryService) List2(ctx context.Context, installationID string, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { path := fmt.Sprintf("user/installations/%s/repositories?%s", installationID, encodeListOptions(opts)) out := new(repositoryList2) @@ -215,7 +248,7 @@ func (s *RepositoryService) DeleteHook(ctx context.Context, repo, id string) (*s return s.client.do(ctx, "DELETE", path, nil, nil) } -// helper function to convert from the gogs repository list to +// helper function to convert from the github repository list to // the common repository structure. func convertRepositoryList(from []*repository) []*scm.Repository { to := []*scm.Repository{} @@ -227,7 +260,7 @@ func convertRepositoryList(from []*repository) []*scm.Repository { return to } -// helper function to convert from the gogs repository structure +// helper function to convert from the github repository structure // to the common repository structure. func convertRepository(from *repository) *scm.Repository { if from == nil { @@ -246,7 +279,7 @@ func convertRepository(from *repository) *scm.Repository { Branch: from.DefaultBranch, Archived: from.Archived, Private: from.Private, - Visibility: convertVisibility(from.Visibility), + Visibility: scm.ConvertVisibility(from.Visibility), Clone: from.CloneURL, CloneSSH: from.SSHURL, Created: from.CreatedAt, @@ -299,19 +332,6 @@ func convertFromHookEvents(from scm.HookEvents) []string { return events } -func convertVisibility(from string) scm.Visibility { - switch from { - case "public": - return scm.VisibilityPublic - case "private": - return scm.VisibilityPrivate - case "internal": - return scm.VisibilityInternal - default: - return scm.VisibilityUndefined - } -} - type status struct { CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` diff --git a/scm/driver/github/repo_test.go b/scm/driver/github/repo_test.go index 214ceb6e5..02627c4d3 100644 --- a/scm/driver/github/repo_test.go +++ b/scm/driver/github/repo_test.go @@ -131,6 +131,82 @@ func TestRepositoryList(t *testing.T) { t.Run("Page", testPage(res)) } +func TestRepositoryListV2(t *testing.T) { + defer gock.Off() + + gock.New("https://api.github.com"). + Get("/search/repositories"). + MatchParam("q", "testRepoin:name"). + MatchParam("q", "user:user123"). + MatchParam("page", "1"). + MatchParam("per_page", "30"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/repos_filter.json") + + client := NewDefault() + got, res, err := client.Repositories.ListV2(context.Background(), scm.RepoListOptions{ + ListOptions: scm.ListOptions{Page: 1, Size: 30}, + RepoSearchTerm: scm.RepoSearchTerm{ + RepoName: "testRepo", + User: "user123", + }, + }) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Repository{} + raw, _ := ioutil.ReadFile("testdata/repos_filter.json.golden") + _ = json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) + t.Run("Page", testPage(res)) +} + +func TestGithubAppInstallationList(t *testing.T) { + defer gock.Off() + + gock.New("https://api.github.com"). + Get("/installation/repositories"). + MatchParam("page", "1"). + MatchParam("per_page", "30"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/github_app_repos.json") + + client := NewDefault() + got, res, err := client.Repositories.(*RepositoryService).ListByInstallation(context.Background(), scm.ListOptions{Page: 1, Size: 30}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Repository{} + raw, _ := ioutil.ReadFile("testdata/repos.json.golden") + _ = json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) + t.Run("Page", testPage(res)) +} + func TestRepositoryList2(t *testing.T) { defer gock.Off() diff --git a/scm/driver/github/testdata/github_app_repos.json b/scm/driver/github/testdata/github_app_repos.json new file mode 100644 index 000000000..2526a4000 --- /dev/null +++ b/scm/driver/github/testdata/github_app_repos.json @@ -0,0 +1,115 @@ +{ + "total_count": 1, + "repositories": [ + { + "id": 1296269, + "owner": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "description": "This your first repo!", + "private": true, + "fork": true, + "visibility": "public", + "url": "https://api.github.com/repos/octocat/Hello-World", + "html_url": "https://github.com/octocat/Hello-World", + "archive_url": "http://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", + "assignees_url": "http://api.github.com/repos/octocat/Hello-World/assignees{/user}", + "blobs_url": "http://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", + "branches_url": "http://api.github.com/repos/octocat/Hello-World/branches{/branch}", + "clone_url": "https://github.com/octocat/Hello-World.git", + "collaborators_url": "http://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", + "comments_url": "http://api.github.com/repos/octocat/Hello-World/comments{/number}", + "commits_url": "http://api.github.com/repos/octocat/Hello-World/commits{/sha}", + "compare_url": "http://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", + "contents_url": "http://api.github.com/repos/octocat/Hello-World/contents/{+path}", + "contributors_url": "http://api.github.com/repos/octocat/Hello-World/contributors", + "deployments_url": "http://api.github.com/repos/octocat/Hello-World/deployments", + "downloads_url": "http://api.github.com/repos/octocat/Hello-World/downloads", + "events_url": "http://api.github.com/repos/octocat/Hello-World/events", + "forks_url": "http://api.github.com/repos/octocat/Hello-World/forks", + "git_commits_url": "http://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", + "git_refs_url": "http://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", + "git_tags_url": "http://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", + "git_url": "git:github.com/octocat/Hello-World.git", + "hooks_url": "http://api.github.com/repos/octocat/Hello-World/hooks", + "issue_comment_url": "http://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", + "issue_events_url": "http://api.github.com/repos/octocat/Hello-World/issues/events{/number}", + "issues_url": "http://api.github.com/repos/octocat/Hello-World/issues{/number}", + "keys_url": "http://api.github.com/repos/octocat/Hello-World/keys{/key_id}", + "labels_url": "http://api.github.com/repos/octocat/Hello-World/labels{/name}", + "languages_url": "http://api.github.com/repos/octocat/Hello-World/languages", + "merges_url": "http://api.github.com/repos/octocat/Hello-World/merges", + "milestones_url": "http://api.github.com/repos/octocat/Hello-World/milestones{/number}", + "mirror_url": "git:git.example.com/octocat/Hello-World", + "notifications_url": "http://api.github.com/repos/octocat/Hello-World/notifications{?since, all, participating}", + "pulls_url": "http://api.github.com/repos/octocat/Hello-World/pulls{/number}", + "releases_url": "http://api.github.com/repos/octocat/Hello-World/releases{/id}", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "stargazers_url": "http://api.github.com/repos/octocat/Hello-World/stargazers", + "statuses_url": "http://api.github.com/repos/octocat/Hello-World/statuses/{sha}", + "subscribers_url": "http://api.github.com/repos/octocat/Hello-World/subscribers", + "subscription_url": "http://api.github.com/repos/octocat/Hello-World/subscription", + "svn_url": "https://svn.github.com/octocat/Hello-World", + "tags_url": "http://api.github.com/repos/octocat/Hello-World/tags", + "teams_url": "http://api.github.com/repos/octocat/Hello-World/teams", + "trees_url": "http://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", + "homepage": "https://github.com", + "language": null, + "forks_count": 9, + "stargazers_count": 80, + "watchers_count": 80, + "size": 108, + "default_branch": "master", + "open_issues_count": 0, + "topics": [ + "octocat", + "atom", + "electron", + "API" + ], + "has_issues": true, + "has_wiki": true, + "has_pages": false, + "has_downloads": true, + "archived": false, + "pushed_at": "2011-01-26T19:06:43Z", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:14:43Z", + "permissions": { + "admin": true, + "push": true, + "pull": true + }, + "allow_rebase_merge": true, + "allow_squash_merge": true, + "allow_merge_commit": true, + "subscribers_count": 42, + "network_count": 0, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "html_url": "http://choosealicense.com/licenses/mit/" + } + } + ] +} \ No newline at end of file diff --git a/scm/driver/github/testdata/pr.json b/scm/driver/github/testdata/pr.json index edcc02d7c..3315fafbc 100644 --- a/scm/driver/github/testdata/pr.json +++ b/scm/driver/github/testdata/pr.json @@ -11,6 +11,7 @@ "comments_url": "https://api.github.com/repos/octocat/Hello-World/issues/1347/comments", "statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e", "number": 1347, + "draft": false, "state": "open", "title": "new-feature", "body": "Please pull these awesome changes", diff --git a/scm/driver/github/testdata/pr.json.golden b/scm/driver/github/testdata/pr.json.golden index 2ea51c709..5bf11ba0c 100644 --- a/scm/driver/github/testdata/pr.json.golden +++ b/scm/driver/github/testdata/pr.json.golden @@ -9,6 +9,7 @@ "Fork": "octocat/Hello-World", "Link": "https://github.com/octocat/Hello-World/pull/1347", "Diff": "https://github.com/octocat/Hello-World/pull/1347.diff", + "Draft": false, "Closed": false, "Merged": true, "Base": { diff --git a/scm/driver/github/testdata/pulls.json b/scm/driver/github/testdata/pulls.json index 611d7d71d..e1f85a075 100644 --- a/scm/driver/github/testdata/pulls.json +++ b/scm/driver/github/testdata/pulls.json @@ -12,6 +12,7 @@ "comments_url": "https://api.github.com/repos/octocat/Hello-World/issues/1347/comments", "statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e", "number": 1347, + "draft": false, "state": "open", "title": "new-feature", "body": "Please pull these awesome changes", diff --git a/scm/driver/github/testdata/pulls.json.golden b/scm/driver/github/testdata/pulls.json.golden index 1a6798b98..f2a97473d 100644 --- a/scm/driver/github/testdata/pulls.json.golden +++ b/scm/driver/github/testdata/pulls.json.golden @@ -10,6 +10,7 @@ "Fork": "octocat/Hello-World", "Link": "https://github.com/octocat/Hello-World/pull/1347", "Diff": "https://github.com/octocat/Hello-World/pull/1347.diff", + "Draft": false, "Closed": false, "Merged": true, "Base": { diff --git a/scm/driver/github/testdata/repos_filter.json b/scm/driver/github/testdata/repos_filter.json new file mode 100644 index 000000000..5e724c4a7 --- /dev/null +++ b/scm/driver/github/testdata/repos_filter.json @@ -0,0 +1,107 @@ +{ + "total_count": 5, + "incomplete_results": false, + "items": [ + { + "id": 508719340, + "node_id": "R_kgDOHlJw7A", + "name": "testRepo2", + "full_name": "user123/testRepo2", + "private": false, + "owner": { + "login": "user123", + "id": 103414561, + "node_id": "U_kgDOBin7IQ", + "avatar_url": "https://avatars.githubusercontent.com/u/103414561?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/user123", + "html_url": "https://github.com/user123", + "followers_url": "https://api.github.com/users/user123/followers", + "following_url": "https://api.github.com/users/user123/following{/other_user}", + "gists_url": "https://api.github.com/users/user123/gists{/gist_id}", + "starred_url": "https://api.github.com/users/user123/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/user123/subscriptions", + "organizations_url": "https://api.github.com/users/user123/orgs", + "repos_url": "https://api.github.com/users/user123/repos", + "events_url": "https://api.github.com/users/user123/events{/privacy}", + "received_events_url": "https://api.github.com/users/user123/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/user123/testRepo2", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/user123/testRepo2", + "forks_url": "https://api.github.com/repos/user123/testRepo2/forks", + "keys_url": "https://api.github.com/repos/user123/testRepo2/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/user123/testRepo2/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/user123/testRepo2/teams", + "hooks_url": "https://api.github.com/repos/user123/testRepo2/hooks", + "issue_events_url": "https://api.github.com/repos/user123/testRepo2/issues/events{/number}", + "events_url": "https://api.github.com/repos/user123/testRepo2/events", + "assignees_url": "https://api.github.com/repos/user123/testRepo2/assignees{/user}", + "branches_url": "https://api.github.com/repos/user123/testRepo2/branches{/branch}", + "tags_url": "https://api.github.com/repos/user123/testRepo2/tags", + "blobs_url": "https://api.github.com/repos/user123/testRepo2/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/user123/testRepo2/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/user123/testRepo2/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/user123/testRepo2/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/user123/testRepo2/statuses/{sha}", + "languages_url": "https://api.github.com/repos/user123/testRepo2/languages", + "stargazers_url": "https://api.github.com/repos/user123/testRepo2/stargazers", + "contributors_url": "https://api.github.com/repos/user123/testRepo2/contributors", + "subscribers_url": "https://api.github.com/repos/user123/testRepo2/subscribers", + "subscription_url": "https://api.github.com/repos/user123/testRepo2/subscription", + "commits_url": "https://api.github.com/repos/user123/testRepo2/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/user123/testRepo2/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/user123/testRepo2/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/user123/testRepo2/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/user123/testRepo2/contents/{+path}", + "compare_url": "https://api.github.com/repos/user123/testRepo2/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/user123/testRepo2/merges", + "archive_url": "https://api.github.com/repos/user123/testRepo2/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/user123/testRepo2/downloads", + "issues_url": "https://api.github.com/repos/user123/testRepo2/issues{/number}", + "pulls_url": "https://api.github.com/repos/user123/testRepo2/pulls{/number}", + "milestones_url": "https://api.github.com/repos/user123/testRepo2/milestones{/number}", + "notifications_url": "https://api.github.com/repos/user123/testRepo2/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/user123/testRepo2/labels{/name}", + "releases_url": "https://api.github.com/repos/user123/testRepo2/releases{/id}", + "deployments_url": "https://api.github.com/repos/user123/testRepo2/deployments", + "created_at": "2022-06-29T14:11:36Z", + "updated_at": "2023-06-27T07:10:05Z", + "pushed_at": "2023-06-07T05:36:36Z", + "git_url": "git://github.com/user123/testRepo2.git", + "ssh_url": "git@github.com:user123/testRepo2.git", + "clone_url": "https://github.com/user123/testRepo2.git", + "svn_url": "https://github.com/user123/testRepo2", + "homepage": null, + "size": 53, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 2, + "license": null, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 2, + "watchers": 0, + "default_branch": "main", + "score": 1.0 + } + ] +} \ No newline at end of file diff --git a/scm/driver/github/testdata/repos_filter.json.golden b/scm/driver/github/testdata/repos_filter.json.golden new file mode 100644 index 000000000..bb164132f --- /dev/null +++ b/scm/driver/github/testdata/repos_filter.json.golden @@ -0,0 +1,20 @@ +[ + { + "ID": "508719340", + "Namespace": "user123", + "Name": "testRepo2", + "Perm": { + "Pull": false, + "Push": false, + "Admin": false + }, + "Branch": "main", + "Private": false, + "Visibility": 1, + "Clone": "https://github.com/user123/testRepo2.git", + "CloneSSH": "git@github.com:user123/testRepo2.git", + "Link": "https://github.com/user123/testRepo2", + "Created": "2022-06-29T14:11:36Z", + "Updated": "2023-06-27T07:10:05Z" + } +] \ No newline at end of file diff --git a/scm/driver/github/testdata/tags.json b/scm/driver/github/testdata/tags.json index 8eee0f95a..eac19260c 100644 --- a/scm/driver/github/testdata/tags.json +++ b/scm/driver/github/testdata/tags.json @@ -1,11 +1,12 @@ [ { - "name": "v0.1", - "commit": { - "sha": "c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc", - "url": "https://api.github.com/repos/octocat/Hello-World/commits/c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc" - }, - "zipball_url": "https://github.com/octocat/Hello-World/zipball/v0.1", - "tarball_url": "https://github.com/octocat/Hello-World/tarball/v0.1" - } + "ref": "refs/tags/v1", + "node_id": "REF_kwDOGvVo46xyZWZzL3RhZ3MvdjE", + "url": "https://api.github.com/repos/vitsafronovici/myrepo/git/refs/tags/v1", + "object": { + "sha": "85fd27bdfd87b962d1ed4a742613cbfacd5c3743", + "type": "tag", + "url": "https://api.github.com/repos/vitsafronovici/myrepo/git/tags/85fd27bdfd87b962d1ed4a742613cbfacd5c3743" + } + } ] \ No newline at end of file diff --git a/scm/driver/github/testdata/tags.json.golden b/scm/driver/github/testdata/tags.json.golden index de3d2df17..c533fd7ee 100644 --- a/scm/driver/github/testdata/tags.json.golden +++ b/scm/driver/github/testdata/tags.json.golden @@ -1,7 +1,7 @@ [ { - "Name": "v0.1", - "Path": "refs/tags/v0.1", - "Sha": "c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc" + "Name": "v1", + "Path": "refs/tags/v1", + "Sha": "85fd27bdfd87b962d1ed4a742613cbfacd5c3743" } ] \ No newline at end of file diff --git a/scm/driver/github/testdata/webhooks/pipeline_hook.json b/scm/driver/github/testdata/webhooks/pipeline_hook.json new file mode 100644 index 000000000..3a7fd0c92 --- /dev/null +++ b/scm/driver/github/testdata/webhooks/pipeline_hook.json @@ -0,0 +1,389 @@ +{ + "action": "in_progress", + "workflow_run": { + "id": 14030131450, + "name": "CI", + "node_id": "WFR_kwLOE_pLVc8AAAADRELQ-g", + "head_branch": "shivamnegi94-patch-27", + "head_sha": "f4229db4b70a8dadeb687f5ccce5fd327c04461a", + "path": ".github/workflows/blank.yml", + "display_title": "Update NewSre_v1.yaml", + "run_number": 2, + "event": "pull_request", + "status": "completed", + "conclusion": "success", + "workflow_id": 151617408, + "check_suite_id": 36111489428, + "check_suite_node_id": "CS_kwDOE_pLVc8AAAAIaGmZlA", + "url": "https://api.github.com/repos/shivamnegi94/testrepo/actions/runs/14030131450", + "html_url": "https://github.com/shivamnegi94/testrepo/actions/runs/14030131450", + "pull_requests": [ + { + "url": "https://api.github.com/repos/shivamnegi94/testrepo/pulls/164", + "id": 2412967773, + "number": 164, + "head": { + "ref": "shivamnegi94-patch-27", + "sha": "f4229db4b70a8dadeb687f5ccce5fd327c04461a", + "repo": { + "id": 335170389, + "url": "https://api.github.com/repos/shivamnegi94/testrepo", + "name": "testrepo" + } + }, + "base": { + "ref": "main", + "sha": "ded75dda298abfbf9f1900092e92b43f23bdd6d2", + "repo": { + "id": 335170389, + "url": "https://api.github.com/repos/shivamnegi94/testrepo", + "name": "testrepo" + } + } + } + ], + "created_at": "2025-03-24T08:03:42Z", + "updated_at": "2025-03-24T08:03:46Z", + "actor": { + "login": "shivamnegi94", + "id": 58415634, + "node_id": "MDQ6VXNlcjU4NDE1NjM0", + "avatar_url": "https://avatars.githubusercontent.com/u/58415634?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/shivamnegi94", + "html_url": "https://github.com/shivamnegi94", + "followers_url": "https://api.github.com/users/shivamnegi94/followers", + "following_url": "https://api.github.com/users/shivamnegi94/following{/other_user}", + "gists_url": "https://api.github.com/users/shivamnegi94/gists{/gist_id}", + "starred_url": "https://api.github.com/users/shivamnegi94/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/shivamnegi94/subscriptions", + "organizations_url": "https://api.github.com/users/shivamnegi94/orgs", + "repos_url": "https://api.github.com/users/shivamnegi94/repos", + "events_url": "https://api.github.com/users/shivamnegi94/events{/privacy}", + "received_events_url": "https://api.github.com/users/shivamnegi94/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "run_attempt": 1, + "referenced_workflows": [ + + ], + "run_started_at": "2025-03-24T08:03:42Z", + "triggering_actor": { + "login": "shivamnegi94", + "id": 58415634, + "node_id": "MDQ6VXNlcjU4NDE1NjM0", + "avatar_url": "https://avatars.githubusercontent.com/u/58415634?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/shivamnegi94", + "html_url": "https://github.com/shivamnegi94", + "followers_url": "https://api.github.com/users/shivamnegi94/followers", + "following_url": "https://api.github.com/users/shivamnegi94/following{/other_user}", + "gists_url": "https://api.github.com/users/shivamnegi94/gists{/gist_id}", + "starred_url": "https://api.github.com/users/shivamnegi94/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/shivamnegi94/subscriptions", + "organizations_url": "https://api.github.com/users/shivamnegi94/orgs", + "repos_url": "https://api.github.com/users/shivamnegi94/repos", + "events_url": "https://api.github.com/users/shivamnegi94/events{/privacy}", + "received_events_url": "https://api.github.com/users/shivamnegi94/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "jobs_url": "https://api.github.com/repos/shivamnegi94/testrepo/actions/runs/14030131450/jobs", + "logs_url": "https://api.github.com/repos/shivamnegi94/testrepo/actions/runs/14030131450/logs", + "check_suite_url": "https://api.github.com/repos/shivamnegi94/testrepo/check-suites/36111489428", + "artifacts_url": "https://api.github.com/repos/shivamnegi94/testrepo/actions/runs/14030131450/artifacts", + "cancel_url": "https://api.github.com/repos/shivamnegi94/testrepo/actions/runs/14030131450/cancel", + "rerun_url": "https://api.github.com/repos/shivamnegi94/testrepo/actions/runs/14030131450/rerun", + "previous_attempt_url": null, + "workflow_url": "https://api.github.com/repos/shivamnegi94/testrepo/actions/workflows/151617408", + "head_commit": { + "id": "f4229db4b70a8dadeb687f5ccce5fd327c04461a", + "tree_id": "36698bb567243f3d104f398e3b6e1a339570d3dc", + "message": "Update NewSre_v1.yaml", + "timestamp": "2025-03-24T08:03:33Z", + "author": { + "name": "Shivam Negi", + "email": "shivam.negi@harness.io" + }, + "committer": { + "name": "GitHub", + "email": "noreply@github.com" + } + }, + "repository": { + "id": 335170389, + "node_id": "MDEwOlJlcG9zaXRvcnkzMzUxNzAzODk=", + "name": "testrepo", + "full_name": "shivamnegi94/testrepo", + "private": false, + "owner": { + "login": "shivamnegi94", + "id": 58415634, + "node_id": "MDQ6VXNlcjU4NDE1NjM0", + "avatar_url": "https://avatars.githubusercontent.com/u/58415634?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/shivamnegi94", + "html_url": "https://github.com/shivamnegi94", + "followers_url": "https://api.github.com/users/shivamnegi94/followers", + "following_url": "https://api.github.com/users/shivamnegi94/following{/other_user}", + "gists_url": "https://api.github.com/users/shivamnegi94/gists{/gist_id}", + "starred_url": "https://api.github.com/users/shivamnegi94/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/shivamnegi94/subscriptions", + "organizations_url": "https://api.github.com/users/shivamnegi94/orgs", + "repos_url": "https://api.github.com/users/shivamnegi94/repos", + "events_url": "https://api.github.com/users/shivamnegi94/events{/privacy}", + "received_events_url": "https://api.github.com/users/shivamnegi94/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/shivamnegi94/testrepo", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/shivamnegi94/testrepo", + "forks_url": "https://api.github.com/repos/shivamnegi94/testrepo/forks", + "keys_url": "https://api.github.com/repos/shivamnegi94/testrepo/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/shivamnegi94/testrepo/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/shivamnegi94/testrepo/teams", + "hooks_url": "https://api.github.com/repos/shivamnegi94/testrepo/hooks", + "issue_events_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues/events{/number}", + "events_url": "https://api.github.com/repos/shivamnegi94/testrepo/events", + "assignees_url": "https://api.github.com/repos/shivamnegi94/testrepo/assignees{/user}", + "branches_url": "https://api.github.com/repos/shivamnegi94/testrepo/branches{/branch}", + "tags_url": "https://api.github.com/repos/shivamnegi94/testrepo/tags", + "blobs_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/shivamnegi94/testrepo/statuses/{sha}", + "languages_url": "https://api.github.com/repos/shivamnegi94/testrepo/languages", + "stargazers_url": "https://api.github.com/repos/shivamnegi94/testrepo/stargazers", + "contributors_url": "https://api.github.com/repos/shivamnegi94/testrepo/contributors", + "subscribers_url": "https://api.github.com/repos/shivamnegi94/testrepo/subscribers", + "subscription_url": "https://api.github.com/repos/shivamnegi94/testrepo/subscription", + "commits_url": "https://api.github.com/repos/shivamnegi94/testrepo/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/shivamnegi94/testrepo/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/shivamnegi94/testrepo/contents/{+path}", + "compare_url": "https://api.github.com/repos/shivamnegi94/testrepo/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/shivamnegi94/testrepo/merges", + "archive_url": "https://api.github.com/repos/shivamnegi94/testrepo/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/shivamnegi94/testrepo/downloads", + "issues_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues{/number}", + "pulls_url": "https://api.github.com/repos/shivamnegi94/testrepo/pulls{/number}", + "milestones_url": "https://api.github.com/repos/shivamnegi94/testrepo/milestones{/number}", + "notifications_url": "https://api.github.com/repos/shivamnegi94/testrepo/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/shivamnegi94/testrepo/labels{/name}", + "releases_url": "https://api.github.com/repos/shivamnegi94/testrepo/releases{/id}", + "deployments_url": "https://api.github.com/repos/shivamnegi94/testrepo/deployments" + }, + "head_repository": { + "id": 335170389, + "node_id": "MDEwOlJlcG9zaXRvcnkzMzUxNzAzODk=", + "name": "testrepo", + "full_name": "shivamnegi94/testrepo", + "private": false, + "owner": { + "login": "shivamnegi94", + "id": 58415634, + "node_id": "MDQ6VXNlcjU4NDE1NjM0", + "avatar_url": "https://avatars.githubusercontent.com/u/58415634?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/shivamnegi94", + "html_url": "https://github.com/shivamnegi94", + "followers_url": "https://api.github.com/users/shivamnegi94/followers", + "following_url": "https://api.github.com/users/shivamnegi94/following{/other_user}", + "gists_url": "https://api.github.com/users/shivamnegi94/gists{/gist_id}", + "starred_url": "https://api.github.com/users/shivamnegi94/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/shivamnegi94/subscriptions", + "organizations_url": "https://api.github.com/users/shivamnegi94/orgs", + "repos_url": "https://api.github.com/users/shivamnegi94/repos", + "events_url": "https://api.github.com/users/shivamnegi94/events{/privacy}", + "received_events_url": "https://api.github.com/users/shivamnegi94/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/shivamnegi94/testrepo", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/shivamnegi94/testrepo", + "forks_url": "https://api.github.com/repos/shivamnegi94/testrepo/forks", + "keys_url": "https://api.github.com/repos/shivamnegi94/testrepo/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/shivamnegi94/testrepo/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/shivamnegi94/testrepo/teams", + "hooks_url": "https://api.github.com/repos/shivamnegi94/testrepo/hooks", + "issue_events_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues/events{/number}", + "events_url": "https://api.github.com/repos/shivamnegi94/testrepo/events", + "assignees_url": "https://api.github.com/repos/shivamnegi94/testrepo/assignees{/user}", + "branches_url": "https://api.github.com/repos/shivamnegi94/testrepo/branches{/branch}", + "tags_url": "https://api.github.com/repos/shivamnegi94/testrepo/tags", + "blobs_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/shivamnegi94/testrepo/statuses/{sha}", + "languages_url": "https://api.github.com/repos/shivamnegi94/testrepo/languages", + "stargazers_url": "https://api.github.com/repos/shivamnegi94/testrepo/stargazers", + "contributors_url": "https://api.github.com/repos/shivamnegi94/testrepo/contributors", + "subscribers_url": "https://api.github.com/repos/shivamnegi94/testrepo/subscribers", + "subscription_url": "https://api.github.com/repos/shivamnegi94/testrepo/subscription", + "commits_url": "https://api.github.com/repos/shivamnegi94/testrepo/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/shivamnegi94/testrepo/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/shivamnegi94/testrepo/contents/{+path}", + "compare_url": "https://api.github.com/repos/shivamnegi94/testrepo/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/shivamnegi94/testrepo/merges", + "archive_url": "https://api.github.com/repos/shivamnegi94/testrepo/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/shivamnegi94/testrepo/downloads", + "issues_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues{/number}", + "pulls_url": "https://api.github.com/repos/shivamnegi94/testrepo/pulls{/number}", + "milestones_url": "https://api.github.com/repos/shivamnegi94/testrepo/milestones{/number}", + "notifications_url": "https://api.github.com/repos/shivamnegi94/testrepo/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/shivamnegi94/testrepo/labels{/name}", + "releases_url": "https://api.github.com/repos/shivamnegi94/testrepo/releases{/id}", + "deployments_url": "https://api.github.com/repos/shivamnegi94/testrepo/deployments" + } + }, + "workflow": { + "id": 151617408, + "node_id": "W_kwDOE_pLVc4JCX-A", + "name": "CI", + "path": ".github/workflows/blank.yml", + "state": "active", + "created_at": "2025-03-24T08:01:34.000Z", + "updated_at": "2025-03-24T08:01:34.000Z", + "url": "https://api.github.com/repos/shivamnegi94/testrepo/actions/workflows/151617408", + "html_url": "https://github.com/shivamnegi94/testrepo/blob/main/.github/workflows/blank.yml", + "badge_url": "https://github.com/shivamnegi94/testrepo/workflows/CI/badge.svg" + }, + "repository": { + "id": 335170389, + "node_id": "MDEwOlJlcG9zaXRvcnkzMzUxNzAzODk=", + "name": "testrepo", + "full_name": "shivamnegi94/testrepo", + "private": false, + "owner": { + "login": "shivamnegi94", + "id": 58415634, + "node_id": "MDQ6VXNlcjU4NDE1NjM0", + "avatar_url": "https://avatars.githubusercontent.com/u/58415634?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/shivamnegi94", + "html_url": "https://github.com/shivamnegi94", + "followers_url": "https://api.github.com/users/shivamnegi94/followers", + "following_url": "https://api.github.com/users/shivamnegi94/following{/other_user}", + "gists_url": "https://api.github.com/users/shivamnegi94/gists{/gist_id}", + "starred_url": "https://api.github.com/users/shivamnegi94/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/shivamnegi94/subscriptions", + "organizations_url": "https://api.github.com/users/shivamnegi94/orgs", + "repos_url": "https://api.github.com/users/shivamnegi94/repos", + "events_url": "https://api.github.com/users/shivamnegi94/events{/privacy}", + "received_events_url": "https://api.github.com/users/shivamnegi94/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/shivamnegi94/testrepo", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/shivamnegi94/testrepo", + "forks_url": "https://api.github.com/repos/shivamnegi94/testrepo/forks", + "keys_url": "https://api.github.com/repos/shivamnegi94/testrepo/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/shivamnegi94/testrepo/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/shivamnegi94/testrepo/teams", + "hooks_url": "https://api.github.com/repos/shivamnegi94/testrepo/hooks", + "issue_events_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues/events{/number}", + "events_url": "https://api.github.com/repos/shivamnegi94/testrepo/events", + "assignees_url": "https://api.github.com/repos/shivamnegi94/testrepo/assignees{/user}", + "branches_url": "https://api.github.com/repos/shivamnegi94/testrepo/branches{/branch}", + "tags_url": "https://api.github.com/repos/shivamnegi94/testrepo/tags", + "blobs_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/shivamnegi94/testrepo/statuses/{sha}", + "languages_url": "https://api.github.com/repos/shivamnegi94/testrepo/languages", + "stargazers_url": "https://api.github.com/repos/shivamnegi94/testrepo/stargazers", + "contributors_url": "https://api.github.com/repos/shivamnegi94/testrepo/contributors", + "subscribers_url": "https://api.github.com/repos/shivamnegi94/testrepo/subscribers", + "subscription_url": "https://api.github.com/repos/shivamnegi94/testrepo/subscription", + "commits_url": "https://api.github.com/repos/shivamnegi94/testrepo/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/shivamnegi94/testrepo/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/shivamnegi94/testrepo/contents/{+path}", + "compare_url": "https://api.github.com/repos/shivamnegi94/testrepo/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/shivamnegi94/testrepo/merges", + "archive_url": "https://api.github.com/repos/shivamnegi94/testrepo/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/shivamnegi94/testrepo/downloads", + "issues_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues{/number}", + "pulls_url": "https://api.github.com/repos/shivamnegi94/testrepo/pulls{/number}", + "milestones_url": "https://api.github.com/repos/shivamnegi94/testrepo/milestones{/number}", + "notifications_url": "https://api.github.com/repos/shivamnegi94/testrepo/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/shivamnegi94/testrepo/labels{/name}", + "releases_url": "https://api.github.com/repos/shivamnegi94/testrepo/releases{/id}", + "deployments_url": "https://api.github.com/repos/shivamnegi94/testrepo/deployments", + "created_at": "2021-02-02T04:41:22Z", + "updated_at": "2025-03-24T08:01:37Z", + "pushed_at": "2025-03-24T08:03:33Z", + "git_url": "git://github.com/shivamnegi94/testrepo.git", + "ssh_url": "git@github.com:shivamnegi94/testrepo.git", + "clone_url": "https://github.com/shivamnegi94/testrepo.git", + "svn_url": "https://github.com/shivamnegi94/testrepo", + "homepage": null, + "size": 209, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 56, + "license": null, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + + ], + "visibility": "public", + "forks": 0, + "open_issues": 56, + "watchers": 0, + "default_branch": "main" + }, + "sender": { + "login": "shivamnegi94", + "id": 58415634, + "node_id": "MDQ6VXNlcjU4NDE1NjM0", + "avatar_url": "https://avatars.githubusercontent.com/u/58415634?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/shivamnegi94", + "html_url": "https://github.com/shivamnegi94", + "followers_url": "https://api.github.com/users/shivamnegi94/followers", + "following_url": "https://api.github.com/users/shivamnegi94/following{/other_user}", + "gists_url": "https://api.github.com/users/shivamnegi94/gists{/gist_id}", + "starred_url": "https://api.github.com/users/shivamnegi94/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/shivamnegi94/subscriptions", + "organizations_url": "https://api.github.com/users/shivamnegi94/orgs", + "repos_url": "https://api.github.com/users/shivamnegi94/repos", + "events_url": "https://api.github.com/users/shivamnegi94/events{/privacy}", + "received_events_url": "https://api.github.com/users/shivamnegi94/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + } +} \ No newline at end of file diff --git a/scm/driver/github/testdata/webhooks/pipeline_hook.json.golden b/scm/driver/github/testdata/webhooks/pipeline_hook.json.golden new file mode 100644 index 000000000..b56869de0 --- /dev/null +++ b/scm/driver/github/testdata/webhooks/pipeline_hook.json.golden @@ -0,0 +1,50 @@ +{ + "Repo": { + "ID": "335170389", + "Namespace": "shivamnegi94", + "Name": "testrepo", + "Clone": "https://github.com/shivamnegi94/testrepo.git", + "CloneSSH": "git@github.com:shivamnegi94/testrepo.git", + "Link": "https://github.com/shivamnegi94/testrepo", + "Branch": "main", + "Created": "2021-02-02T04:41:22Z", + "Updated": "2025-03-24T08:01:37Z", + "Private": false, + "Visibility": 1, + "Perm": {} + }, + "Commit": { + "Sha": "f4229db4b70a8dadeb687f5ccce5fd327c04461a", + "Message": "Update NewSre_v1.yaml", + "Author": { + "Name": "Shivam Negi", + "Email": "shivam.negi@harness.io" + }, + "Committer": { + "Name": "GitHub", + "Email": "noreply@github.com" + } + }, + "Execution": { + "Number": 2, + "Status": "success", + "Created": "2025-03-24T08:03:42Z", + "URL": "https://api.github.com/repos/shivamnegi94/testrepo/actions/runs/14030131450" + }, + "Sender": { + "Login": "shivamnegi94", + "Avatar": "https://avatars.githubusercontent.com/u/58415634?v=4" + }, + "PullRequest": { + "Number": 164, + "Sha": "f4229db4b70a8dadeb687f5ccce5fd327c04461a", + "Ref": "shivamnegi94-patch-27", + "Source": "shivamnegi94-patch-27", + "Target": "main", + "Link": "https://api.github.com/repos/shivamnegi94/testrepo/pulls/164", + "Created": "2025-03-24T08:03:42Z", + "Draft": false, + "Closed": false, + "Merged": false + } +} diff --git a/scm/driver/github/testdata/webhooks/pr_ready_for_review.json b/scm/driver/github/testdata/webhooks/pr_ready_for_review.json new file mode 100644 index 000000000..b9a7e1fdc --- /dev/null +++ b/scm/driver/github/testdata/webhooks/pr_ready_for_review.json @@ -0,0 +1,528 @@ +{ + "action": "ready_for_review", + "number": 38, + "pull_request": { + "url": "https://api.github.com/repos/wings-software/meet-git-sync-test/pulls/38", + "id": 1492580810, + "node_id": "PR_kwDOHbOleM5Y9vnK", + "html_url": "https://github.com/wings-software/meet-git-sync-test/pull/38", + "diff_url": "https://github.com/wings-software/meet-git-sync-test/pull/38.diff", + "patch_url": "https://github.com/wings-software/meet-git-sync-test/pull/38.patch", + "issue_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/issues/38", + "number": 38, + "state": "open", + "locked": false, + "title": "Update dgdggd.me", + "user": { + "login": "rathodmeetsatish", + "id": 84321134, + "node_id": "MDQ6VXNlcjg0MzIxMTM0", + "avatar_url": "https://avatars.githubusercontent.com/u/84321134?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/rathodmeetsatish", + "html_url": "https://github.com/rathodmeetsatish", + "followers_url": "https://api.github.com/users/rathodmeetsatish/followers", + "following_url": "https://api.github.com/users/rathodmeetsatish/following{/other_user}", + "gists_url": "https://api.github.com/users/rathodmeetsatish/gists{/gist_id}", + "starred_url": "https://api.github.com/users/rathodmeetsatish/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rathodmeetsatish/subscriptions", + "organizations_url": "https://api.github.com/users/rathodmeetsatish/orgs", + "repos_url": "https://api.github.com/users/rathodmeetsatish/repos", + "events_url": "https://api.github.com/users/rathodmeetsatish/events{/privacy}", + "received_events_url": "https://api.github.com/users/rathodmeetsatish/received_events", + "type": "User", + "site_admin": false + }, + "body": null, + "created_at": "2023-08-28T19:15:53Z", + "updated_at": "2023-08-28T19:16:06Z", + "closed_at": null, + "merged_at": null, + "merge_commit_sha": "d427e98e038a88f10e57d48c34f287e3ad20a0bf", + "assignee": null, + "assignees": [ + + ], + "requested_reviewers": [ + + ], + "requested_teams": [ + + ], + "labels": [ + + ], + "milestone": null, + "draft": false, + "commits_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/pulls/38/commits", + "review_comments_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/pulls/38/comments", + "review_comment_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/pulls/comments{/number}", + "comments_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/issues/38/comments", + "statuses_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/statuses/212015fb011c49a2913c4a1a860ce07c0821c362", + "head": { + "label": "wings-software:rathodmeetsatish-patch-25", + "ref": "rathodmeetsatish-patch-25", + "sha": "212015fb011c49a2913c4a1a860ce07c0821c362", + "user": { + "login": "wings-software", + "id": 18273000, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjE4MjczMDAw", + "avatar_url": "https://avatars.githubusercontent.com/u/18273000?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/wings-software", + "html_url": "https://github.com/wings-software", + "followers_url": "https://api.github.com/users/wings-software/followers", + "following_url": "https://api.github.com/users/wings-software/following{/other_user}", + "gists_url": "https://api.github.com/users/wings-software/gists{/gist_id}", + "starred_url": "https://api.github.com/users/wings-software/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/wings-software/subscriptions", + "organizations_url": "https://api.github.com/users/wings-software/orgs", + "repos_url": "https://api.github.com/users/wings-software/repos", + "events_url": "https://api.github.com/users/wings-software/events{/privacy}", + "received_events_url": "https://api.github.com/users/wings-software/received_events", + "type": "Organization", + "site_admin": false + }, + "repo": { + "id": 498312568, + "node_id": "R_kgDOHbOleA", + "name": "meet-git-sync-test", + "full_name": "wings-software/meet-git-sync-test", + "private": true, + "owner": { + "login": "wings-software", + "id": 18273000, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjE4MjczMDAw", + "avatar_url": "https://avatars.githubusercontent.com/u/18273000?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/wings-software", + "html_url": "https://github.com/wings-software", + "followers_url": "https://api.github.com/users/wings-software/followers", + "following_url": "https://api.github.com/users/wings-software/following{/other_user}", + "gists_url": "https://api.github.com/users/wings-software/gists{/gist_id}", + "starred_url": "https://api.github.com/users/wings-software/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/wings-software/subscriptions", + "organizations_url": "https://api.github.com/users/wings-software/orgs", + "repos_url": "https://api.github.com/users/wings-software/repos", + "events_url": "https://api.github.com/users/wings-software/events{/privacy}", + "received_events_url": "https://api.github.com/users/wings-software/received_events", + "type": "Organization", + "site_admin": false + }, + "html_url": "https://github.com/wings-software/meet-git-sync-test", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/wings-software/meet-git-sync-test", + "forks_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/forks", + "keys_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/teams", + "hooks_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/hooks", + "issue_events_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/issues/events{/number}", + "events_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/events", + "assignees_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/assignees{/user}", + "branches_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/branches{/branch}", + "tags_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/tags", + "blobs_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/statuses/{sha}", + "languages_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/languages", + "stargazers_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/stargazers", + "contributors_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/contributors", + "subscribers_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/subscribers", + "subscription_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/subscription", + "commits_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/contents/{+path}", + "compare_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/merges", + "archive_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/downloads", + "issues_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/issues{/number}", + "pulls_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/pulls{/number}", + "milestones_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/milestones{/number}", + "notifications_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/labels{/name}", + "releases_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/releases{/id}", + "deployments_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/deployments", + "created_at": "2022-05-31T11:47:10Z", + "updated_at": "2022-05-31T11:47:35Z", + "pushed_at": "2023-08-28T19:15:54Z", + "git_url": "git://github.com/wings-software/meet-git-sync-test.git", + "ssh_url": "git@github.com:wings-software/meet-git-sync-test.git", + "clone_url": "https://github.com/wings-software/meet-git-sync-test.git", + "svn_url": "https://github.com/wings-software/meet-git-sync-test", + "homepage": null, + "size": 171, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Roff", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 23, + "license": null, + "allow_forking": false, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + + ], + "visibility": "private", + "forks": 0, + "open_issues": 23, + "watchers": 0, + "default_branch": "main", + "allow_squash_merge": true, + "allow_merge_commit": true, + "allow_rebase_merge": true, + "allow_auto_merge": false, + "delete_branch_on_merge": false, + "allow_update_branch": false, + "use_squash_pr_title_as_default": false, + "squash_merge_commit_message": "COMMIT_MESSAGES", + "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", + "merge_commit_message": "PR_TITLE", + "merge_commit_title": "MERGE_MESSAGE" + } + }, + "base": { + "label": "wings-software:main", + "ref": "main", + "sha": "8b8d2b3e6a2ee6df108c8429e86c9a750e728f9d", + "user": { + "login": "wings-software", + "id": 18273000, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjE4MjczMDAw", + "avatar_url": "https://avatars.githubusercontent.com/u/18273000?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/wings-software", + "html_url": "https://github.com/wings-software", + "followers_url": "https://api.github.com/users/wings-software/followers", + "following_url": "https://api.github.com/users/wings-software/following{/other_user}", + "gists_url": "https://api.github.com/users/wings-software/gists{/gist_id}", + "starred_url": "https://api.github.com/users/wings-software/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/wings-software/subscriptions", + "organizations_url": "https://api.github.com/users/wings-software/orgs", + "repos_url": "https://api.github.com/users/wings-software/repos", + "events_url": "https://api.github.com/users/wings-software/events{/privacy}", + "received_events_url": "https://api.github.com/users/wings-software/received_events", + "type": "Organization", + "site_admin": false + }, + "repo": { + "id": 498312568, + "node_id": "R_kgDOHbOleA", + "name": "meet-git-sync-test", + "full_name": "wings-software/meet-git-sync-test", + "private": true, + "owner": { + "login": "wings-software", + "id": 18273000, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjE4MjczMDAw", + "avatar_url": "https://avatars.githubusercontent.com/u/18273000?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/wings-software", + "html_url": "https://github.com/wings-software", + "followers_url": "https://api.github.com/users/wings-software/followers", + "following_url": "https://api.github.com/users/wings-software/following{/other_user}", + "gists_url": "https://api.github.com/users/wings-software/gists{/gist_id}", + "starred_url": "https://api.github.com/users/wings-software/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/wings-software/subscriptions", + "organizations_url": "https://api.github.com/users/wings-software/orgs", + "repos_url": "https://api.github.com/users/wings-software/repos", + "events_url": "https://api.github.com/users/wings-software/events{/privacy}", + "received_events_url": "https://api.github.com/users/wings-software/received_events", + "type": "Organization", + "site_admin": false + }, + "html_url": "https://github.com/wings-software/meet-git-sync-test", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/wings-software/meet-git-sync-test", + "forks_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/forks", + "keys_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/teams", + "hooks_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/hooks", + "issue_events_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/issues/events{/number}", + "events_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/events", + "assignees_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/assignees{/user}", + "branches_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/branches{/branch}", + "tags_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/tags", + "blobs_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/statuses/{sha}", + "languages_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/languages", + "stargazers_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/stargazers", + "contributors_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/contributors", + "subscribers_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/subscribers", + "subscription_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/subscription", + "commits_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/contents/{+path}", + "compare_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/merges", + "archive_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/downloads", + "issues_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/issues{/number}", + "pulls_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/pulls{/number}", + "milestones_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/milestones{/number}", + "notifications_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/labels{/name}", + "releases_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/releases{/id}", + "deployments_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/deployments", + "created_at": "2022-05-31T11:47:10Z", + "updated_at": "2022-05-31T11:47:35Z", + "pushed_at": "2023-08-28T19:15:54Z", + "git_url": "git://github.com/wings-software/meet-git-sync-test.git", + "ssh_url": "git@github.com:wings-software/meet-git-sync-test.git", + "clone_url": "https://github.com/wings-software/meet-git-sync-test.git", + "svn_url": "https://github.com/wings-software/meet-git-sync-test", + "homepage": null, + "size": 171, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Roff", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 23, + "license": null, + "allow_forking": false, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + + ], + "visibility": "private", + "forks": 0, + "open_issues": 23, + "watchers": 0, + "default_branch": "main", + "allow_squash_merge": true, + "allow_merge_commit": true, + "allow_rebase_merge": true, + "allow_auto_merge": false, + "delete_branch_on_merge": false, + "allow_update_branch": false, + "use_squash_pr_title_as_default": false, + "squash_merge_commit_message": "COMMIT_MESSAGES", + "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", + "merge_commit_message": "PR_TITLE", + "merge_commit_title": "MERGE_MESSAGE" + } + }, + "_links": { + "self": { + "href": "https://api.github.com/repos/wings-software/meet-git-sync-test/pulls/38" + }, + "html": { + "href": "https://github.com/wings-software/meet-git-sync-test/pull/38" + }, + "issue": { + "href": "https://api.github.com/repos/wings-software/meet-git-sync-test/issues/38" + }, + "comments": { + "href": "https://api.github.com/repos/wings-software/meet-git-sync-test/issues/38/comments" + }, + "review_comments": { + "href": "https://api.github.com/repos/wings-software/meet-git-sync-test/pulls/38/comments" + }, + "review_comment": { + "href": "https://api.github.com/repos/wings-software/meet-git-sync-test/pulls/comments{/number}" + }, + "commits": { + "href": "https://api.github.com/repos/wings-software/meet-git-sync-test/pulls/38/commits" + }, + "statuses": { + "href": "https://api.github.com/repos/wings-software/meet-git-sync-test/statuses/212015fb011c49a2913c4a1a860ce07c0821c362" + } + }, + "author_association": "COLLABORATOR", + "auto_merge": null, + "active_lock_reason": null, + "merged": false, + "mergeable": true, + "rebaseable": true, + "mergeable_state": "clean", + "merged_by": null, + "comments": 0, + "review_comments": 0, + "maintainer_can_modify": false, + "commits": 1, + "additions": 4, + "deletions": 1, + "changed_files": 1 + }, + "repository": { + "id": 498312568, + "node_id": "R_kgDOHbOleA", + "name": "meet-git-sync-test", + "full_name": "wings-software/meet-git-sync-test", + "private": true, + "owner": { + "login": "wings-software", + "id": 18273000, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjE4MjczMDAw", + "avatar_url": "https://avatars.githubusercontent.com/u/18273000?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/wings-software", + "html_url": "https://github.com/wings-software", + "followers_url": "https://api.github.com/users/wings-software/followers", + "following_url": "https://api.github.com/users/wings-software/following{/other_user}", + "gists_url": "https://api.github.com/users/wings-software/gists{/gist_id}", + "starred_url": "https://api.github.com/users/wings-software/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/wings-software/subscriptions", + "organizations_url": "https://api.github.com/users/wings-software/orgs", + "repos_url": "https://api.github.com/users/wings-software/repos", + "events_url": "https://api.github.com/users/wings-software/events{/privacy}", + "received_events_url": "https://api.github.com/users/wings-software/received_events", + "type": "Organization", + "site_admin": false + }, + "html_url": "https://github.com/wings-software/meet-git-sync-test", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/wings-software/meet-git-sync-test", + "forks_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/forks", + "keys_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/teams", + "hooks_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/hooks", + "issue_events_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/issues/events{/number}", + "events_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/events", + "assignees_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/assignees{/user}", + "branches_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/branches{/branch}", + "tags_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/tags", + "blobs_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/statuses/{sha}", + "languages_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/languages", + "stargazers_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/stargazers", + "contributors_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/contributors", + "subscribers_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/subscribers", + "subscription_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/subscription", + "commits_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/contents/{+path}", + "compare_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/merges", + "archive_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/downloads", + "issues_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/issues{/number}", + "pulls_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/pulls{/number}", + "milestones_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/milestones{/number}", + "notifications_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/labels{/name}", + "releases_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/releases{/id}", + "deployments_url": "https://api.github.com/repos/wings-software/meet-git-sync-test/deployments", + "created_at": "2022-05-31T11:47:10Z", + "updated_at": "2022-05-31T11:47:35Z", + "pushed_at": "2023-08-28T19:15:54Z", + "git_url": "git://github.com/wings-software/meet-git-sync-test.git", + "ssh_url": "git@github.com:wings-software/meet-git-sync-test.git", + "clone_url": "https://github.com/wings-software/meet-git-sync-test.git", + "svn_url": "https://github.com/wings-software/meet-git-sync-test", + "homepage": null, + "size": 171, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Roff", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 23, + "license": null, + "allow_forking": false, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + + ], + "visibility": "private", + "forks": 0, + "open_issues": 23, + "watchers": 0, + "default_branch": "main" + }, + "organization": { + "login": "wings-software", + "id": 18273000, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjE4MjczMDAw", + "url": "https://api.github.com/orgs/wings-software", + "repos_url": "https://api.github.com/orgs/wings-software/repos", + "events_url": "https://api.github.com/orgs/wings-software/events", + "hooks_url": "https://api.github.com/orgs/wings-software/hooks", + "issues_url": "https://api.github.com/orgs/wings-software/issues", + "members_url": "https://api.github.com/orgs/wings-software/members{/member}", + "public_members_url": "https://api.github.com/orgs/wings-software/public_members{/member}", + "avatar_url": "https://avatars.githubusercontent.com/u/18273000?v=4", + "description": "" + }, + "enterprise": { + "id": 6657, + "slug": "harness", + "name": "Harness", + "node_id": "MDEwOkVudGVycHJpc2U2NjU3", + "avatar_url": "https://avatars.githubusercontent.com/b/6657?v=4", + "description": "", + "website_url": "https://harness.io", + "html_url": "https://github.com/enterprises/harness", + "created_at": "2021-04-13T17:56:36Z", + "updated_at": "2023-02-06T20:48:35Z" + }, + "sender": { + "login": "rathodmeetsatish", + "id": 84321134, + "node_id": "MDQ6VXNlcjg0MzIxMTM0", + "avatar_url": "https://avatars.githubusercontent.com/u/84321134?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/rathodmeetsatish", + "html_url": "https://github.com/rathodmeetsatish", + "followers_url": "https://api.github.com/users/rathodmeetsatish/followers", + "following_url": "https://api.github.com/users/rathodmeetsatish/following{/other_user}", + "gists_url": "https://api.github.com/users/rathodmeetsatish/gists{/gist_id}", + "starred_url": "https://api.github.com/users/rathodmeetsatish/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rathodmeetsatish/subscriptions", + "organizations_url": "https://api.github.com/users/rathodmeetsatish/orgs", + "repos_url": "https://api.github.com/users/rathodmeetsatish/repos", + "events_url": "https://api.github.com/users/rathodmeetsatish/events{/privacy}", + "received_events_url": "https://api.github.com/users/rathodmeetsatish/received_events", + "type": "User", + "site_admin": false + } +} diff --git a/scm/driver/github/testdata/webhooks/pr_ready_for_review.json.golden b/scm/driver/github/testdata/webhooks/pr_ready_for_review.json.golden new file mode 100644 index 000000000..653a28b1e --- /dev/null +++ b/scm/driver/github/testdata/webhooks/pr_ready_for_review.json.golden @@ -0,0 +1,55 @@ +{ + "Action": "review_ready", + "Repo": { + "ID": "498312568", + "Namespace": "wings-software", + "Name": "meet-git-sync-test", + "Perm": null, + "Branch": "main", + "Private": true, + "Visibility": 3, + "Clone": "https://github.com/wings-software/meet-git-sync-test.git", + "CloneSSH": "git@github.com:wings-software/meet-git-sync-test.git", + "Link": "https://github.com/wings-software/meet-git-sync-test", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 38, + "Title": "Update dgdggd.me", + "Body": null, + "Sha": "212015fb011c49a2913c4a1a860ce07c0821c362", + "Ref": "refs/pull/38/head", + "Target": "main", + "Source": "rathodmeetsatish-patch-25", + "Fork": "wings-software/meet-git-sync-test", + "Link": "https://github.com/wings-software/meet-git-sync-test/pull/38", + "Diff": "https://github.com/wings-software/meet-git-sync-test/pull/38.diff", + "Closed": null, + "Merged": null, + "Base": { + "Sha": "8b8d2b3e6a2ee6df108c8429e86c9a750e728f9d", + "Path": "refs/heads/main", + "Name": "main" + }, + "Head": { + "Sha": "212015fb011c49a2913c4a1a860ce07c0821c362", + "Path": "refs/heads/rathodmeetsatish-patch-25", + "Name": "rathodmeetsatish-patch-25" + }, + "Author": { + "Login": "rathodmeetsatish", + "Name": "", + "Email": "", + "Avatar": "https://avatars.githubusercontent.com/u/84321134?v=4" + }, + "Created": "2023-08-28T19:15:53Z", + "Updated": "2023-08-28T19:16:06Z" + }, + "Sender": { + "Login": "rathodmeetsatish", + "Name": "", + "Email": "", + "Avatar": "https://avatars.githubusercontent.com/u/84321134?v=4" + } +} diff --git a/scm/driver/github/testdata/webhooks/release_created.json b/scm/driver/github/testdata/webhooks/release_created.json new file mode 100644 index 000000000..39a6d8d78 --- /dev/null +++ b/scm/driver/github/testdata/webhooks/release_created.json @@ -0,0 +1,164 @@ +{ + "action": "created", + "release": { + "url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309", + "assets_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309/assets", + "upload_url": "https://uploads.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309/assets{?name,label}", + "html_url": "https://github.com/vcalasansh/harness-ngtriggers-test/releases/tag/v1.0.0", + "id": 81372309, + "author": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + }, + "node_id": "RE_kwDOH5utuc4E2aSV", + "tag_name": "v1.0.0", + "target_commitish": "test-branch", + "name": "New release!", + "draft": false, + "prerelease": false, + "created_at": "2022-10-28T13:03:11Z", + "published_at": "2022-10-28T16:36:52Z", + "assets": [ + + ], + "tarball_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/tarball/v1.0.0", + "zipball_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/zipball/v1.0.0", + "body": "New release!" + }, + "repository": { + "id": 530296249, + "node_id": "R_kgDOH5utuQ", + "name": "harness-ngtriggers-test", + "full_name": "vcalasansh/harness-ngtriggers-test", + "private": true, + "owner": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/vcalasansh/harness-ngtriggers-test", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test", + "forks_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/forks", + "keys_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/teams", + "hooks_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/hooks", + "issue_events_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues/events{/number}", + "events_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/events", + "assignees_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/assignees{/user}", + "branches_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/branches{/branch}", + "tags_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/tags", + "blobs_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/statuses/{sha}", + "languages_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/languages", + "stargazers_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/stargazers", + "contributors_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/contributors", + "subscribers_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/subscribers", + "subscription_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/subscription", + "commits_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/contents/{+path}", + "compare_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/merges", + "archive_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/downloads", + "issues_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues{/number}", + "pulls_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/pulls{/number}", + "milestones_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/milestones{/number}", + "notifications_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/labels{/name}", + "releases_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases{/id}", + "deployments_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/deployments", + "created_at": "2022-08-29T16:12:07Z", + "updated_at": "2022-08-29T16:12:07Z", + "pushed_at": "2022-10-28T16:36:27Z", + "git_url": "git://github.com/vcalasansh/harness-ngtriggers-test.git", + "ssh_url": "git@github.com:vcalasansh/harness-ngtriggers-test.git", + "clone_url": "https://github.com/vcalasansh/harness-ngtriggers-test.git", + "svn_url": "https://github.com/vcalasansh/harness-ngtriggers-test", + "homepage": null, + "size": 11, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": null, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + + ], + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "test-branch" + }, + "sender": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + } +} diff --git a/scm/driver/github/testdata/webhooks/release_created.json.golden b/scm/driver/github/testdata/webhooks/release_created.json.golden new file mode 100644 index 000000000..b7935c46d --- /dev/null +++ b/scm/driver/github/testdata/webhooks/release_created.json.golden @@ -0,0 +1,34 @@ +{ + "Action": "created", + "Release": { + "ID": 81372309, + "Title": "New release!", + "Description": "New release!", + "Link": "https://github.com/vcalasansh/harness-ngtriggers-test/releases/tag/v1.0.0", + "Tag": "v1.0.0", + "Commitish": "test-branch", + "Draft": false, + "Prerelease": false, + "Created": "2022-10-28T13:03:11Z", + "Published": "2022-10-28T16:36:52Z" + }, + "Repo": { + "ID": "530296249", + "Namespace": "vcalasansh", + "Name": "harness-ngtriggers-test", + "Perm": null, + "Branch": "test-branch", + "Private": true, + "Clone": "https://github.com/vcalasansh/harness-ngtriggers-test.git", + "CloneSSH": "git@github.com:vcalasansh/harness-ngtriggers-test.git", + "Link": "https://github.com/vcalasansh/harness-ngtriggers-test", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Sender": { + "Login": "vcalasansh", + "Name": "", + "Email": "", + "Avatar": "https://avatars.githubusercontent.com/u/109106581?v=4" + } +} diff --git a/scm/driver/github/testdata/webhooks/release_deleted.json b/scm/driver/github/testdata/webhooks/release_deleted.json new file mode 100644 index 000000000..a5ba0fef2 --- /dev/null +++ b/scm/driver/github/testdata/webhooks/release_deleted.json @@ -0,0 +1,164 @@ +{ + "action": "deleted", + "release": { + "url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309", + "assets_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309/assets", + "upload_url": "https://uploads.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309/assets{?name,label}", + "html_url": "https://github.com/vcalasansh/harness-ngtriggers-test/releases/tag/v1.0.0", + "id": 81372309, + "author": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + }, + "node_id": "RE_kwDOH5utuc4E2aSV", + "tag_name": "v1.0.0", + "target_commitish": "test-branch", + "name": "New release!", + "draft": false, + "prerelease": false, + "created_at": "2022-10-28T13:03:11Z", + "published_at": "2022-10-28T16:36:52Z", + "assets": [ + + ], + "tarball_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/tarball/v1.0.0", + "zipball_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/zipball/v1.0.0", + "body": "New release!" + }, + "repository": { + "id": 530296249, + "node_id": "R_kgDOH5utuQ", + "name": "harness-ngtriggers-test", + "full_name": "vcalasansh/harness-ngtriggers-test", + "private": true, + "owner": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/vcalasansh/harness-ngtriggers-test", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test", + "forks_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/forks", + "keys_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/teams", + "hooks_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/hooks", + "issue_events_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues/events{/number}", + "events_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/events", + "assignees_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/assignees{/user}", + "branches_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/branches{/branch}", + "tags_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/tags", + "blobs_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/statuses/{sha}", + "languages_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/languages", + "stargazers_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/stargazers", + "contributors_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/contributors", + "subscribers_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/subscribers", + "subscription_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/subscription", + "commits_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/contents/{+path}", + "compare_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/merges", + "archive_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/downloads", + "issues_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues{/number}", + "pulls_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/pulls{/number}", + "milestones_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/milestones{/number}", + "notifications_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/labels{/name}", + "releases_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases{/id}", + "deployments_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/deployments", + "created_at": "2022-08-29T16:12:07Z", + "updated_at": "2022-08-29T16:12:07Z", + "pushed_at": "2022-10-28T16:36:27Z", + "git_url": "git://github.com/vcalasansh/harness-ngtriggers-test.git", + "ssh_url": "git@github.com:vcalasansh/harness-ngtriggers-test.git", + "clone_url": "https://github.com/vcalasansh/harness-ngtriggers-test.git", + "svn_url": "https://github.com/vcalasansh/harness-ngtriggers-test", + "homepage": null, + "size": 11, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": null, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + + ], + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "test-branch" + }, + "sender": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + } +} diff --git a/scm/driver/github/testdata/webhooks/release_deleted.json.golden b/scm/driver/github/testdata/webhooks/release_deleted.json.golden new file mode 100644 index 000000000..30dee53c1 --- /dev/null +++ b/scm/driver/github/testdata/webhooks/release_deleted.json.golden @@ -0,0 +1,34 @@ +{ + "Action": "deleted", + "Release": { + "ID": 81372309, + "Title": "New release!", + "Description": "New release!", + "Link": "https://github.com/vcalasansh/harness-ngtriggers-test/releases/tag/v1.0.0", + "Tag": "v1.0.0", + "Commitish": "test-branch", + "Draft": false, + "Prerelease": false, + "Created": "2022-10-28T13:03:11Z", + "Published": "2022-10-28T16:36:52Z" + }, + "Repo": { + "ID": "530296249", + "Namespace": "vcalasansh", + "Name": "harness-ngtriggers-test", + "Perm": null, + "Branch": "test-branch", + "Private": true, + "Clone": "https://github.com/vcalasansh/harness-ngtriggers-test.git", + "CloneSSH": "git@github.com:vcalasansh/harness-ngtriggers-test.git", + "Link": "https://github.com/vcalasansh/harness-ngtriggers-test", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Sender": { + "Login": "vcalasansh", + "Name": "", + "Email": "", + "Avatar": "https://avatars.githubusercontent.com/u/109106581?v=4" + } +} diff --git a/scm/driver/github/testdata/webhooks/release_edited.json b/scm/driver/github/testdata/webhooks/release_edited.json new file mode 100644 index 000000000..45f7511b4 --- /dev/null +++ b/scm/driver/github/testdata/webhooks/release_edited.json @@ -0,0 +1,164 @@ +{ + "action": "edited", + "release": { + "url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309", + "assets_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309/assets", + "upload_url": "https://uploads.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309/assets{?name,label}", + "html_url": "https://github.com/vcalasansh/harness-ngtriggers-test/releases/tag/v1.0.0", + "id": 81372309, + "author": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + }, + "node_id": "RE_kwDOH5utuc4E2aSV", + "tag_name": "v1.0.0", + "target_commitish": "test-branch", + "name": "New release!", + "draft": false, + "prerelease": false, + "created_at": "2022-10-28T13:03:11Z", + "published_at": "2022-10-28T16:36:52Z", + "assets": [ + + ], + "tarball_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/tarball/v1.0.0", + "zipball_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/zipball/v1.0.0", + "body": "New release!" + }, + "repository": { + "id": 530296249, + "node_id": "R_kgDOH5utuQ", + "name": "harness-ngtriggers-test", + "full_name": "vcalasansh/harness-ngtriggers-test", + "private": true, + "owner": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/vcalasansh/harness-ngtriggers-test", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test", + "forks_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/forks", + "keys_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/teams", + "hooks_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/hooks", + "issue_events_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues/events{/number}", + "events_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/events", + "assignees_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/assignees{/user}", + "branches_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/branches{/branch}", + "tags_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/tags", + "blobs_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/statuses/{sha}", + "languages_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/languages", + "stargazers_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/stargazers", + "contributors_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/contributors", + "subscribers_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/subscribers", + "subscription_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/subscription", + "commits_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/contents/{+path}", + "compare_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/merges", + "archive_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/downloads", + "issues_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues{/number}", + "pulls_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/pulls{/number}", + "milestones_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/milestones{/number}", + "notifications_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/labels{/name}", + "releases_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases{/id}", + "deployments_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/deployments", + "created_at": "2022-08-29T16:12:07Z", + "updated_at": "2022-08-29T16:12:07Z", + "pushed_at": "2022-10-28T16:36:27Z", + "git_url": "git://github.com/vcalasansh/harness-ngtriggers-test.git", + "ssh_url": "git@github.com:vcalasansh/harness-ngtriggers-test.git", + "clone_url": "https://github.com/vcalasansh/harness-ngtriggers-test.git", + "svn_url": "https://github.com/vcalasansh/harness-ngtriggers-test", + "homepage": null, + "size": 11, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": null, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + + ], + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "test-branch" + }, + "sender": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + } +} diff --git a/scm/driver/github/testdata/webhooks/release_edited.json.golden b/scm/driver/github/testdata/webhooks/release_edited.json.golden new file mode 100644 index 000000000..0b1e387ad --- /dev/null +++ b/scm/driver/github/testdata/webhooks/release_edited.json.golden @@ -0,0 +1,34 @@ +{ + "Action": "edited", + "Release": { + "ID": 81372309, + "Title": "New release!", + "Description": "New release!", + "Link": "https://github.com/vcalasansh/harness-ngtriggers-test/releases/tag/v1.0.0", + "Tag": "v1.0.0", + "Commitish": "test-branch", + "Draft": false, + "Prerelease": false, + "Created": "2022-10-28T13:03:11Z", + "Published": "2022-10-28T16:36:52Z" + }, + "Repo": { + "ID": "530296249", + "Namespace": "vcalasansh", + "Name": "harness-ngtriggers-test", + "Perm": null, + "Branch": "test-branch", + "Private": true, + "Clone": "https://github.com/vcalasansh/harness-ngtriggers-test.git", + "CloneSSH": "git@github.com:vcalasansh/harness-ngtriggers-test.git", + "Link": "https://github.com/vcalasansh/harness-ngtriggers-test", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Sender": { + "Login": "vcalasansh", + "Name": "", + "Email": "", + "Avatar": "https://avatars.githubusercontent.com/u/109106581?v=4" + } +} diff --git a/scm/driver/github/testdata/webhooks/release_prereleased.json b/scm/driver/github/testdata/webhooks/release_prereleased.json new file mode 100644 index 000000000..94ab938c8 --- /dev/null +++ b/scm/driver/github/testdata/webhooks/release_prereleased.json @@ -0,0 +1,164 @@ +{ + "action": "prereleased", + "release": { + "url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309", + "assets_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309/assets", + "upload_url": "https://uploads.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309/assets{?name,label}", + "html_url": "https://github.com/vcalasansh/harness-ngtriggers-test/releases/tag/v1.0.0", + "id": 81372309, + "author": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + }, + "node_id": "RE_kwDOH5utuc4E2aSV", + "tag_name": "v1.0.0", + "target_commitish": "test-branch", + "name": "New release!", + "draft": false, + "prerelease": false, + "created_at": "2022-10-28T13:03:11Z", + "published_at": "2022-10-28T16:36:52Z", + "assets": [ + + ], + "tarball_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/tarball/v1.0.0", + "zipball_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/zipball/v1.0.0", + "body": "New release!" + }, + "repository": { + "id": 530296249, + "node_id": "R_kgDOH5utuQ", + "name": "harness-ngtriggers-test", + "full_name": "vcalasansh/harness-ngtriggers-test", + "private": true, + "owner": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/vcalasansh/harness-ngtriggers-test", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test", + "forks_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/forks", + "keys_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/teams", + "hooks_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/hooks", + "issue_events_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues/events{/number}", + "events_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/events", + "assignees_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/assignees{/user}", + "branches_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/branches{/branch}", + "tags_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/tags", + "blobs_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/statuses/{sha}", + "languages_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/languages", + "stargazers_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/stargazers", + "contributors_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/contributors", + "subscribers_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/subscribers", + "subscription_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/subscription", + "commits_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/contents/{+path}", + "compare_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/merges", + "archive_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/downloads", + "issues_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues{/number}", + "pulls_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/pulls{/number}", + "milestones_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/milestones{/number}", + "notifications_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/labels{/name}", + "releases_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases{/id}", + "deployments_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/deployments", + "created_at": "2022-08-29T16:12:07Z", + "updated_at": "2022-08-29T16:12:07Z", + "pushed_at": "2022-10-28T16:36:27Z", + "git_url": "git://github.com/vcalasansh/harness-ngtriggers-test.git", + "ssh_url": "git@github.com:vcalasansh/harness-ngtriggers-test.git", + "clone_url": "https://github.com/vcalasansh/harness-ngtriggers-test.git", + "svn_url": "https://github.com/vcalasansh/harness-ngtriggers-test", + "homepage": null, + "size": 11, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": null, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + + ], + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "test-branch" + }, + "sender": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + } +} diff --git a/scm/driver/github/testdata/webhooks/release_prereleased.json.golden b/scm/driver/github/testdata/webhooks/release_prereleased.json.golden new file mode 100644 index 000000000..996beb3a6 --- /dev/null +++ b/scm/driver/github/testdata/webhooks/release_prereleased.json.golden @@ -0,0 +1,34 @@ +{ + "Action": "prereleased", + "Release": { + "ID": 81372309, + "Title": "New release!", + "Description": "New release!", + "Link": "https://github.com/vcalasansh/harness-ngtriggers-test/releases/tag/v1.0.0", + "Tag": "v1.0.0", + "Commitish": "test-branch", + "Draft": false, + "Prerelease": false, + "Created": "2022-10-28T13:03:11Z", + "Published": "2022-10-28T16:36:52Z" + }, + "Repo": { + "ID": "530296249", + "Namespace": "vcalasansh", + "Name": "harness-ngtriggers-test", + "Perm": null, + "Branch": "test-branch", + "Private": true, + "Clone": "https://github.com/vcalasansh/harness-ngtriggers-test.git", + "CloneSSH": "git@github.com:vcalasansh/harness-ngtriggers-test.git", + "Link": "https://github.com/vcalasansh/harness-ngtriggers-test", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Sender": { + "Login": "vcalasansh", + "Name": "", + "Email": "", + "Avatar": "https://avatars.githubusercontent.com/u/109106581?v=4" + } +} diff --git a/scm/driver/github/testdata/webhooks/release_published.json b/scm/driver/github/testdata/webhooks/release_published.json new file mode 100644 index 000000000..23b9bad66 --- /dev/null +++ b/scm/driver/github/testdata/webhooks/release_published.json @@ -0,0 +1,164 @@ +{ + "action": "published", + "release": { + "url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309", + "assets_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309/assets", + "upload_url": "https://uploads.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309/assets{?name,label}", + "html_url": "https://github.com/vcalasansh/harness-ngtriggers-test/releases/tag/v1.0.0", + "id": 81372309, + "author": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + }, + "node_id": "RE_kwDOH5utuc4E2aSV", + "tag_name": "v1.0.0", + "target_commitish": "test-branch", + "name": "New release!", + "draft": false, + "prerelease": false, + "created_at": "2022-10-28T13:03:11Z", + "published_at": "2022-10-28T16:36:52Z", + "assets": [ + + ], + "tarball_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/tarball/v1.0.0", + "zipball_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/zipball/v1.0.0", + "body": "New release!" + }, + "repository": { + "id": 530296249, + "node_id": "R_kgDOH5utuQ", + "name": "harness-ngtriggers-test", + "full_name": "vcalasansh/harness-ngtriggers-test", + "private": true, + "owner": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/vcalasansh/harness-ngtriggers-test", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test", + "forks_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/forks", + "keys_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/teams", + "hooks_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/hooks", + "issue_events_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues/events{/number}", + "events_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/events", + "assignees_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/assignees{/user}", + "branches_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/branches{/branch}", + "tags_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/tags", + "blobs_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/statuses/{sha}", + "languages_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/languages", + "stargazers_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/stargazers", + "contributors_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/contributors", + "subscribers_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/subscribers", + "subscription_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/subscription", + "commits_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/contents/{+path}", + "compare_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/merges", + "archive_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/downloads", + "issues_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues{/number}", + "pulls_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/pulls{/number}", + "milestones_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/milestones{/number}", + "notifications_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/labels{/name}", + "releases_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases{/id}", + "deployments_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/deployments", + "created_at": "2022-08-29T16:12:07Z", + "updated_at": "2022-08-29T16:12:07Z", + "pushed_at": "2022-10-28T16:36:27Z", + "git_url": "git://github.com/vcalasansh/harness-ngtriggers-test.git", + "ssh_url": "git@github.com:vcalasansh/harness-ngtriggers-test.git", + "clone_url": "https://github.com/vcalasansh/harness-ngtriggers-test.git", + "svn_url": "https://github.com/vcalasansh/harness-ngtriggers-test", + "homepage": null, + "size": 11, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": null, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + + ], + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "test-branch" + }, + "sender": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + } +} diff --git a/scm/driver/github/testdata/webhooks/release_published.json.golden b/scm/driver/github/testdata/webhooks/release_published.json.golden new file mode 100644 index 000000000..a1f070b04 --- /dev/null +++ b/scm/driver/github/testdata/webhooks/release_published.json.golden @@ -0,0 +1,34 @@ +{ + "Action": "published", + "Release": { + "ID": 81372309, + "Title": "New release!", + "Description": "New release!", + "Link": "https://github.com/vcalasansh/harness-ngtriggers-test/releases/tag/v1.0.0", + "Tag": "v1.0.0", + "Commitish": "test-branch", + "Draft": false, + "Prerelease": false, + "Created": "2022-10-28T13:03:11Z", + "Published": "2022-10-28T16:36:52Z" + }, + "Repo": { + "ID": "530296249", + "Namespace": "vcalasansh", + "Name": "harness-ngtriggers-test", + "Perm": null, + "Branch": "test-branch", + "Private": true, + "Clone": "https://github.com/vcalasansh/harness-ngtriggers-test.git", + "CloneSSH": "git@github.com:vcalasansh/harness-ngtriggers-test.git", + "Link": "https://github.com/vcalasansh/harness-ngtriggers-test", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Sender": { + "Login": "vcalasansh", + "Name": "", + "Email": "", + "Avatar": "https://avatars.githubusercontent.com/u/109106581?v=4" + } +} diff --git a/scm/driver/github/testdata/webhooks/release_released.json b/scm/driver/github/testdata/webhooks/release_released.json new file mode 100644 index 000000000..b4af3b457 --- /dev/null +++ b/scm/driver/github/testdata/webhooks/release_released.json @@ -0,0 +1,164 @@ +{ + "action": "released", + "release": { + "url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309", + "assets_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309/assets", + "upload_url": "https://uploads.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309/assets{?name,label}", + "html_url": "https://github.com/vcalasansh/harness-ngtriggers-test/releases/tag/v1.0.0", + "id": 81372309, + "author": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + }, + "node_id": "RE_kwDOH5utuc4E2aSV", + "tag_name": "v1.0.0", + "target_commitish": "test-branch", + "name": "New release!", + "draft": false, + "prerelease": false, + "created_at": "2022-10-28T13:03:11Z", + "published_at": "2022-10-28T16:36:52Z", + "assets": [ + + ], + "tarball_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/tarball/v1.0.0", + "zipball_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/zipball/v1.0.0", + "body": "New release!" + }, + "repository": { + "id": 530296249, + "node_id": "R_kgDOH5utuQ", + "name": "harness-ngtriggers-test", + "full_name": "vcalasansh/harness-ngtriggers-test", + "private": true, + "owner": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/vcalasansh/harness-ngtriggers-test", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test", + "forks_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/forks", + "keys_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/teams", + "hooks_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/hooks", + "issue_events_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues/events{/number}", + "events_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/events", + "assignees_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/assignees{/user}", + "branches_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/branches{/branch}", + "tags_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/tags", + "blobs_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/statuses/{sha}", + "languages_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/languages", + "stargazers_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/stargazers", + "contributors_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/contributors", + "subscribers_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/subscribers", + "subscription_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/subscription", + "commits_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/contents/{+path}", + "compare_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/merges", + "archive_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/downloads", + "issues_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues{/number}", + "pulls_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/pulls{/number}", + "milestones_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/milestones{/number}", + "notifications_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/labels{/name}", + "releases_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases{/id}", + "deployments_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/deployments", + "created_at": "2022-08-29T16:12:07Z", + "updated_at": "2022-08-29T16:12:07Z", + "pushed_at": "2022-10-28T16:36:27Z", + "git_url": "git://github.com/vcalasansh/harness-ngtriggers-test.git", + "ssh_url": "git@github.com:vcalasansh/harness-ngtriggers-test.git", + "clone_url": "https://github.com/vcalasansh/harness-ngtriggers-test.git", + "svn_url": "https://github.com/vcalasansh/harness-ngtriggers-test", + "homepage": null, + "size": 11, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": null, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + + ], + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "test-branch" + }, + "sender": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + } +} diff --git a/scm/driver/github/testdata/webhooks/release_released.json.golden b/scm/driver/github/testdata/webhooks/release_released.json.golden new file mode 100644 index 000000000..3e93aa08e --- /dev/null +++ b/scm/driver/github/testdata/webhooks/release_released.json.golden @@ -0,0 +1,34 @@ +{ + "Action": "released", + "Release": { + "ID": 81372309, + "Title": "New release!", + "Description": "New release!", + "Link": "https://github.com/vcalasansh/harness-ngtriggers-test/releases/tag/v1.0.0", + "Tag": "v1.0.0", + "Commitish": "test-branch", + "Draft": false, + "Prerelease": false, + "Created": "2022-10-28T13:03:11Z", + "Published": "2022-10-28T16:36:52Z" + }, + "Repo": { + "ID": "530296249", + "Namespace": "vcalasansh", + "Name": "harness-ngtriggers-test", + "Perm": null, + "Branch": "test-branch", + "Private": true, + "Clone": "https://github.com/vcalasansh/harness-ngtriggers-test.git", + "CloneSSH": "git@github.com:vcalasansh/harness-ngtriggers-test.git", + "Link": "https://github.com/vcalasansh/harness-ngtriggers-test", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Sender": { + "Login": "vcalasansh", + "Name": "", + "Email": "", + "Avatar": "https://avatars.githubusercontent.com/u/109106581?v=4" + } +} diff --git a/scm/driver/github/testdata/webhooks/release_unpublished.json b/scm/driver/github/testdata/webhooks/release_unpublished.json new file mode 100644 index 000000000..6ee38d4e2 --- /dev/null +++ b/scm/driver/github/testdata/webhooks/release_unpublished.json @@ -0,0 +1,164 @@ +{ + "action": "unpublished", + "release": { + "url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309", + "assets_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309/assets", + "upload_url": "https://uploads.github.com/repos/vcalasansh/harness-ngtriggers-test/releases/81372309/assets{?name,label}", + "html_url": "https://github.com/vcalasansh/harness-ngtriggers-test/releases/tag/v1.0.0", + "id": 81372309, + "author": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + }, + "node_id": "RE_kwDOH5utuc4E2aSV", + "tag_name": "v1.0.0", + "target_commitish": "test-branch", + "name": "New release!", + "draft": false, + "prerelease": false, + "created_at": "2022-10-28T13:03:11Z", + "published_at": "2022-10-28T16:36:52Z", + "assets": [ + + ], + "tarball_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/tarball/v1.0.0", + "zipball_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/zipball/v1.0.0", + "body": "New release!" + }, + "repository": { + "id": 530296249, + "node_id": "R_kgDOH5utuQ", + "name": "harness-ngtriggers-test", + "full_name": "vcalasansh/harness-ngtriggers-test", + "private": true, + "owner": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/vcalasansh/harness-ngtriggers-test", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test", + "forks_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/forks", + "keys_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/teams", + "hooks_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/hooks", + "issue_events_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues/events{/number}", + "events_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/events", + "assignees_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/assignees{/user}", + "branches_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/branches{/branch}", + "tags_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/tags", + "blobs_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/statuses/{sha}", + "languages_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/languages", + "stargazers_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/stargazers", + "contributors_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/contributors", + "subscribers_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/subscribers", + "subscription_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/subscription", + "commits_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/contents/{+path}", + "compare_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/merges", + "archive_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/downloads", + "issues_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/issues{/number}", + "pulls_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/pulls{/number}", + "milestones_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/milestones{/number}", + "notifications_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/labels{/name}", + "releases_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/releases{/id}", + "deployments_url": "https://api.github.com/repos/vcalasansh/harness-ngtriggers-test/deployments", + "created_at": "2022-08-29T16:12:07Z", + "updated_at": "2022-08-29T16:12:07Z", + "pushed_at": "2022-10-28T16:36:27Z", + "git_url": "git://github.com/vcalasansh/harness-ngtriggers-test.git", + "ssh_url": "git@github.com:vcalasansh/harness-ngtriggers-test.git", + "clone_url": "https://github.com/vcalasansh/harness-ngtriggers-test.git", + "svn_url": "https://github.com/vcalasansh/harness-ngtriggers-test", + "homepage": null, + "size": 11, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": null, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + + ], + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "test-branch" + }, + "sender": { + "login": "vcalasansh", + "id": 109106581, + "node_id": "U_kgDOBoDVlQ", + "avatar_url": "https://avatars.githubusercontent.com/u/109106581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vcalasansh", + "html_url": "https://github.com/vcalasansh", + "followers_url": "https://api.github.com/users/vcalasansh/followers", + "following_url": "https://api.github.com/users/vcalasansh/following{/other_user}", + "gists_url": "https://api.github.com/users/vcalasansh/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vcalasansh/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vcalasansh/subscriptions", + "organizations_url": "https://api.github.com/users/vcalasansh/orgs", + "repos_url": "https://api.github.com/users/vcalasansh/repos", + "events_url": "https://api.github.com/users/vcalasansh/events{/privacy}", + "received_events_url": "https://api.github.com/users/vcalasansh/received_events", + "type": "User", + "site_admin": false + } +} diff --git a/scm/driver/github/testdata/webhooks/release_unpublished.json.golden b/scm/driver/github/testdata/webhooks/release_unpublished.json.golden new file mode 100644 index 000000000..21ea08eea --- /dev/null +++ b/scm/driver/github/testdata/webhooks/release_unpublished.json.golden @@ -0,0 +1,34 @@ +{ + "Action": "unpublished", + "Release": { + "ID": 81372309, + "Title": "New release!", + "Description": "New release!", + "Link": "https://github.com/vcalasansh/harness-ngtriggers-test/releases/tag/v1.0.0", + "Tag": "v1.0.0", + "Commitish": "test-branch", + "Draft": false, + "Prerelease": false, + "Created": "2022-10-28T13:03:11Z", + "Published": "2022-10-28T16:36:52Z" + }, + "Repo": { + "ID": "530296249", + "Namespace": "vcalasansh", + "Name": "harness-ngtriggers-test", + "Perm": null, + "Branch": "test-branch", + "Private": true, + "Clone": "https://github.com/vcalasansh/harness-ngtriggers-test.git", + "CloneSSH": "git@github.com:vcalasansh/harness-ngtriggers-test.git", + "Link": "https://github.com/vcalasansh/harness-ngtriggers-test", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Sender": { + "Login": "vcalasansh", + "Name": "", + "Email": "", + "Avatar": "https://avatars.githubusercontent.com/u/109106581?v=4" + } +} diff --git a/scm/driver/github/user.go b/scm/driver/github/user.go index dfccdc8c9..db34ade76 100644 --- a/scm/driver/github/user.go +++ b/scm/driver/github/user.go @@ -31,16 +31,8 @@ func (s *userService) FindLogin(ctx context.Context, login string) (*scm.User, * } func (s *userService) FindEmail(ctx context.Context) (string, *scm.Response, error) { - out := []*email{} - res, err := s.client.do(ctx, "GET", "user/emails", nil, &out) - email := "" - for i := range out { - if out[i].Primary { - email = out[i].Email - break - } - } - return email, res, err + out, res, err := s.ListEmail(ctx, scm.ListOptions{}) + return returnPrimaryEmail(out), res, err } func (s *userService) ListEmail(ctx context.Context, opts scm.ListOptions) ([]*scm.Email, *scm.Response, error) { @@ -78,6 +70,15 @@ func convertUser(from *user) *scm.User { } } +func returnPrimaryEmail(from []*scm.Email) string { + for _, v := range from { + if v.Primary == true { + return v.Value + } + } + return "" +} + // helper function to convert from the github email list to // the common email structure. func convertEmailList(from []*email) []*scm.Email { diff --git a/scm/driver/github/user_test.go b/scm/driver/github/user_test.go index b0b121c8e..a197c762a 100644 --- a/scm/driver/github/user_test.go +++ b/scm/driver/github/user_test.go @@ -87,6 +87,7 @@ func TestUserEmailFind(t *testing.T) { defer gock.Off() gock.New("https://api.github.com"). + Get("/user/emails"). Get("/user/emails"). Reply(200). Type("application/json"). @@ -94,7 +95,7 @@ func TestUserEmailFind(t *testing.T) { SetHeader("X-RateLimit-Limit", "60"). SetHeader("X-RateLimit-Remaining", "59"). SetHeader("X-RateLimit-Reset", "1512076018"). - File("testdata/useremails.json") + File("testdata/emails.json") client := NewDefault() result, res, err := client.Users.FindEmail(context.Background()) diff --git a/scm/driver/github/util.go b/scm/driver/github/util.go index 5d5fb4741..24a0c858c 100644 --- a/scm/driver/github/util.go +++ b/scm/driver/github/util.go @@ -7,6 +7,7 @@ package github import ( "net/url" "strconv" + "strings" "github.com/drone/go-scm/scm" ) @@ -22,6 +23,33 @@ func encodeListOptions(opts scm.ListOptions) string { return params.Encode() } +func encodeRepoListOptions(opts scm.RepoListOptions) string { + var sb strings.Builder + if opts.RepoSearchTerm != (scm.RepoSearchTerm{}) { + if opts.RepoSearchTerm.RepoName != "" { + sb.WriteString("q=") + sb.WriteString(opts.RepoSearchTerm.RepoName) + sb.WriteString("+in:name+user:") + sb.WriteString(opts.RepoSearchTerm.User) + } else { + sb.WriteString("q=") + sb.WriteString("user:") + sb.WriteString(opts.RepoSearchTerm.User) + } + } + if opts.ListOptions != (scm.ListOptions{}) { + if opts.ListOptions.Page != 0 { + sb.WriteString("&page=") + sb.WriteString(strconv.Itoa(opts.ListOptions.Page)) + } + if opts.ListOptions.Size != 0 { + sb.WriteString("&per_page=") + sb.WriteString(strconv.Itoa(opts.ListOptions.Size)) + } + } + return sb.String() +} + func encodeCommitListOptions(opts scm.CommitListOptions) string { params := url.Values{} if opts.Page != 0 { diff --git a/scm/driver/github/webhook.go b/scm/driver/github/webhook.go index 2d2dae333..a4d7265ea 100644 --- a/scm/driver/github/webhook.go +++ b/scm/driver/github/webhook.go @@ -48,6 +48,10 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo // case "issues": case "issue_comment": hook, err = s.parseIssueCommentHook(data) + case "release": + hook, err = s.parseReleaseHook(data) + case "workflow_run": + hook, err = s.parsePipelineHook(data) default: return nil, scm.ErrUnknownEvent } @@ -172,7 +176,9 @@ func (s *webhookService) parsePullRequestHook(data []byte) (scm.Webhook, error) dst.Action = scm.ActionReopen case "synchronize": dst.Action = scm.ActionSync - case "assigned", "unassigned", "review_requested", "review_request_removed", "ready_for_review", "locked", "unlocked": + case "ready_for_review": + dst.Action = scm.ActionReviewReady + case "assigned", "unassigned", "review_requested", "review_request_removed", "locked", "unlocked": dst.Action = scm.ActionUnknown default: dst.Action = scm.ActionUnknown @@ -180,6 +186,90 @@ func (s *webhookService) parsePullRequestHook(data []byte) (scm.Webhook, error) return dst, nil } +func (s *webhookService) parsePipelineHook(data []byte) (scm.Webhook, error) { + src := new(pipelineHook) + err := json.Unmarshal(data, src) + if err != nil { + return nil, err + } + dst, err := convertPipelineHook(src), nil + return dst, nil +} + +func convertPipelineHook(src *pipelineHook) *scm.PipelineHook { + pr := scm.PullRequest{} + if len(src.WorkflowRun.PullRequests) > 0 { + pr = scm.PullRequest{ + Number: src.WorkflowRun.PullRequests[0].Number, + Sha: src.WorkflowRun.PullRequests[0].Head.SHA, + Ref: src.WorkflowRun.PullRequests[0].Head.Ref, + Source: src.WorkflowRun.PullRequests[0].Head.Ref, + Target: src.WorkflowRun.PullRequests[0].Base.Ref, + Link: src.WorkflowRun.PullRequests[0].URL, + Created: src.WorkflowRun.CreatedAt, + } + } + + var execution_status string + if src.WorkflowRun.Status == "completed" { + execution_status = src.WorkflowRun.Conclusion.String + } else { + execution_status = src.WorkflowRun.Status + } + + return &scm.PipelineHook{ + Repo: *convertRepository(&src.Repository), + Commit: scm.Commit{ + Sha: src.WorkflowRun.HeadCommit.ID, + Message: src.WorkflowRun.HeadCommit.Message, + Author: scm.Signature{ + Name: src.WorkflowRun.HeadCommit.Author.Name, + Email: src.WorkflowRun.HeadCommit.Author.Email, + }, + Committer: scm.Signature{ + Name: src.WorkflowRun.HeadCommit.Committer.Name, + Email: src.WorkflowRun.HeadCommit.Committer.Email, + }, + }, + Execution: scm.Execution{ + Number: int(src.WorkflowRun.RunNumber), + Status: scm.ConvertExecutionStatus(execution_status), + Created: src.WorkflowRun.CreatedAt, + URL: src.WorkflowRun.URL, + }, + Sender: *convertUser(&src.Sender), + PullRequest: pr, + } +} + +func (s *webhookService) parseReleaseHook(data []byte) (scm.Webhook, error) { + src := new(releaseHook) + err := json.Unmarshal(data, src) + if err != nil { + return nil, err + } + dst := convertReleaseHook(src) + switch src.Action { + case "created": + dst.Action = scm.ActionCreate + case "edited": + dst.Action = scm.ActionEdit + case "deleted": + dst.Action = scm.ActionDelete + case "published": + dst.Action = scm.ActionPublish + case "unpublished": + dst.Action = scm.ActionUnpublish + case "prereleased": + dst.Action = scm.ActionPrerelease + case "released": + dst.Action = scm.ActionRelease + default: + dst.Action = scm.ActionUnknown + } + return dst, nil +} + func (s *webhookService) parsePingHook(data []byte) (scm.Webhook, error) { src := new(pingHook) err := json.Unmarshal(data, src) @@ -319,6 +409,99 @@ type ( Updated time.Time `json:"updated_at"` } `json:"comment"` } + + // github release webhook payload + releaseHook struct { + Action string `json:"action"` + 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"` + } `json:"release"` + Repository repository `json:"repository"` + Sender user `json:"sender"` + } + + pipelineHook struct { + Action string `json:"action"` + Sender user + WorkflowRun struct { + ID int64 `json:"id"` + Name string `json:"name"` + NodeID string `json:"node_id"` + HeadBranch string `json:"head_branch"` + HeadSHA string `json:"head_sha"` + Path string `json:"path"` + DisplayTitle string `json:"display_title"` + RunNumber int `json:"run_number"` + Event string `json:"event"` + Status string `json:"status"` + Conclusion null.String `json:"conclusion"` + WorkflowID int64 `json:"workflow_id"` + CheckSuiteID int64 `json:"check_suite_id"` + CheckSuiteNodeID string `json:"check_suite_node_id"` + URL string `json:"url"` + HtmlURL string `json:"html_url"` + PullRequests []struct { + URL string `json:"url"` + ID int64 `json:"id"` + Number int `json:"number"` + Head gitRef `json:"head"` + Base gitRef `json:"base"` + } `json:"pull_requests"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Actor owner `json:"actor"` + RunAttempt int `json:"run_attempt"` + RunStartedAt time.Time `json:"run_started_at"` + TriggeringActor owner `json:"triggering_actor"` + JobsURL string `json:"jobs_url"` + LogsURL string `json:"logs_url"` + CheckSuiteURL string `json:"check_suite_url"` + ArtifactsURL string `json:"artifacts_url"` + CancelURL string `json:"cancel_url"` + RerunURL string `json:"rerun_url"` + PreviousAttemptURL null.String `json:"previous_attempt_url"` + WorkflowURL string `json:"workflow_url"` + HeadCommit struct { + ID string `json:"id"` + TreeID string `json:"tree_id"` + Message string `json:"message"` + Timestamp time.Time `json:"timestamp"` + Author author `json:"author"` + Committer author `json:"committer"` + } `json:"head_commit"` + } `json:"workflow_run"` + Repository repository `json:"repository"` + } + + gitRef struct { + Ref string `json:"ref"` + SHA string `json:"sha"` + Repo repository `json:"repo"` + } + + owner struct { + Login string `json:"login"` + ID int64 `json:"id"` + NodeID string `json:"node_id"` + AvatarURL string `json:"avatar_url"` + HTMLURL string `json:"html_url"` + Type string `json:"type"` + SiteAdmin bool `json:"site_admin"` + } + + author struct { + Name string `json:"name"` + Email string `json:"email"` + } ) // @@ -378,7 +561,7 @@ func convertPushHook(src *pushHook) *scm.PushHook { Name: src.Repository.Name, Branch: src.Repository.DefaultBranch, Private: src.Repository.Private, - Visibility: convertVisibility(src.Repository.Visibility), + Visibility: scm.ConvertVisibility(src.Repository.Visibility), Clone: src.Repository.CloneURL, CloneSSH: src.Repository.SSHURL, Link: src.Repository.HTMLURL, @@ -405,7 +588,7 @@ func convertBranchHook(src *createDeleteHook) *scm.BranchHook { Name: src.Repository.Name, Branch: src.Repository.DefaultBranch, Private: src.Repository.Private, - Visibility: convertVisibility(src.Repository.Visibility), + Visibility: scm.ConvertVisibility(src.Repository.Visibility), Clone: src.Repository.CloneURL, CloneSSH: src.Repository.SSHURL, Link: src.Repository.HTMLURL, @@ -425,7 +608,7 @@ func convertTagHook(src *createDeleteHook) *scm.TagHook { Name: src.Repository.Name, Branch: src.Repository.DefaultBranch, Private: src.Repository.Private, - Visibility: convertVisibility(src.Repository.Visibility), + Visibility: scm.ConvertVisibility(src.Repository.Visibility), Clone: src.Repository.CloneURL, CloneSSH: src.Repository.SSHURL, Link: src.Repository.HTMLURL, @@ -443,7 +626,7 @@ func convertPullRequestHook(src *pullRequestHook) *scm.PullRequestHook { Name: src.Repository.Name, Branch: src.Repository.DefaultBranch, Private: src.Repository.Private, - Visibility: convertVisibility(src.Repository.Visibility), + Visibility: scm.ConvertVisibility(src.Repository.Visibility), Clone: src.Repository.CloneURL, CloneSSH: src.Repository.SSHURL, Link: src.Repository.HTMLURL, @@ -469,7 +652,7 @@ func convertDeploymentHook(src *deploymentHook) *scm.DeployHook { Name: src.Repository.Name, Branch: src.Repository.DefaultBranch, Private: src.Repository.Private, - Visibility: convertVisibility(src.Repository.Visibility), + Visibility: scm.ConvertVisibility(src.Repository.Visibility), Clone: src.Repository.CloneURL, CloneSSH: src.Repository.SSHURL, Link: src.Repository.HTMLURL, @@ -518,7 +701,7 @@ func convertIssueCommentHook(src *issueCommentHook) *scm.IssueCommentHook { Name: src.Repository.Name, Branch: src.Repository.DefaultBranch, Private: src.Repository.Private, - Visibility: convertVisibility(src.Repository.Visibility), + Visibility: scm.ConvertVisibility(src.Repository.Visibility), Clone: src.Repository.CloneURL, CloneSSH: src.Repository.SSHURL, Link: src.Repository.HTMLURL, @@ -536,6 +719,36 @@ func convertIssueCommentHook(src *issueCommentHook) *scm.IssueCommentHook { return dst } +func convertReleaseHook(src *releaseHook) *scm.ReleaseHook { + dst := &scm.ReleaseHook{ + Release: scm.Release{ + ID: src.Release.ID, + Title: src.Release.Title, + Description: src.Release.Description, + Link: src.Release.Link, + Tag: src.Release.Tag, + Commitish: src.Release.Commitish, + Draft: src.Release.Draft, + Prerelease: src.Release.Prerelease, + Created: src.Release.Created, + Published: src.Release.Published, + }, + 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, + Visibility: scm.ConvertVisibility(src.Repository.Visibility), + Clone: src.Repository.CloneURL, + CloneSSH: src.Repository.SSHURL, + Link: src.Repository.HTMLURL, + }, + Sender: *convertUser(&src.Sender), + } + 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+).(.+)") diff --git a/scm/driver/github/webhook_test.go b/scm/driver/github/webhook_test.go index e54970f0d..f30804fa3 100644 --- a/scm/driver/github/webhook_test.go +++ b/scm/driver/github/webhook_test.go @@ -25,9 +25,7 @@ func TestWebhooks(t *testing.T) { after string obj interface{} }{ - // // push events - // // push hooks { @@ -126,6 +124,13 @@ func TestWebhooks(t *testing.T) { after: "testdata/webhooks/pr_sync.json.golden", obj: new(scm.PullRequestHook), }, + // pull request ready for review + { + event: "pull_request", + before: "testdata/webhooks/pr_ready_for_review.json", + after: "testdata/webhooks/pr_ready_for_review.json.golden", + obj: new(scm.PullRequestHook), + }, // pull request opened { event: "pull_request", @@ -185,6 +190,57 @@ func TestWebhooks(t *testing.T) { after: "testdata/webhooks/deployment_commit.json.golden", obj: new(scm.DeployHook), }, + // + // release + // + { + event: "release", + before: "testdata/webhooks/release_published.json", + after: "testdata/webhooks/release_published.json.golden", + obj: new(scm.ReleaseHook), + }, + { + event: "release", + before: "testdata/webhooks/release_unpublished.json", + after: "testdata/webhooks/release_unpublished.json.golden", + obj: new(scm.ReleaseHook), + }, + { + event: "release", + before: "testdata/webhooks/release_created.json", + after: "testdata/webhooks/release_created.json.golden", + obj: new(scm.ReleaseHook), + }, + { + event: "release", + before: "testdata/webhooks/release_edited.json", + after: "testdata/webhooks/release_edited.json.golden", + obj: new(scm.ReleaseHook), + }, + { + event: "release", + before: "testdata/webhooks/release_deleted.json", + after: "testdata/webhooks/release_deleted.json.golden", + obj: new(scm.ReleaseHook), + }, + { + event: "release", + before: "testdata/webhooks/release_prereleased.json", + after: "testdata/webhooks/release_prereleased.json.golden", + obj: new(scm.ReleaseHook), + }, + { + event: "release", + before: "testdata/webhooks/release_released.json", + after: "testdata/webhooks/release_released.json.golden", + obj: new(scm.ReleaseHook), + }, + { + event: "workflow_run", + before: "testdata/webhooks/pipeline_hook.json", + after: "testdata/webhooks/pipeline_hook.json.golden", + obj: new(scm.PipelineHook), + }, } for _, test := range tests { diff --git a/scm/driver/gitlab/content.go b/scm/driver/gitlab/content.go index feef351f1..118802220 100644 --- a/scm/driver/gitlab/content.go +++ b/scm/driver/gitlab/content.go @@ -19,7 +19,8 @@ type contentService struct { } func (s *contentService) Find(ctx context.Context, repo, path, ref string) (*scm.Content, *scm.Response, error) { - endpoint := fmt.Sprintf("api/v4/projects/%s/repository/files/%s?ref=%s", encode(repo), encodePath(path), ref) + urlEncodedRef := url.QueryEscape(ref) + endpoint := fmt.Sprintf("api/v4/projects/%s/repository/files/%s?ref=%s", encode(repo), encodePath(path), urlEncodedRef) out := new(content) res, err := s.client.do(ctx, "GET", endpoint, nil, out) raw, berr := base64.StdEncoding.DecodeString(out.Content) diff --git a/scm/driver/gitlab/content_test.go b/scm/driver/gitlab/content_test.go index d7baa5bbe..11cfa50a7 100644 --- a/scm/driver/gitlab/content_test.go +++ b/scm/driver/gitlab/content_test.go @@ -48,6 +48,35 @@ func TestContentFind(t *testing.T) { t.Log(diff) } + gock.New("https://gitlab.com"). + Get("/api/v4/projects/diaspora/diaspora/repository/files/app/models/key.rb"). + MatchParam("ref", "b1&b2"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/content.json") + + client = NewDefault() + got, res, err = client.Contents.Find( + context.Background(), + "diaspora/diaspora", + "app/models/key.rb", + "b1&b2", + ) + if err != nil { + t.Error(err) + return + } + + want = new(scm.Content) + raw, _ = ioutil.ReadFile("testdata/content.json.golden") + json.Unmarshal(raw, want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + t.Run("Request", testRequest(res)) t.Run("Rate", testRate(res)) } diff --git a/scm/driver/gitlab/git.go b/scm/driver/gitlab/git.go index e9a1cffef..3bc37ef7d 100644 --- a/scm/driver/gitlab/git.go +++ b/scm/driver/gitlab/git.go @@ -7,6 +7,8 @@ package gitlab import ( "context" "fmt" + "net/url" + "strings" "time" "github.com/drone/go-scm/scm" @@ -16,7 +18,7 @@ type gitService struct { client *wrapper } -func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.CreateBranch) (*scm.Response, error) { +func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.ReferenceInput) (*scm.Response, error) { path := fmt.Sprintf("api/v4/projects/%s/repository/branches", encode(repo)) in := &createBranch{ Branch: params.Name, @@ -33,6 +35,11 @@ func (s *gitService) FindBranch(ctx context.Context, repo, name string) (*scm.Re } func (s *gitService) FindCommit(ctx context.Context, repo, ref string) (*scm.Commit, *scm.Response, error) { + // if the reference is a branch, ensure forward slashes + // in the branch name are escaped. + if strings.Contains("ref", "/") { + ref = url.PathEscape(ref) + } path := fmt.Sprintf("api/v4/projects/%s/repository/commits/%s", encode(repo), scm.TrimRef(ref)) out := new(commit) res, err := s.client.do(ctx, "GET", path, nil, out) @@ -53,6 +60,13 @@ func (s *gitService) ListBranches(ctx context.Context, repo string, opts scm.Lis return convertBranchList(out), res, err } +func (s *gitService) ListBranchesV2(ctx context.Context, repo string, opts scm.BranchListOptions) ([]*scm.Reference, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/repository/branches?%s", encode(repo), encodeBranchListOptions(opts)) + out := []*branch{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertBranchList(out), res, err +} + func (s *gitService) ListCommits(ctx context.Context, repo string, opts scm.CommitListOptions) ([]*scm.Commit, *scm.Response, error) { path := fmt.Sprintf("api/v4/projects/%s/repository/commits?%s", encode(repo), encodeCommitListOptions(opts)) out := []*commit{} diff --git a/scm/driver/gitlab/git_test.go b/scm/driver/gitlab/git_test.go index 6315b85b9..49fefee66 100644 --- a/scm/driver/gitlab/git_test.go +++ b/scm/driver/gitlab/git_test.go @@ -90,7 +90,7 @@ func TestGitCreateBranch(t *testing.T) { SetHeaders(mockHeaders). File("testdata/branch_create.json") - params := &scm.CreateBranch{ + params := &scm.ReferenceInput{ Name: "yooo", Sha: "0efb1bed7c6a4871cb4ddb862ecc2111e11f31ee", } @@ -206,6 +206,38 @@ func TestGitListBranches(t *testing.T) { t.Run("Page", testPage(res)) } +func TestGitListBranchesWithBranchFilter(t *testing.T) { + defer gock.Off() + + gock.New("https://gitlab.com"). + Get("/api/v4/projects/diaspora/diaspora/repository/branches"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/branches_filter.json") + + client := NewDefault() + got, res, err := client.Git.ListBranchesV2(context.Background(), "diaspora/diaspora", scm.BranchListOptions{SearchTerm: "mast"}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Reference{} + raw, _ := ioutil.ReadFile("testdata/branches_filter.json.golden") + json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) + t.Run("Page", testPage(res)) +} + func TestGitListTags(t *testing.T) { defer gock.Off() diff --git a/scm/driver/gitlab/pr.go b/scm/driver/gitlab/pr.go index 2d4d46720..f161cf28b 100644 --- a/scm/driver/gitlab/pr.go +++ b/scm/driver/gitlab/pr.go @@ -60,14 +60,23 @@ func (s *pullService) ListCommits(ctx context.Context, repo string, number int, } func (s *pullService) Create(ctx context.Context, repo string, input *scm.PullRequestInput) (*scm.PullRequest, *scm.Response, error) { - in := url.Values{} - in.Set("title", input.Title) - in.Set("description", input.Body) - in.Set("source_branch", input.Source) - in.Set("target_branch", input.Target) - path := fmt.Sprintf("api/v4/projects/%s/merge_requests?%s", encode(repo), in.Encode()) + // https://docs.gitlab.com/ee/api/merge_requests.html#create-mr + in := struct { + Title string `json:"title"` + Description string `json:"description"` + SourceBranch string `json:"source_branch"` + TargetBranch string `json:"target_branch"` + }{ + Title: input.Title, + Description: input.Body, + SourceBranch: input.Source, + TargetBranch: input.Target, + } + + path := fmt.Sprintf("api/v4/projects/%s/merge_requests", encode(repo)) + out := new(pr) - res, err := s.client.do(ctx, "POST", path, nil, out) + res, err := s.client.do(ctx, "POST", path, in, out) return convertPullRequest(out), res, err } @@ -99,13 +108,14 @@ func (s *pullService) Close(ctx context.Context, repo string, number int) (*scm. } type pr struct { - Number int `json:"iid"` - Sha string `json:"sha"` - Title string `json:"title"` - Desc string `json:"description"` - State string `json:"state"` - Link string `json:"web_url"` - Author struct { + Number int `json:"iid"` + Sha string `json:"sha"` + Title string `json:"title"` + Desc string `json:"description"` + State string `json:"state"` + WorkInProgress bool `json:"work_in_progress"` + Link string `json:"web_url"` + Author struct { Username string `json:"username"` Email string `json:"email"` Name string `json:"name"` @@ -118,9 +128,9 @@ type pr struct { Closed time.Time Labels []string `json:"labels"` DiffRefs struct { - BaseCommit string `json:"base_sha"` - HeadCommit string `json:"head_sha"` - StartCommit string `json:"start_sha"` + BaseSha string `json:"base_sha"` + HeadSha string `json:"head_sha"` + StartSha string `json:"start_sha"` } `json:"diff_refs"` } type changes struct { @@ -159,6 +169,7 @@ func convertPullRequest(from *pr) *scm.PullRequest { Source: from.SourceBranch, Target: from.TargetBranch, Link: from.Link, + Draft: from.WorkInProgress, Closed: from.State != "opened", Merged: from.State == "merged", Author: scm.User{ @@ -169,8 +180,14 @@ func convertPullRequest(from *pr) *scm.PullRequest { Created: from.Created, Updated: from.Updated, Labels: labels, - Base: scm.Reference{Name: from.TargetBranch, Sha: from.DiffRefs.BaseCommit}, - Head: scm.Reference{Name: from.SourceBranch, Sha: from.DiffRefs.HeadCommit}, + Base: scm.Reference{ + Name: from.TargetBranch, + Sha: from.DiffRefs.BaseSha, + }, + Head: scm.Reference{ + Name: from.SourceBranch, + Sha: from.DiffRefs.HeadSha, + }, } } diff --git a/scm/driver/gitlab/pr_test.go b/scm/driver/gitlab/pr_test.go index fe35f1e8d..c36ab067e 100644 --- a/scm/driver/gitlab/pr_test.go +++ b/scm/driver/gitlab/pr_test.go @@ -162,10 +162,6 @@ func TestPullCreate(t *testing.T) { gock.New("https://gitlab.com"). Post("/api/v4/projects/diaspora/diaspora/merge_requests"). - MatchParam("title", input.Title). - MatchParam("description", input.Body). - MatchParam("source_branch", input.Source). - MatchParam("target_branch", input.Target). Reply(201). Type("application/json"). SetHeaders(mockHeaders). diff --git a/scm/driver/gitlab/repo.go b/scm/driver/gitlab/repo.go index b6af634be..bd8314aa7 100644 --- a/scm/driver/gitlab/repo.go +++ b/scm/driver/gitlab/repo.go @@ -94,6 +94,21 @@ func (s *repositoryService) List(ctx context.Context, opts scm.ListOptions) ([]* return convertRepositoryList(out), res, err } +func (s *repositoryService) ListV2(ctx context.Context, opts scm.RepoListOptions) ([]*scm.Repository, *scm.Response, error) { + // We pass the repo searchTerm in the query params and gitlab filters repos based on this search term + path := fmt.Sprintf("api/v4/projects?%s", encodeRepoListOptions(opts)) + out := []*repository{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertRepositoryList(out), res, err +} + +func (s *repositoryService) ListNamespace(ctx context.Context, namespace string, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { + path := fmt.Sprintf("api/v4/groups/%s/projects?%s", namespace, encodeMemberListOptions(opts)) + out := []*repository{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertRepositoryList(out), res, err +} + func (s *repositoryService) List2(ctx context.Context, orgSlug string, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { return nil, nil, scm.ErrNotSupported } @@ -147,6 +162,9 @@ func (s *repositoryService) CreateHook(ctx context.Context, repo string, input * if input.Events.Tag { params.Set("tag_push_events", "true") } + if input.Events.Pipeline { + params.Set("pipeline_events", "true") + } path := fmt.Sprintf("api/v4/projects/%s/hooks?%s", encode(repo), params.Encode()) out := new(hook) @@ -175,7 +193,7 @@ func (s *repositoryService) DeleteHook(ctx context.Context, repo string, id stri return s.client.do(ctx, "DELETE", path, nil, nil) } -// helper function to convert from the gogs repository list to +// helper function to convert from the gitlab repository list to // the common repository structure. func convertRepositoryList(from []*repository) []*scm.Repository { to := []*scm.Repository{} @@ -185,7 +203,7 @@ func convertRepositoryList(from []*repository) []*scm.Repository { return to } -// helper function to convert from the gogs repository structure +// helper function to convert from the gitlab repository structure // to the common repository structure. func convertRepository(from *repository) *scm.Repository { to := &scm.Repository{ @@ -194,8 +212,8 @@ func convertRepository(from *repository) *scm.Repository { Name: from.Path, Branch: from.DefaultBranch, Archived: from.Archived, - Private: convertPrivate(from.Visibility), - Visibility: convertVisibility(from.Visibility), + Private: scm.ConvertPrivate(from.Visibility), + Visibility: scm.ConvertVisibility(from.Visibility), Clone: from.HTTPURL, CloneSSH: from.SSHURL, Link: from.WebURL, @@ -314,28 +332,6 @@ func convertFromState(from scm.State) string { } } -func convertPrivate(from string) bool { - switch from { - case "public", "": - return false - default: - return true - } -} - -func convertVisibility(from string) scm.Visibility { - switch from { - case "public": - return scm.VisibilityPublic - case "private": - return scm.VisibilityPrivate - case "internal": - return scm.VisibilityInternal - default: - return scm.VisibilityUndefined - } -} - func canPush(proj *repository) bool { switch { case proj.Permissions.ProjectAccess.AccessLevel >= 30: diff --git a/scm/driver/gitlab/repo_test.go b/scm/driver/gitlab/repo_test.go index 48e21db6b..65c175176 100644 --- a/scm/driver/gitlab/repo_test.go +++ b/scm/driver/gitlab/repo_test.go @@ -163,6 +163,45 @@ func TestRepositoryList(t *testing.T) { t.Run("Page", testPage(res)) } +func TestRepositoryListV2(t *testing.T) { + defer gock.Off() + + gock.New("https://gitlab.com"). + Get("/api/v4/projects"). + MatchParam("search", "diaspora"). + MatchParam("page", "1"). + MatchParam("per_page", "30"). + MatchParam("membership", "true"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/repos_filter.json") + + client := NewDefault() + got, res, err := client.Repositories.ListV2(context.Background(), scm.RepoListOptions{ + ListOptions: scm.ListOptions{Page: 1, Size: 30}, + RepoSearchTerm: scm.RepoSearchTerm{RepoName: "diaspora"}, + }) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Repository{} + raw, _ := ioutil.ReadFile("testdata/repos_filter.json.golden") + json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) + t.Run("Page", testPage(res)) +} + func TestStatusList(t *testing.T) { defer gock.Off() @@ -482,25 +521,6 @@ func TestConvertFromState(t *testing.T) { } } -func TestConvertPrivate(t *testing.T) { - tests := []struct { - in string - out bool - }{ - {"public", false}, - {"", false}, - {"private", true}, - {"internal", true}, - {"invalid", true}, - } - - for _, test := range tests { - if got, want := convertPrivate(test.in), test.out; got != want { - t.Errorf("Want private %v, got %v", want, got) - } - } -} - func TestCanPush(t *testing.T) { tests := []struct { in *repository diff --git a/scm/driver/gitlab/testdata/branches_filter.json b/scm/driver/gitlab/testdata/branches_filter.json new file mode 100644 index 000000000..c5072e736 --- /dev/null +++ b/scm/driver/gitlab/testdata/branches_filter.json @@ -0,0 +1,46 @@ +[ + { + "name": "master", + "merged": false, + "protected": true, + "developers_can_push": false, + "developers_can_merge": false, + "commit": { + "author_email": "john@example.com", + "author_name": "John Smith", + "authored_date": "2012-06-27T05:51:39-07:00", + "committed_date": "2012-06-28T03:44:20-07:00", + "committer_email": "john@example.com", + "committer_name": "John Smith", + "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", + "short_id": "7b5c3cc", + "title": "add projects API", + "message": "add projects API", + "parent_ids": [ + "4ad91d3c1144c406e50c7b33bae684bd6837faf8" + ] + } + }, + { + "name": "master-patch", + "merged": false, + "protected": true, + "developers_can_push": false, + "developers_can_merge": false, + "commit": { + "author_email": "john@example.com", + "author_name": "John Smith", + "authored_date": "2012-06-27T05:51:39-07:00", + "committed_date": "2012-06-28T03:44:20-07:00", + "committer_email": "john@example.com", + "committer_name": "John Smith", + "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0d", + "short_id": "7b5c3cc", + "title": "add projects API", + "message": "add projects API", + "parent_ids": [ + "4ad91d3c1144c406e50c7b33bae684bd6837faf9" + ] + } + } +] \ No newline at end of file diff --git a/scm/driver/gitlab/testdata/branches_filter.json.golden b/scm/driver/gitlab/testdata/branches_filter.json.golden new file mode 100644 index 000000000..d6f1a9210 --- /dev/null +++ b/scm/driver/gitlab/testdata/branches_filter.json.golden @@ -0,0 +1,12 @@ +[ + { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c" + }, + { + "Name": "master-patch", + "Path": "refs/heads/master-patch", + "Sha": "7b5c3cc8be40ee161ae89a06bba6229da1032a0d" + } +] \ No newline at end of file diff --git a/scm/driver/gitlab/testdata/merge.json.golden b/scm/driver/gitlab/testdata/merge.json.golden index cd2e71b11..0dee18b16 100644 --- a/scm/driver/gitlab/testdata/merge.json.golden +++ b/scm/driver/gitlab/testdata/merge.json.golden @@ -7,6 +7,7 @@ "Source": "fix", "Target": "master", "Link": "https://gitlab.com/gitlab-org/testme/merge_requests/1", + "Draft": false, "Closed": true, "Merged": false, "Author": { diff --git a/scm/driver/gitlab/testdata/merges.json.golden b/scm/driver/gitlab/testdata/merges.json.golden index 05680dbec..8b67a09bd 100644 --- a/scm/driver/gitlab/testdata/merges.json.golden +++ b/scm/driver/gitlab/testdata/merges.json.golden @@ -8,6 +8,7 @@ "Source": "fix", "Target": "master", "Link": "https://gitlab.com/gitlab-org/testme/merge_requests/1", + "Draft": false, "Closed": true, "Merged": false, "Author": { diff --git a/scm/driver/gitlab/testdata/repos_filter.json b/scm/driver/gitlab/testdata/repos_filter.json new file mode 100644 index 000000000..13f8b4de3 --- /dev/null +++ b/scm/driver/gitlab/testdata/repos_filter.json @@ -0,0 +1,59 @@ +[ + { + "id": 178504, + "description": "", + "default_branch": "master", + "tag_list": [], + "ssh_url_to_repo": "git@gitlab.com:diaspora/diaspora.git", + "http_url_to_repo": "https://gitlab.com/diaspora/diaspora.git", + "web_url": "https://gitlab.com/diaspora/diaspora", + "name": "Diaspora", + "name_with_namespace": "diaspora / Diaspora", + "path": "diaspora", + "path_with_namespace": "diaspora/diaspora", + "avatar_url": null, + "star_count": 0, + "forks_count": 0, + "created_at": "2015-03-03T18:37:05.387Z", + "last_activity_at": "2015-03-03T18:37:20.795Z", + "_links": { + "self": "http://gitlab.com/api/v4/projects/178504", + "issues": "http://gitlab.com/api/v4/projects/178504/issues", + "merge_requests": "http://gitlab.com/api/v4/projects/178504/merge_requests", + "repo_branches": "http://gitlab.com/api/v4/projects/178504/repository/branches", + "labels": "http://gitlab.com/api/v4/projects/178504/labels", + "events": "http://gitlab.com/api/v4/projects/178504/events", + "members": "http://gitlab.com/api/v4/projects/178504/members" + }, + "archived": false, + "visibility": "public", + "resolve_outdated_diff_discussions": null, + "container_registry_enabled": null, + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": true, + "jobs_enabled": true, + "snippets_enabled": false, + "shared_runners_enabled": true, + "lfs_enabled": true, + "creator_id": 57658, + "namespace": { + "id": 120836, + "name": "diaspora", + "path": "diaspora", + "kind": "group", + "full_path": "diaspora", + "parent_id": null + }, + "import_status": "finished", + "open_issues_count": 0, + "public_jobs": true, + "ci_config_path": null, + "shared_with_groups": [], + "only_allow_merge_if_pipeline_succeeds": false, + "request_access_enabled": true, + "only_allow_merge_if_all_discussions_are_resolved": null, + "printing_merge_request_link_enabled": true, + "approvals_before_merge": 0 + } +] \ No newline at end of file diff --git a/scm/driver/gitlab/testdata/repos_filter.json.golden b/scm/driver/gitlab/testdata/repos_filter.json.golden new file mode 100644 index 000000000..5780a5ebd --- /dev/null +++ b/scm/driver/gitlab/testdata/repos_filter.json.golden @@ -0,0 +1,20 @@ +[ + { + "ID": "178504", + "Namespace": "diaspora", + "Name": "diaspora", + "Perm": { + "Pull": true, + "Push": false, + "Admin": false + }, + "Branch": "master", + "Private": false, + "Visibility": 1, + "Clone": "https://gitlab.com/diaspora/diaspora.git", + "CloneSSH": "git@gitlab.com:diaspora/diaspora.git", + "Link": "https://gitlab.com/diaspora/diaspora", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + } +] \ No newline at end of file diff --git a/scm/driver/gitlab/testdata/webhooks/branch_create.json b/scm/driver/gitlab/testdata/webhooks/branch_create.json index 9abeda061..9c99d83b2 100644 --- a/scm/driver/gitlab/testdata/webhooks/branch_create.json +++ b/scm/driver/gitlab/testdata/webhooks/branch_create.json @@ -34,7 +34,7 @@ { "id": "c4c79227ed610f1151f05bbc5be33b4f340d39c8", "message": "update readme\n", - "timestamp": "2017-12-10T08:28:36-08:00", + "timestamp": "2017-12-10T08:28:36+00:00", "url": "https://gitlab.com/gitlab-org/hello-world/commit/c4c79227ed610f1151f05bbc5be33b4f340d39c8", "author": { "name": "Sid Sijbrandij", diff --git a/scm/driver/gitlab/testdata/webhooks/branch_create.json.golden b/scm/driver/gitlab/testdata/webhooks/branch_create.json.golden index 1c611bcf2..1a618b2a9 100644 --- a/scm/driver/gitlab/testdata/webhooks/branch_create.json.golden +++ b/scm/driver/gitlab/testdata/webhooks/branch_create.json.golden @@ -41,14 +41,14 @@ "Author": { "Name": "Sid Sijbrandij", "Email": "noreply@gitlab.com", - "Date": "2017-12-10T08:28:36-08:00", + "Date": "2017-12-10T08:28:36Z", "Login": "", "Avatar": "" }, "Committer": { "Name": "Sid Sijbrandij", "Email": "noreply@gitlab.com", - "Date": "2017-12-10T08:28:36-08:00", + "Date": "2017-12-10T08:28:36Z", "Login": "", "Avatar": "" }, diff --git a/scm/driver/gitlab/testdata/webhooks/pull_request_comment_create.json b/scm/driver/gitlab/testdata/webhooks/merge_request_comment_create.json similarity index 100% rename from scm/driver/gitlab/testdata/webhooks/pull_request_comment_create.json rename to scm/driver/gitlab/testdata/webhooks/merge_request_comment_create.json diff --git a/scm/driver/gitlab/testdata/webhooks/merge_request_comment_create.json.golden b/scm/driver/gitlab/testdata/webhooks/merge_request_comment_create.json.golden new file mode 100644 index 000000000..dcc3e2448 --- /dev/null +++ b/scm/driver/gitlab/testdata/webhooks/merge_request_comment_create.json.golden @@ -0,0 +1,94 @@ +{ + "Action": "created", + "Repo": { + "ID": "4861503", + "Namespace": "gitlab-org", + "Name": "hello-world", + "Perm": null, + "Branch": "master", + "Archived": false, + "Private": false, + "Visibility": 0, + "Clone": "https://gitlab.com/gitlab-org/hello-world.git", + "CloneSSH": "git@gitlab.com:gitlab-org/hello-world.git", + "Link": "https://gitlab.com/gitlab-org/hello-world", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Issue": { + "Number": 1, + "Title": "update readme", + "Body": "update readme", + "Link": "https://gitlab.com/gitlab-org/hello-world", + "Labels": null, + "Closed": false, + "Locked": false, + "Author": { + "Login": "sytses", + "Name": "Sid Sijbrandij", + "Email": "", + "Avatar": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87?s=80\u0026d=identicon", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 1, + "Title": "update readme", + "Body": "adding build instructions to readme", + "Sha": "c4c79227ed610f1151f05bbc5be33b4f340d39c8", + "Ref": "refs/merge-requests/1/head", + "Source": "feature", + "Target": "master", + "Fork": "", + "Link": "https://gitlab.com/gitlab-org/hello-world/merge_requests/1", + "Diff": "", + "Closed": false, + "Merged": false, + "Base": { + "Name": "", + "Path": "", + "Sha": "" + }, + "Head": { + "Name": "", + "Path": "", + "Sha": "" + }, + "Author": { + "Login": "sytses", + "Name": "Sid Sijbrandij", + "Email": "", + "Avatar": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87?s=80\u0026d=identicon", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Created": "2017-12-10T17:01:11Z", + "Updated": "2017-12-10T17:05:14Z", + "Labels": null + }, + "Created": "2017-12-10T17:05:14Z", + "Updated": "2017-12-10T17:05:14Z" + }, + "Comment": { + "ID": 50772616, + "Body": "lgtm", + "Author": { + "Login": "sytses", + "Name": "Sid Sijbrandij", + "Email": "", + "Avatar": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87?s=80\u0026d=identicon", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Created": "2017-12-10T17:05:14Z", + "Updated": "2017-12-10T17:05:14Z" + }, + "Sender": { + "Login": "sytses", + "Name": "Sid Sijbrandij", + "Email": "", + "Avatar": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87?s=80\u0026d=identicon", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + } +} \ No newline at end of file diff --git a/scm/driver/gitlab/testdata/webhooks/pipeline_hook.json b/scm/driver/gitlab/testdata/webhooks/pipeline_hook.json new file mode 100644 index 000000000..6deec0b0e --- /dev/null +++ b/scm/driver/gitlab/testdata/webhooks/pipeline_hook.json @@ -0,0 +1,115 @@ +{ + "object_kind": "pipeline", + "object_attributes":{ + "id": 31, + "iid": 3, + "name": "Pipeline for branch: master", + "ref": "master", + "tag": false, + "sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", + "before_sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", + "source": "merge_request_event", + "status": "success", + "stages":[ + "build", + "test", + "deploy" + ], + "created_at": "2016-08-12 15:23:28 UTC", + "finished_at": "2016-08-12 15:26:29 UTC", + "duration": 63, + "variables": [ + { + "key": "NESTOR_PROD_ENVIRONMENT", + "value": "us-west-1" + } + ], + "url": "http://example.com/gitlab-org/gitlab-test/-/pipelines/31" + }, + "merge_request": { + "id": 371997275, + "iid": 15, + "title": "Edit test.txt", + "source_branch": "shivamnegi94-main-patch-62619", + "source_project_id": 27743392, + "target_branch": "main", + "target_project_id": 27743392, + "state": "opened", + "merge_status": "can_be_merged", + "detailed_merge_status": "mergeable", + "url": "https://gitlab.com/shivamnegi94/test/-/merge_requests/15" + }, + "user":{ + "id": 1, + "name": "Administrator", + "username": "root", + "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon", + "email": "user_email@gitlab.com" + }, + "project":{ + "id": 1, + "name": "Gitlab Test", + "description": "Atque in sunt eos similique dolores voluptatem.", + "web_url": "http://192.168.64.1:3005/gitlab-org/gitlab-test", + "avatar_url": null, + "git_ssh_url": "git@192.168.64.1:gitlab-org/gitlab-test.git", + "git_http_url": "http://192.168.64.1:3005/gitlab-org/gitlab-test.git", + "namespace": "Gitlab Org", + "visibility_level": 20, + "path_with_namespace": "gitlab-org/gitlab-test", + "default_branch": "master" + }, + "commit":{ + "id": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", + "message": "test\n", + "timestamp": "2016-08-12T17:23:21+02:00", + "url": "http://example.com/gitlab-org/gitlab-test/commit/bcbb5ec396a2c0f828686f14fac9b80b780504f2", + "author":{ + "name": "User", + "email": "user@gitlab.com" + } + }, + "source_pipeline":{ + "project":{ + "id": 41, + "web_url": "https://gitlab.example.com/gitlab-org/upstream-project", + "path_with_namespace": "gitlab-org/upstream-project" + }, + "pipeline_id": 30, + "job_id": 3401 + }, + "builds":[ + { + "id": 380, + "stage": "deploy", + "name": "production", + "status": "skipped", + "created_at": "2016-08-12 15:23:28 UTC", + "started_at": null, + "finished_at": null, + "duration": null, + "queued_duration": null, + "failure_reason": null, + "when": "manual", + "manual": true, + "allow_failure": false, + "user":{ + "id": 1, + "name": "Administrator", + "username": "root", + "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon", + "email": "admin@example.com" + }, + "runner": null, + "artifacts_file":{ + "filename": null, + "size": null + }, + "environment": { + "name": "production", + "action": "start", + "deployment_tier": "production" + } + } + ] +} \ No newline at end of file diff --git a/scm/driver/gitlab/testdata/webhooks/pipeline_hook.json.golden b/scm/driver/gitlab/testdata/webhooks/pipeline_hook.json.golden new file mode 100644 index 000000000..8e70f4b6b --- /dev/null +++ b/scm/driver/gitlab/testdata/webhooks/pipeline_hook.json.golden @@ -0,0 +1,50 @@ +{ + "repo": { + "id": "1", + "namespace": "gitlab-org", + "name": "gitlab-test", + "clone": "http://192.168.64.1:3005/gitlab-org/gitlab-test.git", + "cloneSSH": "git@192.168.64.1:gitlab-org/gitlab-test.git", + "link": "http://192.168.64.1:3005/gitlab-org/gitlab-test", + "branch": "master", + "private": false + }, + "commit": { + "sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", + "message": "test\n", + "author": { + "name": "User", + "email": "user@gitlab.com" + }, + "committer": { + "name": "User", + "email": "user@gitlab.com" + }, + "link": "http://example.com/gitlab-org/gitlab-test/commit/bcbb5ec396a2c0f828686f14fac9b80b780504f2" + }, + "Execution": { + "Number": 31, + "status": "success", + "Created": "2016-08-12T15:23:28Z", + "URL": "http://example.com/gitlab-org/gitlab-test/-/pipelines/31" + }, + "sender": { + "login": "root", + "name": "Administrator", + "email": "user_email@gitlab.com", + "avatar": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80&d=identicon" + }, + "PullRequest": { + "Number": 371997275, + "Title": "Edit test.txt", + "Sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", + "Ref": "master", + "Source": "shivamnegi94-main-patch-62619", + "Target": "main", + "Link": "https://gitlab.com/shivamnegi94/test/-/merge_requests/15", + "Created": "2016-08-12T15:23:28Z", + "Draft": false, + "Closed": false, + "Merged": false + } +} diff --git a/scm/driver/gitlab/testdata/webhooks/pull_request_comment_create.json.golden b/scm/driver/gitlab/testdata/webhooks/pull_request_comment_create.json.golden deleted file mode 100644 index e69de29bb..000000000 diff --git a/scm/driver/gitlab/testdata/webhooks/pull_request_review_ready.json b/scm/driver/gitlab/testdata/webhooks/pull_request_review_ready.json new file mode 100644 index 000000000..5a25b03ef --- /dev/null +++ b/scm/driver/gitlab/testdata/webhooks/pull_request_review_ready.json @@ -0,0 +1,154 @@ +{ + "object_kind": "merge_request", + "event_type": "merge_request", + "user": { + "id": 13900456, + "name": "Meet Rathod", + "username": "rathod.meetsatish", + "avatar_url": "https://secure.gravatar.com/avatar/0e68aaeb6c49dd6ba280370c96280803?s=80&d=identicon", + "email": "[REDACTED]" + }, + "project": { + "id": 44067058, + "name": "meet", + "description": null, + "web_url": "https://gitlab.com/rathod.meetsatish/meet", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:rathod.meetsatish/meet.git", + "git_http_url": "https://gitlab.com/rathod.meetsatish/meet.git", + "namespace": "Meet Rathod", + "visibility_level": 0, + "path_with_namespace": "rathod.meetsatish/meet", + "default_branch": "main", + "ci_config_path": "", + "homepage": "https://gitlab.com/rathod.meetsatish/meet", + "url": "git@gitlab.com:rathod.meetsatish/meet.git", + "ssh_url": "git@gitlab.com:rathod.meetsatish/meet.git", + "http_url": "https://gitlab.com/rathod.meetsatish/meet.git" + }, + "object_attributes": { + "assignee_id": null, + "author_id": 13900456, + "created_at": "2023-09-07 19:42:34 UTC", + "description": "", + "draft": true, + "head_pipeline_id": null, + "id": 248466002, + "iid": 3, + "last_edited_at": null, + "last_edited_by_id": null, + "merge_commit_sha": null, + "merge_error": null, + "merge_params": { + "force_remove_source_branch": "1" + }, + "merge_status": "can_be_merged", + "merge_user_id": null, + "merge_when_pipeline_succeeds": false, + "milestone_id": null, + "source_branch": "main1234", + "source_project_id": 44067058, + "state_id": 1, + "target_branch": "main", + "target_project_id": 44067058, + "time_estimate": 0, + "title": "Draft: Update README.md", + "updated_at": "2023-09-07 19:42:45 UTC", + "updated_by_id": 13900456, + "url": "https://gitlab.com/rathod.meetsatish/meet/-/merge_requests/3", + "source": { + "id": 44067058, + "name": "meet", + "description": null, + "web_url": "https://gitlab.com/rathod.meetsatish/meet", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:rathod.meetsatish/meet.git", + "git_http_url": "https://gitlab.com/rathod.meetsatish/meet.git", + "namespace": "Meet Rathod", + "visibility_level": 0, + "path_with_namespace": "rathod.meetsatish/meet", + "default_branch": "main", + "ci_config_path": "", + "homepage": "https://gitlab.com/rathod.meetsatish/meet", + "url": "git@gitlab.com:rathod.meetsatish/meet.git", + "ssh_url": "git@gitlab.com:rathod.meetsatish/meet.git", + "http_url": "https://gitlab.com/rathod.meetsatish/meet.git" + }, + "target": { + "id": 44067058, + "name": "meet", + "description": null, + "web_url": "https://gitlab.com/rathod.meetsatish/meet", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:rathod.meetsatish/meet.git", + "git_http_url": "https://gitlab.com/rathod.meetsatish/meet.git", + "namespace": "Meet Rathod", + "visibility_level": 0, + "path_with_namespace": "rathod.meetsatish/meet", + "default_branch": "main", + "ci_config_path": "", + "homepage": "https://gitlab.com/rathod.meetsatish/meet", + "url": "git@gitlab.com:rathod.meetsatish/meet.git", + "ssh_url": "git@gitlab.com:rathod.meetsatish/meet.git", + "http_url": "https://gitlab.com/rathod.meetsatish/meet.git" + }, + "last_commit": { + "id": "ffd71529ecdfb41a530ee13f91b8fdd3e743c754", + "message": "Update README.md", + "title": "Update README.md", + "timestamp": "2023-09-07T19:42:21+00:00", + "url": "https://gitlab.com/rathod.meetsatish/meet/-/commit/ffd71529ecdfb41a530ee13f91b8fdd3e743c754", + "author": { + "name": "Meet Rathod", + "email": "[REDACTED]" + } + }, + "work_in_progress": true, + "total_time_spent": 0, + "time_change": 0, + "human_total_time_spent": null, + "human_time_change": null, + "human_time_estimate": null, + "assignee_ids": [ + + ], + "reviewer_ids": [ + + ], + "labels": [ + + ], + "state": "opened", + "blocking_discussions_resolved": true, + "first_contribution": true, + "detailed_merge_status": "draft_status", + "action": "update" + }, + "labels": [ + + ], + "changes": { + "draft": { + "previous": false, + "current": true + }, + "title": { + "previous": "Update README.md", + "current": "Draft: Update README.md" + }, + "updated_at": { + "previous": "2023-09-07 19:42:35 UTC", + "current": "2023-09-07 19:42:45 UTC" + }, + "updated_by_id": { + "previous": null, + "current": 13900456 + } + }, + "repository": { + "name": "meet", + "url": "git@gitlab.com:rathod.meetsatish/meet.git", + "description": null, + "homepage": "https://gitlab.com/rathod.meetsatish/meet" + } +} diff --git a/scm/driver/gitlab/testdata/webhooks/pull_request_review_ready.json.golden b/scm/driver/gitlab/testdata/webhooks/pull_request_review_ready.json.golden new file mode 100644 index 000000000..059b6bbd7 --- /dev/null +++ b/scm/driver/gitlab/testdata/webhooks/pull_request_review_ready.json.golden @@ -0,0 +1,44 @@ +{ + "Action": "review_ready", + "Repo": { + "ID": "44067058", + "Namespace": "rathod.meetsatish", + "Name": "meet", + "Perm": null, + "Branch": "main", + "Private": false, + "Clone": "https://gitlab.com/rathod.meetsatish/meet.git", + "CloneSSH": "git@gitlab.com:rathod.meetsatish/meet.git", + "Link": "https://gitlab.com/rathod.meetsatish/meet", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 3, + "Title": "Draft: Update README.md", + "Body": "", + "Sha": "ffd71529ecdfb41a530ee13f91b8fdd3e743c754", + "Ref": "refs/merge-requests/3/head", + "Source": "main1234", + "Target": "main", + "Fork": "Meet Rathod/meet", + "Link": "https://gitlab.com/rathod.meetsatish/meet/-/merge_requests/3", + "Draft": true, + "Closed": false, + "Merged": false, + "Author": { + "Login": "rathod.meetsatish", + "Name": "Meet Rathod", + "Email": "", + "Avatar": "https://secure.gravatar.com/avatar/0e68aaeb6c49dd6ba280370c96280803?s=80&d=identicon" + }, + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Sender": { + "Login": "rathod.meetsatish", + "Name": "Meet Rathod", + "Email": "", + "Avatar": "https://secure.gravatar.com/avatar/0e68aaeb6c49dd6ba280370c96280803?s=80&d=identicon" + } +} diff --git a/scm/driver/gitlab/testdata/webhooks/push.json b/scm/driver/gitlab/testdata/webhooks/push.json index dde1a9a84..40801e1d4 100644 --- a/scm/driver/gitlab/testdata/webhooks/push.json +++ b/scm/driver/gitlab/testdata/webhooks/push.json @@ -34,7 +34,7 @@ { "id": "2adc9465c4edfc33834e173fe89436a7cb899a1d", "message": "added readme\n", - "timestamp": "2017-12-10T08:26:38-08:00", + "timestamp": "2017-12-10T08:26:38+00:00", "url": "https://gitlab.com/gitlab-org/hello-world/commit/2adc9465c4edfc33834e173fe89436a7cb899a1d", "author": { "name": "Sid Sijbrandij", diff --git a/scm/driver/gitlab/testdata/webhooks/push.json.golden b/scm/driver/gitlab/testdata/webhooks/push.json.golden index d7829ecc3..8c8bbf9e8 100644 --- a/scm/driver/gitlab/testdata/webhooks/push.json.golden +++ b/scm/driver/gitlab/testdata/webhooks/push.json.golden @@ -41,14 +41,14 @@ "Author": { "Name": "Sid Sijbrandij", "Email": "noreply@gitlab.com", - "Date": "2017-12-10T08:26:38-08:00", + "Date": "2017-12-10T08:26:38Z", "Login": "", "Avatar": "" }, "Committer": { "Name": "Sid Sijbrandij", "Email": "noreply@gitlab.com", - "Date": "2017-12-10T08:26:38-08:00", + "Date": "2017-12-10T08:26:38Z", "Login": "", "Avatar": "" }, diff --git a/scm/driver/gitlab/testdata/webhooks/tag_create.json b/scm/driver/gitlab/testdata/webhooks/tag_create.json index f28bdc160..4544eec7c 100644 --- a/scm/driver/gitlab/testdata/webhooks/tag_create.json +++ b/scm/driver/gitlab/testdata/webhooks/tag_create.json @@ -34,7 +34,7 @@ { "id": "2adc9465c4edfc33834e173fe89436a7cb899a1d", "message": "added readme\n", - "timestamp": "2017-12-10T08:26:38-08:00", + "timestamp": "2017-12-10T08:26:38+00:00", "url": "https://gitlab.com/gitlab-org/hello-world/commit/2adc9465c4edfc33834e173fe89436a7cb899a1d", "author": { "name": "Sid Sijbrandij", diff --git a/scm/driver/gitlab/testdata/webhooks/tag_create.json.golden b/scm/driver/gitlab/testdata/webhooks/tag_create.json.golden index 381bd190e..963085c35 100644 --- a/scm/driver/gitlab/testdata/webhooks/tag_create.json.golden +++ b/scm/driver/gitlab/testdata/webhooks/tag_create.json.golden @@ -41,14 +41,14 @@ "Author": { "Name": "Sid Sijbrandij", "Email": "noreply@gitlab.com", - "Date": "2017-12-10T08:26:38-08:00", + "Date": "2017-12-10T08:26:38Z", "Login": "", "Avatar": "" }, "Committer": { "Name": "Sid Sijbrandij", "Email": "noreply@gitlab.com", - "Date": "2017-12-10T08:26:38-08:00", + "Date": "2017-12-10T08:26:38Z", "Login": "", "Avatar": "" }, diff --git a/scm/driver/gitlab/user.go b/scm/driver/gitlab/user.go index e57a73a29..7f182bfca 100644 --- a/scm/driver/gitlab/user.go +++ b/scm/driver/gitlab/user.go @@ -49,7 +49,7 @@ func (s *userService) ListEmail(ctx context.Context, opts scm.ListOptions) ([]*s } type user struct { - ID int `json:"ID"` + ID int `json:"id"` Username string `json:"username"` Name string `json:"name"` Email null.String `json:"email"` diff --git a/scm/driver/gitlab/util.go b/scm/driver/gitlab/util.go index 05670bcd2..eb3f06893 100644 --- a/scm/driver/gitlab/util.go +++ b/scm/driver/gitlab/util.go @@ -24,6 +24,22 @@ func encodePath(s string) string { return strings.Replace(url.PathEscape(s), ".", "%2E", -1) } +func encodeBranchListOptions(opts scm.BranchListOptions) string { + params := url.Values{} + if opts.SearchTerm != "" { + params.Set("search", opts.SearchTerm) + } + if opts.PageListOptions != (scm.ListOptions{}) { + if opts.PageListOptions.Page != 0 { + params.Set("page", strconv.Itoa(opts.PageListOptions.Page)) + } + if opts.PageListOptions.Size != 0 { + params.Set("per_page", strconv.Itoa(opts.PageListOptions.Size)) + } + } + return params.Encode() +} + func encodeListOptions(opts scm.ListOptions) string { params := url.Values{} if opts.Page != 0 { @@ -47,6 +63,25 @@ func encodeMemberListOptions(opts scm.ListOptions) string { return params.Encode() } +func encodeRepoListOptions(opts scm.RepoListOptions) string { + params := url.Values{} + params.Set("membership", "true") + if opts.RepoSearchTerm != (scm.RepoSearchTerm{}) { + if opts.RepoSearchTerm.RepoName != "" { + params.Set("search", opts.RepoSearchTerm.RepoName) + } + } + if opts.ListOptions != (scm.ListOptions{}) { + if opts.ListOptions.Page != 0 { + params.Set("page", strconv.Itoa(opts.ListOptions.Page)) + } + if opts.ListOptions.Size != 0 { + params.Set("per_page", strconv.Itoa(opts.ListOptions.Size)) + } + } + return params.Encode() +} + func encodeCommitListOptions(opts scm.CommitListOptions) string { params := url.Values{} if opts.Page != 0 { diff --git a/scm/driver/gitlab/webhook.go b/scm/driver/gitlab/webhook.go index 439b6ac72..c76f33f79 100644 --- a/scm/driver/gitlab/webhook.go +++ b/scm/driver/gitlab/webhook.go @@ -11,6 +11,7 @@ import ( "io/ioutil" "net/http" "strconv" + "time" "github.com/drone/go-scm/scm" "github.com/drone/go-scm/scm/driver/internal/null" @@ -36,6 +37,12 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo return nil, scm.ErrUnknownEvent case "Merge Request Hook": hook, err = parsePullRequestHook(data) + case "Note Hook": + hook, err = parseIssueCommentHook(data) + case "System Hook": + hook, err = parseSystemHook(data) + case "Pipeline Hook": + return parsePipelineHook(data) default: return nil, scm.ErrUnknownEvent } @@ -60,6 +67,49 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo return hook, nil } +func parseSystemHook(data []byte) (scm.Webhook, error) { + src := new(event) + err := json.Unmarshal(data, src) + if err != nil { + return nil, err + } + switch src.ObjectKind { + case "push", "tag_push": + return parsePushHook(data) + case "issue": + return nil, scm.ErrUnknownEvent + case "merge_request": + return parsePullRequestHook(data) + case "note": + return parseIssueCommentHook(data) + default: + return nil, scm.ErrUnknownEvent + } +} + +func parseIssueCommentHook(data []byte) (scm.Webhook, error) { + src := new(commentHook) + err := json.Unmarshal(data, src) + if err != nil { + return nil, err + } + dst, err := convertCommentHook(src) + if err != nil { + return nil, err + } + return dst, nil +} + +func parsePipelineHook(data []byte) (scm.Webhook, error) { + src := new(pipelineHook) + err := json.Unmarshal(data, src) + if err != nil { + return nil, err + } + dst, err := convertPipelineHook(src), nil + return dst, nil +} + func parsePushHook(data []byte) (scm.Webhook, error) { src := new(pushHook) err := json.Unmarshal(data, src) @@ -205,6 +255,78 @@ func converBranchHook(src *pushHook) *scm.BranchHook { } } +func convertCommentHook(src *commentHook) (*scm.IssueCommentHook, error) { + var issue scm.Issue + var comment scm.Comment + + switch src.ObjectAttributes.NoteableType { + case "Commit", "Issue", "Snippet": + return nil, scm.ErrUnknownEvent + case "MergeRequest": + pr := scm.PullRequest{ + Number: src.MergeRequest.Iid, + Title: src.MergeRequest.Title, + Body: src.MergeRequest.Description, + Sha: src.MergeRequest.LastCommit.ID, + Ref: fmt.Sprintf("refs/merge-requests/%d/head", src.MergeRequest.Iid), + Source: src.MergeRequest.SourceBranch, + Target: src.MergeRequest.TargetBranch, + Link: src.MergeRequest.URL, + Draft: src.MergeRequest.WorkInProgress, + Closed: src.MergeRequest.State != "opened", + Merged: src.MergeRequest.State == "merged", + Author: *convertUser(&src.User), + Created: parseTimeString(src.MergeRequest.CreatedAt), + Updated: parseTimeString(src.MergeRequest.UpdatedAt), + } + for _, l := range src.MergeRequest.Labels { + label := scm.Label{ + Name: l.Title, + Color: l.Color, + } + pr.Labels = append(pr.Labels, label) + } + issue = scm.Issue{ + Number: src.MergeRequest.Iid, + Title: src.MergeRequest.Title, + Body: src.MergeRequest.Title, + Link: src.Project.WebURL, + Author: *convertUser(&src.User), + PullRequest: pr, + Created: parseTimeString(src.ObjectAttributes.CreatedAt), + Updated: parseTimeString(src.ObjectAttributes.UpdatedAt), + } + comment = scm.Comment{ + ID: src.ObjectAttributes.ID, + Body: src.ObjectAttributes.Note, + Author: *convertUser(&src.User), + Created: parseTimeString(src.ObjectAttributes.CreatedAt), + Updated: parseTimeString(src.ObjectAttributes.UpdatedAt), + } + default: + return nil, scm.ErrUnknownEvent + } + + namespace, _ := scm.Split(src.Project.PathWithNamespace) + dst := scm.IssueCommentHook{ + Action: scm.ActionCreate, + Repo: scm.Repository{ + ID: strconv.Itoa(src.Project.ID), + Namespace: namespace, + Name: src.Repository.Name, + Clone: src.Project.GitHTTPURL, + CloneSSH: src.Project.GitSSHURL, + Link: src.Project.WebURL, + Branch: src.Project.DefaultBranch, + Private: false, // TODO how do we correctly set Private vs Public? + }, + Issue: issue, + Comment: comment, + Sender: *convertUser(&src.User), + } + return &dst, nil +} + func convertTagHook(src *pushHook) *scm.TagHook { action := scm.ActionCreate commit := src.After @@ -251,6 +373,9 @@ func convertPullRequestHook(src *pullRequestHook) *scm.PullRequestHook { action = scm.ActionMerge case "update": action = scm.ActionSync + if src.Changes.Draft.Previous.Bool == false && src.Changes.Draft.Current.Bool == true { + action = scm.ActionReviewReady + } } fork := scm.Join( src.ObjectAttributes.Source.Namespace, @@ -269,10 +394,9 @@ func convertPullRequestHook(src *pullRequestHook) *scm.PullRequestHook { Target: src.ObjectAttributes.TargetBranch, Fork: fork, Link: src.ObjectAttributes.URL, + Draft: src.ObjectAttributes.WorkInProgress, Closed: src.ObjectAttributes.State != "opened", Merged: src.ObjectAttributes.State == "merged", - // Created : src.ObjectAttributes.CreatedAt, - // Updated : src.ObjectAttributes.UpdatedAt, // 2017-12-10 17:01:11 UTC Author: scm.User{ Login: src.User.Username, Name: src.User.Name, @@ -299,7 +423,70 @@ func convertPullRequestHook(src *pullRequestHook) *scm.PullRequestHook { } } +func parseTimeString(timeString string) time.Time { + layout := "2006-01-02 15:04:05 UTC" + // Returns zero value of time in case of an error 0001-01-01 00:00:00 +0000 UTC + t, _ := time.Parse(layout, timeString) + return t +} + +func convertPipelineHook(src *pipelineHook) *scm.PipelineHook { + namespace, name := scm.Split(src.Project.PathWithNamespace) + return &scm.PipelineHook{ + Repo: scm.Repository{ + ID: strconv.Itoa(src.Project.ID), + Namespace: namespace, + Name: name, + Clone: src.Project.GitHTTPURL, + CloneSSH: src.Project.GitSSHURL, + Link: src.Project.WebURL, + Branch: src.Project.DefaultBranch, + Private: false, + }, + Commit: scm.Commit{ + Sha: src.ObjectAttributes.SHA, + Message: src.Commit.Message, + Author: scm.Signature{ + Name: src.Commit.Author.Name, + Email: src.Commit.Author.Email, + }, + Committer: scm.Signature{ + Name: src.Commit.Author.Name, + Email: src.Commit.Author.Email, + }, + Link: src.Commit.URL, + }, + Execution: scm.Execution{ + Number: src.ObjectAttributes.ID, + Status: scm.ConvertExecutionStatus(src.ObjectAttributes.Status), + Created: parseTimeString(src.ObjectAttributes.CreatedAt), + URL: src.ObjectAttributes.URL, + }, + Sender: scm.User{ + Login: src.User.Username, + Name: src.User.Name, + Email: src.User.Email, + Avatar: src.User.AvatarURL, + }, + PullRequest: scm.PullRequest{ + Number: src.MergeRequest.ID, + Title: src.MergeRequest.Title, + Sha: src.ObjectAttributes.SHA, + Ref: src.ObjectAttributes.Ref, + Source: src.MergeRequest.SourceBranch, + Target: src.MergeRequest.TargetBranch, + Link: src.MergeRequest.URL, + Created: parseTimeString(src.ObjectAttributes.CreatedAt), + }, + } +} + type ( + // Generic struct to detect event type + event struct { + ObjectKind string `json:"object_kind"` + } + pushHook struct { ObjectKind string `json:"object_kind"` EventName string `json:"event_name"` @@ -359,13 +546,10 @@ type ( commentHook struct { ObjectKind string `json:"object_kind"` - User struct { - Name string `json:"name"` - Username string `json:"username"` - AvatarURL string `json:"avatar_url"` - } `json:"user"` - ProjectID int `json:"project_id"` - Project struct { + EventType string `json:"event_type"` + User user `json:"user"` + ProjectID int `json:"project_id"` + Project struct { ID int `json:"id"` Name string `json:"name"` Description string `json:"description"` @@ -384,56 +568,29 @@ type ( HTTPURL string `json:"http_url"` } `json:"project"` ObjectAttributes struct { - ID int `json:"id"` - Note string `json:"note"` - NoteableType string `json:"noteable_type"` - AuthorID int `json:"author_id"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` - ProjectID int `json:"project_id"` - Attachment interface{} `json:"attachment"` - LineCode string `json:"line_code"` - CommitID string `json:"commit_id"` - NoteableID int `json:"noteable_id"` - StDiff interface{} `json:"st_diff"` - System bool `json:"system"` - UpdatedByID interface{} `json:"updated_by_id"` - Type string `json:"type"` - Position struct { - BaseSha string `json:"base_sha"` - StartSha string `json:"start_sha"` - HeadSha string `json:"head_sha"` - OldPath string `json:"old_path"` - NewPath string `json:"new_path"` - PositionType string `json:"position_type"` - OldLine interface{} `json:"old_line"` - NewLine int `json:"new_line"` - } `json:"position"` - OriginalPosition struct { - BaseSha string `json:"base_sha"` - StartSha string `json:"start_sha"` - HeadSha string `json:"head_sha"` - OldPath string `json:"old_path"` - NewPath string `json:"new_path"` - PositionType string `json:"position_type"` - OldLine interface{} `json:"old_line"` - NewLine int `json:"new_line"` - } `json:"original_position"` - ResolvedAt interface{} `json:"resolved_at"` - ResolvedByID interface{} `json:"resolved_by_id"` - DiscussionID string `json:"discussion_id"` - ChangePosition struct { - BaseSha interface{} `json:"base_sha"` - StartSha interface{} `json:"start_sha"` - HeadSha interface{} `json:"head_sha"` - OldPath interface{} `json:"old_path"` - NewPath interface{} `json:"new_path"` - PositionType string `json:"position_type"` - OldLine interface{} `json:"old_line"` - NewLine interface{} `json:"new_line"` - } `json:"change_position"` - ResolvedByPush interface{} `json:"resolved_by_push"` - URL string `json:"url"` + ID int `json:"id"` + Note string `json:"note"` + NoteableType string `json:"noteable_type"` + AuthorID int `json:"author_id"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + ProjectID int `json:"project_id"` + Attachment interface{} `json:"attachment"` + LineCode string `json:"line_code"` + CommitID string `json:"commit_id"` + NoteableID int `json:"noteable_id"` + StDiff interface{} `json:"st_diff"` + System bool `json:"system"` + ResolvedAt interface{} `json:"resolved_at"` + ResolvedByID interface{} `json:"resolved_by_id"` + ResolvedByPush interface{} `json:"resolved_by_push"` + DiscussionID string `json:"discussion_id"` + URL string `json:"url"` + Position interface{} `json:"position"` + OriginalPosition interface{} `json:"original_position"` + ChangePosition interface{} `json:"change_position"` + Type interface{} `json:"type"` + Description string `json:"description"` } `json:"object_attributes"` Repository struct { Name string `json:"name"` @@ -442,34 +599,44 @@ type ( Homepage string `json:"homepage"` } `json:"repository"` MergeRequest struct { - AssigneeID interface{} `json:"assignee_id"` - AuthorID int `json:"author_id"` - CreatedAt string `json:"created_at"` - DeletedAt interface{} `json:"deleted_at"` - Description string `json:"description"` - HeadPipelineID interface{} `json:"head_pipeline_id"` - ID int `json:"id"` - Iid int `json:"iid"` - LastEditedAt interface{} `json:"last_edited_at"` - LastEditedByID interface{} `json:"last_edited_by_id"` - MergeCommitSha interface{} `json:"merge_commit_sha"` - MergeError interface{} `json:"merge_error"` - MergeParams interface{} `json:"-"` - MergeStatus string `json:"merge_status"` - MergeUserID interface{} `json:"merge_user_id"` - MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"` - MilestoneID interface{} `json:"milestone_id"` - SourceBranch string `json:"source_branch"` - SourceProjectID int `json:"source_project_id"` - State string `json:"state"` - TargetBranch string `json:"target_branch"` - TargetProjectID int `json:"target_project_id"` - TimeEstimate int `json:"time_estimate"` - Title string `json:"title"` - UpdatedAt string `json:"updated_at"` - UpdatedByID interface{} `json:"updated_by_id"` - URL string `json:"url"` - Source struct { + AssigneeID interface{} `json:"assignee_id"` + AuthorID int `json:"author_id"` + CreatedAt string `json:"created_at"` + DeletedAt interface{} `json:"deleted_at"` + Description string `json:"description"` + HeadPipelineID interface{} `json:"head_pipeline_id"` + ID int `json:"id"` + Iid int `json:"iid"` + LastEditedAt interface{} `json:"last_edited_at"` + LastEditedByID interface{} `json:"last_edited_by_id"` + MergeCommitSha interface{} `json:"merge_commit_sha"` + MergeError interface{} `json:"merge_error"` + MergeParams interface{} `json:"-"` + MergeStatus string `json:"merge_status"` + MergeUserID interface{} `json:"merge_user_id"` + MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"` + MilestoneID interface{} `json:"milestone_id"` + SourceBranch string `json:"source_branch"` + SourceProjectID int `json:"source_project_id"` + StateID int `json:"state_id"` + State string `json:"state"` + TargetBranch string `json:"target_branch"` + TargetProjectID int `json:"target_project_id"` + TimeEstimate int `json:"time_estimate"` + Title string `json:"title"` + UpdatedAt string `json:"updated_at"` + UpdatedByID interface{} `json:"updated_by_id"` + URL string `json:"url"` + WorkInProgress bool `json:"work_in_progress"` + TimeChange int `json:"time_change"` + HumanTimeChange int `json:"human_time_change"` + TotalTimeSpent int `json:"total_time_spent"` + HumanTotalTimeSpent interface{} `json:"human_total_time_spent"` + HumanTimeEstimate interface{} `json:"human_time_estimate"` + Action string `json:"action"` + AssigneeIDs interface{} `json:"assignee_ids"` + BlockingDiscussionResolved bool `json:"blocking_discussions_resolved"` + Source struct { ID int `json:"id"` Name string `json:"name"` Description string `json:"description"` @@ -515,10 +682,18 @@ type ( Email string `json:"email"` } `json:"author"` } `json:"last_commit"` - WorkInProgress bool `json:"work_in_progress"` - TotalTimeSpent int `json:"total_time_spent"` - HumanTotalTimeSpent interface{} `json:"human_total_time_spent"` - HumanTimeEstimate interface{} `json:"human_time_estimate"` + 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"` + Type string `json:"type"` + GroupID interface{} `json:"group_id"` + } `json:"labels"` } `json:"merge_request"` } @@ -778,6 +953,10 @@ type ( } `json:"object_attributes"` Labels []interface{} `json:"labels"` Changes struct { + Draft struct { + Previous null.Bool `json:"previous"` + Current null.Bool `json:"current"` + } `json:"draft"` } `json:"changes"` Repository struct { Name string `json:"name"` @@ -786,4 +965,131 @@ type ( Homepage string `json:"homepage"` } `json:"repository"` } + + pipelineHook struct { + ObjectKind string `json:"object_kind"` + ObjectAttributes struct { + ID int `json:"id"` + IID int `json:"iid"` + Name string `json:"name"` + Ref string `json:"ref"` + Tag bool `json:"tag"` + SHA string `json:"sha"` + BeforeSHA string `json:"before_sha"` + Source string `json:"source"` + Status string `json:"status"` + Stages []string `json:"stages"` + CreatedAt string `json:"created_at"` + FinishedAt string `json:"finished_at"` + Duration int `json:"duration"` + Variables []variable `json:"variables"` + URL string `json:"url"` + } `json:"object_attributes"` + MergeRequest struct { + ID int `json:"id"` + IID int `json:"iid"` + Title string `json:"title"` + SourceBranch string `json:"source_branch"` + SourceProjectID int `json:"source_project_id"` + TargetBranch string `json:"target_branch"` + TargetProjectID int `json:"target_project_id"` + State string `json:"state"` + MergeStatus string `json:"merge_status"` + DetailedMergeStatus string `json:"detailed_merge_status"` + URL string `json:"url"` + } `json:"merge_request"` + User struct { + ID int `json:"id"` + Name string `json:"name"` + Username string `json:"username"` + AvatarURL string `json:"avatar_url"` + Email string `json:"email"` + } `json:"user"` + Project struct { + ID int `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + WebURL string `json:"web_url"` + AvatarURL null.String `json:"avatar_url"` + GitSSHURL string `json:"git_ssh_url"` + GitHTTPURL string `json:"git_http_url"` + Namespace string `json:"namespace"` + VisibilityLevel int `json:"visibility_level"` + PathWithNamespace string `json:"path_with_namespace"` + DefaultBranch string `json:"default_branch"` + } `json:"project"` + Commit struct { + ID string `json:"id"` + Message string `json:"message"` + Timestamp string `json:"timestamp"` + URL string `json:"url"` + Author author `json:"author"` + } `json:"commit"` + SourcePipeline struct { + Project struct { + ID int `json:"id"` + WebURL string `json:"web_url"` + PathWithNamespace string `json:"path_with_namespace"` + } `json:"project"` + PipelineID int `json:"pipeline_id"` + JobID int `json:"job_id"` + } `json:"source_pipeline"` + Builds []build `json:"builds"` + } + + variable struct { + Key string `json:"key"` + Value string `json:"value"` + } + + author struct { + Name string `json:"name"` + Email string `json:"email"` + } + + build struct { + ID int `json:"id"` + Stage string `json:"stage"` + Name string `json:"name"` + Status string `json:"status"` + CreatedAt string `json:"created_at"` + StartedAt null.String `json:"started_at"` + FinishedAt null.String `json:"finished_at"` + Duration float64 `json:"duration"` + QueuedDuration float64 `json:"queued_duration"` + FailureReason null.String `json:"failure_reason"` + When string `json:"when"` + Manual bool `json:"manual"` + AllowFailure bool `json:"allow_failure"` + User struct { + ID int `json:"id"` + Name string `json:"name"` + Username string `json:"username"` + AvatarURL string `json:"avatar_url"` + Email string `json:"email"` + } `json:"user"` + Runner runner `json:"runner"` + ArtifactsFile artifacts `json:"artifacts_file"` + Environment environment `json:"environment"` + } + + runner struct { + ID int `json:"id"` + Description string `json:"description"` + Active bool `json:"active"` + RunnerType string `json:"runner_type"` + IsShared bool `json:"is_shared"` + Tags []string `json:"tags"` + } + + artifacts struct { + Filename null.String `json:"filename"` + Size null.Int `json:"size"` + } + + environment struct { + Name string `json:"name"` + Action string `json:"action"` + DeploymentTier string `json:"deployment_tier"` + } ) diff --git a/scm/driver/gitlab/webhook_test.go b/scm/driver/gitlab/webhook_test.go index 1f153f20d..e238a615c 100644 --- a/scm/driver/gitlab/webhook_test.go +++ b/scm/driver/gitlab/webhook_test.go @@ -38,6 +38,18 @@ func TestWebhooks(t *testing.T) { after: "testdata/webhooks/branch_delete.json.golden", obj: new(scm.BranchHook), }, + { + event: "System Hook", + before: "testdata/webhooks/branch_create.json", + after: "testdata/webhooks/branch_create.json.golden", + obj: new(scm.PushHook), + }, + { + event: "System Hook", + before: "testdata/webhooks/branch_delete.json", + after: "testdata/webhooks/branch_delete.json.golden", + obj: new(scm.BranchHook), + }, // tag hooks { event: "Tag Push Hook", @@ -51,6 +63,18 @@ func TestWebhooks(t *testing.T) { after: "testdata/webhooks/tag_delete.json.golden", obj: new(scm.TagHook), }, + { + event: "System Hook", + before: "testdata/webhooks/tag_create.json", + after: "testdata/webhooks/tag_create.json.golden", + obj: new(scm.PushHook), + }, + { + event: "System Hook", + before: "testdata/webhooks/tag_delete.json", + after: "testdata/webhooks/tag_delete.json.golden", + obj: new(scm.TagHook), + }, // push hooks { event: "Push Hook", @@ -58,6 +82,12 @@ func TestWebhooks(t *testing.T) { after: "testdata/webhooks/push.json.golden", obj: new(scm.PushHook), }, + { + event: "System Hook", + before: "testdata/webhooks/push.json", + after: "testdata/webhooks/push.json.golden", + obj: new(scm.PushHook), + }, // // issue hooks // { // event: "issues", @@ -79,6 +109,13 @@ func TestWebhooks(t *testing.T) { after: "testdata/webhooks/pull_request_create.json.golden", obj: new(scm.PullRequestHook), }, + { + event: "System Hook", + before: "testdata/webhooks/pull_request_create.json", + after: "testdata/webhooks/pull_request_create.json.golden", + obj: new(scm.PullRequestHook), + }, + // { // event: "Merge Request Hook", // before: "testdata/webhooks/pull_request_edited.json", @@ -97,6 +134,12 @@ func TestWebhooks(t *testing.T) { after: "testdata/webhooks/pull_request_close.json.golden", obj: new(scm.PullRequestHook), }, + { + event: "Merge Request Hook", + before: "testdata/webhooks/pull_request_review_ready.json", + after: "testdata/webhooks/pull_request_review_ready.json.golden", + obj: new(scm.PullRequestHook), + }, { event: "Merge Request Hook", before: "testdata/webhooks/pull_request_reopen.json", @@ -109,13 +152,49 @@ func TestWebhooks(t *testing.T) { after: "testdata/webhooks/pull_request_merge.json.golden", obj: new(scm.PullRequestHook), }, - // // pull request comment hooks - // { - // event: "issue_comment", - // before: "testdata/webhooks/pull_request_comment_created.json", - // after: "testdata/webhooks/pull_request_comment_created.json.golden", - // obj: new(scm.PullRequestCommentHook), - // }, + { + event: "System Hook", + before: "testdata/webhooks/pull_request_close.json", + after: "testdata/webhooks/pull_request_close.json.golden", + obj: new(scm.PullRequestHook), + }, + { + event: "System Hook", + before: "testdata/webhooks/pull_request_review_ready.json", + after: "testdata/webhooks/pull_request_review_ready.json.golden", + obj: new(scm.PullRequestHook), + }, + { + event: "System Hook", + before: "testdata/webhooks/pull_request_reopen.json", + after: "testdata/webhooks/pull_request_reopen.json.golden", + obj: new(scm.PullRequestHook), + }, + { + event: "System Hook", + before: "testdata/webhooks/pull_request_merge.json", + after: "testdata/webhooks/pull_request_merge.json.golden", + obj: new(scm.PullRequestHook), + }, + // Note hook for Gitlab Merge Request comment + { + event: "Note Hook", + before: "testdata/webhooks/merge_request_comment_create.json", + after: "testdata/webhooks/merge_request_comment_create.json.golden", + obj: new(scm.IssueCommentHook), + }, + { + event: "System Hook", + before: "testdata/webhooks/merge_request_comment_create.json", + after: "testdata/webhooks/merge_request_comment_create.json.golden", + obj: new(scm.IssueCommentHook), + }, + { + event: "Pipeline Hook", + before: "testdata/webhooks/pipeline_hook.json", + after: "testdata/webhooks/pipeline_hook.json.golden", + obj: new(scm.PipelineHook), + }, } for _, test := range tests { diff --git a/scm/driver/gogs/git.go b/scm/driver/gogs/git.go index 2cb3c687e..30103cc7b 100644 --- a/scm/driver/gogs/git.go +++ b/scm/driver/gogs/git.go @@ -16,7 +16,7 @@ type gitService struct { client *wrapper } -func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.CreateBranch) (*scm.Response, error) { +func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.ReferenceInput) (*scm.Response, error) { return nil, scm.ErrNotSupported } @@ -28,6 +28,15 @@ func (s *gitService) FindBranch(ctx context.Context, repo, name string) (*scm.Re } func (s *gitService) FindCommit(ctx context.Context, repo, ref string) (*scm.Commit, *scm.Response, error) { + // github and gitlab permit fetching a commit by sha + // or branch. This code emulates the github and gitlab + // behavior for gogs by fetching the commit sha for the + // branch and using in the subsequent API call. + if scm.IsHash(ref) == false { + if branch, _, err := s.FindBranch(ctx, repo, scm.TrimRef(ref)); err == nil { + ref = branch.Sha // replace ref with sha + } + } path := fmt.Sprintf("api/v1/repos/%s/commits/%s", repo, ref) out := new(commitDetail) res, err := s.client.do(ctx, "GET", path, nil, out) @@ -45,6 +54,12 @@ func (s *gitService) ListBranches(ctx context.Context, repo string, _ scm.ListOp return convertBranchList(out), res, err } +func (s *gitService) ListBranchesV2(ctx context.Context, repo string, opts scm.BranchListOptions) ([]*scm.Reference, *scm.Response, error) { + // Gogs doesnt provide support listing based on searchTerm + // Hence calling the ListBranches + return s.ListBranches(ctx, repo, opts.PageListOptions) +} + func (s *gitService) ListCommits(ctx context.Context, repo string, _ scm.CommitListOptions) ([]*scm.Commit, *scm.Response, error) { return nil, nil, scm.ErrNotSupported } diff --git a/scm/driver/gogs/git_test.go b/scm/driver/gogs/git_test.go index 5b226e1db..9fe8d1322 100644 --- a/scm/driver/gogs/git_test.go +++ b/scm/driver/gogs/git_test.go @@ -44,6 +44,40 @@ func TestCommitFind(t *testing.T) { } } +func TestCommitFindBranch(t *testing.T) { + defer gock.Off() + + gock.New("https://try.gogs.io"). + Get("/api/v1/repos/gogits/gogs/branches/master"). + Reply(200). + Type("application/json"). + File("testdata/branch.json") + + gock.New("https://try.gogs.io"). + Get("/api/v1/repos/gogits/gogs/commits/f05f642b892d59a0a9ef6a31f6c905a24b5db13a"). + Reply(200). + Type("application/json"). + File("testdata/commits.json") + + client, _ := New("https://try.gogs.io") + got, _, err := client.Git.FindCommit( + context.Background(), + "gogits/gogs", + "master", + ) + if err != nil { + t.Error(err) + } + want := new(scm.Commit) + raw, _ := ioutil.ReadFile("testdata/commits.json.golden") + json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + func TestCommitList(t *testing.T) { client, _ := New("https://try.gogs.io") _, _, err := client.Git.ListCommits(context.Background(), "gogits/gogs", scm.CommitListOptions{}) diff --git a/scm/driver/gogs/repo.go b/scm/driver/gogs/repo.go index f7ee5b2eb..c9930b858 100644 --- a/scm/driver/gogs/repo.go +++ b/scm/driver/gogs/repo.go @@ -45,6 +45,18 @@ func (s *repositoryService) List(ctx context.Context, _ scm.ListOptions) ([]*scm return convertRepositoryList(out), res, err } +func (s *repositoryService) ListV2(ctx context.Context, opts scm.RepoListOptions) ([]*scm.Repository, *scm.Response, error) { + // Azure does not support search filters, hence calling List api without search filtering + return s.List(ctx, opts.ListOptions) +} + +func (s *repositoryService) ListNamespace(ctx context.Context, namespace string, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { + path := fmt.Sprintf("api/v1/orgs/%s/repos", namespace) + out := []*repository{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertRepositoryList(out), res, err +} + func (s *repositoryService) List2(ctx context.Context, orgSlug string, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { return nil, nil, scm.ErrNotSupported } diff --git a/scm/driver/harness/content.go b/scm/driver/harness/content.go new file mode 100644 index 000000000..16159cb53 --- /dev/null +++ b/scm/driver/harness/content.go @@ -0,0 +1,255 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "context" + "encoding/base64" + "fmt" + "time" + + "github.com/drone/go-scm/scm" +) + +type contentService struct { + client *wrapper +} + +func (s *contentService) Find(ctx context.Context, repo, path, ref string) (*scm.Content, *scm.Response, error) { + slug := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoId, queryParams, err := getRepoAndQueryParams(slug) + if err != nil { + return nil, nil, err + } + endpoint := fmt.Sprintf("api/v1/repos/%s/content/%s?git_ref=%s&include_commit=true&%s", repoId, path, ref, queryParams) + out := new(fileContent) + res, err := s.client.do(ctx, "GET", endpoint, nil, out) + // decode raw output content + raw, _ := base64.StdEncoding.DecodeString(out.Content.Data) + return &scm.Content{ + Path: path, + Sha: out.LatestCommit.Sha, + BlobID: out.Sha, + Data: raw, + }, res, err +} + +func (s *contentService) Create(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { + slug := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoId, queryParams, err := getRepoAndQueryParams(slug) + if err != nil { + return nil, err + } + endpoint := fmt.Sprintf("api/v1/repos/%s/commits?%s", repoId, queryParams) + a := action{ + Action: "CREATE", + Path: path, + Payload: string(params.Data), + Encoding: "string", + } + in := editFile{ + Branch: params.Branch, + Message: params.Message, + Title: params.Message, + Actions: []action{a}, + BypassRules: true, + Author: identity{ + Name: params.Signature.Name, + Email: params.Signature.Email, + }, + } + + res, err := s.client.do(ctx, "POST", endpoint, in, nil) + return res, err +} + +func (s *contentService) Update(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { + slug := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoId, queryParams, err := getRepoAndQueryParams(slug) + if err != nil { + return nil, err + } + endpoint := fmt.Sprintf("api/v1/repos/%s/commits?%s", repoId, queryParams) + a := action{ + Action: "UPDATE", + Path: path, + Payload: string(params.Data), + Encoding: "string", + Sha: params.BlobID, + } + in := editFile{ + Branch: params.Branch, + Message: params.Message, + Title: params.Message, + Actions: []action{a}, + BypassRules: true, + Author: identity{ + Name: params.Signature.Name, + Email: params.Signature.Email, + }, + } + + res, err := s.client.do(ctx, "POST", endpoint, in, nil) + return res, err +} + +func (s *contentService) Delete(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { + slug := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoId, queryParams, err := getRepoAndQueryParams(slug) + if err != nil { + return nil, err + } + endpoint := fmt.Sprintf("api/v1/repos/%s/commits?%s", repoId, queryParams) + a := action{ + Action: "DELETE", + Path: path, + Encoding: "string", + } + in := editFile{ + Branch: params.Branch, + Message: params.Message, + Title: params.Message, + Actions: []action{a}, + BypassRules: true, + Author: identity{ + Name: params.Signature.Name, + Email: params.Signature.Email, + }, + } + + res, err := s.client.do(ctx, "POST", endpoint, in, nil) + return res, err +} + +func (s *contentService) List(ctx context.Context, repo, path, ref string, _ scm.ListOptions) ([]*scm.ContentInfo, *scm.Response, error) { + slug := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoId, queryParams, err := getRepoAndQueryParams(slug) + if err != nil { + return nil, nil, err + } + endpoint := fmt.Sprintf("api/v1/repos/%s/content/%s?git_ref=%s&include_commit=true&%s", repoId, path, ref, queryParams) + out := new(contentList) + res, err := s.client.do(ctx, "GET", endpoint, nil, &out) + return convertContentInfoList(out.Content.Entries), res, err +} + +type ( + identity struct { + Name string `json:"name"` + Email string `json:"email"` + } + + editFile struct { + Actions []action `json:"actions"` + Author identity `json:"author"` + Branch string `json:"branch"` + Message string `json:"message"` + NewBranch string `json:"new_branch"` + Title string `json:"title"` + + BypassRules bool `json:"bypass_rules"` + } + + action struct { + Action string `json:"action"` + Encoding string `json:"encoding"` + Path string `json:"path"` + Payload string `json:"payload"` + Sha string `json:"sha"` + } + + fileContent struct { + Type string `json:"type"` + Sha string `json:"sha"` + Name string `json:"name"` + Path string `json:"path"` + LatestCommit struct { + Sha string `json:"sha"` + Title string `json:"title"` + Message string `json:"message"` + Author struct { + Identity identity `json:"identity"` + When time.Time `json:"when"` + } `json:"author"` + Committer struct { + Identity identity `json:"identity"` + When time.Time `json:"when"` + } `json:"committer"` + } `json:"latest_commit"` + Content struct { + Encoding string `json:"encoding"` + Data string `json:"data"` + Size int `json:"size"` + } `json:"content"` + } + + contentList struct { + Type string `json:"type"` + Sha string `json:"sha"` + Name string `json:"name"` + Path string `json:"path"` + LatestCommit struct { + Sha string `json:"sha"` + Title string `json:"title"` + Message string `json:"message"` + Author struct { + Identity identity `json:"identity"` + When time.Time `json:"when"` + } `json:"author"` + Committer struct { + Identity identity `json:"identity"` + When time.Time `json:"when"` + } `json:"committer"` + } `json:"latest_commit"` + Content struct { + Entries []fileEntry `json:"entries"` + } `json:"content"` + } + + fileEntry struct { + Type string `json:"type"` + Sha string `json:"sha"` + Name string `json:"name"` + Path string `json:"path"` + LatestCommit struct { + Sha string `json:"sha"` + Title string `json:"title"` + Message string `json:"message"` + Author struct { + Identity identity `json:"identity"` + When time.Time `json:"when"` + } `json:"author"` + Committer struct { + Identity identity `json:"identity"` + When time.Time `json:"when"` + } `json:"committer"` + } `json:"latest_commit"` + } +) + +func convertContentInfoList(from []fileEntry) []*scm.ContentInfo { + to := []*scm.ContentInfo{} + for _, v := range from { + to = append(to, convertContentInfo(v)) + } + return to +} + +func convertContentInfo(from fileEntry) *scm.ContentInfo { + to := &scm.ContentInfo{ + Path: from.Path, + Sha: from.LatestCommit.Sha, + BlobID: from.Sha, + } + switch from.Type { + case "file": + to.Kind = scm.ContentKindFile + case "dir": + to.Kind = scm.ContentKindDirectory + default: + to.Kind = scm.ContentKindUnsupported + } + return to +} diff --git a/scm/driver/harness/content_test.go b/scm/driver/harness/content_test.go new file mode 100644 index 000000000..f59776f2c --- /dev/null +++ b/scm/driver/harness/content_test.go @@ -0,0 +1,233 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "context" + "encoding/json" + "io/ioutil" + "net/http" + "strings" + "testing" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/transport" + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +const ( + gockOrigin = "https://qa.harness.io/gateway/code" + harnessOrg = "px7xd_BFRCi-pfWPYXVjvw" + harnessAccount = "default" + harnessProject = "codeciintegration" + harnessRepo = "thomas" + harnessPAT = "" +) + +func TestContentFind(t *testing.T) { + if harnessPAT == "" { + defer gock.Off() + + gock.New(gockOrigin). + Get("/gateway/code/api/v1/repos/thomas/content/README.md"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("plain/text"). + File("testdata/content.json") + } + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + result, _, err := client.Contents.Find( + context.Background(), + harnessRepo, + "README.md", + "98189d5cf2a751a6246c24a72945ba70839f1b20", + ) + if err != nil { + t.Error(err) + } + + if got, want := result.Path, "README.md"; got != want { + t.Errorf("Want file Path %q, got %q", want, got) + } + if !strings.Contains(string(result.Data), "project") { + t.Errorf("Want file Data %q, must contain 'project'", result.Data) + } +} + +func TestContentCreate(t *testing.T) { + if harnessPAT == "" { + defer gock.Off() + + gock.New(gockOrigin). + Post("/gateway/code/api/v1/repos/thomas/commits"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("plain/text"). + BodyString("{\"commit_id\":\"20ecde1f8c277da0e91750bef9f3b88f228d86db\"}") + } + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + result, err := client.Contents.Create( + context.Background(), + harnessRepo, + "README.2", + &scm.ContentParams{ + Data: []byte("hello world"), + Message: "create README.2", + Branch: "main", + }, + ) + if err != nil { + t.Error(err) + } + + if result.Status != 200 { + t.Errorf("Unexpected Results") + } +} + +func TestContentUpdate(t *testing.T) { + if harnessPAT == "" { + defer gock.Off() + + gock.New(gockOrigin). + Post("/gateway/code/api/v1/repos/thomas/commits"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("plain/text"). + BodyString("{\"commit_id\":\"20ecde1f8c277da0e91750bef9f3b88f228d86db\"}") + } + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + result, err := client.Contents.Update( + context.Background(), + harnessRepo, + "README.2", + &scm.ContentParams{ + Data: []byte("hello world 2"), + Message: "update README.2", + Branch: "main", + BlobID: "95d09f2b10159347eece71399a7e2e907ea3df4f", + }, + ) + if err != nil { + t.Error(err) + } + + if result.Status != 200 { + t.Errorf("Unexpected Results") + } +} + +func TestContentDelete(t *testing.T) { + if harnessPAT == "" { + defer gock.Off() + + gock.New(gockOrigin). + Post("/gateway/code/api/v1/repos/thomas/commits"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("plain/text"). + BodyString("{\"commit_id\":\"20ecde1f8c277da0e91750bef9f3b88f228d86db\"}") + } + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + result, err := client.Contents.Delete( + context.Background(), + harnessRepo, + "README.2", + &scm.ContentParams{ + Message: "delete README.2", + Branch: "main", + }, + ) + if err != nil { + t.Error(err) + } + + if result.Status != 200 { + t.Errorf("Unexpected Results") + } +} + +func TestContentList(t *testing.T) { + defer gock.Off() + + gock.New(gockOrigin). + Get("/gateway/code/api/v1/repos/thomas/content/docker"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("application/json"). + File("testdata/content_list.json") + + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + got, _, err := client.Contents.List( + context.Background(), + harnessRepo, + "docker", + "", + scm.ListOptions{}, + ) + if err != nil { + t.Error(err) + } + + want := []*scm.ContentInfo{} + raw, _ := ioutil.ReadFile("testdata/content_list.json.golden") + json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} diff --git a/scm/driver/harness/git.go b/scm/driver/harness/git.go new file mode 100644 index 000000000..f261f7756 --- /dev/null +++ b/scm/driver/harness/git.go @@ -0,0 +1,259 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/drone/go-scm/scm" +) + +type gitService struct { + client *wrapper +} + +func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.ReferenceInput) (*scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoID, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/branches?%s", repoID, queryParams) + in := &branchInput{ + Name: params.Name, + Target: params.Sha, + BypassRules: true, + } + return s.client.do(ctx, "POST", path, in, nil) +} + +func (s *gitService) FindBranch(ctx context.Context, repo, name string) (*scm.Reference, *scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoID, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/branches/%s?%s", repoID, name, queryParams) + 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) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoID, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/commits/%s?%s", repoID, ref, queryParams) + out := new(commitInfo) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertCommitInfo(out), res, err +} + +func (s *gitService) FindTag(ctx context.Context, repo, name string) (*scm.Reference, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *gitService) ListBranches(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Reference, *scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoID, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/branches?%s&%s", repoID, encodeListOptions(opts), queryParams) + out := []*branch{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertBranchList(out), res, err +} + +func (s *gitService) ListBranchesV2(ctx context.Context, repo string, opts scm.BranchListOptions) ([]*scm.Reference, *scm.Response, error) { + // Harness doesnt provide support listing based on searchTerm + // Hence calling the ListBranches + return s.ListBranches(ctx, repo, opts.PageListOptions) +} + +func (s *gitService) ListCommits(ctx context.Context, repo string, opts scm.CommitListOptions) ([]*scm.Commit, *scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoID, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/commits?%s&%s", repoID, encodeCommitListOptions(opts), queryParams) + out := new(commits) + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertCommitList(out), res, err +} + +func (s *gitService) ListTags(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Reference, *scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoID, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/tags?%s&%s", repoID, encodeListOptions(opts), queryParams) + out := []*branch{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertBranchList(out), res, err +} + +func (s *gitService) ListChanges(ctx context.Context, repo, ref string, opts scm.ListOptions) ([]*scm.Change, *scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoID, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/commits/%s/diff?%s&%s", repoID, ref, encodeListOptions(opts), queryParams) + out := []*fileDiff{} + res, err := s.client.do(ctx, "POST", path, nil, &out) + return convertFileDiffs(out), res, err +} + +func (s *gitService) CompareChanges(ctx context.Context, repo, source, target string, _ scm.ListOptions) ([]*scm.Change, *scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoID, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/diff/%s...%s?%s", repoID, source, target, queryParams) + out := []*fileDiff{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertChangeList(out), res, err +} + +// native data structures +type ( + commits struct { + Commits []commitInfo `json:"commits"` + } + + commitInfo struct { + Author struct { + Identity struct { + Email string `json:"email"` + Name string `json:"name"` + } `json:"identity"` + When time.Time `json:"when"` + } `json:"author"` + Committer struct { + Identity struct { + Email string `json:"email"` + Name string `json:"name"` + } `json:"identity"` + When time.Time `json:"when"` + } `json:"committer"` + Message string `json:"message"` + Sha string `json:"sha"` + Title string `json:"title"` + } + branchInput struct { + Name string `json:"name"` + Target string `json:"target"` + BypassRules bool `json:"bypass_rules"` + } + branch struct { + Commit struct { + Author struct { + Identity struct { + Email string `json:"email"` + Name string `json:"name"` + } `json:"identity"` + When time.Time `json:"when"` + } `json:"author"` + Committer struct { + Identity struct { + Email string `json:"email"` + Name string `json:"name"` + } `json:"identity"` + When time.Time `json:"when"` + } `json:"committer"` + Message string `json:"message"` + Sha string `json:"sha"` + Title string `json:"title"` + } `json:"commit"` + Name string `json:"name"` + Sha string `json:"sha"` + } + fileDiff struct { + SHA string `json:"sha"` + OldSHA string `json:"old_sha,omitempty"` + Path string `json:"path"` + OldPath string `json:"old_path,omitempty"` + Status string `json:"status"` + Additions int64 `json:"additions"` + Deletions int64 `json:"deletions"` + Changes int64 `json:"changes"` + ContentURL string `json:"content_url"` + Patch []byte `json:"patch,omitempty"` + IsBinary bool `json:"is_binary"` + IsSubmodule bool `json:"is_submodule"` + } +) + +// +// native data structure conversion +// + +func convertBranchList(src []*branch) []*scm.Reference { + dst := []*scm.Reference{} + for _, v := range src { + dst = append(dst, convertBranch(v)) + } + return dst +} + +func convertBranch(src *branch) *scm.Reference { + return &scm.Reference{ + Name: src.Name, + Path: scm.ExpandRef(src.Name, "refs/heads/"), + Sha: src.Sha, + } +} + +func convertCommitList(src *commits) []*scm.Commit { + var dst []*scm.Commit + for _, v := range src.Commits { + dst = append(dst, convertCommitInfo(&v)) + } + return dst +} + +func convertChangeList(src []*fileDiff) []*scm.Change { + dst := []*scm.Change{} + for _, v := range src { + dst = append(dst, convertChange(v)) + } + return dst +} + +func convertCommitInfo(src *commitInfo) *scm.Commit { + return &scm.Commit{ + Sha: src.Sha, + Message: src.Message, + Author: scm.Signature{ + Name: src.Author.Identity.Name, + Email: src.Author.Identity.Email, + Date: src.Author.When, + }, + Committer: scm.Signature{ + Name: src.Committer.Identity.Name, + Email: src.Committer.Identity.Email, + Date: src.Committer.When, + }, + } +} + +func convertChange(src *fileDiff) *scm.Change { + return &scm.Change{ + Path: src.Path, + PrevFilePath: src.OldPath, + Added: strings.EqualFold(src.Status, "ADDED"), + Renamed: strings.EqualFold(src.Status, "RENAMED"), + Deleted: strings.EqualFold(src.Status, "DELETED"), + } +} diff --git a/scm/driver/harness/git_test.go b/scm/driver/harness/git_test.go new file mode 100644 index 000000000..dfbd5a99e --- /dev/null +++ b/scm/driver/harness/git_test.go @@ -0,0 +1,277 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "testing" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/transport" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/h2non/gock" +) + +func TestListCommits(t *testing.T) { + if harnessPAT == "" { + defer gock.Off() + + gock.New(gockOrigin). + Get("/gateway/code/api/v1/repos/thomas/commits"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("application/json"). + File("testdata/commits.json") + } + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + got, _, err := client.Git.ListCommits(context.Background(), harnessRepo, scm.CommitListOptions{}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Commit{} + raw, _ := ioutil.ReadFile("testdata/commits.json.golden") + wantErr := json.Unmarshal(raw, &want) + if wantErr != nil { + t.Error(wantErr) + return + } + if harnessPAT != "" && len(got) > 0 { + // if testing against a real system and we get commits + return + } + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestFindCommit(t *testing.T) { + if harnessPAT == "" { + defer gock.Off() + + gock.New(gockOrigin). + Get("/gateway/code/api/v1/repos/thomas/commits/1d640265d8bdd818175fa736f0fcbad2c9b716c9"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("application/json"). + File("testdata/commit.json") + } + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + got, _, err := client.Git.FindCommit(context.Background(), harnessRepo, "1d640265d8bdd818175fa736f0fcbad2c9b716c9") + if err != nil { + t.Error(err) + return + } + + want := new(scm.Commit) + raw, _ := ioutil.ReadFile("testdata/commit.json.golden") + wantErr := json.Unmarshal(raw, &want) + if wantErr != nil { + t.Error(wantErr) + return + } + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestFindBranch(t *testing.T) { + if harnessPAT == "" { + defer gock.Off() + + gock.New(gockOrigin). + Get("/gateway/code/api/v1/repos/thomas/branches/main"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("application/json"). + File("testdata/branch.json") + } + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + got, _, err := client.Git.FindBranch(context.Background(), harnessRepo, "main") + if err != nil { + t.Error(err) + return + } + + want := new(scm.Reference) + raw, _ := ioutil.ReadFile("testdata/branch.json.golden") + wantErr := json.Unmarshal(raw, &want) + if wantErr != nil { + t.Error(wantErr) + return + } + + if diff := cmp.Diff(got, want, cmpopts.IgnoreFields(scm.Reference{}, "Sha")); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestListBranches(t *testing.T) { + if harnessPAT == "" { + defer gock.Off() + + gock.New(gockOrigin). + Get("/gateway/code/api/v1/repos/thomas/branches"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("application/json"). + File("testdata/branches.json") + } + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + got, _, err := client.Git.ListBranches(context.Background(), harnessRepo, scm.ListOptions{}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Reference{} + raw, _ := ioutil.ReadFile("testdata/branches.json.golden") + wantErr := json.Unmarshal(raw, &want) + if wantErr != nil { + t.Error(wantErr) + return + } + + if diff := cmp.Diff(got, want, cmpopts.IgnoreFields(scm.Reference{}, "Sha")); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestCreateBranch(t *testing.T) { + + defer gock.Off() + + gock.New(gockOrigin). + Post("/gateway/code/api/v1/repos/thomas/branches"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("application/json"). + File("testdata/branch.json") + + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + input := &scm.ReferenceInput{ + Name: "test", + Sha: "e8ef0374ca0cee8048e94b28eaf0d9e2e2515a14", + } + result, err := client.Git.CreateBranch(context.Background(), harnessRepo, input) + if err != nil { + t.Error(err) + return + } + + if result.Status != 200 { + t.Errorf("Unexpected Results") + } + +} + +func TestCompareChanges(t *testing.T) { + source := "542ddabd47d7bfa79359b7b4e2af7f975354e35f" + target := "c7d0d4b21d5cfdf47475ff1f6281ef1a91883d" + defer gock.Off() + + gock.New(gockOrigin). + Get(fmt.Sprintf("/gateway/code/api/v1/repos/thomas/diff/%s...%s", source, target)). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("application/json"). + File("testdata/gitdiff.json") + + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + got, result, err := client.Git.CompareChanges(context.Background(), harnessRepo, source, target, scm.ListOptions{}) + if err != nil { + t.Error(err) + return + } + + if result.Status != 200 { + t.Errorf("Unexpected Results") + } + + want := []*scm.Change{} + raw, _ := ioutil.ReadFile("testdata/gitdiff.json.golden") + wantErr := json.Unmarshal(raw, &want) + if wantErr != nil { + t.Error(wantErr) + return + } + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} diff --git a/scm/driver/harness/harness.go b/scm/driver/harness/harness.go new file mode 100644 index 000000000..cf71dd7f5 --- /dev/null +++ b/scm/driver/harness/harness.go @@ -0,0 +1,111 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "bytes" + "context" + "encoding/json" + "io" + "net/url" + "strings" + + "github.com/drone/go-scm/scm" +) + +// New returns a new gitness API client. +func New(uri, account, organization, project string) (*scm.Client, error) { + base, err := url.Parse(uri) + if err != nil { + return nil, err + } + if !strings.HasSuffix(base.Path, "/") { + base.Path = base.Path + "/" + } + client := &wrapper{new(scm.Client), account, organization, project} + client.BaseURL = base + // initialize services + client.Driver = scm.DriverHarness + client.Linker = &linker{base.String()} + client.Contents = &contentService{client} + client.Git = &gitService{client} + client.Issues = &issueService{client} + client.Milestones = &milestoneService{client} + client.Organizations = &organizationService{client} + client.PullRequests = &pullService{client} + client.Repositories = &repositoryService{client} + client.Releases = &releaseService{client} + client.Reviews = &reviewService{client} + client.Users = &userService{client} + client.Webhooks = &webhookService{client} + return client.Client, nil +} + +// wraper wraps the Client to provide high level helper functions +// for making http requests and unmarshaling the response. +type wrapper struct { + *scm.Client + account string + organization string + project string +} + +// 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) { + req := &scm.Request{ + Method: method, + Path: path, + } + // if we are posting or putting data, we need to + // write it to the body of the request. + if in != nil { + buf := new(bytes.Buffer) + json.NewEncoder(buf).Encode(in) + req.Header = map[string][]string{ + "Content-Type": {"application/json"}, + } + req.Body = buf + } + + // execute the http request + res, err := c.Client.Do(ctx, req) + if err != nil { + return nil, err + } + defer res.Body.Close() + + // 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 + } + + if out == nil { + return res, nil + } + + // if raw output is expected, copy to the provided + // buffer and exit. + if w, ok := out.(io.Writer); ok { + io.Copy(w, res.Body) + return res, nil + } + + // if a json response is expected, parse and return + // the json response. + return res, json.NewDecoder(res.Body).Decode(out) +} + +// Error represents a Harness CODE error. +type Error struct { + Message string `json:"message"` +} + +func (e *Error) Error() string { + return e.Message +} diff --git a/scm/driver/harness/harness_test.go b/scm/driver/harness/harness_test.go new file mode 100644 index 000000000..a1ccc6f90 --- /dev/null +++ b/scm/driver/harness/harness_test.go @@ -0,0 +1,47 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// package gitea implements a Gogs client. +package harness + +import ( + "fmt" + "testing" + + "github.com/drone/go-scm/scm" +) + +func TestClient(t *testing.T) { + client, err := New(gockOrigin, "", "", "") + if err != nil { + t.Error(err) + } + if got, want := client.BaseURL.String(), fmt.Sprintf("%s/", gockOrigin); got != want { + t.Errorf("Want Client URL %q, got %q", want, got) + } +} + +func TestClient_Error(t *testing.T) { + _, err := New("http://a b.com/", "", "", "") + if err == nil { + t.Errorf("Expect error when invalid URL") + } +} + +func testPage(res *scm.Response) func(t *testing.T) { + return func(t *testing.T) { + if got, want := res.Page.Next, 2; got != want { + t.Errorf("Want next page %d, got %d", want, got) + } + if got, want := res.Page.Prev, 1; got != want { + t.Errorf("Want prev page %d, got %d", want, got) + } + if got, want := res.Page.First, 1; got != want { + t.Errorf("Want first page %d, got %d", want, got) + } + if got, want := res.Page.Last, 5; got != want { + t.Errorf("Want last page %d, got %d", want, got) + } + } +} diff --git a/scm/driver/harness/issue.go b/scm/driver/harness/issue.go new file mode 100644 index 000000000..99d904791 --- /dev/null +++ b/scm/driver/harness/issue.go @@ -0,0 +1,55 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "context" + + "github.com/drone/go-scm/scm" +) + +type issueService struct { + client *wrapper +} + +func (s *issueService) Find(ctx context.Context, repo string, number int) (*scm.Issue, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *issueService) FindComment(ctx context.Context, repo string, index, id int) (*scm.Comment, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *issueService) List(ctx context.Context, repo string, opts scm.IssueListOptions) ([]*scm.Issue, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *issueService) ListComments(ctx context.Context, repo string, index int, opts scm.ListOptions) ([]*scm.Comment, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *issueService) Create(ctx context.Context, repo string, input *scm.IssueInput) (*scm.Issue, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *issueService) CreateComment(ctx context.Context, repo string, index int, input *scm.CommentInput) (*scm.Comment, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *issueService) DeleteComment(ctx context.Context, repo string, index, id int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + +func (s *issueService) Close(ctx context.Context, repo string, number int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + +func (s *issueService) Lock(ctx context.Context, repo string, number int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + +func (s *issueService) Unlock(ctx context.Context, repo string, number int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} diff --git a/scm/driver/harness/issue_test.go b/scm/driver/harness/issue_test.go new file mode 100644 index 000000000..5d232e2ff --- /dev/null +++ b/scm/driver/harness/issue_test.go @@ -0,0 +1,5 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness diff --git a/scm/driver/harness/linker.go b/scm/driver/harness/linker.go new file mode 100644 index 000000000..e0c01d820 --- /dev/null +++ b/scm/driver/harness/linker.go @@ -0,0 +1,27 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "context" + + "github.com/drone/go-scm/scm" +) + +type linker struct { + base string +} + +// Resource returns a link to the resource. +func (l *linker) Resource(ctx context.Context, repo string, ref scm.Reference) (string, error) { + return "", scm.ErrNotSupported + +} + +// Diff returns a link to the diff. +func (l *linker) Diff(ctx context.Context, repo string, source, target scm.Reference) (string, error) { + return "", scm.ErrNotSupported + +} diff --git a/scm/driver/harness/linker_test.go b/scm/driver/harness/linker_test.go new file mode 100644 index 000000000..5d232e2ff --- /dev/null +++ b/scm/driver/harness/linker_test.go @@ -0,0 +1,5 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness diff --git a/scm/driver/harness/milestone.go b/scm/driver/harness/milestone.go new file mode 100644 index 000000000..34784287a --- /dev/null +++ b/scm/driver/harness/milestone.go @@ -0,0 +1,90 @@ +package harness + +import ( + "context" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/internal/null" +) + +type milestoneService struct { + client *wrapper +} + +func (s *milestoneService) Find(ctx context.Context, repo string, id int) (*scm.Milestone, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported + +} + +func (s *milestoneService) List(ctx context.Context, repo string, opts scm.MilestoneListOptions) ([]*scm.Milestone, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported + +} + +func (s *milestoneService) Create(ctx context.Context, repo string, input *scm.MilestoneInput) (*scm.Milestone, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported + +} + +func (s *milestoneService) Delete(ctx context.Context, repo string, id int) (*scm.Response, error) { + return nil, scm.ErrNotSupported + +} + +func (s *milestoneService) Update(ctx context.Context, repo string, id int, input *scm.MilestoneInput) (*scm.Milestone, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +// stateType issue state type +type stateType string + +const ( + // stateOpen pr/issue is open + stateOpen stateType = "open" + // stateClosed pr/issue is closed + stateClosed stateType = "closed" + // stateAll is all + stateAll stateType = "all" +) + +type milestone struct { + ID int64 `json:"id"` + Title string `json:"title"` + Description string `json:"description"` + State stateType `json:"state"` + OpenIssues int `json:"open_issues"` + ClosedIssues int `json:"closed_issues"` + Created null.Time `json:"created_at"` + Updated null.Time `json:"updated_at"` + Closed null.Time `json:"closed_at"` + Deadline null.Time `json:"due_on"` +} + +type milestoneInput struct { + Title string `json:"title"` + Description string `json:"description"` + State stateType `json:"state"` + Deadline null.Time `json:"due_on"` +} + +func convertMilestoneList(src []*milestone) []*scm.Milestone { + var dst []*scm.Milestone + for _, v := range src { + dst = append(dst, convertMilestone(v)) + } + return dst +} + +func convertMilestone(src *milestone) *scm.Milestone { + if src == nil || src.Deadline.IsZero() { + return nil + } + return &scm.Milestone{ + Number: int(src.ID), + ID: int(src.ID), + Title: src.Title, + Description: src.Description, + State: string(src.State), + DueDate: src.Deadline.ValueOrZero(), + } +} diff --git a/scm/driver/harness/milestone_test.go b/scm/driver/harness/milestone_test.go new file mode 100644 index 000000000..1815bffed --- /dev/null +++ b/scm/driver/harness/milestone_test.go @@ -0,0 +1 @@ +package harness diff --git a/scm/driver/harness/org.go b/scm/driver/harness/org.go new file mode 100644 index 000000000..718aa77dd --- /dev/null +++ b/scm/driver/harness/org.go @@ -0,0 +1,61 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "context" + + "github.com/drone/go-scm/scm" +) + +type organizationService struct { + client *wrapper +} + +func (s *organizationService) Find(ctx context.Context, name string) (*scm.Organization, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported + +} + +func (s *organizationService) FindMembership(ctx context.Context, name, username string) (*scm.Membership, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *organizationService) List(ctx context.Context, opts scm.ListOptions) ([]*scm.Organization, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported + +} + +func (s *organizationService) ListMemberships(ctx context.Context, orgNameList []string, username string, opts scm.ListOptions) ([]*scm.Membership, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +// +// native data structures +// + +type org struct { + Name string `json:"username"` + Avatar string `json:"avatar_url"` +} + +// +// native data structure conversion +// + +func convertOrgList(from []*org) []*scm.Organization { + to := []*scm.Organization{} + for _, v := range from { + to = append(to, convertOrg(v)) + } + return to +} + +func convertOrg(from *org) *scm.Organization { + return &scm.Organization{ + Name: from.Name, + Avatar: from.Avatar, + } +} diff --git a/scm/driver/harness/org_test.go b/scm/driver/harness/org_test.go new file mode 100644 index 000000000..5d232e2ff --- /dev/null +++ b/scm/driver/harness/org_test.go @@ -0,0 +1,5 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness diff --git a/scm/driver/harness/pr.go b/scm/driver/harness/pr.go new file mode 100644 index 000000000..167ba9bf7 --- /dev/null +++ b/scm/driver/harness/pr.go @@ -0,0 +1,341 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "context" + "fmt" + "github.com/drone/go-scm/scm/driver/internal/null" + "strconv" + "strings" + "time" + + "github.com/drone/go-scm/scm" +) + +type pullService struct { + client *wrapper +} + +func (s *pullService) Find(ctx context.Context, repo string, index int) (*scm.PullRequest, *scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoId, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/pullreq/%d?%s", repoId, index, queryParams) + out := new(pr) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertPullRequest(out), res, err + +} + +func (s *pullService) FindComment(context.Context, string, int, int) (*scm.Comment, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *pullService) List(ctx context.Context, repo string, opts scm.PullRequestListOptions) ([]*scm.PullRequest, *scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoId, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/pullreq?%s&%s", repoId, encodePullRequestListOptions(opts), queryParams) + out := []*pr{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertPullRequestList(out), res, err +} + +func (s *pullService) ListComments(context.Context, string, int, scm.ListOptions) ([]*scm.Comment, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *pullService) ListCommits(ctx context.Context, repo string, index int, opts scm.ListOptions) ([]*scm.Commit, *scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoId, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/pullreq/%d/commits?%s&%s", repoId, index, encodeListOptions(opts), queryParams) + out := []*commit{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertCommits(out), res, err +} + +func (s *pullService) ListChanges(ctx context.Context, repo string, number int, _ scm.ListOptions) ([]*scm.Change, *scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoId, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/pullreq/%d/diff?%s", repoId, number, queryParams) + out := []*fileDiff{} + res, err := s.client.do(ctx, "POST", path, nil, &out) + return convertFileDiffs(out), res, err +} + +func (s *pullService) Create(ctx context.Context, repo string, input *scm.PullRequestInput) (*scm.PullRequest, *scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoId, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/pullreq?%s", repoId, queryParams) + in := &prInput{ + Title: input.Title, + Description: input.Body, + SourceBranch: input.Source, + TargetBranch: input.Target, + } + out := new(pr) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertPullRequest(out), res, err +} + +func (s *pullService) CreateComment(ctx context.Context, repo string, prNumber int, input *scm.CommentInput) (*scm.Comment, *scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoId, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/pullreq/%d/comments?%s", repoId, prNumber, queryParams) + in := &prComment{ + Text: input.Body, + } + out := new(prCommentResponse) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertComment(out), res, err +} + +func (s *pullService) DeleteComment(context.Context, string, int, int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + +func (s *pullService) Merge(ctx context.Context, repo string, index int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + +func (s *pullService) Close(context.Context, string, int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + +// native data structures +type ( + pr struct { + Author principal `json:"author"` + Created int64 `json:"created"` + Description string `json:"description"` + Edited int64 `json:"edited"` + IsDraft bool `json:"is_draft"` + + MergeTargetSHA null.String `json:"merge_target_sha"` + MergeBaseSha string `json:"merge_base_sha"` + Merged null.Int `json:"merged"` + MergeMethod null.String `json:"merge_method"` + MergeSHA null.String `json:"merge_sha"` + MergeCheckStatus string `json:"merge_check_status"` + MergeConflicts []string `json:"merge_conflicts,omitempty"` + Merger *principal `json:"merger"` + + Number int64 `json:"number"` + + SourceBranch string `json:"source_branch"` + SourceRepoID int64 `json:"source_repo_id"` + SourceSHA string `json:"source_sha"` + TargetBranch string `json:"target_branch"` + TargetRepoID int64 `json:"target_repo_id"` + + State string `json:"state"` + Stats struct { + Commits null.Int `json:"commits,omitempty"` + Conversations int `json:"conversations,omitempty"` + FilesChanged null.Int `json:"files_changed,omitempty"` + UnresolvedCount int `json:"unresolved_count,omitempty"` + } `json:"stats"` + + Title string `json:"title"` + } + + reference struct { + Repo repository `json:"repo"` + Name string `json:"ref"` + Sha string `json:"sha"` + } + + prInput struct { + Description string `json:"description"` + IsDraft bool `json:"is_draft"` + SourceBranch string `json:"source_branch"` + SourceRepoRef string `json:"source_repo_ref"` + TargetBranch string `json:"target_branch"` + Title string `json:"title"` + } + + commit struct { + Author struct { + Identity struct { + Email string `json:"email"` + Name string `json:"name"` + } `json:"identity"` + When time.Time `json:"when"` + } `json:"author"` + Committer struct { + Identity struct { + Email string `json:"email"` + Name string `json:"name"` + } `json:"identity"` + When time.Time `json:"when"` + } `json:"committer"` + Message string `json:"message"` + Sha string `json:"sha"` + Title string `json:"title"` + } + prComment struct { + LineEnd int `json:"line_end"` + LineEndNew bool `json:"line_end_new"` + LineStart int `json:"line_start"` + LineStartNew bool `json:"line_start_new"` + ParentID int `json:"parent_id"` + Path string `json:"path"` + SourceCommitSha string `json:"source_commit_sha"` + TargetCommitSha string `json:"target_commit_sha"` + Text string `json:"text"` + } + prCommentResponse struct { + Id int `json:"id"` + Created int64 `json:"created"` + Updated int64 `json:"updated"` + Edited int64 `json:"edited"` + ParentId interface{} `json:"parent_id"` + RepoId int `json:"repo_id"` + PullreqId int `json:"pullreq_id"` + Order int `json:"order"` + SubOrder int `json:"sub_order"` + Type string `json:"type"` + Kind string `json:"kind"` + Text string `json:"text"` + Payload struct{} `json:"payload"` + Metadata interface{} `json:"metadata"` + Author struct { + Id int `json:"id"` + Uid string `json:"uid"` + DisplayName string `json:"display_name"` + Email string `json:"email"` + Type string `json:"type"` + Created int64 `json:"created"` + Updated int64 `json:"updated"` + } `json:"author"` + } +) + +// native data structure conversion +func convertPullRequests(src []*pr) []*scm.PullRequest { + dst := []*scm.PullRequest{} + for _, v := range src { + dst = append(dst, convertPullRequest(v)) + } + return dst +} + +func convertPullRequest(src *pr) *scm.PullRequest { + return &scm.PullRequest{ + Number: int(src.Number), + Title: src.Title, + Body: src.Description, + Sha: src.SourceSHA, + Source: src.SourceBranch, + Target: src.TargetBranch, + Merged: src.Merged.Valid, + Author: scm.User{ + Login: src.Author.Email, + Name: src.Author.DisplayName, + ID: src.Author.UID, + Email: src.Author.Email, + }, + Head: scm.Reference{ + Name: src.SourceBranch, + Path: scm.ExpandRef(src.SourceBranch, "refs/heads"), + Sha: src.SourceSHA, + }, + Base: scm.Reference{ + Name: src.TargetBranch, + Path: scm.ExpandRef(src.TargetBranch, "refs/heads"), + Sha: src.MergeTargetSHA.String, + }, + Fork: "fork", + Ref: fmt.Sprintf("refs/pullreq/%d/head", src.Number), + Closed: src.State == "closed", + Created: time.UnixMilli(src.Created), + Updated: time.UnixMilli(src.Edited), + } +} + +func convertCommits(src []*commit) []*scm.Commit { + dst := []*scm.Commit{} + for _, v := range src { + dst = append(dst, convertCommit(v)) + } + return dst +} + +func convertCommit(src *commit) *scm.Commit { + return &scm.Commit{ + Message: src.Message, + Sha: src.Sha, + Author: scm.Signature{ + Name: src.Author.Identity.Name, + Email: src.Author.Identity.Email, + }, + Committer: scm.Signature{ + Name: src.Committer.Identity.Name, + Email: src.Committer.Identity.Email, + }, + } +} + +func convertFileDiffs(diff []*fileDiff) []*scm.Change { + var dst []*scm.Change + for _, v := range diff { + dst = append(dst, convertFileDiff(v)) + } + return dst +} + +func convertFileDiff(diff *fileDiff) *scm.Change { + return &scm.Change{ + Path: diff.Path, + Added: strings.EqualFold(diff.Status, "ADDED"), + Renamed: strings.EqualFold(diff.Status, "RENAMED"), + Deleted: strings.EqualFold(diff.Status, "DELETED"), + Sha: diff.SHA, + BlobID: "", + PrevFilePath: diff.OldPath, + } +} + +func convertPullRequestList(from []*pr) []*scm.PullRequest { + to := []*scm.PullRequest{} + for _, v := range from { + to = append(to, convertPullRequest(v)) + } + return to +} + +func convertComment(comment *prCommentResponse) *scm.Comment { + return &scm.Comment{ + ID: comment.Id, + Body: comment.Text, + Author: scm.User{ + Login: comment.Author.Uid, + Name: comment.Author.DisplayName, + ID: strconv.Itoa(comment.Author.Id), + Email: comment.Author.Email, + Created: time.UnixMilli(comment.Author.Created), + Updated: time.UnixMilli(comment.Author.Updated), + }, + Created: time.UnixMilli(comment.Created), + Updated: time.UnixMilli(comment.Updated), + } +} diff --git a/scm/driver/harness/pr_test.go b/scm/driver/harness/pr_test.go new file mode 100644 index 000000000..fa26ebb4c --- /dev/null +++ b/scm/driver/harness/pr_test.go @@ -0,0 +1,193 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "testing" + + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/transport" + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestPRFind(t *testing.T) { + if harnessPAT == "" { + defer gock.Off() + + gock.New(gockOrigin). + Get("/gateway/code/api/v1/repos/thomas/pullreq/1"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("plain/text"). + File("testdata/pr.json") + } + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + got, _, err := client.PullRequests.Find(context.Background(), harnessRepo, 1) + if err != nil { + t.Error(err) + } + + want := new(scm.PullRequest) + raw, err := ioutil.ReadFile("testdata/pr.json.golden") + if err != nil { + t.Error(err) + } + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + } + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestPRCommits(t *testing.T) { + if harnessPAT == "" { + defer gock.Off() + + gock.New(gockOrigin). + Get("/gateway/code/api/v1/repos/thomas/pullreq/1/commits"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("plain/text"). + File("testdata/pr_commits.json") + } + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + got, _, err := client.PullRequests.ListCommits(context.Background(), harnessRepo, 1, scm.ListOptions{}) + if err != nil { + t.Error(err) + } + + want := []*scm.Commit{} + raw, err := ioutil.ReadFile("testdata/pr_commits.json.golden") + if err != nil { + t.Error(err) + } + err = json.Unmarshal(raw, &want) + if err != nil { + t.Error(err) + } + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestPullCreate(t *testing.T) { + defer gock.Off() + gock.New(gockOrigin). + Post("/gateway/code/api/v1/repos/thomas/pullreq"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("plain/text"). + File("testdata/pr.json") + + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + + input := scm.PullRequestInput{ + Title: "pull title", + Body: "pull description", + Source: "bla", + Target: "main", + } + + got, _, err := client.PullRequests.Create(context.Background(), harnessRepo, &input) + if err != nil { + t.Error(err) + return + } + + want := new(scm.PullRequest) + raw, _ := ioutil.ReadFile("testdata/pr.json.golden") + _ = json.Unmarshal(raw, want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestPRComment(t *testing.T) { + defer gock.Off() + gock.New(gockOrigin). + Post(fmt.Sprintf("/gateway/code/api/v1/repos/%s/pullreq/1/comments", harnessRepo)). + MatchParam("accountIdentifier", harnessAccount). + MatchParam("orgIdentifier", harnessOrg). + MatchParam("projectIdentifier", harnessProject). + Reply(201). + Type("plain/text"). + File("testdata/comment.json") + + client, _ := New(gockOrigin, harnessAccount, harnessOrg, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + + input := scm.CommentInput{ + Body: "Comment to be created in the PR", + } + + got, _, err := client.PullRequests.CreateComment(context.Background(), harnessRepo, 1, &input) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Comment) + raw, _ := ioutil.ReadFile("testdata/comment.json.golden") + _ = json.Unmarshal(raw, want) + + if diff := cmp.Diff(got, want, + cmpopts.IgnoreFields(scm.Comment{}, "Created", "Updated"), + cmpopts.IgnoreFields(scm.User{}, "Created", "Updated")); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} diff --git a/scm/driver/harness/release.go b/scm/driver/harness/release.go new file mode 100644 index 000000000..66d62cdb3 --- /dev/null +++ b/scm/driver/harness/release.go @@ -0,0 +1,112 @@ +package harness + +import ( + "context" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/internal/null" +) + +type releaseService struct { + client *wrapper +} + +func (s *releaseService) Find(ctx context.Context, repo string, id int) (*scm.Release, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *releaseService) FindByTag(ctx context.Context, repo string, tag string) (*scm.Release, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *releaseService) List(ctx context.Context, repo string, opts scm.ReleaseListOptions) ([]*scm.Release, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *releaseService) Create(ctx context.Context, repo string, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *releaseService) Delete(ctx context.Context, repo string, id int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + +func (s *releaseService) DeleteByTag(ctx context.Context, repo string, tag string) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + +func (s *releaseService) Update(ctx context.Context, repo string, id int, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *releaseService) UpdateByTag(ctx context.Context, repo string, tag string, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +type ReleaseInput struct { + TagName string `json:"tag_name"` + Target string `json:"target_commitish"` + Title string `json:"name"` + Note string `json:"body"` + IsDraft bool `json:"draft"` + IsPrerelease bool `json:"prerelease"` +} + +// release represents a repository release +type release struct { + ID int64 `json:"id"` + TagName string `json:"tag_name"` + Target string `json:"target_commitish"` + Title string `json:"name"` + Note string `json:"body"` + URL string `json:"url"` + HTMLURL string `json:"html_url"` + TarURL string `json:"tarball_url"` + ZipURL string `json:"zipball_url"` + IsDraft bool `json:"draft"` + IsPrerelease bool `json:"prerelease"` + CreatedAt null.Time `json:"created_at"` + PublishedAt null.Time `json:"published_at"` + Publisher *string `json:"author"` + Attachments []*Attachment `json:"assets"` +} + +type Attachment struct { + ID int64 `json:"id"` + Name string `json:"name"` + Size int64 `json:"size"` + DownloadCount int64 `json:"download_count"` + Created null.Time `json:"created_at"` + UUID string `json:"uuid"` + DownloadURL string `json:"browser_download_url"` +} + +func convertRelease(src *release) *scm.Release { + return &scm.Release{ + ID: int(src.ID), + Title: src.Title, + Description: src.Note, + Link: convertAPIURLToHTMLURL(src.URL, src.TagName), + Tag: src.TagName, + Commitish: src.Target, + Draft: src.IsDraft, + Prerelease: src.IsPrerelease, + Created: src.CreatedAt.ValueOrZero(), + Published: src.PublishedAt.ValueOrZero(), + } +} + +func convertReleaseList(src []*release) []*scm.Release { + var dst []*scm.Release + for _, v := range src { + dst = append(dst, convertRelease(v)) + } + return dst +} + +func releaseListOptionsToGiteaListOptions(in scm.ReleaseListOptions) ListOptions { + return ListOptions{ + Page: in.Page, + PageSize: in.Size, + } +} diff --git a/scm/driver/harness/release_test.go b/scm/driver/harness/release_test.go new file mode 100644 index 000000000..1815bffed --- /dev/null +++ b/scm/driver/harness/release_test.go @@ -0,0 +1 @@ +package harness diff --git a/scm/driver/harness/repo.go b/scm/driver/harness/repo.go new file mode 100644 index 000000000..2ef3ceca6 --- /dev/null +++ b/scm/driver/harness/repo.go @@ -0,0 +1,225 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "context" + "errors" + "fmt" + "strconv" + + "github.com/drone/go-scm/scm" +) + +type repositoryService struct { + client *wrapper +} + +func (s *repositoryService) Find(ctx context.Context, repo string) (*scm.Repository, *scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoId, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("api/v1/repos/%s?%s", repoId, queryParams) + out := new(repository) + res, err := s.client.do(ctx, "GET", path, nil, out) + if err != nil { + return nil, res, err + } + convertedRepo := convertRepository(out) + if convertedRepo == nil { + return nil, res, errors.New("Harness returned an unexpected null repository") + } + return convertedRepo, res, err +} + +func (s *repositoryService) FindHook(ctx context.Context, repo string, id string) (*scm.Hook, *scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoId, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/webhooks/%s?%s", repoId, id, queryParams) + out := new(hook) + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertHook(out), res, err +} + +func (s *repositoryService) FindPerms(ctx context.Context, repo string) (*scm.Perm, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *repositoryService) List(ctx context.Context, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { + queryParams := fmt.Sprintf("%s=%s&%s=%s&%s=%s&%s=%s", + projectIdentifier, s.client.project, orgIdentifier, s.client.organization, accountIdentifier, s.client.account, + routingId, s.client.account) + + path := fmt.Sprintf("api/v1/repos?sort=path&order=asc&%s&%s", encodeListOptions(opts), queryParams) + out := []*repository{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertRepositoryList(out), res, err +} + +func (s *repositoryService) ListV2(ctx context.Context, opts scm.RepoListOptions) ([]*scm.Repository, *scm.Response, error) { + // harness does not support search filters, hence calling List api without search filtering + return s.List(ctx, opts.ListOptions) +} + +func (s *repositoryService) ListNamespace(ctx context.Context, _ string, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { + // Client already has context about namespace + return s.List(ctx, opts) +} + +func (s *repositoryService) ListHooks(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Hook, *scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoId, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/webhooks?sort=display_name&order=asc&%s&%s", repoId, encodeListOptions(opts), queryParams) + out := []*hook{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertHookList(out), res, err +} + +func (s *repositoryService) ListStatus(ctx context.Context, repo string, ref string, opts scm.ListOptions) ([]*scm.Status, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *repositoryService) CreateHook(ctx context.Context, repo string, input *scm.HookInput) (*scm.Hook, *scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoId, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/webhooks?%s", repoId, queryParams) + in := new(hook) + in.Enabled = true + in.Identifier = input.Name + in.Secret = input.Secret + in.Insecure = input.SkipVerify + in.URL = input.Target + in.Triggers = input.NativeEvents + out := new(hook) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertHook(out), res, err +} + +func (s *repositoryService) List2(ctx context.Context, orgSlug string, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} +func (s *repositoryService) ListRepoLanguages(context.Context, string) (map[string]float64, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *repositoryService) CreateStatus(ctx context.Context, repo string, ref string, input *scm.StatusInput) (*scm.Status, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *repositoryService) UpdateHook(ctx context.Context, repo, id string, input *scm.HookInput) (*scm.Hook, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *repositoryService) DeleteHook(ctx context.Context, repo string, id string) (*scm.Response, error) { + harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo) + repoId, queryParams, err := getRepoAndQueryParams(harnessURI) + if err != nil { + return nil, err + } + path := fmt.Sprintf("api/v1/repos/%s/webhooks/%s?%s", repoId, id, queryParams) + return s.client.do(ctx, "DELETE", path, nil, nil) +} + +// +// native data structures +// + +type ( + // harness repository resource. + repository struct { + ID int `json:"id"` + ParentID int `json:"parent_id"` + UID string `json:"uid"` + Path string `json:"path"` + Description string `json:"description"` + IsPublic bool `json:"is_public"` + CreatedBy int `json:"created_by"` + Created int64 `json:"created"` + Updated int64 `json:"updated"` + DefaultBranch string `json:"default_branch"` + ForkID int `json:"fork_id"` + NumForks int `json:"num_forks"` + NumPulls int `json:"num_pulls"` + NumClosedPulls int `json:"num_closed_pulls"` + NumOpenPulls int `json:"num_open_pulls"` + NumMergedPulls int `json:"num_merged_pulls"` + GitURL string `json:"git_url"` + } + hook struct { + Created int `json:"created"` + CreatedBy int `json:"created_by"` + Description string `json:"description"` + Enabled bool `json:"enabled"` + HasSecret bool `json:"has_secret"` + Secret string `json:"secret"` + Identifier string `json:"identifier"` + Insecure bool `json:"insecure"` + LatestExecutionResult string `json:"latest_execution_result"` + ParentID int `json:"parent_id"` + ParentType string `json:"parent_type"` + Triggers []string `json:"triggers"` + Updated int `json:"updated"` + URL string `json:"url"` + Version int `json:"version"` + } +) + +// +// native data structure conversion +// + +func convertRepositoryList(src []*repository) []*scm.Repository { + var dst []*scm.Repository + for _, v := range src { + dst = append(dst, convertRepository(v)) + } + return dst +} + +func convertRepository(src *repository) *scm.Repository { + return &scm.Repository{ + ID: strconv.Itoa(src.ID), + Namespace: src.Path, + Name: src.UID, + Branch: src.DefaultBranch, + Private: !src.IsPublic, + Clone: src.GitURL, + CloneSSH: src.GitURL, + Link: src.GitURL, + // Created: time.Unix(src.Created, 0), + // Updated: time.Unix(src.Updated, 0), + } +} + +func convertHookList(from []*hook) []*scm.Hook { + to := []*scm.Hook{} + for _, v := range from { + to = append(to, convertHook(v)) + } + return to +} + +func convertHook(from *hook) *scm.Hook { + return &scm.Hook{ + // keeping id same as name + ID: from.Identifier, + Name: from.Identifier, + Active: from.Enabled, + Target: from.URL, + Events: from.Triggers, + SkipVerify: from.Insecure, + } +} diff --git a/scm/driver/harness/repo_test.go b/scm/driver/harness/repo_test.go new file mode 100644 index 000000000..1fc861084 --- /dev/null +++ b/scm/driver/harness/repo_test.go @@ -0,0 +1,254 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "testing" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/transport" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/h2non/gock" +) + +func TestRepositoryFind(t *testing.T) { + if harnessPAT == "" { + defer gock.Off() + + gock.New(gockOrigin). + Get("/gateway/code/api/v1/repos/demo"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("application/json"). + File("testdata/repo.json") + } + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + got, _, err := client.Repositories.Find(context.Background(), "demo") + if err != nil { + t.Error(err) + return + } + + want := new(scm.Repository) + raw, _ := ioutil.ReadFile("testdata/repo.json.golden") + _ = json.Unmarshal(raw, want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestRepositoryList(t *testing.T) { + if harnessPAT == "" { + defer gock.Off() + + gock.New(gockOrigin). + Get("/gateway/code/api/v1/repos"). + MatchParam("page", "1"). + MatchParam("limit", "20"). + MatchParam("sort", "path"). + MatchParam("order", "asc"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("application/json"). + File("testdata/repos.json") + } + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + got, _, err := client.Repositories.List(context.Background(), scm.ListOptions{Page: 1, Size: 20}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Repository{} + raw, _ := ioutil.ReadFile("testdata/repos.json.golden") + _ = json.Unmarshal(raw, &want) + + if harnessPAT != "" && len(got) > 0 { + // pass when running against a live harness instance and we get more than one repo + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestRepositoryHookList(t *testing.T) { + if harnessPAT == "" { + defer gock.Off() + + gock.New(gockOrigin). + Get("/gateway/code/api/v1/repos/thomas/webhooks"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("page", "1"). + MatchParam("limit", "30"). + MatchParam("sort", "display_name"). + MatchParam("order", "asc"). + Reply(200). + Type("application/json"). + File("testdata/hooks.json") + } + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + got, _, err := client.Repositories.ListHooks(context.Background(), harnessRepo, scm.ListOptions{Page: 1, Size: 30}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Hook{} + raw, _ := ioutil.ReadFile("testdata/hooks.json.golden") + _ = json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestRepositoryFindHook(t *testing.T) { + if harnessPAT == "" { + defer gock.Off() + + gock.New(gockOrigin). + Get("/gateway/code/api/v1/repos/thomas/webhooks/6"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("application/json"). + File("testdata/hook.json") + } + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + got, _, err := client.Repositories.FindHook(context.Background(), harnessRepo, "6") + if err != nil { + t.Error(err) + return + } + + want := new(scm.Hook) + raw, _ := ioutil.ReadFile("testdata/hook.json.golden") + _ = json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestRepositoryHookCreateDelete(t *testing.T) { + if harnessPAT == "" { + defer gock.Off() + + gock.New(gockOrigin). + Post("/gateway/code/api/v1/repos/thomas/webhooks"). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(200). + Type("application/json"). + File("testdata/hook_create.json") + } + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + in := &scm.HookInput{ + Name: "drone", + Target: "https://example.com", + Secret: "topsecret", + SkipVerify: true, + } + got, _, err := client.Repositories.CreateHook(context.Background(), harnessRepo, in) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Hook) + raw, _ := ioutil.ReadFile("testdata/hook_create.json.golden") + _ = json.Unmarshal(raw, want) + + if diff := cmp.Diff(got, want, cmpopts.IgnoreFields(scm.Hook{}, "ID")); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + // delete webhook + if harnessPAT == "" { + defer gock.Off() + + gock.New(gockOrigin). + Delete(fmt.Sprintf("/gateway/code/api/v1/repos/thomas/webhooks/%s", got.ID)). + MatchParam("accountIdentifier", "px7xd_BFRCi-pfWPYXVjvw"). + MatchParam("orgIdentifier", "default"). + MatchParam("projectIdentifier", "codeciintegration"). + MatchParam("routingId", "px7xd_BFRCi-pfWPYXVjvw"). + Reply(204) + } + client, _ = New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + + _, deleteErr := client.Repositories.DeleteHook(context.Background(), harnessRepo, got.ID) + if deleteErr != nil { + t.Error(deleteErr) + return + } +} diff --git a/scm/driver/harness/review.go b/scm/driver/harness/review.go new file mode 100644 index 000000000..898595bd4 --- /dev/null +++ b/scm/driver/harness/review.go @@ -0,0 +1,31 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "context" + + "github.com/drone/go-scm/scm" +) + +type reviewService struct { + client *wrapper +} + +func (s *reviewService) Find(ctx context.Context, repo string, number, id int) (*scm.Review, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *reviewService) List(ctx context.Context, repo string, number int, opts scm.ListOptions) ([]*scm.Review, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *reviewService) Create(ctx context.Context, repo string, number int, input *scm.ReviewInput) (*scm.Review, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *reviewService) Delete(ctx context.Context, repo string, number, id int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} diff --git a/scm/driver/harness/review_test.go b/scm/driver/harness/review_test.go new file mode 100644 index 000000000..5d232e2ff --- /dev/null +++ b/scm/driver/harness/review_test.go @@ -0,0 +1,5 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness diff --git a/scm/driver/harness/testdata/branch.json b/scm/driver/harness/testdata/branch.json new file mode 100644 index 000000000..79159c0fc --- /dev/null +++ b/scm/driver/harness/testdata/branch.json @@ -0,0 +1,23 @@ +{ + "name": "main", + "sha": "1d640265d8bdd818175fa736f0fcbad2c9b716c9", + "commit": { + "sha": "1d640265d8bdd818175fa736f0fcbad2c9b716c9", + "title": "delete README.2", + "message": "delete README.2\n\ndelete README.2", + "author": { + "identity": { + "name": "thomas.honey", + "email": "thomas.honey@harness.io" + }, + "when": "2023-02-08T16:17:50Z" + }, + "committer": { + "identity": { + "name": "Harness", + "email": "noreply@harness.io" + }, + "when": "2023-02-08T16:17:50Z" + } + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/branch.json.golden b/scm/driver/harness/testdata/branch.json.golden new file mode 100644 index 000000000..0b5426713 --- /dev/null +++ b/scm/driver/harness/testdata/branch.json.golden @@ -0,0 +1,5 @@ +{ + "Name": "main", + "Path": "refs/heads/main", + "Sha": "1d640265d8bdd818175fa736f0fcbad2c9b716c9" +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/branches.json b/scm/driver/harness/testdata/branches.json new file mode 100644 index 000000000..2490e4ae3 --- /dev/null +++ b/scm/driver/harness/testdata/branches.json @@ -0,0 +1,71 @@ +[ + { + "name": "bla", + "sha": "0c221fd126b9457d0ad2037641416083549f59c5", + "commit": { + "sha": "0c221fd126b9457d0ad2037641416083549f59c5", + "title": "Create bla_file", + "message": "Create bla_file", + "author": { + "identity": { + "name": "thomas.honey", + "email": "thomas.honey@harness.io" + }, + "when": "2023-02-09T11:20:14Z" + }, + "committer": { + "identity": { + "name": "Harness", + "email": "noreply@harness.io" + }, + "when": "2023-02-09T11:20:14Z" + } + } + }, + { + "name": "branch3", + "sha": "59e1cdf0e421fd14b106f4861fb02dfd56b4dc34", + "commit": { + "sha": "59e1cdf0e421fd14b106f4861fb02dfd56b4dc34", + "title": "delete README.2", + "message": "delete README.2\n\ndelete README.2", + "author": { + "identity": { + "name": "thomas.honey", + "email": "thomas.honey@harness.io" + }, + "when": "2023-02-09T12:39:37Z" + }, + "committer": { + "identity": { + "name": "Harness", + "email": "noreply@harness.io" + }, + "when": "2023-02-09T12:39:37Z" + } + } + }, + { + "name": "main", + "sha": "de2837f8911710cfb7bbb323d0de285fd2ef9155", + "commit": { + "sha": "de2837f8911710cfb7bbb323d0de285fd2ef9155", + "title": "delete README.2", + "message": "delete README.2\n\ndelete README.2", + "author": { + "identity": { + "name": "thomas.honey", + "email": "thomas.honey@harness.io" + }, + "when": "2023-02-09T12:39:37Z" + }, + "committer": { + "identity": { + "name": "Harness", + "email": "noreply@harness.io" + }, + "when": "2023-02-09T12:39:37Z" + } + } + } +] \ No newline at end of file diff --git a/scm/driver/harness/testdata/branches.json.golden b/scm/driver/harness/testdata/branches.json.golden new file mode 100644 index 000000000..3f2458b08 --- /dev/null +++ b/scm/driver/harness/testdata/branches.json.golden @@ -0,0 +1,17 @@ +[ + { + "Name": "bla", + "Path": "refs/heads/bla", + "Sha": "0c221fd126b9457d0ad2037641416083549f59c5" + }, + { + "Name": "branch3", + "Path": "refs/heads/branch3", + "Sha": "59e1cdf0e421fd14b106f4861fb02dfd56b4dc34" + }, + { + "Name": "main", + "Path": "refs/heads/main", + "Sha": "1d640265d8bdd818175fa736f0fcbad2c9b716c9" + } +] \ No newline at end of file diff --git a/scm/driver/harness/testdata/comment.json b/scm/driver/harness/testdata/comment.json new file mode 100644 index 000000000..fa1a823f5 --- /dev/null +++ b/scm/driver/harness/testdata/comment.json @@ -0,0 +1,25 @@ +{ + "id": 123, + "created": 1708354973112, + "updated": 1708354973112, + "edited": 1708354973112, + "parent_id": null, + "repo_id": 123, + "pullreq_id": 123, + "order": 1, + "sub_order": 0, + "type": "comment", + "kind": "comment", + "text": "Comment to be created in the PR", + "payload": {}, + "metadata": null, + "author": { + "id": 1, + "uid": "identifier", + "display_name": "displayName", + "email": "email@emailprovider.com", + "type": "service", + "created": 1695706039266, + "updated": 1695706039266 + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/comment.json.golden b/scm/driver/harness/testdata/comment.json.golden new file mode 100644 index 000000000..f2e347a95 --- /dev/null +++ b/scm/driver/harness/testdata/comment.json.golden @@ -0,0 +1,15 @@ +{ + "ID": 123, + "Body": "Comment to be created in the PR", + "Author": { + "ID": "1", + "Login": "identifier", + "Name": "displayName", + "Email": "email@emailprovider.com", + "Avatar": "", + "Created": 1695706039266, + "Updated": 1695706039266 + }, + "Created": 1708354973112, + "Updated": 1708354973112 +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/commit.json b/scm/driver/harness/testdata/commit.json new file mode 100644 index 000000000..38a6066ad --- /dev/null +++ b/scm/driver/harness/testdata/commit.json @@ -0,0 +1,19 @@ +{ + "sha": "1d640265d8bdd818175fa736f0fcbad2c9b716c9", + "title": "delete README.2", + "message": "delete README.2\n\ndelete README.2", + "author": { + "identity": { + "name": "thomas.honey", + "email": "thomas.honey@harness.io" + }, + "when": "2023-02-08T16:17:50Z" + }, + "committer": { + "identity": { + "name": "Harness", + "email": "noreply@harness.io" + }, + "when": "2023-02-08T16:17:50Z" + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/commit.json.golden b/scm/driver/harness/testdata/commit.json.golden new file mode 100644 index 000000000..01d7f0f40 --- /dev/null +++ b/scm/driver/harness/testdata/commit.json.golden @@ -0,0 +1,19 @@ +{ + "Sha": "1d640265d8bdd818175fa736f0fcbad2c9b716c9", + "Message": "delete README.2\n\ndelete README.2", + "Author": { + "Name": "thomas.honey", + "Email": "thomas.honey@harness.io", + "Date": "2023-02-08T16:17:50Z", + "Login": "", + "Avatar": "" + }, + "Committer": { + "Name": "Harness", + "Email": "noreply@harness.io", + "Date": "2023-02-08T16:17:50Z", + "Login": "", + "Avatar": "" + }, + "Link": "" +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/commits.json b/scm/driver/harness/testdata/commits.json new file mode 100644 index 000000000..4045985d6 --- /dev/null +++ b/scm/driver/harness/testdata/commits.json @@ -0,0 +1,23 @@ +{ + "commits": [ + { + "sha": "1d640265d8bdd818175fa736f0fcbad2c9b716c9", + "title": "delete README.2", + "message": "delete README.2\n\ndelete README.2", + "author": { + "identity": { + "name": "thomas.honey", + "email": "thomas.honey@harness.io" + }, + "when": "2023-02-08T16:17:50Z" + }, + "committer": { + "identity": { + "name": "Harness", + "email": "noreply@harness.io" + }, + "when": "2023-02-08T16:17:50Z" + } + } + ] +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/commits.json.golden b/scm/driver/harness/testdata/commits.json.golden new file mode 100644 index 000000000..83570e704 --- /dev/null +++ b/scm/driver/harness/testdata/commits.json.golden @@ -0,0 +1,21 @@ +[ + { + "Sha": "1d640265d8bdd818175fa736f0fcbad2c9b716c9", + "Message": "delete README.2\n\ndelete README.2", + "Author": { + "Name": "thomas.honey", + "Email": "thomas.honey@harness.io", + "Date": "2023-02-08T16:17:50Z", + "Login": "", + "Avatar": "" + }, + "Committer": { + "Name": "Harness", + "Email": "noreply@harness.io", + "Date": "2023-02-08T16:17:50Z", + "Login": "", + "Avatar": "" + }, + "Link": "" + } +] \ No newline at end of file diff --git a/scm/driver/harness/testdata/content.json b/scm/driver/harness/testdata/content.json new file mode 100644 index 000000000..fbcda4f5f --- /dev/null +++ b/scm/driver/harness/testdata/content.json @@ -0,0 +1,30 @@ +{ + "type": "file", + "sha": "7839122fc2ec4af9d5a6c14c779a82a05c5769b5", + "name": "README.md", + "path": "README.md", + "latest_commit": { + "sha": "98189d5cf2a751a6246c24a72945ba70839f1b20", + "title": "initial commit", + "message": "initial commit", + "author": { + "identity": { + "name": "gitness", + "email": "system@gitness" + }, + "when": "2023-02-02T14:12:13Z" + }, + "committer": { + "identity": { + "name": "gitness", + "email": "system@gitness" + }, + "when": "2023-02-02T14:12:13Z" + } + }, + "content": { + "encoding": "base64", + "data": "IyB0aG9tYXMKUGxheWdyb3VuZCBwcm9qZWN0IGZvciBUaG9tYXM=", + "size": 38 + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/content_list.json b/scm/driver/harness/testdata/content_list.json new file mode 100644 index 000000000..33575adee --- /dev/null +++ b/scm/driver/harness/testdata/content_list.json @@ -0,0 +1,79 @@ +{ + "type": "dir", + "sha": "4fdc5acb2f9074a6d6ec826f01518fb27fe20a06", + "name": "", + "path": "", + "latest_commit": { + "sha": "4381eecb9dd29c34972087c4185f392c20d9f7c0", + "title": "move to version 1.1.2", + "message": "move to version 1.1.2", + "author": { + "identity": { + "name": "Johannes Batzill", + "email": "johannes.batzill@harness.io" + }, + "when": "2023-02-01T02:27:42Z" + }, + "committer": { + "identity": { + "name": "Johannes Batzill", + "email": "johannes.batzill@harness.io" + }, + "when": "2023-02-01T02:27:42Z" + } + }, + "content": { + "entries": [ + { + "type": "file", + "sha": "41fdf994e79e42bd4136c7e3004367f6d21d800d", + "name": ".gitignore", + "path": ".gitignore", + "latest_commit": { + "sha": "f8de11b6f3e4499889e16b989977c66c84ad02c9", + "title": "add initial version of demo application", + "message": "add initial version of demo application", + "author": { + "identity": { + "name": "Johannes Batzill", + "email": "johannes.batzill@harness.io" + }, + "when": "2023-02-01T00:08:20Z" + }, + "committer": { + "identity": { + "name": "Johannes Batzill", + "email": "johannes.batzill@harness.io" + }, + "when": "2023-02-01T00:08:20Z" + } + } + }, + { + "type": "file", + "sha": "261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64", + "name": "LICENSE", + "path": "LICENSE", + "latest_commit": { + "sha": "a2a1bb3664f096e69f4b15b80f4650cc9f8ae913", + "title": "Initial commit", + "message": "Initial commit", + "author": { + "identity": { + "name": "Johannes Batzill", + "email": "johannes.batzill@harness.io" + }, + "when": "2023-01-31T23:54:24Z" + }, + "committer": { + "identity": { + "name": "GitHub", + "email": "noreply@github.com" + }, + "when": "2023-01-31T23:54:24Z" + } + } + } + ] + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/content_list.json.golden b/scm/driver/harness/testdata/content_list.json.golden new file mode 100644 index 000000000..c23fd5007 --- /dev/null +++ b/scm/driver/harness/testdata/content_list.json.golden @@ -0,0 +1,14 @@ +[ + { + "Path": ".gitignore", + "Sha": "f8de11b6f3e4499889e16b989977c66c84ad02c9", + "BlobID": "41fdf994e79e42bd4136c7e3004367f6d21d800d", + "kind": "file" + }, + { + "Path": "LICENSE", + "Sha": "a2a1bb3664f096e69f4b15b80f4650cc9f8ae913", + "BlobID": "261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64", + "kind": "file" + } +] diff --git a/scm/driver/harness/testdata/gitdiff.json b/scm/driver/harness/testdata/gitdiff.json new file mode 100644 index 000000000..c4dd5768d --- /dev/null +++ b/scm/driver/harness/testdata/gitdiff.json @@ -0,0 +1,53 @@ +[ + { + "sha": "c4e897c1fcd1cae04abf761f034ae4c5e210caad", + "old_sha": "0000000000000000000000000000000000000000", + "path": "hello.go", + "old_path": "hello.go", + "status": "ADDED", + "additions": 8, + "deletions": 0, + "changes": 8, + "content_url": "/api/v1/hello.go", + "is_binary": false, + "is_submodule": false + }, + { + "sha": "0000000000000000000000000000000000000000", + "old_sha": "d7fcbf28651697b00add519d8b4402a5ab46ffc2", + "path": "null.go", + "old_path": "null.go", + "status": "DELETED", + "additions": 0, + "deletions": 118, + "changes": 118, + "content_url": "/api/v1/null.go", + "is_binary": false, + "is_submodule": false + }, + { + "sha": "ce5a2cd34b697f7a8507192e7074b33737c6740c", + "old_sha": "7697802e4d16b255e7ea22a86071cfbe9af6aa39", + "path": "version4.go", + "old_path": "version4.go", + "status": "MODIFIED", + "additions": 8, + "deletions": 7, + "changes": 15, + "content_url": "/api/v1/version4.go", + "is_binary": false, + "is_submodule": false + }, + { + "sha": "", + "path": "version_1.go", + "old_path": "version1.go", + "status": "RENAMED", + "additions": 0, + "deletions": 0, + "changes": 0, + "content_url": "/api/v1/version_1.go", + "is_binary": false, + "is_submodule": false + } +] \ No newline at end of file diff --git a/scm/driver/harness/testdata/gitdiff.json.golden b/scm/driver/harness/testdata/gitdiff.json.golden new file mode 100644 index 000000000..c3258c315 --- /dev/null +++ b/scm/driver/harness/testdata/gitdiff.json.golden @@ -0,0 +1,38 @@ +[ + { + "Path": "hello.go", + "Added": true, + "Renamed": false, + "Deleted": false, + "Sha": "", + "BlobID": "", + "PrevFilePath": "hello.go" + }, + { + "Path": "null.go", + "Added": false, + "Renamed": false, + "Deleted": true, + "Sha": "", + "BlobID": "", + "PrevFilePath": "null.go" + }, + { + "Path": "version4.go", + "Added": false, + "Renamed": false, + "Deleted": false, + "Sha": "", + "BlobID": "", + "PrevFilePath": "version4.go" + }, + { + "Path": "version_1.go", + "Added": false, + "Renamed": true, + "Deleted": false, + "Sha": "", + "BlobID": "", + "PrevFilePath": "version1.go" + } +] \ No newline at end of file diff --git a/scm/driver/harness/testdata/hook.json b/scm/driver/harness/testdata/hook.json new file mode 100644 index 000000000..cfae54972 --- /dev/null +++ b/scm/driver/harness/testdata/hook.json @@ -0,0 +1,16 @@ +{ + "version": 1, + "parent_id": 11, + "parent_type": "repo", + "created_by": 14, + "created": 1675867490853, + "updated": 1675867531549, + "identifier": "webhookname", + "description": "webhookdescription", + "url": "http://1.1.1.1", + "enabled": true, + "insecure": true, + "triggers": [], + "latest_execution_result": "success", + "has_secret": true +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/hook.json.golden b/scm/driver/harness/testdata/hook.json.golden new file mode 100644 index 000000000..686b5db97 --- /dev/null +++ b/scm/driver/harness/testdata/hook.json.golden @@ -0,0 +1,8 @@ +{ + "ID": "webhookname", + "Name": "webhookname", + "Target": "http://1.1.1.1", + "Events": [], + "Active": true, + "SkipVerify": true +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/hook_create.json b/scm/driver/harness/testdata/hook_create.json new file mode 100644 index 000000000..cd88b4357 --- /dev/null +++ b/scm/driver/harness/testdata/hook_create.json @@ -0,0 +1,17 @@ +{ + "id": 9, + "version": 1, + "parent_id": 11, + "parent_type": "repo", + "created_by": 14, + "created": 1675872629243, + "updated": 1675872777592, + "identifier": "drone", + "description": "", + "url": "https://example.com", + "enabled": true, + "insecure": true, + "triggers": [], + "latest_execution_result": "success", + "has_secret": true +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/hook_create.json.golden b/scm/driver/harness/testdata/hook_create.json.golden new file mode 100644 index 000000000..06e9a45dc --- /dev/null +++ b/scm/driver/harness/testdata/hook_create.json.golden @@ -0,0 +1,8 @@ +{ + "ID": "9", + "Name": "drone", + "Target": "https://example.com", + "Events": [], + "Active": true, + "SkipVerify": true +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/hooks.json b/scm/driver/harness/testdata/hooks.json new file mode 100644 index 000000000..9e539cecd --- /dev/null +++ b/scm/driver/harness/testdata/hooks.json @@ -0,0 +1,18 @@ +[ + { + "version": 1, + "parent_id": 11, + "parent_type": "repo", + "created_by": 14, + "created": 1675867490853, + "updated": 1675867531549, + "identifier": "webhookname", + "description": "webhookdescription", + "url": "http://1.1.1.1", + "enabled": true, + "insecure": true, + "triggers": [], + "latest_execution_result": "success", + "has_secret": true + } +] \ No newline at end of file diff --git a/scm/driver/harness/testdata/hooks.json.golden b/scm/driver/harness/testdata/hooks.json.golden new file mode 100644 index 000000000..317aa8125 --- /dev/null +++ b/scm/driver/harness/testdata/hooks.json.golden @@ -0,0 +1,10 @@ +[ + { + "ID": "webhookname", + "Name": "webhookname", + "Target": "http://1.1.1.1", + "Events": [], + "Active": true, + "SkipVerify": true + } +] \ No newline at end of file diff --git a/scm/driver/harness/testdata/pr.json b/scm/driver/harness/testdata/pr.json new file mode 100644 index 000000000..57fc7d9de --- /dev/null +++ b/scm/driver/harness/testdata/pr.json @@ -0,0 +1,36 @@ +{ + "number": 1, + "created": 1710818863810, + "edited": 1710818863810, + "state": "open", + "is_draft": false, + "title": "feat: self as codeowner can be skipped", + "description": "123", + "source_repo_id": 7, + "source_branch": "abhinav/CODE-1508", + "source_sha": "6c4ab583f5201ed0421d0ef93ee5b0925ac08f62", + "target_repo_id": 7, + "target_branch": "main", + "merged": null, + "merge_method": null, + "merge_check_status": "mergeable", + "merge_target_sha": "b772dca15553986cc90fc6254a0fa47f4047526c", + "merge_base_sha": "b772dca15553986cc90fc6254a0fa47f4047526c", + "merge_sha": "ff13c81504ab3b04bd76b6af71e9c368333181a5", + "author": { + "id": 27, + "uid": "aqm0RQXGQI6v3m_f7u7C5A", + "display_name": "Abhinav Singh", + "email": "abhinav.singh@harness.io", + "type": "user", + "created": 1681264009453, + "updated": 1681264009453 + }, + "merger": null, + "stats": { + "commits": 1, + "files_changed": 1, + "conversations": 1, + "unresolved_count": 1 + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/pr.json.golden b/scm/driver/harness/testdata/pr.json.golden new file mode 100644 index 000000000..ae5dc76da --- /dev/null +++ b/scm/driver/harness/testdata/pr.json.golden @@ -0,0 +1,33 @@ +{ + "Number": 1, + "Title": "feat: self as codeowner can be skipped", + "Body": "123", + "Sha": "6c4ab583f5201ed0421d0ef93ee5b0925ac08f62", + "Ref": "refs/pullreq/1/head", + "Source": "abhinav/CODE-1508", + "Target": "main", + "Fork": "fork", + "Closed": false, + "Merged": false, + "Fork": "fork", + "Link": "", + "Diff": "", + "Base": { + "Sha": "b772dca15553986cc90fc6254a0fa47f4047526c", + "Path": "refs/heads/main", + "Name": "main" + }, + "Head": { + "Sha": "6c4ab583f5201ed0421d0ef93ee5b0925ac08f62", + "Path": "refs/heads/abhinav/CODE-1508", + "Name": "abhinav/CODE-1508" + }, + "Author": { + "ID": "aqm0RQXGQI6v3m_f7u7C5A", + "Login": "abhinav.singh@harness.io", + "Name": "Abhinav Singh", + "Email": "abhinav.singh@harness.io" + }, + "Created": "2024-03-18T20:27:43.81-07:00", + "Updated": "2024-03-18T20:27:43.81-07:00" +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/pr_commits.json b/scm/driver/harness/testdata/pr_commits.json new file mode 100644 index 000000000..286654d14 --- /dev/null +++ b/scm/driver/harness/testdata/pr_commits.json @@ -0,0 +1,21 @@ +[ + { + "author": { + "identity": { + "email": "thomas.honey@harness.io", + "name": "thomas.honey" + }, + "when": "2023-02-09T17:12:10.976Z" + }, + "committer": { + "identity": { + "email": "noreply@harness.io", + "name": "Harness" + }, + "when": "2023-02-09T17:12:10.976Z" + }, + "message": "Create bla_file", + "sha": "0c221fd126b9457d0ad2037641416083549f59c5", + "title": "string" + } +] \ No newline at end of file diff --git a/scm/driver/harness/testdata/pr_commits.json.golden b/scm/driver/harness/testdata/pr_commits.json.golden new file mode 100644 index 000000000..aeceed89f --- /dev/null +++ b/scm/driver/harness/testdata/pr_commits.json.golden @@ -0,0 +1,19 @@ +[ + { + "Sha": "0c221fd126b9457d0ad2037641416083549f59c5", + "Message": "Create bla_file", + "Author": { + "Name": "thomas.honey", + "Email": "thomas.honey@harness.io", + "Login": "", + "Avatar": "" + }, + "Committer": { + "Name": "Harness", + "Email": "noreply@harness.io", + "Login": "", + "Avatar": "" + }, + "Link": "" + } +] \ No newline at end of file diff --git a/scm/driver/harness/testdata/repo.json b/scm/driver/harness/testdata/repo.json new file mode 100644 index 000000000..7e246e625 --- /dev/null +++ b/scm/driver/harness/testdata/repo.json @@ -0,0 +1,19 @@ +{ + "id": 9, + "parent_id": 16, + "uid": "demo", + "path": "px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/demo", + "description": "", + "is_public": false, + "created_by": 10, + "created": 1675210116158, + "updated": 1675389801066, + "default_branch": "main", + "fork_id": 0, + "num_forks": 0, + "num_pulls": 4, + "num_closed_pulls": 0, + "num_open_pulls": 1, + "num_merged_pulls": 3, + "git_url": "https://qa.harness.io/code/git/px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/demo.git" +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/repo.json.golden b/scm/driver/harness/testdata/repo.json.golden new file mode 100644 index 000000000..4e187a6d4 --- /dev/null +++ b/scm/driver/harness/testdata/repo.json.golden @@ -0,0 +1,10 @@ +{ + "ID": "9", + "Namespace": "px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/demo", + "Name": "demo", + "Branch": "main", + "Private": true, + "Clone": "https://qa.harness.io/code/git/px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/demo.git", + "CloneSSH": "https://qa.harness.io/code/git/px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/demo.git", + "Link": "https://qa.harness.io/code/git/px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/demo.git" +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/repos.json b/scm/driver/harness/testdata/repos.json new file mode 100644 index 000000000..77fb6f96e --- /dev/null +++ b/scm/driver/harness/testdata/repos.json @@ -0,0 +1,40 @@ +[ + { + "id": 9, + "parent_id": 16, + "uid": "demo", + "path": "px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/demo", + "description": "", + "is_public": false, + "created_by": 10, + "created": 1675210116158, + "updated": 1675389801066, + "default_branch": "main", + "fork_id": 0, + "num_forks": 0, + "num_pulls": 4, + "num_closed_pulls": 0, + "num_open_pulls": 1, + "num_merged_pulls": 3, + "git_url": "https://qa.harness.io/code/git/px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/demo.git" + }, + { + "id": 11, + "parent_id": 16, + "uid": "thomas", + "path": "px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/thomas", + "description": "Playground project for Thomas", + "is_public": true, + "created_by": 10, + "created": 1675458112548, + "updated": 1675458112548, + "default_branch": "main", + "fork_id": 0, + "num_forks": 0, + "num_pulls": 0, + "num_closed_pulls": 0, + "num_open_pulls": 0, + "num_merged_pulls": 0, + "git_url": "https://qa.harness.io/code/git/px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/thomas.git" + } +] \ No newline at end of file diff --git a/scm/driver/harness/testdata/repos.json.golden b/scm/driver/harness/testdata/repos.json.golden new file mode 100644 index 000000000..d58eb804b --- /dev/null +++ b/scm/driver/harness/testdata/repos.json.golden @@ -0,0 +1,22 @@ +[ + { + "ID": "9", + "Namespace": "px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/demo", + "Name": "demo", + "Branch": "main", + "Private": true, + "Clone": "https://qa.harness.io/code/git/px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/demo.git", + "CloneSSH": "https://qa.harness.io/code/git/px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/demo.git", + "Link": "https://qa.harness.io/code/git/px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/demo.git" + }, + { + "ID": "11", + "Namespace": "px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/thomas", + "Name": "thomas", + "Branch": "main", + "Private": false, + "Clone": "https://qa.harness.io/code/git/px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/thomas.git", + "CloneSSH": "https://qa.harness.io/code/git/px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/thomas.git", + "Link": "https://qa.harness.io/code/git/px7xd_BFRCi-pfWPYXVjvw/default/codeciintegration/thomas.git" + } +] \ No newline at end of file diff --git a/scm/driver/harness/testdata/user.json b/scm/driver/harness/testdata/user.json new file mode 100644 index 000000000..21ea693f2 --- /dev/null +++ b/scm/driver/harness/testdata/user.json @@ -0,0 +1,47 @@ +{ + "status": "SUCCESS", + "data": { + "uuid": "0Nnoezs6RGa_fOWvG_Ta4w", + "name": "thomas.honey", + "email": "thomas.honey@harness.io", + "token": null, + "defaultAccountId": "px7xd_BFRCi-pfWPYXVjvw", + "intent": null, + "accounts": [ + { + "uuid": "px7xd_BFRCi-pfWPYXVjvw", + "accountName": "harness-dev", + "companyName": "harness-dev", + "defaultExperience": "NG", + "createdFromNG": false, + "nextGenEnabled": true + }, + { + "uuid": "Ws0xvw71Sm2YmpSC7A8z4g", + "accountName": "OPA-Governance", + "companyName": "Feature-Flag", + "defaultExperience": "NG", + "createdFromNG": false, + "nextGenEnabled": true + } + ], + "admin": false, + "twoFactorAuthenticationEnabled": false, + "emailVerified": true, + "locked": false, + "disabled": false, + "signupAction": null, + "edition": null, + "billingFrequency": null, + "utmInfo": { + "utmSource": null, + "utmContent": null, + "utmMedium": null, + "utmTerm": null, + "utmCampaign": null + }, + "externallyManaged": false + }, + "metaData": null, + "correlationId": "c4014fdb-10a1-4dc4-ace0-6fad93544993" +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/user.json.golden b/scm/driver/harness/testdata/user.json.golden new file mode 100644 index 000000000..5f81bfeba --- /dev/null +++ b/scm/driver/harness/testdata/user.json.golden @@ -0,0 +1,7 @@ +{ + "ID": "0Nnoezs6RGa_fOWvG_Ta4w", + "Login": "thomas.honey@harness.io", + "Name": "thomas.honey", + "Email": "thomas.honey@harness.io", + "Avatar": "" +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/branch_create.json b/scm/driver/harness/testdata/webhooks/branch_create.json new file mode 100644 index 000000000..426f9c54e --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/branch_create.json @@ -0,0 +1,68 @@ +{ + "trigger": "branch_created", + "repo": { + "id": 13, + "path": "kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba", + "uid": "aba", + "default_branch": "main", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git" + }, + "principal": { + "id": 8, + "uid": "0osgWsTZRsSZ8RWfjLRkEg", + "display_name": "default", + "email": "default@harness.io", + "type": "user", + "created": 1675390885380, + "updated": 1675390885380 + }, + "ref": { + "name": "refs/heads/new2", + "repo": { + "id": 13, + "path": "kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba", + "uid": "aba", + "default_branch": "main", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git" + } + }, + "sha": "aeafa0e2e4ec6909ad75cb8fad57c0b1eb5986e6", + "commit": { + "sha": "aeafa0e2e4ec6909ad75cb8fad57c0b1eb5986e6", + "message": "version 4", + "author": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-02-01T13:21:15-08:00" + }, + "committer": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-02-01T13:21:15-08:00" + } + }, + "head_commit": { + "sha": "aeafa0e2e4ec6909ad75cb8fad57c0b1eb5986e6", + "message": "version 4", + "author": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-02-01T13:21:15-08:00" + }, + "committer": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-02-01T13:21:15-08:00" + } + }, + "old_sha": "0000000000000000000000000000000000000000", + "forced": false +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/branch_create.json.golden b/scm/driver/harness/testdata/webhooks/branch_create.json.golden new file mode 100644 index 000000000..967f51f17 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/branch_create.json.golden @@ -0,0 +1,29 @@ +{ + "Ref": { + "Name": "refs/heads/new2", + "Sha": "aeafa0e2e4ec6909ad75cb8fad57c0b1eb5986e6" + }, + "Action": "created", + "Repo": { + "ID": "13", + "Namespace": "", + "Name": "aba", + "Perm": null, + "Branch": "main", + "Private": false, + "Clone": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git", + "CloneSSH": "", + "Link": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Sender": { + "ID": "0osgWsTZRsSZ8RWfjLRkEg", + "Login": "0osgWsTZRsSZ8RWfjLRkEg", + "Name": "default", + "Email": "default@harness.io", + "Avatar": "", + "Created": "2023-02-02T18:21:25.38-08:00", + "Updated": "2023-02-02T18:21:25.38-08:00" + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/branch_delete.json b/scm/driver/harness/testdata/webhooks/branch_delete.json new file mode 100644 index 000000000..ba496b75d --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/branch_delete.json @@ -0,0 +1,34 @@ +{ + "trigger": "branch_deleted", + "repo": { + "id": 16, + "path": "kmpySmUISimoRrJL6NL73w/harness-core", + "identifier": "harness-core", + "default_branch": "develop", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/harness-core.git", + "uid": "harness-core" + }, + "principal": { + "id": 2, + "uid": "lv0euRhKRCyiXWzS7pOg6g", + "display_name": "Admin", + "email": "admin@harness.io", + "type": "user", + "created": 1701091219051, + "updated": 1701091219051 + }, + "ref": { + "name": "refs/heads/das", + "repo": { + "id": 16, + "path": "kmpySmUISimoRrJL6NL73w/harness-core", + "identifier": "harness-core", + "default_branch": "develop", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/harness-core.git", + "uid": "harness-core" + } + }, + "sha": "0000000000000000000000000000000000000000", + "old_sha": "0f1835abe08473e07863540712d8389984b72dad", + "forced": false +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/branch_delete.json.golden b/scm/driver/harness/testdata/webhooks/branch_delete.json.golden new file mode 100644 index 000000000..b9a0ad8f7 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/branch_delete.json.golden @@ -0,0 +1,29 @@ +{ + "Ref": { + "Name": "refs/heads/das", + "Sha": "0000000000000000000000000000000000000000" + }, + "Action": "deleted", + "Repo": { + "ID": "16", + "Namespace": "", + "Name": "harness-core", + "Perm": null, + "Branch": "develop", + "Private": false, + "Clone": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/harness-core.git", + "CloneSSH": "", + "Link": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/harness-core.git", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Sender": { + "ID": "lv0euRhKRCyiXWzS7pOg6g", + "Login": "lv0euRhKRCyiXWzS7pOg6g", + "Name": "Admin", + "Email": "admin@harness.io", + "Avatar": "", + "Created": "2023-11-27T05:20:19.051-08:00", + "Updated": "2023-11-27T05:20:19.051-08:00" + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/branch_updated.json b/scm/driver/harness/testdata/webhooks/branch_updated.json new file mode 100644 index 000000000..844bcfd03 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/branch_updated.json @@ -0,0 +1,68 @@ +{ + "trigger": "branch_updated", + "repo": { + "id": 68, + "path": "vpCkHKsDSxK9_KYfjCTMKA/default/Repo_With_PR_checks/abhinav-git-sync", + "uid": "abhinav-git-sync", + "default_branch": "master", + "git_url": "https://git.harness.io/vpCkHKsDSxK9_KYfjCTMKA/default/Repo_With_PR_checks/abhinav-git-sync.git" + }, + "principal": { + "id": 59, + "uid": "ec9UfvFwTf663F47Hlqxbg", + "display_name": "abhinav.singh@harness.io", + "email": "abhinav.singh@harness.io", + "type": "user", + "created": 1697617589873, + "updated": 1697617589873 + }, + "ref": { + "name": "refs/heads/master", + "repo": { + "id": 68, + "path": "vpCkHKsDSxK9_KYfjCTMKA/default/Repo_With_PR_checks/abhinav-git-sync", + "uid": "abhinav-git-sync", + "default_branch": "master", + "git_url": "https://git.harness.io/vpCkHKsDSxK9_KYfjCTMKA/default/Repo_With_PR_checks/abhinav-git-sync.git" + } + }, + "sha": "92e21bfcddc1418079cddbb518ad6fd72917798a", + "commit": { + "sha": "92e21bfcddc1418079cddbb518ad6fd72917798a", + "message": "Create asdsad (#2)", + "author": { + "identity": { + "name": "abhinav.singh@harness.io", + "email": "abhinav.singh@harness.io" + }, + "when": "2023-12-05T11:59:39Z" + }, + "committer": { + "identity": { + "name": "Harness", + "email": "noreply@harness.io" + }, + "when": "2023-12-05T11:59:39Z" + } + }, + "head_commit": { + "sha": "92e21bfcddc1418079cddbb518ad6fd72917798a", + "message": "Create asdsad (#2)", + "author": { + "identity": { + "name": "abhinav.singh@harness.io", + "email": "abhinav.singh@harness.io" + }, + "when": "2023-12-05T11:59:39Z" + }, + "committer": { + "identity": { + "name": "Harness", + "email": "noreply@harness.io" + }, + "when": "2023-12-05T11:59:39Z" + } + }, + "old_sha": "a273c385628167932e10caaa58e12550c491f241", + "forced": false +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/branch_updated.json.golden b/scm/driver/harness/testdata/webhooks/branch_updated.json.golden new file mode 100644 index 000000000..550cf3b1d --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/branch_updated.json.golden @@ -0,0 +1,46 @@ +{ + "Ref": "refs/heads/master", + "Before": "a273c385628167932e10caaa58e12550c491f241", + "After": "92e21bfcddc1418079cddbb518ad6fd72917798a", + "Repo": { + "ID": "68", + "Namespace": "", + "Name": "abhinav-git-sync", + "Perm": null, + "Branch": "master", + "Private": false, + "Clone": "https://git.harness.io/vpCkHKsDSxK9_KYfjCTMKA/default/Repo_With_PR_checks/abhinav-git-sync.git", + "CloneSSH": "", + "Link": "https://git.harness.io/vpCkHKsDSxK9_KYfjCTMKA/default/Repo_With_PR_checks/abhinav-git-sync.git", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Commit": { + "Sha": "92e21bfcddc1418079cddbb518ad6fd72917798a", + "Message": "Create asdsad (#2)", + "Author": { + "Name": "abhinav.singh@harness.io", + "Email": "abhinav.singh@harness.io", + "Date" : "0001-01-01T00:00:00Z", + "Login": "", + "Avatar": "" + }, + "Committer": { + "Name": "Harness", + "Email": "noreply@harness.io", + "Date": "0001-01-01T00:00:00Z", + "Login": "", + "Avatar": "" + }, + "Link": "" + }, + "Sender": { + "ID": "ec9UfvFwTf663F47Hlqxbg", + "Login": "ec9UfvFwTf663F47Hlqxbg", + "Name": "abhinav.singh@harness.io", + "Email": "abhinav.singh@harness.io", + "Avatar": "", + "Created": "2023-10-18T13:56:29.873+05:30", + "Updated": "2023-10-18T13:56:29.873+05:30" + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/pull_request_branch_updated.json b/scm/driver/harness/testdata/webhooks/pull_request_branch_updated.json new file mode 100644 index 000000000..dec4c06f6 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_branch_updated.json @@ -0,0 +1,100 @@ +{ + "trigger": "pullreq_branch_updated", + "repo": { + "id": 13, + "path": "kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba", + "uid": "aba", + "default_branch": "main", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git" + }, + "principal": { + "id": 8, + "uid": "0osgWsTZRsSZ8RWfjLRkEg", + "display_name": "default", + "email": "default@harness.io", + "type": "user", + "created": 1675390885380, + "updated": 1675390885380 + }, + "pull_req": { + "number": 4, + "state": "open", + "is_draft": false, + "title": "aw", + "source_repo_id": 13, + "source_branch": "b", + "target_repo_id": 13, + "target_branch": "main", + "merge_strategy": null, + "merge_base_sha": "5473eebbc0ce1d08981c955161b07a7989566b7b", + "author": { + "id": 8, + "uid": "0osgWsTZRsSZ8RWfjLRkEg", + "display_name": "Admin", + "email": "admin@harness.io", + "type": "user", + "created": 1675390885380, + "updated": 1675390885380 + }, + "pr_url": "http://localhost:3000/codeowners/asdsad/pulls/14" + }, + "target_ref": { + "name": "refs/heads/main", + "repo": { + "id": 13, + "path": "kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba", + "uid": "aba", + "default_branch": "main", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git" + } + }, + "ref": { + "name": "refs/heads/b", + "repo": { + "id": 13, + "path": "kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba", + "uid": "aba", + "default_branch": "main", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git" + } + }, + "sha": "f74f3d2a88d1b7cb19ff3bf069aa423763d341ef", + "commit": { + "sha": "f74f3d2a88d1b7cb19ff3bf069aa423763d341ef", + "message": "updated b2", + "author": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-02-01T13:28:55-08:00" + }, + "committer": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-02-01T13:28:55-08:00" + } + }, + "head_commit": { + "sha": "f74f3d2a88d1b7cb19ff3bf069aa423763d341ef", + "message": "updated b2", + "author": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-02-01T13:28:55-08:00" + }, + "committer": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-02-01T13:28:55-08:00" + } + }, + "old_sha": "d74b1ebfe520ac01b209dd9085f005884cc9f4cd", + "forced": false +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/pull_request_branch_updated.json.golden b/scm/driver/harness/testdata/webhooks/pull_request_branch_updated.json.golden new file mode 100644 index 000000000..0cc22af45 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_branch_updated.json.golden @@ -0,0 +1,58 @@ +{ + "Action": "updated", + "Repo": { + "ID": "13", + "Namespace": "", + "Name": "aba", + "Branch": "main", + "Private": false, + "Clone": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git", + "CloneSSH": "", + "Link": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 4, + "Title": "aw", + "Body": "", + "Sha": "f74f3d2a88d1b7cb19ff3bf069aa423763d341ef", + "Ref": "refs/heads/b", + "Source": "b", + "Target": "main", + "Fork": "fork", + "Link": "http://localhost:3000/codeowners/asdsad/pulls/14", + "Closed": false, + "Merged": false, + "Author": { + "ID": "0osgWsTZRsSZ8RWfjLRkEg", + "Login": "0osgWsTZRsSZ8RWfjLRkEg", + "Name": "Admin", + "Email": "admin@harness.io", + "Avatar": "", + "Created": "2023-02-02T18:21:25.38-08:00", + "Updated": "2023-02-02T18:21:25.38-08:00" + }, + "Base": { + "Name": "main", + "Path": "refs/heads/main", + "Sha": "5473eebbc0ce1d08981c955161b07a7989566b7b" + }, + "Head": { + "Name": "b", + "Path": "refs/heads/b", + "Sha": "f74f3d2a88d1b7cb19ff3bf069aa423763d341ef" + }, + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Sender": { + "ID": "0osgWsTZRsSZ8RWfjLRkEg", + "Login": "0osgWsTZRsSZ8RWfjLRkEg", + "Name": "default", + "Email": "default@harness.io", + "Avatar": "", + "Created": "2023-02-02T18:21:25.38-08:00", + "Updated": "2023-02-02T18:21:25.38-08:00" + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/pull_request_closed.json b/scm/driver/harness/testdata/webhooks/pull_request_closed.json new file mode 100644 index 000000000..4039bc208 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_closed.json @@ -0,0 +1,97 @@ +{ + "trigger": "pullreq_closed", + "repo": { + "id": 22, + "path": "codeowners/asdsad", + "uid": "asdsad", + "default_branch": "main", + "git_url": "http://localhost:3000/git/codeowners/asdsad.git" + }, + "principal": { + "id": 3, + "uid": "admin", + "display_name": "Administrator", + "email": "admin@gitness.io", + "type": "user", + "created": 1696332021613, + "updated": 1696332021613 + }, + "pull_req": { + "number": 6, + "state": "closed", + "is_draft": false, + "title": "Create sad", + "source_repo_id": 22, + "source_branch": "asdxsa", + "target_repo_id": 22, + "target_branch": "main", + "merge_base_sha": "5473eebbc0ce1d08981c955161b07a7989566b7b", + "author": { + "id": 3, + "uid": "admin", + "display_name": "Administrator", + "email": "admin@gitness.io", + "type": "user", + "created": 1696332021613, + "updated": 1696332021613 + }, + "pr_url": "http://localhost:3000/codeowners/asdsad/pulls/14" + }, + "target_ref": { + "name": "refs/heads/main", + "repo": { + "id": 22, + "path": "codeowners/asdsad", + "uid": "asdsad", + "default_branch": "main", + "git_url": "http://localhost:3000/git/codeowners/asdsad.git" + } + }, + "ref": { + "name": "refs/heads/asdxsa", + "repo": { + "id": 22, + "path": "codeowners/asdsad", + "uid": "asdsad", + "default_branch": "main", + "git_url": "http://localhost:3000/git/codeowners/asdsad.git" + } + }, + "sha": "27822dd2ec788f924c97b0b194c5bfd906f2e574", + "commit": { + "sha": "27822dd2ec788f924c97b0b194c5bfd906f2e574", + "message": "", + "author": { + "identity": { + "name": "Administrator", + "email": "admin@gitness.io" + }, + "when": "2023-12-20T13:10:47+05:30" + }, + "committer": { + "identity": { + "name": "Gitness", + "email": "system@gitness.io" + }, + "when": "2023-12-20T13:10:47+05:30" + } + }, + "head_commit": { + "sha": "27822dd2ec788f924c97b0b194c5bfd906f2e574", + "message": "", + "author": { + "identity": { + "name": "Administrator", + "email": "admin@gitness.io" + }, + "when": "2023-12-20T13:10:47+05:30" + }, + "committer": { + "identity": { + "name": "Gitness", + "email": "system@gitness.io" + }, + "when": "2023-12-20T13:10:47+05:30" + } + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/pull_request_closed.json.golden b/scm/driver/harness/testdata/webhooks/pull_request_closed.json.golden new file mode 100644 index 000000000..bfd493649 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_closed.json.golden @@ -0,0 +1,58 @@ +{ + "Action": "closed", + "Repo": { + "ID": "22", + "Namespace": "", + "Name": "asdsad", + "Branch": "main", + "Private": false, + "Clone": "http://localhost:3000/git/codeowners/asdsad.git", + "CloneSSH": "", + "Link": "http://localhost:3000/git/codeowners/asdsad.git", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 6, + "Title": "Create sad", + "Body": "", + "Sha": "27822dd2ec788f924c97b0b194c5bfd906f2e574", + "Ref": "refs/heads/asdxsa", + "Source": "asdxsa", + "Target": "main", + "Fork": "fork", + "Link": "http://localhost:3000/codeowners/asdsad/pulls/14", + "Closed": true, + "Merged": false, + "Author": { + "ID": "admin", + "Login": "admin", + "Name": "Administrator", + "Email": "admin@gitness.io", + "Avatar": "", + "Created": "2023-10-03T16:50:21.613+05:30", + "Updated": "2023-10-03T16:50:21.613+05:30" + }, + "Base": { + "Name": "main", + "Path": "refs/heads/main", + "Sha": "5473eebbc0ce1d08981c955161b07a7989566b7b" + }, + "Head": { + "Name": "asdxsa", + "Path": "refs/heads/asdxsa", + "Sha": "27822dd2ec788f924c97b0b194c5bfd906f2e574" + }, + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Sender": { + "ID": "admin", + "Login": "admin", + "Name": "Administrator", + "Email": "admin@gitness.io", + "Avatar": "", + "Created": "2023-10-03T16:50:21.613+05:30", + "Updated": "2023-10-03T16:50:21.613+05:30" + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/pull_request_comment_created.json b/scm/driver/harness/testdata/webhooks/pull_request_comment_created.json new file mode 100644 index 000000000..cc69241e8 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_comment_created.json @@ -0,0 +1,105 @@ +{ + "trigger": "pullreq_comment_created", + "repo": { + "id": 18, + "path": "asd/demo", + "uid": "demo", + "default_branch": "main", + "git_url": "http://localhost:3000/git/asd/demo.git" + }, + "principal": { + "id": 3, + "uid": "admin", + "display_name": "Administrator", + "email": "admin@gitness.io", + "type": "user", + "created": 1696332021613, + "updated": 1696332021613 + }, + "pull_req": { + "number": 2, + "state": "open", + "is_draft": false, + "title": "Update test.txt", + "source_repo_id": 18, + "source_branch": "pr2", + "target_repo_id": 18, + "target_branch": "main", + "merge_strategy": null, + "merge_base_sha": "5473eebbc0ce1d08981c955161b07a7989566b7b", + "author": { + "id": 8, + "uid": "0osgWsTZRsSZ8RWfjLRkEg", + "display_name": "Admin", + "email": "admin@harness.io", + "type": "user", + "created": 1675390885380, + "updated": 1675390885380 + }, + "pr_url": "http://localhost:3000/codeowners/asdsad/pulls/14" + }, + "target_ref": { + "name": "refs/heads/main", + "repo": { + "id": 18, + "path": "asd/demo", + "uid": "demo", + "default_branch": "main", + "git_url": "http://localhost:3000/git/asd/demo.git" + } + }, + "ref": { + "name": "refs/heads/pr2", + "repo": { + "id": 18, + "path": "asd/demo", + "uid": "demo", + "default_branch": "main", + "git_url": "http://localhost:3000/git/asd/demo.git" + } + }, + "sha": "f74f3d2a88d1b7cb19ff3bf069aa423763d341ef", + "commit": { + "sha": "f74f3d2a88d1b7cb19ff3bf069aa423763d341ef", + "message": "updated b2", + "author": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-02-01T13:28:55-08:00" + }, + "committer": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-02-01T13:28:55-08:00" + } + }, + "head_commit": { + "sha": "f74f3d2a88d1b7cb19ff3bf069aa423763d341ef", + "message": "updated b2", + "author": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-02-01T13:28:55-08:00" + }, + "committer": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-02-01T13:28:55-08:00" + } + }, + "comment": { + "id": 1, + "text": "pr comment", + "created": 1745471063621, + "updated": 1745471063621, + "kind": "comment" + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/pull_request_comment_created.json.golden b/scm/driver/harness/testdata/webhooks/pull_request_comment_created.json.golden new file mode 100644 index 000000000..a10e6efb6 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_comment_created.json.golden @@ -0,0 +1,61 @@ +{ + "Repo": { + "ID": "18", + "Namespace": "", + "Name": "demo", + "Branch": "main", + "Private": false, + "Clone": "http://localhost:3000/git/asd/demo.git", + "CloneSSH": "", + "Link": "http://localhost:3000/git/asd/demo.git", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 2, + "Title": "Update test.txt", + "Body": "", + "Sha": "f74f3d2a88d1b7cb19ff3bf069aa423763d341ef", + "Ref": "refs/heads/pr2", + "Source": "pr2", + "Target": "main", + "Fork": "fork", + "Link": "http://localhost:3000/codeowners/asdsad/pulls/14", + "Closed": false, + "Merged": false, + "Author": { + "ID": "0osgWsTZRsSZ8RWfjLRkEg", + "Login": "0osgWsTZRsSZ8RWfjLRkEg", + "Name": "Admin", + "Email": "admin@harness.io", + "Avatar": "", + "Created": "2023-02-02T18:21:25.38-08:00", + "Updated": "2023-02-02T18:21:25.38-08:00" + }, + "Base": { + "Name": "main", + "Path": "refs/heads/main", + "Sha": "5473eebbc0ce1d08981c955161b07a7989566b7b" + }, + "Head": { + "Name": "pr2", + "Path": "refs/heads/pr2", + "Sha": "f74f3d2a88d1b7cb19ff3bf069aa423763d341ef" + }, + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Comment": { + "ID": 1, + "Body": "pr comment" + }, + "Sender": { + "ID": "admin", + "Login": "admin", + "Name": "Administrator", + "Email": "admin@gitness.io", + "Avatar": "", + "Created": "2023-10-03T04:20:21.613-07:00", + "Updated": "2023-10-03T04:20:21.613-07:00" + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/pull_request_merged.json b/scm/driver/harness/testdata/webhooks/pull_request_merged.json new file mode 100644 index 000000000..dac50c97f --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_merged.json @@ -0,0 +1,98 @@ +{ + "trigger": "pullreq_merged", + "repo": { + "id": 22, + "path": "codeowners/asdsad", + "uid": "asdsad", + "default_branch": "main", + "git_url": "http://localhost:3000/git/codeowners/asdsad.git" + }, + "principal": { + "id": 3, + "uid": "admin", + "display_name": "Administrator", + "email": "admin@gitness.io", + "type": "user", + "created": 1696332021613, + "updated": 1696332021613 + }, + "pull_req": { + "number": 10, + "state": "merged", + "is_draft": false, + "title": "Create xxasc", + "source_repo_id": 22, + "source_branch": "xas", + "target_repo_id": 22, + "target_branch": "main", + "merge_strategy": "squash", + "merge_base_sha": "5473eebbc0ce1d08981c955161b07a7989566b7b", + "author": { + "id": 3, + "uid": "admin", + "display_name": "Administrator", + "email": "admin@gitness.io", + "type": "user", + "created": 1696332021613, + "updated": 1696332021613 + }, + "pr_url": "http://localhost:3000/codeowners/asdsad/pulls/14" + }, + "target_ref": { + "name": "refs/heads/main", + "repo": { + "id": 22, + "path": "codeowners/asdsad", + "uid": "asdsad", + "default_branch": "main", + "git_url": "http://localhost:3000/git/codeowners/asdsad.git" + } + }, + "ref": { + "name": "refs/heads/xas", + "repo": { + "id": 22, + "path": "codeowners/asdsad", + "uid": "asdsad", + "default_branch": "main", + "git_url": "http://localhost:3000/git/codeowners/asdsad.git" + } + }, + "sha": "4ec41187008f77222a60dfa21cdbd980f6490443", + "commit": { + "sha": "4ec41187008f77222a60dfa21cdbd980f6490443", + "message": "", + "author": { + "identity": { + "name": "Administrator", + "email": "admin@gitness.io" + }, + "when": "2023-12-20T13:40:52+05:30" + }, + "committer": { + "identity": { + "name": "Gitness", + "email": "system@gitness.io" + }, + "when": "2023-12-20T13:40:52+05:30" + } + }, + "head_commit": { + "sha": "4ec41187008f77222a60dfa21cdbd980f6490443", + "message": "", + "author": { + "identity": { + "name": "Administrator", + "email": "admin@gitness.io" + }, + "when": "2023-12-20T13:40:52+05:30" + }, + "committer": { + "identity": { + "name": "Gitness", + "email": "system@gitness.io" + }, + "when": "2023-12-20T13:40:52+05:30" + } + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/pull_request_merged.json.golden b/scm/driver/harness/testdata/webhooks/pull_request_merged.json.golden new file mode 100644 index 000000000..7237cea0d --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_merged.json.golden @@ -0,0 +1,58 @@ +{ + "Action": "merged", + "Repo": { + "ID": "22", + "Namespace": "", + "Name": "asdsad", + "Branch": "main", + "Private": false, + "Clone": "http://localhost:3000/git/codeowners/asdsad.git", + "CloneSSH": "", + "Link": "http://localhost:3000/git/codeowners/asdsad.git", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 10, + "Title": "Create xxasc", + "Body": "", + "Sha": "4ec41187008f77222a60dfa21cdbd980f6490443", + "Ref": "refs/heads/xas", + "Source": "xas", + "Target": "main", + "Fork": "fork", + "Link": "http://localhost:3000/codeowners/asdsad/pulls/14", + "Closed": true, + "Merged": true, + "Author": { + "ID": "admin", + "Login": "admin", + "Name": "Administrator", + "Email": "admin@gitness.io", + "Avatar": "", + "Created": "2023-10-03T16:50:21.613+05:30", + "Updated": "2023-10-03T16:50:21.613+05:30" + }, + "Base": { + "Name": "main", + "Path": "refs/heads/main", + "Sha": "5473eebbc0ce1d08981c955161b07a7989566b7b" + }, + "Head": { + "Name": "xas", + "Path": "refs/heads/xas", + "Sha": "4ec41187008f77222a60dfa21cdbd980f6490443" + }, + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Sender": { + "ID": "admin", + "Login": "admin", + "Name": "Administrator", + "Email": "admin@gitness.io", + "Avatar": "", + "Created": "2023-10-03T16:50:21.613+05:30", + "Updated": "2023-10-03T16:50:21.613+05:30" + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/pull_request_opened.json b/scm/driver/harness/testdata/webhooks/pull_request_opened.json new file mode 100644 index 000000000..bfafcef5a --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_opened.json @@ -0,0 +1,98 @@ +{ + "trigger": "pullreq_created", + "repo": { + "id": 13, + "path": "kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba", + "uid": "aba", + "default_branch": "main", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git" + }, + "principal": { + "id": 8, + "uid": "0osgWsTZRsSZ8RWfjLRkEg", + "display_name": "default", + "email": "default@harness.io", + "type": "user", + "created": 1675390885380, + "updated": 1675390885380 + }, + "pull_req": { + "number": 4, + "state": "open", + "is_draft": false, + "title": "aw", + "source_repo_id": 13, + "source_branch": "b", + "target_repo_id": 13, + "target_branch": "main", + "merge_strategy": null, + "merge_base_sha": "5473eebbc0ce1d08981c955161b07a7989566b7b", + "author": { + "id": 8, + "uid": "0osgWsTZRsSZ8RWfjLRkEg", + "display_name": "Admin", + "email": "admin@harness.io", + "type": "user", + "created": 1675390885380, + "updated": 1675390885380 + }, + "pr_url": "http://localhost:3000/codeowners/asdsad/pulls/14" + }, + "target_ref": { + "name": "refs/heads/main", + "repo": { + "id": 13, + "path": "kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba", + "uid": "aba", + "default_branch": "main", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git" + } + }, + "ref": { + "name": "refs/heads/b", + "repo": { + "id": 13, + "path": "kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba", + "uid": "aba", + "default_branch": "main", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git" + } + }, + "sha": "d74b1ebfe520ac01b209dd9085f005884cc9f4cd", + "commit": { + "sha": "d74b1ebfe520ac01b209dd9085f005884cc9f4cd", + "message": "Update b.txt", + "author": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-01-31T22:01:55-08:00" + }, + "committer": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-01-31T22:01:55-08:00" + } + }, + "head_commit": { + "sha": "d74b1ebfe520ac01b209dd9085f005884cc9f4cd", + "message": "Update b.txt", + "author": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-01-31T22:01:55-08:00" + }, + "committer": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-01-31T22:01:55-08:00" + } + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/pull_request_opened.json.golden b/scm/driver/harness/testdata/webhooks/pull_request_opened.json.golden new file mode 100644 index 000000000..a1fe53904 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_opened.json.golden @@ -0,0 +1,58 @@ +{ + "Action": "created", + "Repo": { + "ID": "13", + "Namespace": "", + "Name": "aba", + "Branch": "main", + "Private": false, + "Clone": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git", + "CloneSSH": "", + "Link": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 4, + "Title": "aw", + "Body": "", + "Sha": "d74b1ebfe520ac01b209dd9085f005884cc9f4cd", + "Ref": "refs/heads/b", + "Source": "b", + "Target": "main", + "Fork": "fork", + "Link": "http://localhost:3000/codeowners/asdsad/pulls/14", + "Closed": false, + "Merged": false, + "Author": { + "ID": "0osgWsTZRsSZ8RWfjLRkEg", + "Login": "0osgWsTZRsSZ8RWfjLRkEg", + "Name": "Admin", + "Email": "admin@harness.io", + "Avatar": "", + "Created": "2023-02-02T18:21:25.38-08:00", + "Updated": "2023-02-02T18:21:25.38-08:00" + }, + "Base": { + "Name": "main", + "Path": "refs/heads/main", + "Sha": "5473eebbc0ce1d08981c955161b07a7989566b7b" + }, + "Head": { + "Name": "b", + "Path": "refs/heads/b", + "Sha": "d74b1ebfe520ac01b209dd9085f005884cc9f4cd" + }, + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Sender": { + "ID": "0osgWsTZRsSZ8RWfjLRkEg", + "Login": "0osgWsTZRsSZ8RWfjLRkEg", + "Name": "default", + "Email": "default@harness.io", + "Avatar": "", + "Created": "2023-02-02T18:21:25.38-08:00", + "Updated": "2023-02-02T18:21:25.38-08:00" + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/pull_request_reopened.json b/scm/driver/harness/testdata/webhooks/pull_request_reopened.json new file mode 100644 index 000000000..3915d0b45 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_reopened.json @@ -0,0 +1,98 @@ +{ + "trigger": "pullreq_reopened", + "repo": { + "id": 13, + "path": "kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba", + "uid": "aba", + "default_branch": "main", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git" + }, + "principal": { + "id": 8, + "uid": "0osgWsTZRsSZ8RWfjLRkEg", + "display_name": "default", + "email": "default@harness.io", + "type": "user", + "created": 1675390885380, + "updated": 1675390885380 + }, + "pull_req": { + "number": 4, + "state": "open", + "is_draft": false, + "title": "aw", + "source_repo_id": 13, + "source_branch": "b", + "target_repo_id": 13, + "target_branch": "main", + "merge_strategy": null, + "merge_base_sha": "5473eebbc0ce1d08981c955161b07a7989566b7b", + "author": { + "id": 8, + "uid": "0osgWsTZRsSZ8RWfjLRkEg", + "display_name": "Admin", + "email": "admin@harness.io", + "type": "user", + "created": 1675390885380, + "updated": 1675390885380 + }, + "pr_url": "http://localhost:3000/codeowners/asdsad/pulls/14" + }, + "target_ref": { + "name": "refs/heads/main", + "repo": { + "id": 13, + "path": "kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba", + "uid": "aba", + "default_branch": "main", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git" + } + }, + "ref": { + "name": "refs/heads/b", + "repo": { + "id": 13, + "path": "kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba", + "uid": "aba", + "default_branch": "main", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git" + } + }, + "sha": "f74f3d2a88d1b7cb19ff3bf069aa423763d341ef", + "commit": { + "sha": "f74f3d2a88d1b7cb19ff3bf069aa423763d341ef", + "message": "updated b2", + "author": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-02-01T13:28:55-08:00" + }, + "committer": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-02-01T13:28:55-08:00" + } + }, + "head_commit": { + "sha": "f74f3d2a88d1b7cb19ff3bf069aa423763d341ef", + "message": "updated b2", + "author": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-02-01T13:28:55-08:00" + }, + "committer": { + "identity": { + "name": "Admin", + "email": "admin@harness.io" + }, + "when": "2023-02-01T13:28:55-08:00" + } + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/pull_request_reopened.json.golden b/scm/driver/harness/testdata/webhooks/pull_request_reopened.json.golden new file mode 100644 index 000000000..3c00c475c --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_reopened.json.golden @@ -0,0 +1,58 @@ +{ + "Action": "reopened", + "Repo": { + "ID": "13", + "Namespace": "", + "Name": "aba", + "Branch": "main", + "Private": false, + "Clone": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git", + "CloneSSH": "", + "Link": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/myOrg/myProject/aba.git", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 4, + "Title": "aw", + "Body": "", + "Sha": "f74f3d2a88d1b7cb19ff3bf069aa423763d341ef", + "Ref": "refs/heads/b", + "Source": "b", + "Target": "main", + "Fork": "fork", + "Link": "http://localhost:3000/codeowners/asdsad/pulls/14", + "Closed": false, + "Merged": false, + "Author": { + "ID": "0osgWsTZRsSZ8RWfjLRkEg", + "Login": "0osgWsTZRsSZ8RWfjLRkEg", + "Name": "Admin", + "Email": "admin@harness.io", + "Avatar": "", + "Created": "2023-02-02T18:21:25.38-08:00", + "Updated": "2023-02-02T18:21:25.38-08:00" + }, + "Base": { + "Name": "main", + "Path": "refs/heads/main", + "Sha": "5473eebbc0ce1d08981c955161b07a7989566b7b" + }, + "Head": { + "Name": "b", + "Path": "refs/heads/b", + "Sha": "f74f3d2a88d1b7cb19ff3bf069aa423763d341ef" + }, + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Sender": { + "ID": "0osgWsTZRsSZ8RWfjLRkEg", + "Login": "0osgWsTZRsSZ8RWfjLRkEg", + "Name": "default", + "Email": "default@harness.io", + "Avatar": "", + "Created": "2023-02-02T18:21:25.38-08:00", + "Updated": "2023-02-02T18:21:25.38-08:00" + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/tag_create.json b/scm/driver/harness/testdata/webhooks/tag_create.json new file mode 100644 index 000000000..f67e9700b --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/tag_create.json @@ -0,0 +1,76 @@ +{ + "trigger": "tag_created", + "repo": { + "id": 16, + "path": "kmpySmUISimoRrJL6NL73w/harness-core", + "identifier": "harness-core", + "default_branch": "develop", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/harness-core.git", + "uid": "harness-core" + }, + "principal": { + "id": 2, + "uid": "lv0euRhKRCyiXWzS7pOg6g", + "display_name": "Admin", + "email": "admin@harness.io", + "type": "user", + "created": 1701091219051, + "updated": 1701091219051 + }, + "ref": { + "name": "refs/tags/asd", + "repo": { + "id": 16, + "path": "kmpySmUISimoRrJL6NL73w/harness-core", + "identifier": "harness-core", + "default_branch": "develop", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/harness-core.git", + "uid": "harness-core" + } + }, + "sha": "3e4da2d65c3631c3e84b52fabe714c978aff540b", + "head_commit": { + "sha": "0f1835abe08473e07863540712d8389984b72dad", + "message": "", + "author": { + "identity": { + "name": "admin", + "email": "admin@harness.io" + }, + "when": "2024-03-01T07:54:35-08:00" + }, + "committer": { + "identity": { + "name": "GitHub", + "email": "noreply@github.com" + }, + "when": "2024-03-01T07:54:35-08:00" + }, + "added": [], + "removed": [], + "modified": [] + }, + "commit": { + "sha": "0f1835abe08473e07863540712d8389984b72dad", + "message": "", + "author": { + "identity": { + "name": "Jenny James", + "email": "jenny.james@harness.io" + }, + "when": "2024-03-01T07:54:35-08:00" + }, + "committer": { + "identity": { + "name": "GitHub", + "email": "noreply@github.com" + }, + "when": "2024-03-01T07:54:35-08:00" + }, + "added": [], + "removed": [], + "modified": [] + }, + "old_sha": "0000000000000000000000000000000000000000", + "forced": false +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/tag_create.json.golden b/scm/driver/harness/testdata/webhooks/tag_create.json.golden new file mode 100644 index 000000000..f6a8a53e4 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/tag_create.json.golden @@ -0,0 +1,29 @@ +{ + "Ref": { + "Name": "refs/tags/asd", + "Sha": "3e4da2d65c3631c3e84b52fabe714c978aff540b" + }, + "Action": "created", + "Repo": { + "ID": "16", + "Namespace": "", + "Name": "harness-core", + "Perm": null, + "Branch": "develop", + "Private": false, + "Clone": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/harness-core.git", + "CloneSSH": "", + "Link": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/harness-core.git", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Sender": { + "ID": "lv0euRhKRCyiXWzS7pOg6g", + "Login": "lv0euRhKRCyiXWzS7pOg6g", + "Name": "Admin", + "Email": "admin@harness.io", + "Avatar": "", + "Created": "2023-11-27T05:20:19.051-08:00", + "Updated": "2023-11-27T05:20:19.051-08:00" + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/tag_delete.json b/scm/driver/harness/testdata/webhooks/tag_delete.json new file mode 100644 index 000000000..3fa9348ee --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/tag_delete.json @@ -0,0 +1,34 @@ +{ + "trigger": "tag_deleted", + "repo": { + "id": 16, + "path": "kmpySmUISimoRrJL6NL73w/harness-core", + "identifier": "harness-core", + "default_branch": "develop", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/harness-core.git", + "uid": "harness-core" + }, + "principal": { + "id": 2, + "uid": "lv0euRhKRCyiXWzS7pOg6g", + "display_name": "Admin", + "email": "admin@harness.io", + "type": "user", + "created": 1701091219051, + "updated": 1701091219051 + }, + "ref": { + "name": "refs/tags/asd", + "repo": { + "id": 16, + "path": "kmpySmUISimoRrJL6NL73w/harness-core", + "identifier": "harness-core", + "default_branch": "develop", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/harness-core.git", + "uid": "harness-core" + } + }, + "sha": "0000000000000000000000000000000000000000", + "old_sha": "3e4da2d65c3631c3e84b52fabe714c978aff540b", + "forced": false +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/tag_delete.json.golden b/scm/driver/harness/testdata/webhooks/tag_delete.json.golden new file mode 100644 index 000000000..cfd67a8b1 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/tag_delete.json.golden @@ -0,0 +1,29 @@ +{ + "Ref": { + "Name": "refs/tags/asd", + "Sha": "0000000000000000000000000000000000000000" + }, + "Action": "deleted", + "Repo": { + "ID": "16", + "Namespace": "", + "Name": "harness-core", + "Perm": null, + "Branch": "develop", + "Private": false, + "Clone": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/harness-core.git", + "CloneSSH": "", + "Link": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/harness-core.git", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Sender": { + "ID": "lv0euRhKRCyiXWzS7pOg6g", + "Login": "lv0euRhKRCyiXWzS7pOg6g", + "Name": "Admin", + "Email": "admin@harness.io", + "Avatar": "", + "Created": "2023-11-27T05:20:19.051-08:00", + "Updated": "2023-11-27T05:20:19.051-08:00" + } +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/tag_update.json b/scm/driver/harness/testdata/webhooks/tag_update.json new file mode 100644 index 000000000..b16eac070 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/tag_update.json @@ -0,0 +1,100 @@ +{ + "trigger": "tag_updated", + "repo": { + "id": 16, + "path": "kmpySmUISimoRrJL6NL73w/harness-core", + "identifier": "harness-core", + "default_branch": "develop", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/harness-core.git", + "uid": "harness-core" + }, + "principal": { + "id": 2, + "uid": "lv0euRhKRCyiXWzS7pOg6g", + "display_name": "Admin", + "email": "admin@harness.io", + "type": "user", + "created": 1701091219051, + "updated": 1701091219051 + }, + "ref": { + "name": "refs/tags/ddxas", + "repo": { + "id": 16, + "path": "kmpySmUISimoRrJL6NL73w/harness-core", + "identifier": "harness-core", + "default_branch": "develop", + "git_url": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/harness-core.git", + "uid": "harness-core" + } + }, + "sha": "700b3dab8e7a5cebf5e1ce54e7dd5bde60099912", + "head_commit": { + "sha": "700b3dab8e7a5cebf5e1ce54e7dd5bde60099912", + "message": "Asd", + "author": { + "identity": { + "name": "Abhinav Singh", + "email": "abhinav.singh@harness.io" + }, + "when": "2024-03-07T03:18:51-08:00" + }, + "committer": { + "identity": { + "name": "Abhinav Singh", + "email": "abhinav.singh@harness.io" + }, + "when": "2024-03-07T03:18:51-08:00" + }, + "added": [], + "removed": [], + "modified": [] + }, + "commits": [ + { + "sha": "700b3dab8e7a5cebf5e1ce54e7dd5bde60099912", + "message": "Asd", + "author": { + "identity": { + "name": "Abhinav Singh", + "email": "abhinav.singh@harness.io" + }, + "when": "2024-03-07T03:18:51-08:00" + }, + "committer": { + "identity": { + "name": "Abhinav Singh", + "email": "abhinav.singh@harness.io" + }, + "when": "2024-03-07T03:18:51-08:00" + }, + "added": [], + "removed": [], + "modified": [] + } + ], + "total_commits_count": 1, + "commit": { + "sha": "700b3dab8e7a5cebf5e1ce54e7dd5bde60099912", + "message": "Asd", + "author": { + "identity": { + "name": "Abhinav Singh", + "email": "abhinav.singh@harness.io" + }, + "when": "2024-03-07T03:18:51-08:00" + }, + "committer": { + "identity": { + "name": "Abhinav Singh", + "email": "abhinav.singh@harness.io" + }, + "when": "2024-03-07T03:18:51-08:00" + }, + "added": [], + "removed": [], + "modified": [] + }, + "old_sha": "0f1835abe08473e07863540712d8389984b72dad", + "forced": true +} \ No newline at end of file diff --git a/scm/driver/harness/testdata/webhooks/tag_update.json.golden b/scm/driver/harness/testdata/webhooks/tag_update.json.golden new file mode 100644 index 000000000..408447db1 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/tag_update.json.golden @@ -0,0 +1,67 @@ +{ + "Ref": "refs/tags/ddxas", + "Before": "0f1835abe08473e07863540712d8389984b72dad", + "After": "700b3dab8e7a5cebf5e1ce54e7dd5bde60099912", + "Repo": { + "ID": "16", + "Namespace": "", + "Name": "harness-core", + "Perm": null, + "Branch": "develop", + "Private": false, + "Clone": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/harness-core.git", + "CloneSSH": "", + "Link": "http://localhost:3000/git/kmpySmUISimoRrJL6NL73w/harness-core.git", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Commit": { + "Sha": "700b3dab8e7a5cebf5e1ce54e7dd5bde60099912", + "Message": "Asd", + "Author": { + "Name": "Abhinav Singh", + "Email": "abhinav.singh@harness.io", + "Date": "0001-01-01T00:00:00Z", + "Login": "", + "Avatar": "" + }, + "Committer": { + "Name": "Abhinav Singh", + "Email": "abhinav.singh@harness.io", + "Date": "0001-01-01T00:00:00Z", + "Login": "", + "Avatar": "" + }, + "Link": "" + }, + "Commits": [ + { + "Sha": "700b3dab8e7a5cebf5e1ce54e7dd5bde60099912", + "Message": "Asd", + "Author": { + "Name": "Abhinav Singh", + "Email": "abhinav.singh@harness.io", + "Date": "0001-01-01T00:00:00Z", + "Login": "", + "Avatar": "" + }, + "Committer": { + "Name": "Abhinav Singh", + "Email": "abhinav.singh@harness.io", + "Date": "0001-01-01T00:00:00Z", + "Login": "", + "Avatar": "" + }, + "Link": "" + } + ], + "Sender": { + "ID": "lv0euRhKRCyiXWzS7pOg6g", + "Login": "lv0euRhKRCyiXWzS7pOg6g", + "Name": "Admin", + "Email": "admin@harness.io", + "Avatar": "", + "Created": "2023-11-27T05:20:19.051-08:00", + "Updated": "2023-11-27T05:20:19.051-08:00" + } +} \ No newline at end of file diff --git a/scm/driver/harness/user.go b/scm/driver/harness/user.go new file mode 100644 index 000000000..500cad249 --- /dev/null +++ b/scm/driver/harness/user.go @@ -0,0 +1,100 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "context" + "fmt" + "strings" + + "github.com/drone/go-scm/scm" +) + +type userService struct { + client *wrapper +} + +func (s *userService) Find(ctx context.Context) (*scm.User, *scm.Response, error) { + out := new(harnessUser) + // the following is for the corporate version of Harness code + tempUserService := *s + // get the basepath + basePath := tempUserService.client.BaseURL.Path + // use the NG user endpoint + basePath = strings.Replace(basePath, "code", "ng", 1) + // set the new basepath + tempUserService.client.BaseURL.Path = basePath + // set the path + path := fmt.Sprintf("api/user/currentUser") + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertHarnessUser(out), res, err +} + +func (s *userService) FindLogin(ctx context.Context, login string) (*scm.User, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *userService) FindEmail(ctx context.Context) (string, *scm.Response, error) { + return "", nil, scm.ErrNotSupported +} + +func (s *userService) ListEmail(context.Context, scm.ListOptions) ([]*scm.Email, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +// +// native data structures +// + +type harnessUser struct { + Status string `json:"status"` + Data struct { + UUID string `json:"uuid"` + Name string `json:"name"` + Email string `json:"email"` + Token interface{} `json:"token"` + Defaultaccountid string `json:"defaultAccountId"` + Intent interface{} `json:"intent"` + Accounts []struct { + UUID string `json:"uuid"` + Accountname string `json:"accountName"` + Companyname string `json:"companyName"` + Defaultexperience string `json:"defaultExperience"` + Createdfromng bool `json:"createdFromNG"` + Nextgenenabled bool `json:"nextGenEnabled"` + } `json:"accounts"` + Admin bool `json:"admin"` + Twofactorauthenticationenabled bool `json:"twoFactorAuthenticationEnabled"` + Emailverified bool `json:"emailVerified"` + Locked bool `json:"locked"` + Disabled bool `json:"disabled"` + Signupaction interface{} `json:"signupAction"` + Edition interface{} `json:"edition"` + Billingfrequency interface{} `json:"billingFrequency"` + Utminfo struct { + Utmsource interface{} `json:"utmSource"` + Utmcontent interface{} `json:"utmContent"` + Utmmedium interface{} `json:"utmMedium"` + Utmterm interface{} `json:"utmTerm"` + Utmcampaign interface{} `json:"utmCampaign"` + } `json:"utmInfo"` + Externallymanaged bool `json:"externallyManaged"` + } `json:"data"` + Metadata interface{} `json:"metaData"` + Correlationid string `json:"correlationId"` +} + +// +// native data structure conversion +// + +func convertHarnessUser(src *harnessUser) *scm.User { + return &scm.User{ + Login: src.Data.Email, + Email: src.Data.Email, + Name: src.Data.Name, + ID: src.Data.UUID, + } +} diff --git a/scm/driver/harness/user_test.go b/scm/driver/harness/user_test.go new file mode 100644 index 000000000..886494c13 --- /dev/null +++ b/scm/driver/harness/user_test.go @@ -0,0 +1,59 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "context" + "encoding/json" + "io/ioutil" + "net/http" + "strings" + "testing" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/transport" + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestUsersFind(t *testing.T) { + if harnessPAT == "" { + defer gock.Off() + + harnessUserOrigin := strings.Replace(gockOrigin, "code", "ng", 1) + + gock.New(harnessUserOrigin). + Get("/gateway/ng/api/user/currentUser"). + Reply(200). + Type("application/json"). + File("testdata/user.json") + } + client, _ := New(gockOrigin, harnessOrg, harnessAccount, harnessProject) + client.Client = &http.Client{ + Transport: &transport.Custom{ + Before: func(r *http.Request) { + r.Header.Set("x-api-key", harnessPAT) + }, + }, + } + got, _, err := client.Users.Find(context.Background()) + if err != nil { + t.Error(err) + return + } + + want := new(scm.User) + raw, _ := ioutil.ReadFile("testdata/user.json.golden") + wantErr := json.Unmarshal(raw, &want) + if wantErr != nil { + t.Error(wantErr) + return + } + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} diff --git a/scm/driver/harness/util.go b/scm/driver/harness/util.go new file mode 100644 index 000000000..4be210068 --- /dev/null +++ b/scm/driver/harness/util.go @@ -0,0 +1,174 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "fmt" + "net/url" + "strconv" + "strings" + + "github.com/drone/go-scm/scm" +) + +const ( + accountIdentifier = "accountIdentifier" + projectIdentifier = "projectIdentifier" + orgIdentifier = "orgIdentifier" + routingId = "routingId" +) + +func buildHarnessURI(account, organization, project, repo string) (uri string) { + if account != "" { + if project != "" { + uri = fmt.Sprintf("%s/%s/%s/", account, organization, project) + } else if organization != "" { + uri = fmt.Sprintf("%s/%s/", account, organization) + } else { + uri = fmt.Sprintf("%s/", account) + } + if repo != "" { + uri += fmt.Sprintf("%s/+", repo) + } else { + uri += "+" + } + return uri + } + return repo +} + +func getRepoAndQueryParams(slug string) (string, string, error) { + params := url.Values{} + s := strings.TrimSuffix(slug, "/+") + splitSlug := strings.Split(s, "/") + if len(splitSlug) == 0 || len(splitSlug) == 1 { + return "", "", fmt.Errorf("split length: %d is small for slug %s", len(splitSlug), slug) + } + + params.Set(accountIdentifier, splitSlug[0]) + params.Set(routingId, splitSlug[0]) + var repoId string + switch len(splitSlug) { + case 2: + repoId = splitSlug[1] + case 3: + params.Set(orgIdentifier, splitSlug[1]) + repoId = splitSlug[2] + case 4: + params.Set(orgIdentifier, splitSlug[1]) + params.Set(projectIdentifier, splitSlug[2]) + repoId = splitSlug[3] + default: + return "", "", fmt.Errorf("split length more than %d encountered for slug %s", len(splitSlug), slug) + + } + return repoId, params.Encode(), nil +} + +func encodeListOptions(opts scm.ListOptions) string { + params := url.Values{} + if opts.Page != 0 { + params.Set("page", strconv.Itoa(opts.Page)) + } + if opts.Size != 0 { + params.Set("limit", strconv.Itoa(opts.Size)) + } + return params.Encode() +} + +func encodeIssueListOptions(opts scm.IssueListOptions) string { + params := url.Values{} + if opts.Page != 0 { + params.Set("page", strconv.Itoa(opts.Page)) + } + if opts.Size != 0 { + params.Set("limit", 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 encodePullRequestListOptions(opts scm.PullRequestListOptions) string { + params := url.Values{} + if opts.Page != 0 { + params.Set("page", strconv.Itoa(opts.Page)) + } + if opts.Size != 0 { + params.Set("limit", strconv.Itoa(opts.Size)) + } + if opts.Open && opts.Closed { + params.Set("state", "all") + } else if opts.Closed { + params.Set("state", "closed") + } + return params.Encode() +} + +// convertAPIURLToHTMLURL converts an release API endpoint into a html endpoint +func convertAPIURLToHTMLURL(apiURL string, tagName string) string { + // "url": "https://try.gitea.com/api/v1/repos/octocat/Hello-World/123", + // "html_url": "https://try.gitea.com/octocat/Hello-World/releases/tag/v1.0.0", + // the url field is the API url, not the html url, so until go-sdk v0.13.3, build it ourselves + link, err := url.Parse(apiURL) + if err != nil { + return "" + } + + pathParts := strings.Split(link.Path, "/") + if len(pathParts) != 7 { + return "" + } + link.Path = fmt.Sprintf("/%s/%s/releases/tag/%s", pathParts[4], pathParts[5], tagName) + return link.String() +} + +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() +} + +type ListOptions struct { + Page int + PageSize int +} + +func encodeReleaseListOptions(o ListOptions) string { + query := make(url.Values) + query.Add("page", fmt.Sprintf("%d", o.Page)) + query.Add("limit", fmt.Sprintf("%d", o.PageSize)) + return query.Encode() +} + +func encodeCommitListOptions(opts scm.CommitListOptions) string { + params := url.Values{} + if opts.Page != 0 { + params.Set("page", strconv.Itoa(opts.Page)) + } + if opts.Size != 0 { + params.Set("limit", strconv.Itoa(opts.Size)) + } + if opts.Ref != "" { + params.Set("git_ref", opts.Ref) + } + if opts.Path != "" { + params.Set("path", opts.Path) + } + return params.Encode() +} diff --git a/scm/driver/harness/util_test.go b/scm/driver/harness/util_test.go new file mode 100644 index 000000000..2264536e0 --- /dev/null +++ b/scm/driver/harness/util_test.go @@ -0,0 +1,81 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "testing" + + "github.com/drone/go-scm/scm" +) + +func Test_encodeListOptions(t *testing.T) { + opts := scm.ListOptions{ + Page: 10, + Size: 30, + } + want := "limit=30&page=10" + got := encodeListOptions(opts) + if got != want { + t.Errorf("Want encoded list options %q, got %q", want, got) + } +} + +func Test_encodeIssueListOptions(t *testing.T) { + opts := scm.IssueListOptions{ + Page: 10, + Size: 30, + Open: true, + Closed: true, + } + want := "limit=30&page=10&state=all" + got := encodeIssueListOptions(opts) + if got != want { + t.Errorf("Want encoded issue list options %q, got %q", want, got) + } +} + +func Test_encodeIssueListOptions_Closed(t *testing.T) { + opts := scm.IssueListOptions{ + Page: 10, + Size: 30, + Open: false, + Closed: true, + } + want := "limit=30&page=10&state=closed" + got := encodeIssueListOptions(opts) + if got != want { + t.Errorf("Want encoded issue list options %q, got %q", want, got) + } +} + +func Test_encodePullRequestListOptions(t *testing.T) { + t.Parallel() + opts := scm.PullRequestListOptions{ + Page: 10, + Size: 30, + Open: true, + Closed: true, + } + want := "limit=30&page=10&state=all" + got := encodePullRequestListOptions(opts) + if got != want { + t.Errorf("Want encoded pr list options %q, got %q", want, got) + } +} + +func Test_encodePullRequestListOptions_Closed(t *testing.T) { + t.Parallel() + opts := scm.PullRequestListOptions{ + Page: 10, + Size: 30, + Open: false, + Closed: true, + } + want := "limit=30&page=10&state=closed" + got := encodePullRequestListOptions(opts) + if got != want { + t.Errorf("Want encoded pr list options %q, got %q", want, got) + } +} diff --git a/scm/driver/harness/webhook.go b/scm/driver/harness/webhook.go new file mode 100644 index 000000000..cb79b71fa --- /dev/null +++ b/scm/driver/harness/webhook.go @@ -0,0 +1,404 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "crypto/sha256" + "encoding/json" + "io" + "io/ioutil" + "net/http" + "strconv" + "strings" + "time" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/internal/hmac" +) + +type webhookService struct { + client *wrapper +} + +func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhook, error) { + data, err := ioutil.ReadAll( + io.LimitReader(req.Body, 10000000), + ) + if err != nil { + return nil, err + } + + var hook scm.Webhook + switch req.Header.Get("X-Harness-Trigger") { + // case "create": + // hook, err = s.parseCreateHook(data) + // case "delete": + // hook, err = s.parseDeleteHook(data) + // case "issues": + // hook, err = s.parseIssueHook(data) + case "branch_updated", "tag_updated": + hook, err = s.parsePushHook(data) + case "branch_created", "branch_deleted": + hook, err = s.parseBranchHook(data) + case "tag_created", "tag_deleted": + hook, err = s.parseTagHook(data) + case "pullreq_created", "pullreq_reopened", "pullreq_branch_updated", "pullreq_closed", "pullreq_merged": + hook, err = s.parsePullRequestHook(data) + case "pullreq_comment_created": + hook, err = s.parsePullRequestCommentHook(data) + default: + return nil, scm.ErrUnknownEvent + } + if err != nil { + return nil, err + } + + // get the gitea signature key to verify the payload + // signature. If no key is provided, no validation + // is performed. + key, err := fn(hook) + if err != nil { + return hook, err + } else if key == "" { + return hook, nil + } + + secret := req.FormValue("secret") + signature := req.Header.Get("X-Harness-Signature") + + // fail if no signature passed + if signature == "" && secret == "" { + return hook, scm.ErrSignatureInvalid + } + + // test signature if header not set and secret is in payload + if signature == "" && secret != "" && secret != key { + return hook, scm.ErrSignatureInvalid + } + + // test signature using header + if signature != "" && !hmac.Validate(sha256.New, data, []byte(key), signature) { + return hook, scm.ErrSignatureInvalid + } + + return hook, nil +} + +func (s *webhookService) parsePullRequestHook(data []byte) (scm.Webhook, error) { + dst := new(pullRequestHook) + err := json.Unmarshal(data, dst) + return convertPullRequestHook(dst), err +} + +func (s *webhookService) parsePushHook(data []byte) (scm.Webhook, error) { + dst := new(pushHook) + err := json.Unmarshal(data, dst) + return convertPushHook(dst), err +} + +func (s *webhookService) parsePullRequestCommentHook(data []byte) (scm.Webhook, error) { + dst := new(pullRequestCommentHook) + err := json.Unmarshal(data, dst) + return convertPullRequestCommentHook(dst), err +} + +func (s *webhookService) parseBranchHook(data []byte) (scm.Webhook, error) { + // using pushHook object since it is same as branch events + dst := new(pushHook) + err := json.Unmarshal(data, dst) + return convertBranchHook(dst), err +} + +func (s *webhookService) parseTagHook(data []byte) (scm.Webhook, error) { + // using pushHook object since it is same as tag events + dst := new(pushHook) + err := json.Unmarshal(data, dst) + return convertTagHook(dst), err +} + +// native data structures +type ( + repo struct { + ID int `json:"id"` + Path string `json:"path"` + UID string `json:"uid"` + DefaultBranch string `json:"default_branch"` + GitURL string `json:"git_url"` + } + principal struct { + ID int `json:"id"` + UID string `json:"uid"` + DisplayName string `json:"display_name"` + Email string `json:"email"` + Type string `json:"type"` + Created int64 `json:"created"` + Updated int64 `json:"updated"` + } + pullReq struct { + Number int `json:"number"` + State string `json:"state"` + IsDraft bool `json:"is_draft"` + Title string `json:"title"` + Description string `json:"description"` + SourceRepoID int `json:"source_repo_id"` + SourceBranch string `json:"source_branch"` + TargetRepoID int `json:"target_repo_id"` + TargetBranch string `json:"target_branch"` + MergeBaseSHA string `json:"merge_base_sha"` + MergeStrategy interface{} `json:"merge_strategy"` + Author principal `json:"author"` + PrURL string `json:"pr_url"` + } + targetRef struct { + Name string `json:"name"` + Repo struct { + ID int `json:"id"` + Path string `json:"path"` + UID string `json:"uid"` + DefaultBranch string `json:"default_branch"` + GitURL string `json:"git_url"` + } `json:"repo"` + } + ref struct { + Name string `json:"name"` + Repo struct { + ID int `json:"id"` + Path string `json:"path"` + UID string `json:"uid"` + DefaultBranch string `json:"default_branch"` + GitURL string `json:"git_url"` + } `json:"repo"` + } + hookCommit struct { + Sha string `json:"sha"` + Message string `json:"message"` + URL string `json:"url"` + Author struct { + Identity struct { + Name string `json:"name"` + Email string `json:"email"` + } `json:"identity"` + When string `json:"when"` + } `json:"author"` + Committer struct { + Identity struct { + Name string `json:"name"` + Email string `json:"email"` + } `json:"identity"` + When string `json:"when"` + } `json:"committer"` + Added []string `json:"added"` + Modified []string `json:"modified"` + Removed []string `json:"removed"` + } + comment struct { + ID int `json:"id"` + Text string `json:"text"` + } + // harness pull request webhook payload + pullRequestHook struct { + Trigger string `json:"trigger"` + Repo repo `json:"repo"` + Principal principal `json:"principal"` + PullReq pullReq `json:"pull_req"` + TargetRef targetRef `json:"target_ref"` + Ref ref `json:"ref"` + Sha string `json:"sha"` + HeadCommit hookCommit `json:"head_commit"` + Commits []hookCommit `json:"commits"` + TotalCommitsCount int64 `json:"total_commits_count"` + } + // harness push webhook payload + pushHook struct { + Trigger string `json:"trigger"` + Repo repo `json:"repo"` + Principal principal `json:"principal"` + Ref ref `json:"ref"` + HeadCommit hookCommit `json:"head_commit"` + Sha string `json:"sha"` + OldSha string `json:"old_sha"` + Forced bool `json:"forced"` + Commits []hookCommit `json:"commits"` + TotalCommitsCount int64 `json:"total_commits_count"` + } + // harness pull request comment webhook payload + pullRequestCommentHook struct { + Trigger string `json:"trigger"` + Repo repo `json:"repo"` + Principal principal `json:"principal"` + PullReq pullReq `json:"pull_req"` + TargetRef targetRef `json:"target_ref"` + Ref ref `json:"ref"` + Sha string `json:"sha"` + HeadCommit hookCommit `json:"head_commit"` + Comment comment `json:"comment"` + } +) + +// native data structure conversion +func convertPullRequestHook(src *pullRequestHook) *scm.PullRequestHook { + return &scm.PullRequestHook{ + Action: convertPRAction(src.Trigger), + PullRequest: convertPullReq(src.PullReq, src.Ref, src.HeadCommit), + Repo: convertRepo(src.Repo), + Sender: convertUser(src.Principal), + } +} + +func convertPushHook(src *pushHook) *scm.PushHook { + var commits []scm.Commit + for _, c := range src.Commits { + commits = append(commits, convertHookCommit(c)) + } + return &scm.PushHook{ + Ref: src.Ref.Name, + Before: src.OldSha, + After: src.Sha, + Repo: convertRepo(src.Repo), + Commit: convertHookCommit(src.HeadCommit), + Sender: convertUser(src.Principal), + Commits: commits, + } +} + +func convertHookCommit(c hookCommit) scm.Commit { + return scm.Commit{ + Sha: c.Sha, + Message: c.Message, + Author: scm.Signature{ + Name: c.Author.Identity.Name, + Email: c.Author.Identity.Email, + }, + Committer: scm.Signature{ + Name: c.Committer.Identity.Name, + Email: c.Committer.Identity.Email, + }, + Link: c.URL, + } +} + +func convertPullRequestCommentHook(src *pullRequestCommentHook) *scm.PullRequestCommentHook { + return &scm.PullRequestCommentHook{ + PullRequest: convertPullReq(src.PullReq, src.Ref, src.HeadCommit), + Repo: convertRepo(src.Repo), + Comment: scm.Comment{ + Body: src.Comment.Text, + ID: src.Comment.ID, + }, + Sender: convertUser(src.Principal), + } +} +func convertBranchHook(dst *pushHook) *scm.BranchHook { + return &scm.BranchHook{ + Ref: convertRef(dst), + Repo: convertRepo(dst.Repo), + Action: convertBranchAction(dst.Trigger), + Sender: convertUser(dst.Principal), + } +} + +func convertTagHook(dst *pushHook) *scm.TagHook { + return &scm.TagHook{ + Ref: convertRef(dst), + Repo: convertRepo(dst.Repo), + Action: convertTagAction(dst.Trigger), + Sender: convertUser(dst.Principal), + } +} + +func convertRef(dst *pushHook) scm.Reference { + return scm.Reference{ + Name: dst.Ref.Name, + Sha: dst.Sha, + } +} + +func convertPRAction(src string) (action scm.Action) { + switch strings.ToLower(src) { + case "pullreq_created": + return scm.ActionCreate + case "pullreq_branch_updated": + return scm.ActionUpdate + case "pullreq_reopened": + return scm.ActionReopen + case "pullreq_closed": + return scm.ActionClose + case "pullreq_merged": + return scm.ActionMerge + default: + return scm.ActionUnknown + } +} + +func convertBranchAction(src string) (action scm.Action) { + switch strings.ToLower(src) { + case "branch_created": + return scm.ActionCreate + case "branch_deleted": + return scm.ActionDelete + default: + return scm.ActionUnknown + } +} + +func convertTagAction(src string) (action scm.Action) { + switch strings.ToLower(src) { + case "tag_created": + return scm.ActionCreate + case "tag_deleted": + return scm.ActionDelete + default: + return scm.ActionUnknown + } +} + +func convertPullReq(pr pullReq, ref ref, commit hookCommit) scm.PullRequest { + return scm.PullRequest{ + Number: pr.Number, + Title: pr.Title, + Body: pr.Description, + Closed: pr.State != "open", + Source: pr.SourceBranch, + Target: pr.TargetBranch, + Merged: pr.State == "merged", + Fork: "fork", + Link: pr.PrURL, + Draft: pr.IsDraft, + Sha: commit.Sha, + Ref: ref.Name, + Author: convertUser(pr.Author), + Head: scm.Reference{ + Name: pr.SourceBranch, + Path: scm.ExpandRef(pr.SourceBranch, "refs/heads"), + Sha: commit.Sha, + }, + Base: scm.Reference{ + Name: pr.TargetBranch, + Path: scm.ExpandRef(pr.TargetBranch, "refs/heads"), + Sha: pr.MergeBaseSHA, + }, + } +} + +func convertRepo(repo repo) scm.Repository { + return scm.Repository{ + ID: strconv.Itoa(repo.ID), + Name: repo.UID, + Branch: repo.DefaultBranch, + Link: repo.GitURL, + Clone: repo.GitURL, + } +} + +func convertUser(principal principal) scm.User { + return scm.User{ + Name: principal.DisplayName, + ID: principal.UID, + Login: principal.UID, + Email: principal.Email, + Created: time.Unix(0, principal.Created*int64(time.Millisecond)), + Updated: time.Unix(0, principal.Updated*int64(time.Millisecond)), + } +} diff --git a/scm/driver/harness/webhook_test.go b/scm/driver/harness/webhook_test.go new file mode 100644 index 000000000..a4cf093b1 --- /dev/null +++ b/scm/driver/harness/webhook_test.go @@ -0,0 +1,178 @@ +// Copyright 2017 Drone.IO Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package harness + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "net/http" + "os" + "testing" + + "github.com/drone/go-scm/scm" + "github.com/google/go-cmp/cmp" +) + +func TestWebhooks(t *testing.T) { + tests := []struct { + event string + before string + after string + obj interface{} + }{ + // + // branch events + // + // push branch create + { + event: "branch_created", + before: "testdata/webhooks/branch_create.json", + after: "testdata/webhooks/branch_create.json.golden", + obj: new(scm.BranchHook), + }, + // push branch update + { + event: "branch_updated", + before: "testdata/webhooks/branch_updated.json", + after: "testdata/webhooks/branch_updated.json.golden", + obj: new(scm.PushHook), + }, + // push branch delete + { + event: "branch_deleted", + before: "testdata/webhooks/branch_delete.json", + after: "testdata/webhooks/branch_delete.json.golden", + obj: new(scm.BranchHook), + }, + // + // tag events + // + // push tag create + { + event: "tag_created", + before: "testdata/webhooks/tag_create.json", + after: "testdata/webhooks/tag_create.json.golden", + obj: new(scm.TagHook), + }, + // push tag update + { + event: "tag_updated", + before: "testdata/webhooks/tag_update.json", + after: "testdata/webhooks/tag_update.json.golden", + obj: new(scm.PushHook), + }, + // push tag delete + { + event: "tag_deleted", + before: "testdata/webhooks/tag_delete.json", + after: "testdata/webhooks/tag_delete.json.golden", + obj: new(scm.TagHook), + }, + + // + // pull request events + // + // pull request opened + { + event: "pullreq_created", + before: "testdata/webhooks/pull_request_opened.json", + after: "testdata/webhooks/pull_request_opened.json.golden", + obj: new(scm.PullRequestHook), + }, + // pull request reopened + { + event: "pullreq_reopened", + before: "testdata/webhooks/pull_request_reopened.json", + after: "testdata/webhooks/pull_request_reopened.json.golden", + obj: new(scm.PullRequestHook), + }, + // pull request branch updated + { + event: "pullreq_branch_updated", + before: "testdata/webhooks/pull_request_branch_updated.json", + after: "testdata/webhooks/pull_request_branch_updated.json.golden", + obj: new(scm.PullRequestHook), + }, + // pull request comment created + { + event: "pullreq_comment_created", + before: "testdata/webhooks/pull_request_comment_created.json", + after: "testdata/webhooks/pull_request_comment_created.json.golden", + obj: new(scm.PullRequestCommentHook), + }, + // pull request closed + { + event: "pullreq_reopened", + before: "testdata/webhooks/pull_request_closed.json", + after: "testdata/webhooks/pull_request_closed.json.golden", + obj: new(scm.PullRequestHook), + }, + // pull request merged + { + event: "pullreq_reopened", + before: "testdata/webhooks/pull_request_merged.json", + after: "testdata/webhooks/pull_request_merged.json.golden", + obj: new(scm.PullRequestHook), + }, + } + + for _, test := range tests { + before, err := ioutil.ReadFile(test.before) + if err != nil { + t.Error(err) + continue + } + after, err := ioutil.ReadFile(test.after) + if err != nil { + t.Error(err) + continue + } + + buf := bytes.NewBuffer(before) + r, _ := http.NewRequest("GET", "/", buf) + r.Header.Set("X-Harness-Trigger", test.event) + + s := new(webhookService) + o, err := s.Parse(r, secretFunc) + if err != nil && err != scm.ErrSignatureInvalid { + t.Error(err) + continue + } + + err = json.Unmarshal(after, test.obj) + if err != nil { + t.Error(err) + continue + } + + if diff := cmp.Diff(test.obj, o); diff != "" { + t.Errorf("Error unmarshaling %s", test.before) + t.Log(diff) + + // debug only. remove once implemented + _ = json.NewEncoder(os.Stdout).Encode(o) + + } + + // switch event := o.(type) { + // case *scm.PushHook: + // if !strings.HasPrefix(event.Ref, "refs/") { + // t.Errorf("Push hook reference must start with refs/") + // } + // case *scm.BranchHook: + // if strings.HasPrefix(event.Ref.Name, "refs/") { + // t.Errorf("Branch hook reference must not start with refs/") + // } + // case *scm.TagHook: + // if strings.HasPrefix(event.Ref.Name, "refs/") { + // t.Errorf("Branch hook reference must not start with refs/") + // } + // } + } +} +func secretFunc(scm.Webhook) (string, error) { + return "topsecret", nil +} diff --git a/scm/driver/stash/content.go b/scm/driver/stash/content.go index f03b6b1bc..fe921e528 100644 --- a/scm/driver/stash/content.go +++ b/scm/driver/stash/content.go @@ -8,6 +8,7 @@ import ( "bytes" "context" "fmt" + "net/url" "github.com/drone/go-scm/scm" ) @@ -17,8 +18,9 @@ type contentService struct { } func (s *contentService) Find(ctx context.Context, repo, path, ref string) (*scm.Content, *scm.Response, error) { + urlEncodedRef := url.QueryEscape(ref) namespace, name := scm.Split(repo) - endpoint := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/raw/%s?at=%s", namespace, name, path, ref) + endpoint := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/raw/%s?at=%s", namespace, name, path, urlEncodedRef) out := new(bytes.Buffer) res, err := s.client.do(ctx, "GET", endpoint, nil, out) return &scm.Content{ diff --git a/scm/driver/stash/content_test.go b/scm/driver/stash/content_test.go index f5ff36965..68f84f050 100644 --- a/scm/driver/stash/content_test.go +++ b/scm/driver/stash/content_test.go @@ -40,6 +40,28 @@ func TestContentFind(t *testing.T) { t.Errorf("Unexpected Results") t.Log(diff) } + + gock.New("http://example.com:7990"). + Get("/rest/api/1.0/projects/PRJ/repos/my-repo/raw/README"). + MatchParam("at", "b1&b2"). + Reply(200). + Type("text/plain"). + File("testdata/content.txt") + + client, _ = New("http://example.com:7990") + got, _, err = client.Contents.Find(context.Background(), "PRJ/my-repo", "README", "b1&b2") + if err != nil { + t.Error(err) + } + + want = new(scm.Content) + raw, _ = ioutil.ReadFile("testdata/content.json.golden") + _ = json.Unmarshal(raw, want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } } func TestContentCreate(t *testing.T) { diff --git a/scm/driver/stash/git.go b/scm/driver/stash/git.go index 2c38c4cd4..221b59911 100644 --- a/scm/driver/stash/git.go +++ b/scm/driver/stash/git.go @@ -19,7 +19,7 @@ type gitService struct { client *wrapper } -func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.CreateBranch) (*scm.Response, error) { +func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.ReferenceInput) (*scm.Response, error) { namespace, repoName := scm.Split(repo) path := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/branches", namespace, repoName) in := &createBranch{ @@ -79,13 +79,22 @@ func (s *gitService) ListBranches(ctx context.Context, repo string, opts scm.Lis return convertBranchList(out), res, err } +func (s *gitService) ListBranchesV2(ctx context.Context, repo string, opts scm.BranchListOptions) ([]*scm.Reference, *scm.Response, error) { + namespace, name := scm.Split(repo) + path := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/branches?%s", namespace, name, encodeBranchListOptions(opts)) + out := new(branches) + res, err := s.client.do(ctx, "GET", path, nil, out) + copyPagination(out.pagination, res) + return convertBranchList(out), res, err +} + func (s *gitService) ListCommits(ctx context.Context, repo string, opts scm.CommitListOptions) ([]*scm.Commit, *scm.Response, error) { namespace, name := scm.Split(repo) var requestPath string if opts.Path != "" { - requestPath = fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/commits?path=%s", namespace, name, opts.Path) + requestPath = fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/commits?until=%s&path=%s", namespace, name, opts.Ref, opts.Path) } else { - requestPath = fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/commits", namespace, name) + requestPath = fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/commits?until=%s", namespace, name, opts.Ref) } out := new(commits) res, err := s.client.do(ctx, "GET", requestPath, nil, out) diff --git a/scm/driver/stash/git_test.go b/scm/driver/stash/git_test.go index dfa37bfba..f93952ace 100644 --- a/scm/driver/stash/git_test.go +++ b/scm/driver/stash/git_test.go @@ -98,6 +98,7 @@ func TestGitListCommits(t *testing.T) { gock.New("http://example.com:7990"). Get("/rest/api/1.0/projects/PRJ/repos/my-repo/commits"). + MatchParam("until", ""). Reply(200). Type("application/json"). File("testdata/commits.json") @@ -146,6 +147,34 @@ func TestGitListBranches(t *testing.T) { // t.Run("Page", testPage(res)) } +func TestGitListBranchesWithBranchFilter(t *testing.T) { + defer gock.Off() + + gock.New("http://example.com:7990"). + Get("/rest/api/1.0/projects/PRJ/repos/my-repo/branches"). + MatchParam("filterText", "mast"). + Reply(200). + Type("application/json"). + File("testdata/branches_filter.json") + + client, _ := New("http://example.com:7990") + got, _, err := client.Git.ListBranchesV2(context.Background(), "PRJ/my-repo", scm.BranchListOptions{SearchTerm: "mast"}) + if err != nil { + t.Error(err) + } + + want := []*scm.Reference{} + raw, _ := ioutil.ReadFile("testdata/branches_filter.json.golden") + _ = json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + // + // t.Run("Page", testPage(res)) +} + func TestGitListTags(t *testing.T) { defer gock.Off() @@ -238,7 +267,7 @@ func TestCreateBranch(t *testing.T) { File("testdata/branch_create.json") client, _ := New("http://example.com:7990") - params := &scm.CreateBranch{ + params := &scm.ReferenceInput{ Name: "Hello", Sha: "312797ba52425353dec56871a255e2a36fc96344", } diff --git a/scm/driver/stash/integration/content_test.go b/scm/driver/stash/integration/content_test.go index a65b1b838..d6a22bbcb 100644 --- a/scm/driver/stash/integration/content_test.go +++ b/scm/driver/stash/integration/content_test.go @@ -11,8 +11,8 @@ import ( ) func TestCreateUpdateDeleteFileStash(t *testing.T) { - if token == "" { - t.Skip("Skipping, Acceptance test") + if token == "" || username == "" { + t.Skip("Skipping, Acceptance test. Missing BITBUCKET_SERVER_TOKEN or BITBUCKET_USERNAME") } client, _ = stash.New(endpoint) client.Client = &http.Client{ diff --git a/scm/driver/stash/integration/git_test.go b/scm/driver/stash/integration/git_test.go index bd5933f25..d1607f8de 100644 --- a/scm/driver/stash/integration/git_test.go +++ b/scm/driver/stash/integration/git_test.go @@ -11,8 +11,8 @@ import ( ) func TestCreateBranch(t *testing.T) { - if token == "" { - t.Skip("Skipping, Acceptance test") + if token == "" || username == "" { + t.Skip("Skipping, Acceptance test. Missing BITBUCKET_SERVER_TOKEN or BITBUCKET_USERNAME") } client, _ = stash.New(endpoint) client.Client = &http.Client{ @@ -23,7 +23,7 @@ func TestCreateBranch(t *testing.T) { } commitId, _ := GetCurrentCommitOfBranch(client, "master") - input := &scm.CreateBranch{ + input := &scm.ReferenceInput{ Name: "test_branch", Sha: commitId, } @@ -37,8 +37,8 @@ func TestCreateBranch(t *testing.T) { } func TestGetLatestCommitOfBranch(t *testing.T) { - if token == "" { - t.Skip("Skipping, Acceptance test") + if token == "" || username == "" { + t.Skip("Skipping, Acceptance test. Missing BITBUCKET_SERVER_TOKEN or BITBUCKET_USERNAME") } client, _ = stash.New(endpoint) client.Client = &http.Client{ @@ -62,3 +62,57 @@ func TestGetLatestCommitOfBranch(t *testing.T) { } } } + +func TestGetLatestCommitOfNonDefaultBranch(t *testing.T) { + if token == "" || username == "" { + t.Skip("Skipping, Acceptance test. Missing BITBUCKET_SERVER_TOKEN or BITBUCKET_USERNAME") + } + client, _ = stash.New(endpoint) + client.Client = &http.Client{ + Transport: &transport.BasicAuth{ + Username: username, + Password: token, + }, + } + + commits, response, err := client.Git.ListCommits(context.Background(), repoID, scm.CommitListOptions{Ref: "main", Path: "do-not-touch.txt"}) + + if err != nil { + t.Errorf("GetLatestCommitOfFile got an error %v", err) + } else { + if response.Status != http.StatusOK { + t.Errorf("GetLatestCommitOfFile did not get a 200 back %v", response.Status) + } + + if commits[0].Sha != "76fb1762048a277596d3fa330b3da140cd12d361" { + t.Errorf("Got the commitId %s instead of the top commit of the file", commits[0].Sha) + } + } +} + +func TestGetLatestCommitOfBranchWhenNoRefPassed(t *testing.T) { + if token == "" || username == "" { + t.Skip("Skipping, Acceptance test. Missing BITBUCKET_SERVER_TOKEN or BITBUCKET_USERNAME") + } + client, _ = stash.New(endpoint) + client.Client = &http.Client{ + Transport: &transport.BasicAuth{ + Username: username, + Password: token, + }, + } + + commits, response, err := client.Git.ListCommits(context.Background(), repoID, scm.CommitListOptions{Path: "README"}) + + if err != nil { + t.Errorf("GetLatestCommitOfFile got an error %v", err) + } else { + if response.Status != http.StatusOK { + t.Errorf("GetLatestCommitOfFile did not get a 200 back %v", response.Status) + } + + if commits[0].Sha != "2cc4dbe084f0d66761318b305c408cb0ea300c9a" { + t.Errorf("Got the commitId %s instead of the top commit of the file", commits[0].Sha) + } + } +} diff --git a/scm/driver/stash/integration/testSettings.go b/scm/driver/stash/integration/integration.go similarity index 92% rename from scm/driver/stash/integration/testSettings.go rename to scm/driver/stash/integration/integration.go index 7a3dfce71..56cae697d 100644 --- a/scm/driver/stash/integration/testSettings.go +++ b/scm/driver/stash/integration/integration.go @@ -13,7 +13,7 @@ var ( endpoint = "https://bitbucket.dev.harness.io/" repoID = "har/scm-integration-test-repo" - username = "harnessadmin" + username = os.Getenv("BITBUCKET_USERNAME") ) func GetCurrentCommitOfBranch(client *scm.Client, branch string) (string, error) { diff --git a/scm/driver/stash/pr.go b/scm/driver/stash/pr.go index 836c5392b..86f88c35c 100644 --- a/scm/driver/stash/pr.go +++ b/scm/driver/stash/pr.go @@ -34,7 +34,7 @@ func (s *pullService) FindComment(ctx context.Context, repo string, number int, func (s *pullService) List(ctx context.Context, repo string, opts scm.PullRequestListOptions) ([]*scm.PullRequest, *scm.Response, error) { namespace, name := scm.Split(repo) - path := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/pull-requests", namespace, name) + path := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/pull-requests?%s", namespace, name, encodePullRequestListOptions(opts)) out := new(prs) res, err := s.client.do(ctx, "GET", path, nil, out) if !out.pagination.LastPage.Bool { @@ -67,7 +67,7 @@ func (s *pullService) ListComments(context.Context, string, int, scm.ListOptions func (s *pullService) ListCommits(ctx context.Context, repo string, number int, opts scm.ListOptions) ([]*scm.Commit, *scm.Response, error) { namespace, name := scm.Split(repo) - path := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/pull-requests/%d/commits", namespace, name, number) + path := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/pull-requests/%d/commits?%s", namespace, name, number, encodeListOptionsV2(opts)) out := new(commits) res, err := s.client.do(ctx, "GET", path, nil, out) if !out.pagination.LastPage.Bool { @@ -173,6 +173,12 @@ type pr struct { Links struct { Self []link `json:"self"` } `json:"links"` + Properties struct { + MergeCommit struct { + ID string `json:"id"` + DisplayID string `json:"displayId"` + } `json:"mergeCommit"` + } `json:"properties"` } type prs struct { @@ -221,6 +227,7 @@ func convertPullRequest(from *pr) *scm.PullRequest { Title: from.Title, Body: from.Description, Sha: from.FromRef.LatestCommit, + Merge: from.Properties.MergeCommit.ID, Ref: fmt.Sprintf("refs/pull-requests/%d/from", from.ID), Source: from.FromRef.DisplayID, Target: from.ToRef.DisplayID, diff --git a/scm/driver/stash/repo.go b/scm/driver/stash/repo.go index 27e9b02b7..d7b864a0a 100644 --- a/scm/driver/stash/repo.go +++ b/scm/driver/stash/repo.go @@ -81,7 +81,7 @@ type hookInput struct { URL string `json:"url"` Active bool `json:"active"` Config struct { - Secret string `json:"secret"` + Secret string `json:"secret,omitempty"` } `json:"configuration"` } @@ -103,7 +103,19 @@ func (s *repositoryService) Find(ctx context.Context, repo string) (*scm.Reposit path := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s", namespace, name) out := new(repository) res, err := s.client.do(ctx, "GET", path, nil, out) - return convertRepository(out), res, err + outputRepo := convertRepository(out) + + branch := new(branch) + pathBranch := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/branches/default", namespace, name) + _, errBranch := s.client.do(ctx, "GET", pathBranch, nil, branch) + if errBranch == nil { + outputRepo.Branch = branch.DisplayID + } + if err == nil { + err = errBranch + } + + return outputRepo, res, err } // FindHook returns a repository hook. @@ -168,6 +180,30 @@ func (s *repositoryService) List(ctx context.Context, opts scm.ListOptions) ([]* return convertRepositoryList(out), res, err } +// ListV2 returns the user repository list based on the searchTerm passed. +func (s *repositoryService) ListV2(ctx context.Context, opts scm.RepoListOptions) ([]*scm.Repository, *scm.Response, error) { + path := fmt.Sprintf("rest/api/1.0/repos?%s", encodeRepoListOptions(opts)) + out := new(repositories) + res, err := s.client.do(ctx, "GET", path, nil, &out) + if res != nil && !out.pagination.LastPage.Bool { + res.Page.First = 1 + res.Page.Next = opts.ListOptions.Page + 1 + } + return convertRepositoryList(out), res, err +} + +// ListNamespace returns the user repository list based on searchterm and namespace. +func (s *repositoryService) ListNamespace(ctx context.Context, namespace string, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { + path := fmt.Sprintf("rest/api/1.0/projects/%s/repos?%s", namespace, encodeListRoleOptions(opts)) + out := new(repositories) + res, err := s.client.do(ctx, "GET", path, nil, &out) + if res != nil && !out.pagination.LastPage.Bool { + res.Page.First = 1 + res.Page.Next = opts.Page + 1 + } + return convertRepositoryList(out), res, err +} + func (s *repositoryService) List2(ctx context.Context, orgSlug string, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { return nil, nil, scm.ErrNotSupported } diff --git a/scm/driver/stash/repo_test.go b/scm/driver/stash/repo_test.go index 83924a8ba..ff7138df1 100644 --- a/scm/driver/stash/repo_test.go +++ b/scm/driver/stash/repo_test.go @@ -25,6 +25,12 @@ func TestRepositoryFind(t *testing.T) { Type("application/json"). File("testdata/repo.json") + gock.New("http://example.com:7990"). + Get("/rest/api/1.0/projects/PRJ/repos/my-repo/branches/default"). + Reply(200). + Type("application/json"). + File("testdata/default_branch.json") + client, _ := New("http://example.com:7990") got, _, err := client.Repositories.Find(context.Background(), "PRJ/my-repo") if err != nil { @@ -76,6 +82,12 @@ func TestRepositoryPerms(t *testing.T) { Type("application/json"). File("testdata/webhooks.json") + gock.New("http://example.com:7990"). + Get("/rest/api/1.0/projects/PRJ/repos/my-repo/branches/default"). + Reply(200). + Type("application/json"). + File("testdata/default_branch.json") + client, _ := New("http://example.com:7990") got, _, err := client.Repositories.FindPerms(context.Background(), "PRJ/my-repo") if err != nil { @@ -117,6 +129,12 @@ func TestRepositoryPerms_ReadOnly(t *testing.T) { Type("application/json"). File("testdata/repo.json") + gock.New("http://example.com:7990"). + Get("/rest/api/1.0/projects/PRJ/repos/my-repo/branches/default"). + Reply(200). + Type("application/json"). + File("testdata/default_branch.json") + client, _ := New("http://example.com:7990") got, _, err := client.Repositories.FindPerms(context.Background(), "PRJ/my-repo") if err != nil { @@ -162,6 +180,12 @@ func TestRepositoryPerms_Write(t *testing.T) { Type("application/json"). File("testdata/repos.json") + gock.New("http://example.com:7990"). + Get("/rest/api/1.0/projects/PRJ/repos/my-repo/branches/default"). + Reply(200). + Type("application/json"). + File("testdata/default_branch.json") + client, _ := New("http://example.com:7990") got, _, err := client.Repositories.FindPerms(context.Background(), "PRJ/my-repo") if err != nil { @@ -207,6 +231,12 @@ func TestRepositoryPermsDifferentProjectName_Write(t *testing.T) { Type("application/json"). File("testdata/repos.json") + gock.New("http://example.com:7990"). + Get("/rest/api/1.0/projects/PRJ/repos/quux/branches/default"). + Reply(200). + Type("application/json"). + File("testdata/default_branch.json") + client, _ := New("http://example.com:7990") got, _, err := client.Repositories.FindPerms(context.Background(), "PRJ/quux") if err != nil { @@ -289,6 +319,47 @@ func TestRepositoryList(t *testing.T) { } } +func TestRepositoryListV2(t *testing.T) { + defer gock.Off() + + gock.New("http://example.com:7990"). + Get("/rest/api/1.0/repos"). + MatchParam("name", "quux"). + MatchParam("limit", "25"). + MatchParam("start", "50"). + MatchParam("permission", "REPO_READ"). + Reply(200). + Type("application/json"). + File("testdata/repos_filter.json") + + client, _ := New("http://example.com:7990") + got, res, err := client.Repositories.ListV2(context.Background(), scm.RepoListOptions{ + ListOptions: scm.ListOptions{Page: 3, Size: 25}, + RepoSearchTerm: scm.RepoSearchTerm{ + RepoName: "quux", + }, + }) + if err != nil { + t.Error(err) + } + + if got, want := res.Page.First, 1; got != want { + t.Errorf("Want Page.First %d, got %d", want, got) + } + if got, want := res.Page.Next, 4; got != want { + t.Errorf("Want Page.Next %d, got %d", want, got) + } + + want := []*scm.Repository{} + raw, _ := ioutil.ReadFile("testdata/repos_filter.json.golden") + _ = json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + func TestStatusList(t *testing.T) { client, _ := New("http://example.com:7990") _, _, err := client.Repositories.ListStatus(context.Background(), "PRJ/my-repo", "a6e5e7d797edf751cbd839d6bd4aef86c941eec9", scm.ListOptions{Size: 30, Page: 1}) diff --git a/scm/driver/stash/stash.go b/scm/driver/stash/stash.go index 440cf3844..62db1c7fd 100644 --- a/scm/driver/stash/stash.go +++ b/scm/driver/stash/stash.go @@ -69,7 +69,8 @@ func (c *wrapper) do(ctx context.Context, method, path string, in, out interface Method: method, Path: path, Header: map[string][]string{ - "Accept": {"application/json"}, + "Accept": {"application/json"}, + "x-atlassian-token": {"no-check"}, }, } // if we are posting or putting data, we need to @@ -94,7 +95,8 @@ func (c *wrapper) do(ctx context.Context, method, path string, in, out interface req.Body = &b // write the content type that contains the length of the multipart req.Header = map[string][]string{ - "Content-Type": {mw.FormDataContentType()}, + "Content-Type": {mw.FormDataContentType()}, + "x-atlassian-token": {"no-check"}, } default: buf := new(bytes.Buffer) diff --git a/scm/driver/stash/testdata/branches_filter.json b/scm/driver/stash/testdata/branches_filter.json new file mode 100644 index 000000000..f6b88ab8f --- /dev/null +++ b/scm/driver/stash/testdata/branches_filter.json @@ -0,0 +1,24 @@ +{ + "size": 1, + "limit": 25, + "isLastPage": true, + "values": [ + { + "id": "refs/heads/master", + "displayId": "master", + "type": "BRANCH", + "latestCommit": "11ce869211917dd65610e70fcee454943b35ac6e", + "latestChangeset": "11ce869211917dd65610e70fcee454943b35ac6e", + "isDefault": true + }, + { + "id": "refs/heads/master-patch", + "displayId": "master-patch", + "type": "BRANCH", + "latestCommit": "11ce869211917dd65610e70fcee454943b35ac6f", + "latestChangeset": "11ce869211917dd65610e70fcee454943b35ac6f", + "isDefault": true + } + ], + "start": 0 +} \ No newline at end of file diff --git a/scm/driver/stash/testdata/branches_filter.json.golden b/scm/driver/stash/testdata/branches_filter.json.golden new file mode 100644 index 000000000..a158fbac2 --- /dev/null +++ b/scm/driver/stash/testdata/branches_filter.json.golden @@ -0,0 +1,12 @@ +[ + { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "11ce869211917dd65610e70fcee454943b35ac6e" + }, + { + "Name": "master-patch", + "Path": "refs/heads/master-patch", + "Sha": "11ce869211917dd65610e70fcee454943b35ac6f" + } +] \ No newline at end of file diff --git a/scm/driver/stash/testdata/content_list.json b/scm/driver/stash/testdata/content_list.json index ec0447795..4d5f72873 100644 --- a/scm/driver/stash/testdata/content_list.json +++ b/scm/driver/stash/testdata/content_list.json @@ -27,7 +27,8 @@ "testdata/branches.json.golden", "testdata/changes.json", "testdata/changes.json.golden", - "testdata/commit.json" + "testdata/commit.json", + "testdata/default_branch.json" ], "start": 0, "nextPageStart": 25 diff --git a/scm/driver/stash/testdata/content_list.json.golden b/scm/driver/stash/testdata/content_list.json.golden index 72d6fcf30..f02920ac4 100644 --- a/scm/driver/stash/testdata/content_list.json.golden +++ b/scm/driver/stash/testdata/content_list.json.golden @@ -98,5 +98,9 @@ { "path": "testdata/commit.json", "kind": "file" + }, + { + "path": "testdata/default_branch.json", + "kind": "file" } ] diff --git a/scm/driver/stash/testdata/default_branch.json b/scm/driver/stash/testdata/default_branch.json new file mode 100644 index 000000000..ceeec302e --- /dev/null +++ b/scm/driver/stash/testdata/default_branch.json @@ -0,0 +1,8 @@ +{ + "id": "refs/heads/feature_branch", + "displayId": "feature_branch", + "type": "BRANCH", + "latestCommit": "c567b3f4a2980299e2a1148360f23ffb0f4c9764", + "latestChangeset": "c567b3f4a2980299e2a1148360f23ffb0f4c9764", + "isDefault": true +} \ No newline at end of file diff --git a/scm/driver/stash/testdata/repo.json.golden b/scm/driver/stash/testdata/repo.json.golden index e7257362f..66414388a 100644 --- a/scm/driver/stash/testdata/repo.json.golden +++ b/scm/driver/stash/testdata/repo.json.golden @@ -3,7 +3,7 @@ "Namespace": "PRJ", "Name": "my-repo", "Perm": null, - "Branch": "master", + "Branch": "feature_branch", "Private": true, "Clone": "http://example.com:7990/scm/prj/my-repo.git", "CloneSSH": "ssh://git@example.com:7999/prj/my-repo.git", diff --git a/scm/driver/stash/testdata/repos_filter.json b/scm/driver/stash/testdata/repos_filter.json new file mode 100644 index 000000000..80bb1c9a4 --- /dev/null +++ b/scm/driver/stash/testdata/repos_filter.json @@ -0,0 +1,49 @@ +{ + "size": 25, + "limit": 25, + "isLastPage": false, + "values": [ + { + "slug": "quux", + "id": 2, + "name": "quux", + "scmId": "git", + "state": "AVAILABLE", + "statusMessage": "Available", + "forkable": true, + "project": { + "key": "PRJ", + "id": 2, + "name": "different_name", + "public": false, + "type": "NORMAL", + "links": { + "self": [ + { + "href": "http://example.com:7990/projects/PRJ" + } + ] + } + }, + "public": false, + "links": { + "clone": [ + { + "href": "ssh://git@example.com:7999/prj/quux.git", + "name": "ssh" + }, + { + "href": "http://jcitizen@example.com:7990/scm/prj/quux.git", + "name": "http" + } + ], + "self": [ + { + "href": "http://example.com:7990/projects/PRJ/repos/quux/browse" + } + ] + } + } + ], + "start": 0 +} \ No newline at end of file diff --git a/scm/driver/stash/testdata/repos_filter.json.golden b/scm/driver/stash/testdata/repos_filter.json.golden new file mode 100644 index 000000000..34ff2307b --- /dev/null +++ b/scm/driver/stash/testdata/repos_filter.json.golden @@ -0,0 +1,15 @@ +[ + { + "ID": "2", + "Namespace": "PRJ", + "Name": "quux", + "Perm": null, + "Branch": "master", + "Private": true, + "Clone": "http://example.com:7990/scm/prj/quux.git", + "CloneSSH": "ssh://git@example.com:7999/prj/quux.git", + "Link": "http://example.com:7990/projects/PRJ/repos/quux/browse", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + } +] \ No newline at end of file diff --git a/scm/driver/stash/testdata/webhooks/pr_merged.json.golden b/scm/driver/stash/testdata/webhooks/pr_merged.json.golden index 344032d2c..2b3367535 100644 --- a/scm/driver/stash/testdata/webhooks/pr_merged.json.golden +++ b/scm/driver/stash/testdata/webhooks/pr_merged.json.golden @@ -18,6 +18,7 @@ "Title": "Develop", "Body": "* added LICENSE\r\n* add COPYING file", "Sha": "b9eaed50a03c073b20dfa82e5e753d295e7f0e56", + "Merge": "83f836ca538dc4f43d29fda46a5b85ea49f1b8e7", "Ref": "refs/pull-requests/3/from", "Source": "develop", "Target": "master", diff --git a/scm/driver/stash/testdata/webhooks/push_v5.json b/scm/driver/stash/testdata/webhooks/push_v5.json new file mode 100644 index 000000000..444d2ff44 --- /dev/null +++ b/scm/driver/stash/testdata/webhooks/push_v5.json @@ -0,0 +1,44 @@ +{ + "eventKey": "repo:refs_changed", + "date": "2023-05-30T15:40:47-0400", + "actor": { + "name": "trangineni", + "emailAddress": "tanuja.rangineni@transamerica.com", + "id": 39725, + "displayName": "Rangineni, Tanuja", + "active": true, + "slug": "trangineni", + "type": "NORMAL" + }, + "repository": { + "slug": "transamerica.cloud.individual.tftest", + "id": 13027, + "name": "transamerica.cloud.individual.tftest", + "scmId": "git", + "state": "AVAILABLE", + "statusMessage": "Available", + "forkable": true, + "project": { + "key": "ISCLOUD", + "id": 1453, + "name": "Individual Cloud", + "description": "Project for Individual Solutions application terraform.", + "public": false, + "type": "NORMAL" + }, + "public": false + }, + "changes": [ + { + "ref": { + "id": "refs/heads/trangineni/devtfvars-1685475548410", + "displayId": "trangineni/devtfvars-1685475548410", + "type": "BRANCH" + }, + "refId": "refs/heads/trangineni/devtfvars-1685475548410", + "fromHash": "b2b710209761a3fab9fc867aad7b7725fd0fd028", + "toHash": "51a33664b6d7fb5aa15063064eb230362cd02e9e", + "type": "UPDATE" + } + ] +} \ No newline at end of file diff --git a/scm/driver/stash/testdata/webhooks/push_v5.json.golden b/scm/driver/stash/testdata/webhooks/push_v5.json.golden new file mode 100644 index 000000000..ffe8c4c87 --- /dev/null +++ b/scm/driver/stash/testdata/webhooks/push_v5.json.golden @@ -0,0 +1,50 @@ +{ + "Ref": "refs/heads/trangineni/devtfvars-1685475548410", + "After": "51a33664b6d7fb5aa15063064eb230362cd02e9e", + "Before": "b2b710209761a3fab9fc867aad7b7725fd0fd028", + "Repo": { + "ID": "13027", + "Namespace": "ISCLOUD", + "Name": "transamerica.cloud.individual.tftest", + "Perm": null, + "Branch": "master", + "Private": true, + "Clone": "", + "CloneSSH": "", + "Link": "", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Commit": { + "Sha": "51a33664b6d7fb5aa15063064eb230362cd02e9e", + "Message": "", + "Author": { + "Name": "Rangineni, Tanuja", + "Email": "tanuja.rangineni@transamerica.com", + "Date": "0001-01-01T00:00:00Z", + "Login": "trangineni", + "Avatar": "https://www.gravatar.com/avatar/1c0ba1559ee8ed291204dad48479149b.jpg" + }, + "Committer": { + "Name": "Rangineni, Tanuja", + "Email": "tanuja.rangineni@transamerica.com", + "Date": "0001-01-01T00:00:00Z", + "Login": "trangineni", + "Avatar": "https://www.gravatar.com/avatar/1c0ba1559ee8ed291204dad48479149b.jpg" + }, + "Link": "" + }, + "Commits": [ + { + "Sha": "51a33664b6d7fb5aa15063064eb230362cd02e9e", + "Message": "", + "Link": "" + } + ], + "Sender": { + "Login": "trangineni", + "Name": "Rangineni, Tanuja", + "Email": "tanuja.rangineni@transamerica.com", + "Avatar": "https://www.gravatar.com/avatar/1c0ba1559ee8ed291204dad48479149b.jpg" + } +} \ No newline at end of file diff --git a/scm/driver/stash/util.go b/scm/driver/stash/util.go index 64e982ba2..5f56e21ed 100644 --- a/scm/driver/stash/util.go +++ b/scm/driver/stash/util.go @@ -12,6 +12,10 @@ import ( "github.com/drone/go-scm/scm" ) +const ( + defaultLimit = 25 +) + func encodeListOptions(opts scm.ListOptions) string { params := url.Values{} if opts.Page > 1 { @@ -25,6 +29,40 @@ func encodeListOptions(opts scm.ListOptions) string { return params.Encode() } +func encodeListOptionsV2(opts scm.ListOptions) string { + params := url.Values{} + limit := defaultLimit + if opts.Size != 0 { + limit = opts.Size + } + params.Set("limit", strconv.Itoa(limit)) + + if opts.Page > 0 { + params.Set("start", strconv.Itoa( + (opts.Page-1)*limit), + ) + } + return params.Encode() +} + +func encodeBranchListOptions(opts scm.BranchListOptions) string { + params := url.Values{} + if opts.SearchTerm != "" { + params.Set("filterText", opts.SearchTerm) + } + if opts.PageListOptions != (scm.ListOptions{}) { + if opts.PageListOptions.Page > 1 { + params.Set("start", strconv.Itoa( + (opts.PageListOptions.Page-1)*opts.PageListOptions.Size), + ) + } + if opts.PageListOptions.Size != 0 { + params.Set("limit", strconv.Itoa(opts.PageListOptions.Size)) + } + } + return params.Encode() +} + func encodeListRoleOptions(opts scm.ListOptions) string { params := url.Values{} if opts.Page > 1 { @@ -39,6 +77,27 @@ func encodeListRoleOptions(opts scm.ListOptions) string { return params.Encode() } +func encodeRepoListOptions(opts scm.RepoListOptions) string { + params := url.Values{} + if opts.RepoSearchTerm != (scm.RepoSearchTerm{}) { + if opts.RepoSearchTerm.RepoName != "" { + params.Set("name", opts.RepoSearchTerm.RepoName) + } + } + if opts.ListOptions != (scm.ListOptions{}) { + if opts.ListOptions.Page > 1 { + params.Set("start", strconv.Itoa( + (opts.ListOptions.Page-1)*opts.ListOptions.Size), + ) + } + if opts.ListOptions.Size != 0 { + params.Set("limit", strconv.Itoa(opts.ListOptions.Size)) + } + } + params.Set("permission", "REPO_READ") + return params.Encode() +} + func encodePullRequestListOptions(opts scm.PullRequestListOptions) string { params := url.Values{} if opts.Page > 1 { @@ -52,7 +111,7 @@ func encodePullRequestListOptions(opts scm.PullRequestListOptions) string { if opts.Open && opts.Closed { params.Set("state", "all") } else if opts.Closed { - params.Set("state", "closed") + params.Set("state", "declined") } return params.Encode() } diff --git a/scm/driver/stash/util_test.go b/scm/driver/stash/util_test.go index 86e2e331d..d9e86101c 100644 --- a/scm/driver/stash/util_test.go +++ b/scm/driver/stash/util_test.go @@ -32,6 +32,28 @@ func Test_encodeListOptions(t *testing.T) { } } +func Test_encodeListOptionsV2(t *testing.T) { + tests := []struct { + page int + size int + text string + }{ + {page: 0, size: 30, text: "limit=30"}, + {page: 1, size: 30, text: "limit=30&start=0"}, + {page: 5, size: 30, text: "limit=30&start=120"}, + {page: 2, size: 5, text: "limit=5&start=5"}, + } + for _, test := range tests { + opts := scm.ListOptions{ + Page: test.page, + Size: test.size, + } + if got, want := encodeListOptionsV2(opts), test.text; got != want { + t.Errorf("Want encoded list options %q, got %q", want, got) + } + } +} + func Test_encodePullRequestListOptions(t *testing.T) { t.Parallel() opts := scm.PullRequestListOptions{ diff --git a/scm/driver/stash/webhook_test.go b/scm/driver/stash/webhook_test.go index 711adc694..28e72a0ad 100644 --- a/scm/driver/stash/webhook_test.go +++ b/scm/driver/stash/webhook_test.go @@ -37,7 +37,14 @@ func TestWebhooks(t *testing.T) { after: "testdata/webhooks/push.json.golden", obj: new(scm.PushHook), }, - + // v5 test + { + sig: "71295b197fa25f4356d2fb9965df3f2379d903d7", + event: "repo:refs_changed", + before: "testdata/webhooks/push_v5.json", + after: "testdata/webhooks/push_v5.json.golden", + obj: new(scm.PushHook), + }, // // tag events // diff --git a/scm/git.go b/scm/git.go index 21da2bc4a..b2d125136 100644 --- a/scm/git.go +++ b/scm/git.go @@ -13,16 +13,16 @@ import ( const EmptyCommit = "0000000000000000000000000000000000000000" type ( - // CreateBranch provides a SHA for creating a branch. - CreateBranch struct { + // Reference represents a git reference. + Reference struct { Name string + Path string Sha string } - // Reference represents a git reference. - Reference struct { + // ReferenceInput provides a SHA for creating a reference. + ReferenceInput struct { Name string - Path string Sha string } @@ -59,10 +59,19 @@ type ( Avatar string } + // Pipeline Execution details + Execution struct { + Number int + Status ExecutionStatus + Created time.Time + Updated time.Time + URL string + } + // GitService provides access to git resources. GitService interface { // CreateBranch creates a git branch by name given a sha. - CreateBranch(ctx context.Context, repo string, params *CreateBranch) (*Response, error) + CreateBranch(ctx context.Context, repo string, params *ReferenceInput) (*Response, error) // FindBranch finds a git branch by name. FindBranch(ctx context.Context, repo, name string) (*Reference, *Response, error) @@ -76,6 +85,9 @@ type ( // ListBranches returns a list of git branches. ListBranches(ctx context.Context, repo string, opts ListOptions) ([]*Reference, *Response, error) + // ListBranchesV2 returns a list of git branches based on the searchTerm passed. + ListBranchesV2(ctx context.Context, repo string, opts BranchListOptions) ([]*Reference, *Response, error) + // ListCommits returns a list of git commits. ListCommits(ctx context.Context, repo string, opts CommitListOptions) ([]*Commit, *Response, error) @@ -91,4 +103,8 @@ type ( // return a 2-way or 3-way diff changeset. CompareChanges(ctx context.Context, repo, source, target string, opts ListOptions) ([]*Change, *Response, error) } + + // CreateBranch is a type alias for upstream projects + // that use the previous CreateBranch type name. + CreateBranch = ReferenceInput ) diff --git a/scm/pr.go b/scm/pr.go index b36254a34..1e9a74945 100644 --- a/scm/pr.go +++ b/scm/pr.go @@ -22,8 +22,10 @@ type ( Fork string Link string Diff string + Draft bool Closed bool Merged bool + Merge string Base Reference Head Reference Author User diff --git a/scm/repo.go b/scm/repo.go index 29055dbd2..16e97e7fc 100644 --- a/scm/repo.go +++ b/scm/repo.go @@ -65,6 +65,7 @@ type ( Deployment bool Issue bool IssueComment bool + Pipeline bool PullRequest bool PullRequestComment bool Push bool @@ -120,6 +121,12 @@ type ( // List returns a list of repositories. List(context.Context, ListOptions) ([]*Repository, *Response, error) + // ListV2 returns a list of repositories based on the searchTerm passed. + ListV2(context.Context, RepoListOptions) ([]*Repository, *Response, error) + + // ListNamespace returns a list of repos in namespace + ListNamespace(context.Context, string, ListOptions) ([]*Repository, *Response, error) + // List2 returns a list of repositories . List2(context.Context, string, ListOptions) ([]*Repository, *Response, error) diff --git a/scm/traverse/repos.go b/scm/traverse/repos.go index dcad3ddd6..c417d2704 100644 --- a/scm/traverse/repos.go +++ b/scm/traverse/repos.go @@ -22,7 +22,7 @@ func Repos(ctx context.Context, client *scm.Client) ([]*scm.Repository, error) { } for _, src := range result { if src != nil { - list = append(list, result...) + list = append(list, src) } } opts.Page = meta.Page.Next diff --git a/scm/user.go b/scm/user.go index e1ea08fa5..fd448770a 100644 --- a/scm/user.go +++ b/scm/user.go @@ -12,6 +12,7 @@ import ( type ( // User represents a user account. User struct { + ID string Login string Name string Email string diff --git a/scm/util.go b/scm/util.go index 0a8c3a2ca..4e72f524f 100644 --- a/scm/util.go +++ b/scm/util.go @@ -89,3 +89,42 @@ func IsPullRequest(ref string) bool { func IsHash(s string) bool { return sha1.MatchString(s) || sha256.MatchString(s) } + +func ConvertVisibility(from string) Visibility { + switch from { + case "public": + return VisibilityPublic + case "private": + return VisibilityPrivate + case "internal": + return VisibilityInternal + default: + return VisibilityUndefined + } +} + +func ConvertExecutionStatus(from string) ExecutionStatus { + switch from { + case "running", "in_progress", "INPROGRESS": + return StatusRunning + case "success", "completed", "SUCCESSFUL": + return StatusSuccess + case "Failed", "failure", "FAILED": + return StatusFailed + case "Canceled", "cancelled", "STOPPED": + return StatusCanceled + case "pending", "queued": + return StatusPending + default: + return StatusUnknown + } +} + +func ConvertPrivate(from string) bool { + switch from { + case "public", "": + return false + default: + return true + } +} diff --git a/scm/util_test.go b/scm/util_test.go index 41332276d..c2b87ae74 100644 --- a/scm/util_test.go +++ b/scm/util_test.go @@ -239,3 +239,42 @@ func TestIsHash(t *testing.T) { } } } + +func TestConvertVisibility(t *testing.T) { + tests := []struct { + in string + out Visibility + }{ + {"public", 1}, + {"", 0}, + {"private", 3}, + {"internal", 2}, + {"invalid", 0}, + {"unknown", 0}, + } + + for _, test := range tests { + if got, want := ConvertVisibility(test.in), test.out; got != want { + t.Errorf("Want %d for %v type, got %d", want, test.in, got) + } + } +} + +func TestConvertPrivate(t *testing.T) { + tests := []struct { + in string + out bool + }{ + {"public", false}, + {"", false}, + {"private", true}, + {"internal", true}, + {"invalid", true}, + } + + for _, test := range tests { + if got, want := ConvertPrivate(test.in), test.out; got != want { + t.Errorf("Want private %v, got %v", want, got) + } + } +} diff --git a/scm/webhook.go b/scm/webhook.go index f84023288..07bb62d9b 100644 --- a/scm/webhook.go +++ b/scm/webhook.go @@ -37,6 +37,15 @@ type ( Commits []Commit } + // PipelineHook + PipelineHook struct { + Commit Commit + Execution Execution + PullRequest PullRequest + Repo Repository + Sender User + } + // BranchHook represents a branch or tag event, // eg create and delete github event types. BranchHook struct { @@ -115,6 +124,15 @@ type ( Task string } + // ReleaseHook represents a release event. This is + // currently a GitHub-specific event type. + ReleaseHook struct { + Action Action + Release Release + Repo Repository + Sender User + } + // PingHook represents a ping hook, eg ping events. PingHook struct { Repo Repository @@ -146,4 +164,6 @@ func (h *IssueCommentHook) Repository() Repository { return h.Repo } func (h *PullRequestHook) Repository() Repository { return h.Repo } func (h *PullRequestCommentHook) Repository() Repository { return h.Repo } func (h *ReviewCommentHook) Repository() Repository { return h.Repo } +func (h *ReleaseHook) Repository() Repository { return h.Repo } +func (h *PipelineHook) Repository() Repository { return h.Repo } func (h *PingHook) Repository() Repository { return h.Repo }