diff --git a/.drone.yml b/.drone.yml index 4a688bf36..f723ac8f8 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,15 +1,56 @@ +--- kind: pipeline +type: vm name: default -workspace: - base: /go - path: src/github.com/drone/go-scm - +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.11 + 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: - - go get github.com/google/go-cmp/cmp - - go get github.com/h2non/gock - - go test -cover github.com/drone/go-scm/scm/... + - 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/.github_changelog_generator b/.github_changelog_generator new file mode 100644 index 000000000..3051fa60c --- /dev/null +++ b/.github_changelog_generator @@ -0,0 +1 @@ +since-tag=v1.15.1 diff --git a/.gitignore b/.gitignore index cbc620eda..2cada1ba5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ *.out _*.md .vscode +.idea cmd \ No newline at end of file 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 2311d619d..d63a81137 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,596 @@ # 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) + +**Implemented enhancements:** + +- Add the support to fetch commit of a particular file [\#182](https://github.com/drone/go-scm/pull/182) ([DeepakPatankar](https://github.com/DeepakPatankar)) + +**Fixed bugs:** + +- 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) + +**Implemented enhancements:** + +- \[feat\]: \[PL-24913\]: Add the support for create and update file in bitbucket server [\#177](https://github.com/drone/go-scm/pull/177) ([DeepakPatankar](https://github.com/DeepakPatankar)) +- \[feat\]: \[PL-24915\]: Add the support for create branches in bitbucket server [\#174](https://github.com/drone/go-scm/pull/174) ([DeepakPatankar](https://github.com/DeepakPatankar)) +- \[PL-24911\]: Make project name as optional param in Azure Repo APIs [\#173](https://github.com/drone/go-scm/pull/173) ([DeepakPatankar](https://github.com/DeepakPatankar)) + +**Fixed bugs:** + +- \[feat\]: \[PL-25025\]: Updated Project validation for Azure API [\#179](https://github.com/drone/go-scm/pull/179) ([mankrit-singh](https://github.com/mankrit-singh)) +- \[fix\]: \[PL-24880\]: Trim the ref when fetching default branch in get Repo API [\#172](https://github.com/drone/go-scm/pull/172) ([DeepakPatankar](https://github.com/DeepakPatankar)) +- fixbug: gitee populatePageValues [\#167](https://github.com/drone/go-scm/pull/167) ([kit101](https://github.com/kit101)) + +**Closed issues:** + +- gitea find commit [\#125](https://github.com/drone/go-scm/issues/125) + +**Merged pull requests:** + +- \[feat\]: \[PL-25025\]: Changelog Updated/New Version [\#180](https://github.com/drone/go-scm/pull/180) ([mankrit-singh](https://github.com/mankrit-singh)) + +## [v1.21.1](https://github.com/drone/go-scm/tree/v1.21.1) (2022-04-22) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.21.0...v1.21.1) + +**Fixed bugs:** + +- remove double invocation of convertRepository [\#170](https://github.com/drone/go-scm/pull/170) ([d1wilko](https://github.com/d1wilko)) + +**Merged pull requests:** + +- \(maint\) release prep for 1.21.1 [\#171](https://github.com/drone/go-scm/pull/171) ([d1wilko](https://github.com/d1wilko)) + +## [v1.21.0](https://github.com/drone/go-scm/tree/v1.21.0) (2022-04-22) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.20.0...v1.21.0) + +**Implemented enhancements:** + +- Add support for repository find in azure [\#164](https://github.com/drone/go-scm/pull/164) ([goelsatyam2](https://github.com/goelsatyam2)) +- \(feat\) add azure webhook parsing, creation deletion & list [\#163](https://github.com/drone/go-scm/pull/163) ([tphoney](https://github.com/tphoney)) +- \(DRON-242\) azure add compare commits,get commit,list repos [\#162](https://github.com/drone/go-scm/pull/162) ([tphoney](https://github.com/tphoney)) + +**Fixed bugs:** + +- \(fix\) handle nil repos in github responses [\#168](https://github.com/drone/go-scm/pull/168) ([tphoney](https://github.com/tphoney)) + +**Closed issues:** + +- When attempting to clone my git repo from GitLab drone hangs on git fetch. [\#161](https://github.com/drone/go-scm/issues/161) +- Fix dump response [\#119](https://github.com/drone/go-scm/issues/119) + +**Merged pull requests:** + +- \(maint\) release prep for 1.21.0 [\#169](https://github.com/drone/go-scm/pull/169) ([d1wilko](https://github.com/d1wilko)) + +## [v1.20.0](https://github.com/drone/go-scm/tree/v1.20.0) (2022-03-08) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.19.1...v1.20.0) + +**Implemented enhancements:** + +- \(DRON-242\) initial implementation of azure devops support [\#158](https://github.com/drone/go-scm/pull/158) ([tphoney](https://github.com/tphoney)) + +**Fixed bugs:** + +- fixed raw response dumping in client [\#159](https://github.com/drone/go-scm/pull/159) ([marko-gacesa](https://github.com/marko-gacesa)) + +**Merged pull requests:** + +- \(maint\) release prep for 1.20.0 [\#160](https://github.com/drone/go-scm/pull/160) ([d1wilko](https://github.com/d1wilko)) + +## [v1.19.1](https://github.com/drone/go-scm/tree/v1.19.1) (2022-02-23) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.19.0...v1.19.1) + +**Fixed bugs:** + +- Bitbucket list files fix [\#154](https://github.com/drone/go-scm/pull/154) ([mohitg0795](https://github.com/mohitg0795)) +- GitHub list commits fix [\#152](https://github.com/drone/go-scm/pull/152) ([mohitg0795](https://github.com/mohitg0795)) +- Bitbucket compare changes fix for rename and removed file ops [\#151](https://github.com/drone/go-scm/pull/151) ([mohitg0795](https://github.com/mohitg0795)) + +**Merged pull requests:** + +- prep for v1.19.1 [\#155](https://github.com/drone/go-scm/pull/155) ([tphoney](https://github.com/tphoney)) + +## [v1.19.0](https://github.com/drone/go-scm/tree/v1.19.0) (2022-02-09) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.18.0...v1.19.0) + +**Implemented enhancements:** + +- \(feat\) add path support for list commits on github and gitlab [\#149](https://github.com/drone/go-scm/pull/149) ([tphoney](https://github.com/tphoney)) +- Extending bitbucket listCommits API to fetch commits for a given file [\#148](https://github.com/drone/go-scm/pull/148) ([mohitg0795](https://github.com/mohitg0795)) +- Update GitHub signature header to use sha256 [\#123](https://github.com/drone/go-scm/pull/123) ([nlecoy](https://github.com/nlecoy)) + +**Merged pull requests:** + +- v1.19.0 release prep [\#150](https://github.com/drone/go-scm/pull/150) ([tphoney](https://github.com/tphoney)) + +## [v1.18.0](https://github.com/drone/go-scm/tree/v1.18.0) (2022-01-18) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.17.0...v1.18.0) + +**Implemented enhancements:** + +- Added support for parsing prevFilePath field from github compare commits API response [\#143](https://github.com/drone/go-scm/pull/143) ([mohitg0795](https://github.com/mohitg0795)) + +**Fixed bugs:** + +- Implement parsing/handling for missing pull request webhook events for BitBucket Server \(Stash\) driver [\#130](https://github.com/drone/go-scm/pull/130) ([raphendyr](https://github.com/raphendyr)) + +**Closed issues:** + +- Bitbucket Stash driver doesn't handle event `pr:from_ref_updated` \(new commits / force push\) [\#116](https://github.com/drone/go-scm/issues/116) + +**Merged pull requests:** + +- release prep v1.18.0 [\#147](https://github.com/drone/go-scm/pull/147) ([eoinmcafee00](https://github.com/eoinmcafee00)) + +## [v1.17.0](https://github.com/drone/go-scm/tree/v1.17.0) (2022-01-07) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.16.3...v1.17.0) + +**Implemented enhancements:** + +- \(feat\) map archive flag to repo response [\#141](https://github.com/drone/go-scm/pull/141) ([eoinmcafee00](https://github.com/eoinmcafee00)) +- Add the support for delete of the bitbucket file [\#139](https://github.com/drone/go-scm/pull/139) ([DeepakPatankar](https://github.com/DeepakPatankar)) + +**Fixed bugs:** + +- Fix the syntax error of the example code [\#135](https://github.com/drone/go-scm/pull/135) ([LinuxSuRen](https://github.com/LinuxSuRen)) + +**Closed issues:** + +- The deprecation of Bitbucket API endpoint /2.0/teams breaks user registration [\#136](https://github.com/drone/go-scm/issues/136) + +**Merged pull requests:** + +- release prep for v1.17.0 [\#142](https://github.com/drone/go-scm/pull/142) ([eoinmcafee00](https://github.com/eoinmcafee00)) + +## [v1.16.3](https://github.com/drone/go-scm/tree/v1.16.3) (2021-12-30) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.16.2...v1.16.3) + +**Fixed bugs:** + +- fix the deprecation of Bitbucket API endpoint /2.0/teams breaks user registration \(136\) [\#137](https://github.com/drone/go-scm/pull/137) ([eoinmcafee00](https://github.com/eoinmcafee00)) + +**Closed issues:** + +- Any plans to support manage wehook [\#134](https://github.com/drone/go-scm/issues/134) + +**Merged pull requests:** + +- V1.16.3 [\#138](https://github.com/drone/go-scm/pull/138) ([eoinmcafee00](https://github.com/eoinmcafee00)) + +## [v1.16.2](https://github.com/drone/go-scm/tree/v1.16.2) (2021-11-30) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.16.1...v1.16.2) + +**Merged pull requests:** + +- release prep v1.16.2 [\#132](https://github.com/drone/go-scm/pull/132) ([marko-gacesa](https://github.com/marko-gacesa)) +- fixbug: gitee webhook parse [\#131](https://github.com/drone/go-scm/pull/131) ([kit101](https://github.com/kit101)) + +## [v1.16.1](https://github.com/drone/go-scm/tree/v1.16.1) (2021-11-19) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.16.0...v1.16.1) + +**Fixed bugs:** + +- swap repo and target in bitbucket CompareChanges [\#127](https://github.com/drone/go-scm/pull/127) ([jimsheldon](https://github.com/jimsheldon)) + +**Merged pull requests:** + +- release prep v1.16.1 [\#129](https://github.com/drone/go-scm/pull/129) ([eoinmcafee00](https://github.com/eoinmcafee00)) + +## [v1.16.0](https://github.com/drone/go-scm/tree/v1.16.0) (2021-11-19) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.15.2...v1.16.0) + +**Implemented enhancements:** + +- release prep for 1.16.0 [\#128](https://github.com/drone/go-scm/pull/128) ([eoinmcafee00](https://github.com/eoinmcafee00)) +- Feat: implemented gitee provider [\#124](https://github.com/drone/go-scm/pull/124) ([kit101](https://github.com/kit101)) +- add release & milestone functionality [\#121](https://github.com/drone/go-scm/pull/121) ([eoinmcafee00](https://github.com/eoinmcafee00)) + +**Fixed bugs:** + +- Fix Gitea example code on README.md [\#126](https://github.com/drone/go-scm/pull/126) ([lunny](https://github.com/lunny)) + +## [v1.15.2](https://github.com/drone/go-scm/tree/v1.15.2) (2021-07-20) + +[Full Changelog](https://github.com/drone/go-scm/compare/v1.15.1...v1.15.2) + +**Fixed bugs:** + +- Fixing Gitea commit API in case `ref/heads/` prefix is added to ref [\#108](https://github.com/drone/go-scm/pull/108) ([Vici37](https://github.com/Vici37)) +- use access json header / extend error message parsing for stash [\#89](https://github.com/drone/go-scm/pull/89) ([bakito](https://github.com/bakito)) + +**Closed issues:** + +- Drone and Bitbucket broken for write permission detection for drone build restart permission. [\#87](https://github.com/drone/go-scm/issues/87) + +**Merged pull requests:** + +- \(maint\) prep for v.1.15.2 release [\#118](https://github.com/drone/go-scm/pull/118) ([tphoney](https://github.com/tphoney)) +- Add a vet step to drone config [\#83](https://github.com/drone/go-scm/pull/83) ([tboerger](https://github.com/tboerger)) + All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 1.15.1 +### Added +- (DRON-88) github fix pr ListChanges deleted/renamed status, from [@tphoney](https://github.com/tphoney). See [#113](https://github.com/drone/go-scm/pull/113). +- (DRON-84) github fix pr write permission issue with bitbucket server, from [@eoinmcafee0](https://github.com/eoinmcafee00). See [#114](https://github.com/drone/go-scm/pull/114). + +## 1.15.0 +### Added +- add delete file for github and gitlab, from [@tphoney](https://github.com/tphoney). See [#110](https://github.com/drone/go-scm/pull/110). + +## 1.14.1 +### Fixed +- fix gitlab repo encoding in commits from pr request, from [@aradisavljevic](https://github.com/aradisavljevic). See [#109](https://github.com/drone/go-scm/pull/109). + +## 1.14.0 +### Added +- Added ListCommits in pull request api, from [@aradisavljevic](https://github.com/aradisavljevic). See [#106](https://github.com/drone/go-scm/pull/106). + +## 1.13.1 +### Fixed +- gitlab, content.find return last_commit_id not commit_id, from [@tphoney](https://github.com/tphoney). See [#104](https://github.com/drone/go-scm/pull/104). + +## 1.13.0 +### Added +- Create branch functionality, from [@tphoney](https://github.com/tphoney). See [#103](https://github.com/drone/go-scm/pull/103). + +## 1.12.0 +### Added +- return sha/blob_id for content.list, from [@tphoney](https://github.com/tphoney). See [#102](https://github.com/drone/go-scm/pull/102). + +## 1.11.0 +### Added +- normalise sha in content, add bitbucket create/update, from [@tphoney](https://github.com/tphoney). See [#101](https://github.com/drone/go-scm/pull/101). + +## 1.10.0 +### Added +- return hash/object_id for files changed in github, from [@tphoney](https://github.com/tphoney). See [#99](https://github.com/drone/go-scm/pull/99). + +## 1.9.0 +### Added +- Added issue_comment parsing for github webhook, from [@aman-harness](https://github.com/aman-harness). See [#91](https://github.com/drone/go-scm/pull/91). +- Added Pr in issue, from [@aman-harness](https://github.com/aman-harness). See [#93](https://github.com/drone/go-scm/pull/93). +- gitlab contents. Find returns hash/blob, from [@tphoney](https://github.com/tphoney). See [#97](https://github.com/drone/go-scm/pull/97). +- add ListCommits for gitea and stash, from [@tphoney](https://github.com/tphoney). See [#98](https://github.com/drone/go-scm/pull/98). + +### Changed +- retry with event subset for legacy stash versions, from [@bakito](https://github.com/bakito). See [#90](https://github.com/drone/go-scm/pull/90). + ## 1.8.0 ### Added - Support for GitLab visibility attribute, from [@bradrydzewski](https://github.com/bradrydzewski). See [79951ad](https://github.com/drone/go-scm/commit/79951ad7a0d0b1989ea84d99be31fcb9320ae348). @@ -76,3 +663,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix missing avatar in Gitea commit from [@jgeek1011](https://github.com/geek1011). - Implement GET commit endpoint for Gogs from [@ogarcia](https://github.com/ogarcia). + + +\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* diff --git a/HISTORY.md b/HISTORY.md new file mode 100644 index 000000000..2bcfdc061 --- /dev/null +++ b/HISTORY.md @@ -0,0 +1,125 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 1.15.1 +### Added +- (DRON-88) github fix pr ListChanges deleted/renamed status, from [@tphoney](https://github.com/tphoney). See [#113](https://github.com/drone/go-scm/pull/113). +- (DRON-84) github fix pr write permission issue with bitbucket server, from [@eoinmcafee0](https://github.com/eoinmcafee00). See [#114](https://github.com/drone/go-scm/pull/114). + +## 1.15.0 +### Added +- add delete file for github and gitlab, from [@tphoney](https://github.com/tphoney). See [#110](https://github.com/drone/go-scm/pull/110). + +## 1.14.1 +### Fixed +- fix gitlab repo encoding in commits from pr request, from [@aradisavljevic](https://github.com/aradisavljevic). See [#109](https://github.com/drone/go-scm/pull/109). + +## 1.14.0 +### Added +- Added ListCommits in pull request api, from [@aradisavljevic](https://github.com/aradisavljevic). See [#106](https://github.com/drone/go-scm/pull/106). + +## 1.13.1 +### Fixed +- gitlab, content.find return last_commit_id not commit_id, from [@tphoney](https://github.com/tphoney). See [#104](https://github.com/drone/go-scm/pull/104). + +## 1.13.0 +### Added +- Create branch functionality, from [@tphoney](https://github.com/tphoney). See [#103](https://github.com/drone/go-scm/pull/103). + +## 1.12.0 +### Added +- return sha/blob_id for content.list, from [@tphoney](https://github.com/tphoney). See [#102](https://github.com/drone/go-scm/pull/102). + +## 1.11.0 +### Added +- normalise sha in content, add bitbucket create/update, from [@tphoney](https://github.com/tphoney). See [#101](https://github.com/drone/go-scm/pull/101). + +## 1.10.0 +### Added +- return hash/object_id for files changed in github, from [@tphoney](https://github.com/tphoney). See [#99](https://github.com/drone/go-scm/pull/99). + +## 1.9.0 +### Added +- Added issue_comment parsing for github webhook, from [@aman-harness](https://github.com/aman-harness). See [#91](https://github.com/drone/go-scm/pull/91). +- Added Pr in issue, from [@aman-harness](https://github.com/aman-harness). See [#93](https://github.com/drone/go-scm/pull/93). +- gitlab contents. Find returns hash/blob, from [@tphoney](https://github.com/tphoney). See [#97](https://github.com/drone/go-scm/pull/97). +- add ListCommits for gitea and stash, from [@tphoney](https://github.com/tphoney). See [#98](https://github.com/drone/go-scm/pull/98). + +### Changed +- retry with event subset for legacy stash versions, from [@bakito](https://github.com/bakito). See [#90](https://github.com/drone/go-scm/pull/90). + +## 1.8.0 +### Added +- Support for GitLab visibility attribute, from [@bradrydzewski](https://github.com/bradrydzewski). See [79951ad](https://github.com/drone/go-scm/commit/79951ad7a0d0b1989ea84d99be31fcb9320ae348). +- Support for GitHub visibility attribute, from [@bradrydzewski](https://github.com/bradrydzewski). See [5141b8e](https://github.com/drone/go-scm/commit/5141b8e1db921fe2101c12594c5159b9ffffebc3). + +### Changed +- Support for parsing unknown pull request events, from [@bradrydzewski](https://github.com/bradrydzewski). See [ffa46d9](https://github.com/drone/go-scm/commit/ffa46d955454baa609975eebbe9fdfc4b0a9f7e9). + +## 1.7.2 +### Added +- Support for finding and listing repository tags in GitHub driver, from [@chhsia0](https://github.com/chhsia0). See [#79](https://github.com/drone/go-scm/pull/79). +- Support for finding and listing repository tags in Gitea driver, from [@bradyrdzewski](https://github.com/bradyrdzewski). See [427b8a8](https://github.com/drone/go-scm/commit/427b8a85897c892148801824760bc66d3a3cdcdb). +- Support for git object hashes in GitHub, from from [@bradyrdzewski](https://github.com/bradyrdzewski). See [5230330](https://github.com/drone/go-scm/commit/523033025a7ee875fcfb156f4c660b37e269b1a8). +- Support for before and after commit sha in Stash driver, from [@jlehtimaki](https://github.com/jlehtimaki). See [#82](https://github.com/drone/go-scm/pull/82). +- Support for before and after commit sha in GitLab and Bitbucket driver, from [@shubhag](https://github.com/shubhag). See [#85](https://github.com/drone/go-scm/pull/85). + +## 1.7.1 +### Added +- Support for skip verification in Bitbucket webhook creation, from [@chhsia0](https://github.com/chhsia0). See [#63](https://github.com/drone/go-scm/pull/63). +- Support for Gitea pagination, from [@CirnoT](https://github.com/CirnoT). See [#66](https://github.com/drone/go-scm/pull/66). +- Support for labels in pull request resources, from [@takirala](https://github.com/takirala). See [#67](https://github.com/drone/go-scm/pull/67). +- Support for updating webhooks, from [@chhsia0](https://github.com/chhsia0). See [#71](https://github.com/drone/go-scm/pull/71). + +### Fixed +- Populate diff links in pull request resources, from [@shubhag](https://github.com/shubhag). See [#75](https://github.com/drone/go-scm/pull/75). +- Filter Bitbucket repository search by project, from [@bradrydzewski](https://github.com/bradrydzewski). + +## 1.7.0 +### Added +- Improve status display text in new bitbucket pull request screen, from [@bradrydzewski](https://github.com/bradrydzewski). See [#27](https://github.com/drone/go-scm/issues/27). +- Implement timestamp value for GitHub push webhooks, from [@bradrydzewski](https://github.com/bradrydzewski). +- Implement deep link to branch. +- Implement git compare function to compare two separate commits, from [@chhsia0](https://github.com/chhsia0). +- Implement support for creating and updating GitLab and GitHub repository contents, from [@zhuxiaoyang](https://github.com/zhuxiaoyang). +- Capture Repository link for Gitea, Gogs and Gitlab, from [@chhsia0](https://github.com/chhsia0). + +### Fixed +- Fix issue with GitHub enterprise deep link including API prefix, from [@bradrydzewski](https://github.com/bradrydzewski). +- Fix issue with GitHub deploy hooks for commits having an invalid reference, from [@bradrydzewski](https://github.com/bradrydzewski). +- Support for Skipping SSL verification for GitLab webhooks. See [#40](https://github.com/drone/go-scm/pull/40). +- Support for Skipping SSL verification for GitHub webhooks. See [#44](https://github.com/drone/go-scm/pull/40). +- Fix issue with handling slashes in Bitbucket branch names. See [#7](https://github.com/drone/go-scm/pull/47). +- Fix incorrect Gitea tag link. See [#52](https://github.com/drone/go-scm/pull/52). +- Encode ref when making Gitea API calls. See [#61](https://github.com/drone/go-scm/pull/61). + +## [1.6.0] +### Added +- Support Head and Base sha for GitHub pull request, from [@bradrydzewski](https://github.com/bradrydzewski). +- Support Before sha for Bitbucket, from [@jkdev81](https://github.com/jkdev81). +- Support for creating GitHub deployment hooks, from [@bradrydzewski](https://github.com/bradrydzewski). +- Endpoint to get organization membership for GitHub, from [@bradrydzewski](https://github.com/bradrydzewski). +- Functions to generate deep links to git resources, from [@bradrydzewski](https://github.com/bradrydzewski). + +### Fixed +- Fix issue getting a GitLab commit by ref, from [@bradrydzewski](https://github.com/bradrydzewski). + +## [1.5.0] +### Added + +- Fix missing sha for Gitea tag hooks, from [@techknowlogick](https://github.com/techknowlogick). See [#22](https://github.com/drone/go-scm/pull/22). +- Support for Gitea webhook signature verification, from [@techknowlogick](https://github.com/techknowlogick). + +## [1.4.0] +### Added + +- Fix issues base64 decoding GitLab content, from [@bradrydzewski](https://github.com/bradrydzewski). + +## [1.3.0] +### Added + +- Fix missing avatar in Gitea commit from [@jgeek1011](https://github.com/geek1011). +- Implement GET commit endpoint for Gogs from [@ogarcia](https://github.com/ogarcia). diff --git a/README.md b/README.md index 66349fb6c..a95de0461 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ +# go-scm + [![Go Doc](https://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](http://godoc.org/github.com/drone/go-scm/scm) -Package scm provides a unified interface to multiple source code management systems including GitHub, GitHub Enterprise, Bitbucket, Bitbucket Server, Gitea and Gogs. +Package scm provides a unified interface to multiple source code management systems including GitHub, GitHub Enterprise, Bitbucket, Bitbucket Server, Gitee, Gitea and Gogs. -# Getting Started +## Getting Started Create a GitHub client: @@ -10,12 +12,12 @@ Create a GitHub client: package main import ( - "github.com/drone/go-scm/scm" - "github.com/drone/go-scm/scm/driver/github" + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/github" ) func main() { - client := github.NewDefault() +client := github.NewDefault() } ``` @@ -23,8 +25,8 @@ Create a GitHub Enterprise client: ```Go import ( - "github.com/drone/go-scm/scm" - "github.com/drone/go-scm/scm/driver/github" + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/github" ) func main() { @@ -36,8 +38,8 @@ Create a Bitbucket client: ```Go import ( - "github.com/drone/go-scm/scm" - "github.com/drone/go-scm/scm/driver/bitbucket" + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/bitbucket" ) func main() { @@ -49,8 +51,8 @@ Create a Bitbucket Server (Stash) client: ```Go import ( - "github.com/drone/go-scm/scm" - "github.com/drone/go-scm/scm/driver/stash" + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/stash" ) func main() { @@ -62,50 +64,130 @@ Create a Gitea client: ```Go import ( - "github.com/drone/go-scm/scm" - "github.com/drone/go-scm/scm/driver/github" + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/gitea" ) func main() { - client, err := gitea.New("https://gitea.company.com") + client, err := gitea.New("https://gitea.company.com") } ``` -# Authentication +Create a Gitee client: -The scm client does not directly handle authentication. Instead, when creating a new client, provide a `http.Client` that can handle authentication for you. For convenience, this library includes oauth1 and oauth2 implementations that can be used to authenticate requests. +```Go +import ( + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/gitee" +) + +func main() { + client, err := gitee.New("https://gitee.com/api/v5") +} +``` + +## Authentication + +The scm client does not directly handle authentication. Instead, when creating a new client, provide an `http.Client` that can handle authentication for you. For convenience, this library includes oauth1 and oauth2 implementations that can be used to authenticate requests. ```Go package main import ( - "github.com/drone/go-scm/scm" - "github.com/drone/go-scm/scm/driver/github" - "github.com/drone/go-scm/scm/driver/transport/oauth2" + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/github" + "github.com/drone/go-scm/scm/transport" + "github.com/drone/go-scm/scm/transport/oauth2" ) func main() { - client := github.NewDefault() - - // provide a custom http.Client with a transport - // that injects the oauth2 token. - client.Client := &http.Client{ - Transport: &Transport{ - Source: StaticTokenSource( - &scm.Token{ - Token: "ecf4c1f9869f59758e679ab54b4", - }, - ), - }, - } - - // provide a custom http.Client with a transport - // that injects the private GitLab token through - // the PRIVATE_TOKEN header variable. - client.Client := &http.Client{ - Transport: &PrivateToken{ - Token: "ecf4c1f9869f59758e679ab54b4", - }, - } + client := github.NewDefault() + + // provide a custom http.Client with a transport + // that injects the oauth2 token. + client.Client = &http.Client{ + Transport: &oauth2.Transport{ + Source: oauth2.StaticTokenSource( + &scm.Token{ + Token: "ecf4c1f9869f59758e679ab54b4", + }, + ), + }, + } + + // provide a custom http.Client with a transport + // that injects the private GitLab token through + // the PRIVATE_TOKEN header variable. + client.Client = &http.Client{ + Transport: &transport.PrivateToken{ + Token: "ecf4c1f9869f59758e679ab54b4", + }, + } } ``` + +## Usage + +The scm client exposes dozens of endpoints for working with repositories, issues, comments, files and more. Please see the [godocs](https://pkg.go.dev/github.com/drone/go-scm/scm#pkg-examples) to learn more. + +Example code to get an issue: + +```Go +issue, _, err := client.Issues.Find(ctx, "octocat/Hello-World", 1) +``` + +Example code to get a list of issues: + +```Go +opts := scm.IssueListOptions{ + Page: 1, + Size: 30, + Open: true, + Closed: false, +} + +issues, _, err := client.Issues.List(ctx, "octocat/Hello-World", opts) +``` + +Example code to create an issue comment: + +```Go +in := &scm.CommentInput{ + Body: "Found a bug", +} + +comment, _, err := client.Issues.CreateComment(ctx, "octocat/Hello-World", 1, in) +``` + +## Useful links + +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) +- [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/#/) +- [Gitee API](https://gitee.com/api/swagger/#/) +- [Github API](https://docs.github.com/en/rest/reference) +- [Gitlab API](https://docs.gitlab.com/ee/api/api_resources.html) +- [Gogs API](https://github.com/gogs/docs-api) + +## Release procedure + +Run the changelog generator. + +```BASH +docker run -it --rm -v "$(pwd)":/usr/local/src/your-app githubchangeloggenerator/github-changelog-generator -u drone -p go-scm -t +``` + +You can generate a token by logging into your GitHub account and going to Settings -> Personal access tokens. + +Next we tag the PR's with the fixes or enhancements labels. If the PR does not fufil the requirements, do not add a label. + +Run the changelog generator again with the future version according to semver. + +```BASH +docker run -it --rm -v "$(pwd)":/usr/local/src/your-app githubchangeloggenerator/github-changelog-generator -u drone -p go-scm -t --future-release v1.15.2 +``` + +Create your pull request for the release. Get it merged then tag the release. diff --git a/go.mod b/go.mod index cd3f85a78..1a7e7c5ea 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/drone/go-scm require ( github.com/google/go-cmp v0.2.0 github.com/h2non/gock v1.0.9 + github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 // indirect ) go 1.13 diff --git a/go.sum b/go.sum index 5f9a39cba..6d69376b6 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,6 @@ 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/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/h2non/gock v1.0.9 h1:17gCehSo8ZOgEsFKpQgqHiR7VLyjxdAG3lkhVvO9QZU= -github.com/h2non/gock v1.0.9/go.mod h1:CZMcB0Lg5IWnr9bF79pPMg9WeV6WumxQiUJ1UvdO1iE= \ No newline at end of file +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= diff --git a/scm/client.go b/scm/client.go index e6cbc5ae9..0d05b3b9a 100644 --- a/scm/client.go +++ b/scm/client.go @@ -10,6 +10,7 @@ import ( "io" "net/http" "net/url" + "os" "strconv" "strings" "sync" @@ -67,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 { @@ -93,8 +114,10 @@ type ( Git GitService Organizations OrganizationService Issues IssueService + Milestones MilestoneService PullRequests PullRequestService Repositories RepositoryService + Releases ReleaseService Reviews ReviewService Users UserService Webhooks WebhookService @@ -165,7 +188,9 @@ func (c *Client) Do(ctx context.Context, in *Request) (*Response, error) { // dumps the response for debugging purposes. if c.DumpResponse != nil { - c.DumpResponse(res, true) + if raw, errDump := c.DumpResponse(res, true); errDump == nil { + _, _ = os.Stdout.Write(raw) + } } return newResponse(res), nil } diff --git a/scm/const.go b/scm/const.go index ac81da919..73fa7a9e6 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 } @@ -121,6 +149,9 @@ const ( DriverBitbucket DriverStash DriverCoding + DriverGitee + DriverAzure + DriverHarness ) // String returns the string representation of Driver. @@ -140,6 +171,12 @@ func (d Driver) String() (s string) { return "stash" case DriverCoding: return "coding" + case DriverGitee: + return "gitee" + case DriverAzure: + return "azure" + case DriverHarness: + return "harness" default: return "unknown" } @@ -195,6 +232,11 @@ func (k ContentKind) String() string { } } +// MarshalJSON returns the JSON-encoded Action. +func (k ContentKind) MarshalJSON() ([]byte, error) { + return json.Marshal(k.String()) +} + // UnmarshalJSON unmarshales the JSON-encoded ContentKind. func (k *ContentKind) UnmarshalJSON(data []byte) error { var s string @@ -240,3 +282,5 @@ func (v Visibility) String() (s string) { return "unknown" } } + +const SearchTimeFormat = "2006-01-02T15:04:05Z" diff --git a/scm/content.go b/scm/content.go index e28dc7b56..2d5cb6fde 100644 --- a/scm/content.go +++ b/scm/content.go @@ -9,12 +9,10 @@ import "context" type ( // Content stores the contents of a repository file. Content struct { - Path string - Data []byte - - // the has of the blob. this is the equivalent - // to running the git hash-object command. - Hash string + Path string + Data []byte + Sha string + BlobID string } // ContentParams provide parameters for creating and @@ -25,13 +23,16 @@ type ( Message string Data []byte Sha string + BlobID string Signature Signature } // ContentInfo stores the kind of any content in a repository. ContentInfo struct { - Path string - Kind ContentKind + Path string + Sha string + BlobID string + Kind ContentKind } // ContentService provides access to repositroy content. @@ -39,14 +40,14 @@ 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(ctx context.Context, repo, path, ref string) (*Response, error) + // 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 // up to the driver to list the directory recursively or non-recursively, diff --git a/scm/driver/azure/azure.go b/scm/driver/azure/azure.go new file mode 100644 index 000000000..e762a6db1 --- /dev/null +++ b/scm/driver/azure/azure.go @@ -0,0 +1,126 @@ +// 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 azure implements a azure client. +package azure + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "net/url" + "strings" + + "github.com/drone/go-scm/scm" +) + +// New returns a new azure API client. +func New(uri, owner, 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 + "/" + } + if owner == "" { + return nil, fmt.Errorf("azure owner is required") + } + client := &wrapper{ + new(scm.Client), + owner, + project, + } + client.BaseURL = base + // initialize services + client.Driver = scm.DriverAzure + client.Linker = &linker{base.String()} + client.Contents = &contentService{client} + client.Git = &gitService{client} + client.Issues = &issueService{client} + client.Organizations = &organizationService{client} + client.PullRequests = &pullService{&issueService{client}} + client.Repositories = &RepositoryService{client} + client.Reviews = &reviewService{client} + client.Users = &userService{client} + client.Webhooks = &webhookService{client} + return client.Client, nil +} + +// NewDefault returns a new azure API client. +func NewDefault(owner, project string) *scm.Client { + client, _ := New("https://dev.azure.com", owner, project) + return client +} + +// wrapper wraps the Client to provide high level helper functions for making http requests and unmarshaling the response. +type wrapper struct { + *scm.Client + owner 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() + + // error response. + if res.Status > 300 { + err := new(Error) + _ = json.NewDecoder(res.Body).Decode(err) + return res, err + } + // the following is used for debugging purposes. + // bytes, err := io.ReadAll(res.Body) + // if err != nil { + // log.Fatal(err) + // } + // fmt.Println(string(bytes)) + + if out == nil { + return res, nil + } + // if a json response is expected, parse and return the json response. + decodeErr := json.NewDecoder(res.Body).Decode(out) + // following line is used for debugging purposes. + //_ = json.NewEncoder(os.Stdout).Encode(out) + return res, decodeErr +} + +// Error represents am Azure error. +type Error struct { + Message string `json:"message"` +} + +func (e *Error) Error() string { + return e.Message +} + +func ProjectRequiredError() error { + return errors.New("This API endpoint requires a project to be specified") +} + +func SanitizeBranchName(name string) string { + return "refs/heads/" + name +} diff --git a/scm/driver/azure/azure_test.go b/scm/driver/azure/azure_test.go new file mode 100644 index 000000000..c3cc56732 --- /dev/null +++ b/scm/driver/azure/azure_test.go @@ -0,0 +1,71 @@ +// 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 azure + +import ( + "testing" +) + +func TestClient_Base(t *testing.T) { + client, err := New("https://dev.azure.com", "org", "proj") + if err != nil { + t.Error(err) + } + got, want := client.BaseURL.String(), "https://dev.azure.com/" + if got != want { + t.Errorf("Want Client URL %q, got %q", want, got) + } +} + +func TestClient_Default(t *testing.T) { + client := NewDefault("org", "proj") + if got, want := client.BaseURL.String(), "https://dev.azure.com/"; got != want { + t.Errorf("Want Client URL %q, got %q", want, got) + } +} + +func TestClient_azure_special(t *testing.T) { + client, _ := New("https://dev.azure.com", "org", "") + if got, want := client.BaseURL.String(), "https://dev.azure.com/"; got != want { + t.Errorf("Want Client URL %q, got %q", want, got) + } + client2, _ := New("https://dev.azure.com", "", "proj") + if client2 != nil { + t.Errorf("Want nil client, got %v", client2) + } +} + +func TestSanitizeBranchName(t *testing.T) { + type args struct { + name string + } + tests := []struct { + name string + args args + want string + }{ + { + "master", + args{ + "master", + }, + "refs/heads/master", + }, + { + "feature/main-patch", + args{ + "feature/main-patch", + }, + "refs/heads/feature/main-patch", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := SanitizeBranchName(tt.args.name); got != tt.want { + t.Errorf("SanitizeBranchName() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/scm/driver/azure/content.go b/scm/driver/azure/content.go new file mode 100644 index 000000000..b300049f6 --- /dev/null +++ b/scm/driver/azure/content.go @@ -0,0 +1,215 @@ +// 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 azure + +import ( + "context" + "encoding/base64" + "fmt" + "net/url" + + "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) { + // 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() + } + 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(urlEncodedRef) + endpoint += "&api-version=6.0" + out := new(content) + res, err := s.client.do(ctx, "GET", endpoint, nil, out) + data := []byte(out.Content) + return &scm.Content{ + Path: out.Path, + Data: data, + Sha: out.CommitID, + BlobID: out.ObjectID, + }, res, err +} + +func (s *contentService) Create(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { + if s.client.project == "" { + 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), + OldObjectID: params.Ref, + } + cha := change{ + ChangeType: "add", + } + cha.Item.Path = path + cha.NewContent.Content = base64.StdEncoding.EncodeToString(params.Data) + cha.NewContent.ContentType = "base64encoded" + + com := commit{ + Comment: params.Message, + Changes: []change{cha}, + } + in := &contentCreateUpdate{ + RefUpdates: []refUpdate{ref}, + Commits: []commit{com}, + } + + 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) { + if s.client.project == "" { + 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), + OldObjectID: params.Sha, + } + cha := change{ + ChangeType: "edit", + } + cha.Item.Path = path + cha.NewContent.Content = base64.StdEncoding.EncodeToString(params.Data) + cha.NewContent.ContentType = "base64encoded" + + com := commit{ + Comment: params.Message, + Changes: []change{cha}, + } + in := &contentCreateUpdate{ + RefUpdates: []refUpdate{ref}, + Commits: []commit{com}, + } + + 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) { + if s.client.project == "" { + 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), + OldObjectID: params.Sha, + } + change1 := change{ + ChangeType: "delete", + } + change1.Item.Path = path + com := commit{ + Comment: params.Message, + Changes: []change{change1}, + } + in := &contentCreateUpdate{ + RefUpdates: []refUpdate{ref}, + Commits: []commit{com}, + } + + 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) { + // 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?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) + return convertContentInfoList(out.Value), res, err +} + +type content struct { + ObjectID string `json:"objectId"` + GitObjectType string `json:"gitObjectType"` + CommitID string `json:"commitId"` + Path string `json:"path"` + Content string `json:"content"` + URL string `json:"url"` + Links struct { + Self struct { + Href string `json:"href"` + } `json:"self"` + Repository struct { + Href string `json:"href"` + } `json:"repository"` + Blob struct { + Href string `json:"href"` + } `json:"blob"` + } `json:"_links"` +} + +type contentList struct { + Count int `json:"count"` + Value []*content `json:"value"` +} +type refUpdate struct { + Name string `json:"name"` + OldObjectID string `json:"oldObjectId,omitempty"` +} +type change struct { + ChangeType string `json:"changeType"` + Item struct { + Path string `json:"path"` + } `json:"item"` + NewContent struct { + Content string `json:"content,omitempty"` + ContentType string `json:"contentType,omitempty"` + } `json:"newContent,omitempty"` +} +type commit struct { + Comment string `json:"comment"` + Changes []change `json:"changes"` +} +type contentCreateUpdate struct { + RefUpdates []refUpdate `json:"refUpdates"` + Commits []commit `json:"commits"` +} + +func convertContentInfoList(from []*content) []*scm.ContentInfo { + to := []*scm.ContentInfo{} + for _, v := range from { + to = append(to, convertContentInfo(v)) + } + return to +} +func convertContentInfo(from *content) *scm.ContentInfo { + to := &scm.ContentInfo{Path: from.Path} + switch from.GitObjectType { + case "blob": + to.Kind = scm.ContentKindFile + case "tree": + to.Kind = scm.ContentKindDirectory + default: + to.Kind = scm.ContentKindUnsupported + } + to.Path = from.Path + to.BlobID = from.ObjectID + to.Sha = from.CommitID + return to +} + +func generateURIFromRef(ref string) (uri string) { + if ref != "" { + if len(ref) == 40 { + return fmt.Sprintf("&versionDescriptor.versionType=commit&versionDescriptor.version=%s", ref) + } else { + return fmt.Sprintf("&versionDescriptor.versionType=branch&versionDescriptor.version=%s", ref) + } + } + return "" +} diff --git a/scm/driver/azure/content_test.go b/scm/driver/azure/content_test.go new file mode 100644 index 000000000..ad857ccd9 --- /dev/null +++ b/scm/driver/azure/content_test.go @@ -0,0 +1,203 @@ +package azure + +import ( + "context" + "encoding/json" + "io/ioutil" + "testing" + + "github.com/drone/go-scm/scm" + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestContentFind(t *testing.T) { + defer gock.Off() + + 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") + + client := NewDefault("ORG", "PROJ") + got, _, err := client.Contents.Find( + context.Background(), + "REPOID", + "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) + } +} + +func TestContentCreate(t *testing.T) { + defer gock.Off() + + gock.New("https:/dev.azure.com/"). + Post("/ORG/PROJ/_apis/git/repositories/REPOID/"). + Reply(201). + Type("application/json"). + File("testdata/content_create.json") + + params := &scm.ContentParams{ + Message: "my commit message", + Data: []byte("bXkgbmV3IGZpbGUgY29udGVudHM="), + } + + client := NewDefault("ORG", "PROJ") + res, err := client.Contents.Create( + context.Background(), + "REPOID", + "README", + params, + ) + + if err != nil { + t.Error(err) + return + } + + if res.Status != 201 { + t.Errorf("Unexpected Results") + } +} + +func TestContentUpdate(t *testing.T) { + defer gock.Off() + + gock.New("https:/dev.azure.com/"). + Post("/ORG/PROJ/_apis/git/repositories/REPOID/"). + Reply(200). + Type("application/json"). + File("testdata/content_update.json") + + params := &scm.ContentParams{ + Message: "a new commit message", + Data: []byte("bXkgdXBkYXRlZCBmaWxlIGNvbnRlbnRz"), + Sha: "95b966ae1c166bd92f8ae7d1c313e738c731dfc3", + } + + client := NewDefault("ORG", "PROJ") + res, err := client.Contents.Update( + context.Background(), + "REPOID", + "README", + params, + ) + + if err != nil { + t.Error(err) + return + } + + if res.Status != 200 { + t.Errorf("Unexpected Results") + } +} + +func TestContentDelete(t *testing.T) { + defer gock.Off() + + gock.New("https:/dev.azure.com/"). + Post("/ORG/PROJ/_apis/git/repositories/REPOID/"). + Reply(200). + Type("application/json"). + File("testdata/content_delete.json") + + params := &scm.ContentParams{ + Message: "a new commit message", + BlobID: "95b966ae1c166bd92f8ae7d1c313e738c731dfc3", + } + + client := NewDefault("ORG", "PROJ") + res, err := client.Contents.Delete( + context.Background(), + "REPOID", + "README", + params, + ) + + if err != nil { + t.Error(err) + return + } + + if res.Status != 200 { + t.Errorf("Unexpected Results") + } +} + +func TestContentList(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/content_list.json") + + client := NewDefault("ORG", "PROJ") + got, _, err := client.Contents.List( + context.Background(), + "REPOID", + "", + "", + scm.ListOptions{}, + ) + if err != nil { + t.Error(err) + return + } + + 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) + } +} + +func Test_generateURIFromRef(t *testing.T) { + type args struct { + ref string + } + tests := []struct { + name string + args args + wantUri string + }{ + { + name: "branch", + args: args{ref: "branch"}, + wantUri: "&versionDescriptor.versionType=branch&versionDescriptor.version=branch", + }, + { + name: "commit", + args: args{ref: "6bbcbc818c804d35b88a12bbd2ed297e41c4d10d"}, + wantUri: "&versionDescriptor.versionType=commit&versionDescriptor.version=6bbcbc818c804d35b88a12bbd2ed297e41c4d10d", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if gotUri := generateURIFromRef(tt.args.ref); gotUri != tt.wantUri { + t.Errorf("generateURIFromRef() = %v, want %v", gotUri, tt.wantUri) + } + }) + } +} diff --git a/scm/driver/azure/git.go b/scm/driver/azure/git.go new file mode 100644 index 000000000..af6656c13 --- /dev/null +++ b/scm/driver/azure/git.go @@ -0,0 +1,271 @@ +// 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 azure + +import ( + "context" + "fmt" + "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) { + // 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() + } + 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) + in[0].Name = scm.ExpandRef(params.Name, "refs/heads") + in[0].NewObjectID = params.Sha + in[0].OldObjectID = "0000000000000000000000000000000000000000" + return s.client.do(ctx, "POST", endpoint, in, nil) +} + +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, 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() + } + 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) + return convertCommit(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, _ 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?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 +} + +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() + } + 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) + } + if opts.Path != "" { + endpoint += fmt.Sprintf("searchCriteria.itemPath=%s&", opts.Path) + } + endpoint += "api-version=6.0" + + out := new(commitList) + res, err := s.client.do(ctx, "GET", endpoint, nil, &out) + return convertCommitList(out.Value), res, err +} + +func (s *gitService) ListTags(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Reference, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *gitService) ListChanges(ctx context.Context, repo, ref string, _ scm.ListOptions) ([]*scm.Change, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +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() + } + 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) + // add target + endpoint += fmt.Sprintf("targetVersion=%s&targetVersionType=commit&api-version=6.0", target) + out := new(compare) + res, err := s.client.do(ctx, "GET", endpoint, nil, &out) + + changes := out.Changes + return convertChangeList(changes), res, err +} + +type crudBranch []struct { + Name string `json:"name"` + OldObjectID string `json:"oldObjectId"` + NewObjectID string `json:"newObjectId"` +} + +type branchList struct { + Value []*branch `json:"value"` + Count int `json:"count"` +} + +type branch 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"` +} + +type commitList struct { + Value []*gitCommit `json:"value"` + Count int `json:"count"` +} +type gitCommit struct { + CommitID string `json:"commitId"` + Author struct { + Name string `json:"name"` + Email string `json:"email"` + Date time.Time `json:"date"` + } `json:"author"` + Committer struct { + Name string `json:"name"` + Email string `json:"email"` + Date time.Time `json:"date"` + } `json:"committer"` + Comment string `json:"comment"` + CommentTruncated bool `json:"commentTruncated"` + ChangeCounts struct { + Add int `json:"Add"` + Edit int `json:"Edit"` + Delete int `json:"Delete"` + } `json:"changeCounts"` + URL string `json:"url"` + RemoteURL string `json:"remoteUrl"` +} + +type file struct { + ChangeType string `json:"changeType"` + Item struct { + CommitID string `json:"commitId"` + GitObjectType string `json:"gitObjectType"` + IsFolder bool `json:"isFolder"` + ObjectID string `json:"objectId"` + OriginalObjectID string `json:"originalObjectId"` + Path string `json:"path"` + URL string `json:"url"` + } `json:"item"` +} + +type compare struct { + AheadCount int64 `json:"aheadCount"` + AllChangesIncluded bool `json:"allChangesIncluded"` + BaseCommit string `json:"baseCommit"` + BehindCount int64 `json:"behindCount"` + ChangeCounts struct { + Add int64 `json:"Add"` + Edit int64 `json:"Edit"` + } `json:"changeCounts"` + Changes []*file `json:"changes"` + CommonCommit string `json:"commonCommit"` + TargetCommit string `json:"targetCommit"` +} + +func convertBranchList(from []*branch) []*scm.Reference { + to := []*scm.Reference{} + for _, v := range from { + to = append(to, convertBranch(v)) + } + return to +} + +func convertBranch(from *branch) *scm.Reference { + return &scm.Reference{ + Name: scm.TrimRef(from.Name), + Path: from.Name, + Sha: from.ObjectID, + } +} + +func convertCommitList(from []*gitCommit) []*scm.Commit { + to := []*scm.Commit{} + for _, v := range from { + to = append(to, convertCommit(v)) + } + return to +} + +func convertCommit(from *gitCommit) *scm.Commit { + return &scm.Commit{ + Message: from.Comment, + 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, + }, + } +} + +func convertChangeList(from []*file) []*scm.Change { + to := []*scm.Change{} + for _, v := range from { + to = append(to, convertChange(v)) + } + return to +} + +func convertChange(from *file) *scm.Change { + returnVal := &scm.Change{ + Path: from.Item.Path, + } + switch from.ChangeType { + case "add": + returnVal.Added = true + case "delete": + returnVal.Deleted = true + case "rename": + returnVal.Renamed = true + } + + return returnVal +} diff --git a/scm/driver/azure/git_test.go b/scm/driver/azure/git_test.go new file mode 100644 index 000000000..f150dc38e --- /dev/null +++ b/scm/driver/azure/git_test.go @@ -0,0 +1,177 @@ +// 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 azure + +import ( + "context" + "encoding/json" + "io/ioutil" + "testing" + + "github.com/drone/go-scm/scm" + + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestGitFindCommit(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/commit.json") + + client := NewDefault("ORG", "PROJ") + + got, _, err := client.Git.FindCommit(context.Background(), "REPOID", "14897f4465d2d63508242b5cbf68aa2865f693e7") + if err != nil { + t.Error(err) + return + } + + 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 TestGitCreateBranch(t *testing.T) { + defer gock.Off() + + gock.New("https:/dev.azure.com/"). + Post("/ORG/PROJ/_apis/git/repositories/REPOID/"). + Reply(201). + Type("application/json"). + File("testdata/branch_create.json") + + params := &scm.ReferenceInput{ + Name: "test_branch", + Sha: "312797ba52425353dec56871a255e2a36fc96344", + } + + client := NewDefault("ORG", "PROJ") + res, err := client.Git.CreateBranch(context.Background(), "REPOID", params) + + if err != nil { + t.Error(err) + return + } + + if res.Status != 201 { + t.Errorf("Unexpected Results") + } +} + +func TestGitListCommits(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/commits.json") + + client := NewDefault("ORG", "PROJ") + got, _, err := client.Git.ListCommits(context.Background(), "REPOID", scm.CommitListOptions{}) + 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) + } +} + +func TestGitListBranches(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.json") + + client := NewDefault("ORG", "PROJ") + got, _, err := client.Git.ListBranches(context.Background(), "REPOID", scm.ListOptions{}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Reference{} + raw, _ := ioutil.ReadFile("testdata/branches.json.golden") + _ = json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +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() + + gock.New("https:/dev.azure.com/"). + Get("/ORG/PROJ/_apis/git/repositories/REPOID/"). + Reply(200). + Type("application/json"). + File("testdata/compare.json") + + client := NewDefault("ORG", "PROJ") + got, _, err := client.Git.CompareChanges(context.Background(), "REPOID", "9788e5ddf8b387cb79228628f34d8dc18582d606", "66df312dad61e84dd896d1e8d14ee3dce53b62f0", scm.ListOptions{}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Change{} + raw, _ := ioutil.ReadFile("testdata/compare.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/integration/content_test.go b/scm/driver/azure/integration/content_test.go new file mode 100644 index 000000000..b2b200052 --- /dev/null +++ b/scm/driver/azure/integration/content_test.go @@ -0,0 +1,132 @@ +package integration + +import ( + "context" + "fmt" + "net/http" + "testing" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/azure" + "github.com/drone/go-scm/scm/transport" +) + +func TestContentsFind(t *testing.T) { + if token == "" { + t.Skip("Skipping, Integration 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)) + }, + }, + } + content, response, err := client.Contents.Find(context.Background(), repoID, "README.md", "") + if err != nil { + t.Errorf("We got an error %v", err) + } + if content.Sha == "" { + t.Errorf("we did not get a sha back %v", content.Sha) + } + if response.Status != http.StatusOK { + t.Errorf("we did not get a 200 back %v", response.Status) + } +} + +func TestCreateUpdateDeleteFileAzure(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)) + }, + }, + } + // get latest commit first + currentCommit, commitErr := GetCurrentCommitOfBranch(client, "main") + if commitErr != nil { + t.Errorf("we got an error %v", commitErr) + } + // create a new file + createParams := scm.ContentParams{ + Message: "go-scm create crud file", + Data: []byte("hello"), + Branch: "refs/heads/main", + Ref: currentCommit, + } + createResponse, createErr := client.Contents.Create(context.Background(), repoID, "CRUD", &createParams) + if createErr != nil { + t.Errorf("Contents.Create we got an error %v", createErr) + } + if createResponse.Status != http.StatusCreated { + t.Errorf("Contents.Create we did not get a 201 back %v", createResponse.Status) + } + // get latest commit first + currentCommit, commitErr = GetCurrentCommitOfBranch(client, "main") + if commitErr != nil { + t.Errorf("we got an error %v", commitErr) + } + // update the file + updateParams := scm.ContentParams{ + Message: "go-scm update crud file", + Data: []byte("updated test data"), + Branch: "refs/heads/main", + Sha: currentCommit, + } + updateResponse, updateErr := client.Contents.Update(context.Background(), repoID, "CRUD", &updateParams) + if updateErr != nil { + t.Errorf("Contents.Update we got an error %v", updateErr) + } + if updateResponse.Status != http.StatusCreated { + t.Errorf("Contents.Update we did not get a 201 back %v", updateResponse.Status) + } + // get latest commit first + currentCommit, commitErr = GetCurrentCommitOfBranch(client, "main") + if commitErr != nil { + t.Errorf("we got an error %v", commitErr) + } + // delete the file + deleteParams := scm.ContentParams{ + Message: "go-scm delete crud file", + Branch: "refs/heads/main", + Sha: currentCommit, + } + deleteResponse, deleteErr := client.Contents.Delete(context.Background(), repoID, "CRUD", &deleteParams) + if deleteErr != nil { + t.Errorf("Contents.Delete we got an error %v", deleteErr) + } + if deleteResponse.Status != http.StatusCreated { + t.Errorf("Contents.Delete we did not get a 201 back %v", deleteResponse.Status) + } +} + +func TestListFiles(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)) + }, + }, + } + contentInfo, listResponse, listerr := client.Contents.List(context.Background(), + repoID, "", "", scm.ListOptions{}) + if listerr != nil { + t.Errorf("Contents.List we got an error %v", listerr) + } + if listResponse.Status != http.StatusOK { + t.Errorf("Contents.Delete we did not get a 200 back %v", listResponse.Status) + } + if 2 >= len(contentInfo) { + t.Errorf("Contents.List there should be at least 2 files %d", len(contentInfo)) + } + +} diff --git a/scm/driver/azure/integration/git_test.go b/scm/driver/azure/integration/git_test.go new file mode 100644 index 000000000..aeb9f41b8 --- /dev/null +++ b/scm/driver/azure/integration/git_test.go @@ -0,0 +1,154 @@ +package integration + +import ( + "context" + "fmt" + "net/http" + "testing" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/azure" + "github.com/drone/go-scm/scm/transport" +) + +func TestListBranches(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)) + }, + }, + } + references, response, listerr := client.Git.ListBranches(context.Background(), repoID, scm.ListOptions{}) + if listerr != nil { + t.Errorf("ListBranches got an error %v", listerr) + } + if response.Status != http.StatusOK { + t.Errorf("ListBranches did not get a 200 back %v", response.Status) + } + if len(references) < 1 { + t.Errorf("ListBranches should have at least 1 branch %d", len(references)) + } + if references[0].Sha == "" { + t.Errorf("ListBranches first entry did not get a sha back %v", references[0].Sha) + } +} + +func TestCreateBranch(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)) + }, + }, + } + currentCommit, commitErr := GetCurrentCommitOfBranch(client, "main") + if commitErr != nil { + t.Errorf("we got an error %v", commitErr) + } + input := &scm.ReferenceInput{ + Name: "test_branch", + Sha: currentCommit, + } + response, listerr := client.Git.CreateBranch(context.Background(), repoID, input) + if listerr != nil { + t.Errorf("CreateBranch got an error %v", listerr) + } + if response.Status != http.StatusOK { + t.Errorf("CreateBranch did not get a 200 back %v", response.Status) + } + +} + +func TestFindCommit(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)) + }, + }, + } + currentCommit, commitErr := GetCurrentCommitOfBranch(client, "main") + if commitErr != nil { + t.Errorf("we got an error %v", commitErr) + } + commit, response, listerr := client.Git.FindCommit(context.Background(), repoID, currentCommit) + if listerr != nil { + t.Errorf("FindCommit got an error %v", listerr) + } + if response.Status != http.StatusOK { + t.Errorf("FindCommit did not get a 200 back %v", response.Status) + } + if commit.Author.Name == "" { + t.Errorf("There is no author %v", commit.Author) + } +} + +func TestListCommits(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, listerr := client.Git.ListCommits(context.Background(), repoID, scm.CommitListOptions{}) + if listerr != nil { + t.Errorf("ListCommits got an error %v", listerr) + } + if response.Status != http.StatusOK { + t.Errorf("ListCommitsdid not get a 200 back %v", response.Status) + } + if len(commits) < 1 { + t.Errorf("Contents.List there should be at least 1 commit %d", len(commits)) + } + if commits[0].Sha == "" { + t.Errorf("Contents.List first entry did not get a sha back %v", commits[0].Sha) + } +} + +func TestCompareChanges(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)) + }, + }, + } + // get all the commits + commits, _, err := client.Git.ListCommits(context.Background(), repoID, scm.CommitListOptions{}) + if err != nil { + t.Errorf("we got an error %v", err) + } + // compare the last two commits + changes, response, listerr := client.Git.CompareChanges(context.Background(), repoID, commits[10].Sha, commits[0].Sha, scm.ListOptions{}) + if listerr != nil { + t.Errorf("CompareChanges got an error %v", listerr) + } + if response.Status != http.StatusOK { + t.Errorf("CompareChanges did not get a 200 back %v", response.Status) + } + if len(changes) == 0 { + t.Errorf("There is at least one change %d", len(changes)) + } +} diff --git a/scm/driver/azure/integration/integration.go b/scm/driver/azure/integration/integration.go new file mode 100644 index 000000000..682b35830 --- /dev/null +++ b/scm/driver/azure/integration/integration.go @@ -0,0 +1,25 @@ +package integration + +import ( + "context" + "os" + + "github.com/drone/go-scm/scm" +) + +var ( + client *scm.Client + token = os.Getenv("AZURE_TOKEN") + + organization = "tphoney" + project = "test_project" + repoID = "fde2d21f-13b9-4864-a995-83329045289a" +) + +func GetCurrentCommitOfBranch(client *scm.Client, branch string) (string, error) { + commit, _, err := client.Contents.List(context.Background(), repoID, "", "main", scm.ListOptions{}) + if err != nil { + return "", err + } + return commit[0].Sha, nil +} diff --git a/scm/driver/azure/integration/pr_test.go b/scm/driver/azure/integration/pr_test.go new file mode 100644 index 000000000..b82307340 --- /dev/null +++ b/scm/driver/azure/integration/pr_test.go @@ -0,0 +1,93 @@ +package integration + +import ( + "context" + "fmt" + "net/http" + "testing" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/azure" + "github.com/drone/go-scm/scm/transport" +) + +func TestCreatePR(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)) + }, + }, + } + input := &scm.PullRequestInput{ + Title: "test_pr", + Body: "test_pr_body", + Source: "pr_branch", + Target: "main", + } + outputPR, response, listerr := client.PullRequests.Create(context.Background(), repoID, input) + if listerr != nil { + t.Errorf("PullRequests.Create got an error %v", listerr) + } + if response.Status != http.StatusCreated { + t.Errorf("PullRequests.Create did not get a 201 back %v", response.Status) + } + if outputPR.Title != "test_pr" { + 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/integration/repo_test.go b/scm/driver/azure/integration/repo_test.go new file mode 100644 index 000000000..27f0bf543 --- /dev/null +++ b/scm/driver/azure/integration/repo_test.go @@ -0,0 +1,109 @@ +package integration + +import ( + "context" + "fmt" + "net/http" + "testing" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/azure" + "github.com/drone/go-scm/scm/transport" +) + +func TestListRepos(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)) + }, + }, + } + references, response, listerr := client.Repositories.List(context.Background(), scm.ListOptions{}) + if listerr != nil { + t.Errorf("List got an error %v", listerr) + } + if response.Status != http.StatusOK { + t.Errorf("List did not get a 200 back %v", response.Status) + } + if len(references) < 1 { + t.Errorf("List should have at least 1 repo %d", len(references)) + } +} + +func TestListHooks(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)) + }, + }, + } + hooks, response, listerr := client.Repositories.ListHooks(context.Background(), repoID, scm.ListOptions{}) + if listerr != nil { + t.Errorf("List got an error %v", listerr) + } + if response.Status != http.StatusOK { + t.Errorf("List did not get a 200 back %v", response.Status) + } + if len(hooks) < 1 { + t.Errorf("List should have at least 1 hook %d", len(hooks)) + } +} + +func TestCreateDeleteHooks(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)) + }, + }, + } + originalHooks, _, _ := client.Repositories.ListHooks(context.Background(), repoID, scm.ListOptions{}) + // create a new hook + inputHook := &scm.HookInput{ + Name: "web", + NativeEvents: []string{"git.push"}, + Target: "http://www.example.com/webhook", + } + outHook, createResponse, createErr := client.Repositories.CreateHook(context.Background(), repoID, inputHook) + if createErr != nil { + t.Errorf("Create got an error %v", createErr) + } + if createResponse.Status != http.StatusOK { + t.Errorf("Create did not get a 200 back %v", createResponse.Status) + } + if len(outHook.Events) != 1 { + t.Errorf("New hook has one event %d", len(outHook.Events)) + } + // get the hooks again, and make sure the new hook is there + afterCreate, _, _ := client.Repositories.ListHooks(context.Background(), repoID, scm.ListOptions{}) + if len(afterCreate) != len(originalHooks)+1 { + t.Errorf("After create, the number of hooks is not correct %d. It should be %d", len(afterCreate), len(originalHooks)+1) + } + // delete the hook we created + deleteResponse, deleteErr := client.Repositories.DeleteHook(context.Background(), repoID, outHook.ID) + if deleteErr != nil { + t.Errorf("Delete got an error %v", deleteErr) + } + if deleteResponse.Status != http.StatusNoContent { + t.Errorf("Delete did not get a 204 back, got %v", deleteResponse.Status) + } + // get the hooks again, and make sure the new hook is gone + afterDelete, _, _ := client.Repositories.ListHooks(context.Background(), repoID, scm.ListOptions{}) + if len(afterDelete) != len(originalHooks) { + t.Errorf("After Delete, the number of hooks is not correct %d. It should be %d", len(afterDelete), len(originalHooks)) + } +} diff --git a/scm/driver/azure/issue.go b/scm/driver/azure/issue.go new file mode 100644 index 000000000..6179d8312 --- /dev/null +++ b/scm/driver/azure/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 azure + +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, number int, input *scm.CommentInput) (*scm.Comment, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *issueService) DeleteComment(ctx context.Context, repo string, number, 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/azure/linker.go b/scm/driver/azure/linker.go new file mode 100644 index 000000000..fc08ef2cc --- /dev/null +++ b/scm/driver/azure/linker.go @@ -0,0 +1,25 @@ +// 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 azure + +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/azure/org.go b/scm/driver/azure/org.go new file mode 100644 index 000000000..9ad977b9b --- /dev/null +++ b/scm/driver/azure/org.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 azure + +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 +} diff --git a/scm/driver/azure/pr.go b/scm/driver/azure/pr.go new file mode 100644 index 000000000..d2e36c48f --- /dev/null +++ b/scm/driver/azure/pr.go @@ -0,0 +1,189 @@ +// 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 azure + +import ( + "context" + "fmt" + "time" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/internal/null" +) + +type pullService struct { + *issueService +} + +func (s *pullService) Find(ctx context.Context, repo string, number int) (*scm.PullRequest, *scm.Response, error) { + // 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) { + return nil, nil, scm.ErrNotSupported +} + +func (s *pullService) ListChanges(ctx context.Context, repo string, number int, opts scm.ListOptions) ([]*scm.Change, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *pullService) ListCommits(ctx context.Context, repo string, number int, opts scm.ListOptions) ([]*scm.Commit, *scm.Response, error) { + // 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) { + return nil, scm.ErrNotSupported +} + +func (s *pullService) Close(ctx context.Context, repo string, number int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + +func (s *pullService) Create(ctx context.Context, repo string, input *scm.PullRequestInput) (*scm.PullRequest, *scm.Response, error) { + // https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull-requests/create?view=azure-devops-rest-6.0 + endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/pullrequests?api-version=6.0", s.client.owner, s.client.project, repo) + in := &prInput{ + Title: input.Title, + Description: input.Body, + SourceRefName: scm.ExpandRef(input.Source, "refs/heads"), + TargetRefName: scm.ExpandRef(input.Target, "refs/heads"), + } + out := new(pr) + res, err := s.client.do(ctx, "POST", endpoint, in, out) + return convertPullRequest(out), res, err +} + +type prInput struct { + SourceRefName string `json:"sourceRefName"` + TargetRefName string `json:"targetRefName"` + Title string `json:"title"` + Description string `json:"description"` + Reviewers []struct { + ID string `json:"id"` + } `json:"reviewers"` +} + +type pr struct { + Repository struct { + ID string `json:"id"` + Name string `json:"name"` + URL string `json:"url"` + Project struct { + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + URL string `json:"url"` + State string `json:"state"` + Revision int `json:"revision"` + } `json:"project"` + RemoteURL string `json:"remoteUrl"` + } `json:"repository"` + PullRequestID int `json:"pullRequestId"` + CodeReviewID int `json:"codeReviewId"` + Status string `json:"status"` + CreatedBy struct { + ID string `json:"id"` + DisplayName string `json:"displayName"` + UniqueName string `json:"uniqueName"` + URL string `json:"url"` + ImageURL string `json:"imageUrl"` + } `json:"createdBy"` + 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"` + } `json:"lastMergeSourceCommit"` + LastMergeTargetCommit struct { + CommitID string `json:"commitId"` + URL string `json:"url"` + } `json:"lastMergeTargetCommit"` + Reviewers []struct { + ReviewerURL string `json:"reviewerUrl"` + Vote int `json:"vote"` + ID string `json:"id"` + DisplayName string `json:"displayName"` + UniqueName string `json:"uniqueName"` + URL string `json:"url"` + ImageURL string `json:"imageUrl"` + } `json:"reviewers"` + URL string `json:"url"` + Links struct { + Self struct { + Href string `json:"href"` + } `json:"self"` + Repository struct { + Href string `json:"href"` + } `json:"repository"` + WorkItems struct { + Href string `json:"href"` + } `json:"workItems"` + SourceBranch struct { + Href string `json:"href"` + } `json:"sourceBranch"` + TargetBranch struct { + Href string `json:"href"` + } `json:"targetBranch"` + SourceCommit struct { + Href string `json:"href"` + } `json:"sourceCommit"` + TargetCommit struct { + Href string `json:"href"` + } `json:"targetCommit"` + CreatedBy struct { + Href string `json:"href"` + } `json:"createdBy"` + Iterations struct { + Href string `json:"href"` + } `json:"iterations"` + } `json:"_links"` + SupportsIterations bool `json:"supportsIterations"` + ArtifactID string `json:"artifactId"` +} + +func convertPullRequest(from *pr) *scm.PullRequest { + return &scm.PullRequest{ + Number: from.PullRequestID, + Title: from.Title, + Body: from.Description, + Sha: from.LastMergeSourceCommit.CommitID, + 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.LastMergeTargetCommit.CommitID, + }, + Author: scm.User{ + Login: from.CreatedBy.UniqueName, + Avatar: from.CreatedBy.ImageURL, + }, + Created: from.CreationDate, + } +} diff --git a/scm/driver/azure/pr_test.go b/scm/driver/azure/pr_test.go new file mode 100644 index 000000000..42b60dfe7 --- /dev/null +++ b/scm/driver/azure/pr_test.go @@ -0,0 +1,102 @@ +// 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 azure + +import ( + "context" + "encoding/json" + "io/ioutil" + "testing" + + "github.com/drone/go-scm/scm" + + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestPullCreate(t *testing.T) { + defer gock.Off() + + gock.New("https:/dev.azure.com/"). + Post("/ORG/PROJ/_apis/git/repositories/REPOID/"). + Reply(201). + Type("application/json"). + File("testdata/pr.json") + + input := scm.PullRequestInput{ + Title: "test_pr", + Body: "test_pr_body", + Source: "pr_branch", + Target: "main", + } + + client := NewDefault("ORG", "PROJ") + got, _, err := client.PullRequests.Create(context.Background(), "REPOID", &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 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 new file mode 100644 index 000000000..64eead88b --- /dev/null +++ b/scm/driver/azure/repo.go @@ -0,0 +1,319 @@ +// 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 azure + +import ( + "context" + "fmt" + "net/url" + "strings" + + "github.com/drone/go-scm/scm" +) + +// RepositoryService implements the repository service for +// the GitHub driver. +type RepositoryService struct { + client *wrapper +} + +// Find returns the repository by name. +func (s *RepositoryService) Find(ctx context.Context, repo string) (*scm.Repository, *scm.Response, error) { + // https://docs.microsoft.com/en-us/rest/api/azure/devops/git/repositories/get?view=azure-devops-rest-4.1 + if s.client.project == "" { + return nil, nil, ProjectRequiredError() + } + endpoint := fmt.Sprintf("%s/%s/_apis/git/repositories/%s?api-version=6.0", s.client.owner, s.client.project, repo) + + out := new(repository) + res, err := s.client.do(ctx, "GET", endpoint, nil, &out) + return convertRepository(out, s.client.owner), res, err +} + +// FindHook returns a repository hook. +func (s *RepositoryService) FindHook(ctx context.Context, repo string, id string) (*scm.Hook, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +// FindPerms returns the repository permissions. +func (s *RepositoryService) FindPerms(ctx context.Context, repo string) (*scm.Perm, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +// List returns the user repository list. +func (s *RepositoryService) List(ctx context.Context, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { + // https://docs.microsoft.com/en-us/rest/api/azure/devops/git/repositories/list?view=azure-devops-rest-6.0 + var endpoint string + if s.client.project == "" { + endpoint = fmt.Sprintf("%s/_apis/git/repositories?api-version=6.0", s.client.owner) + } else { + endpoint = fmt.Sprintf("%s/%s/_apis/git/repositories?api-version=6.0", s.client.owner, s.client.project) + } + + out := new(repositories) + res, err := s.client.do(ctx, "GET", endpoint, nil, &out) + 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) +} + +// ListHooks returns a list or repository hooks. +func (s *RepositoryService) ListHooks(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Hook, *scm.Response, error) { + // https://docs.microsoft.com/en-us/rest/api/azure/devops/hooks/subscriptions/list?view=azure-devops-rest-6.0 + 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, projectID, repo), res, err +} + +// ListStatus returns a list of commit statuses. +func (s *RepositoryService) ListStatus(ctx context.Context, repo, ref string, opts scm.ListOptions) ([]*scm.Status, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +// CreateHook creates a new repository webhook. +func (s *RepositoryService) CreateHook(ctx context.Context, repo string, input *scm.HookInput) (*scm.Hook, *scm.Response, error) { + // https://docs.microsoft.com/en-us/rest/api/azure/devops/hooks/subscriptions/create?view=azure-devops-rest-6.0 + if s.client.project == "" { + return nil, nil, ProjectRequiredError() + } + endpoint := fmt.Sprintf("%s/_apis/hooks/subscriptions?api-version=6.0", s.client.owner) + in := new(subscription) + in.Status = "enabled" + in.PublisherID = "tfs" + in.ResourceVersion = "1.0" + in.ConsumerID = "webHooks" + in.ConsumerActionID = "httpRequest" + // we do not support scm hookevents, only native events + if input.NativeEvents == nil { + return nil, nil, fmt.Errorf("CreateHook, You must pass at least one native event") + } + if len(input.NativeEvents) > 1 { + return nil, nil, fmt.Errorf("CreateHook, Azure only allows the creation of a single hook at a time %v", input.NativeEvents) + } + in.EventType = input.NativeEvents[0] + // publisher + projectID, projErr := s.getProjectIDFromProjectName(ctx, s.client.project) + if projErr != nil { + return nil, nil, fmt.Errorf("CreateHook was unable to look up the project's projectID, %s", projErr) + } + in.PublisherInputs.ProjectID = projectID + in.PublisherInputs.Repository = repo + // consumer + in.ConsumerInputs.URL = input.Target + 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 +} + +// CreateStatus creates a new commit status. +func (s *RepositoryService) CreateStatus(ctx context.Context, repo, ref string, input *scm.StatusInput) (*scm.Status, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +// CreateDeployStatus creates a new deployment status. +func (s *RepositoryService) CreateDeployStatus(ctx context.Context, repo string, input *scm.DeployStatus) (*scm.DeployStatus, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +// UpdateHook updates a repository webhook. +func (s *RepositoryService) UpdateHook(ctx context.Context, repo, id string, input *scm.HookInput) (*scm.Hook, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +// DeleteHook deletes a repository webhook. +func (s *RepositoryService) DeleteHook(ctx context.Context, repo, id string) (*scm.Response, error) { + // https://docs.microsoft.com/en-us/rest/api/azure/devops/hooks/subscriptions/delete?view=azure-devops-rest-6.0 + if s.client.project == "" { + return nil, ProjectRequiredError() + } + endpoint := fmt.Sprintf("%s/_apis/hooks/subscriptions/%s?api-version=6.0", s.client.owner, id) + return s.client.do(ctx, "DELETE", endpoint, nil, nil) +} + +// 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"` + Value []struct { + Description string `json:"description"` + ID string `json:"id"` + Name string `json:"name"` + State string `json:"state"` + URL string `json:"url"` + } `json:"value"` + } + + out := new(projects) + response, err := s.client.do(ctx, "GET", endpoint, nil, &out) + if err != nil { + fmt.Println(response) + return "", fmt.Errorf("failed to list projects: %s", err) + } + for _, v := range out.Value { + if v.Name == projectName { + return v.ID, nil + } + } + return "", fmt.Errorf("failed to find project id for %s", projectName) +} + +type repositories struct { + Count int64 `json:"count"` + Value []*repository `json:"value"` +} + +type repository struct { + DefaultBranch string `json:"defaultBranch"` + 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"` + Visibility string `json:"visibility"` + } `json:"project"` + RemoteURL string `json:"remoteUrl"` + URL string `json:"url"` +} + +type subscriptions struct { + Count int64 `json:"count"` + Value []*subscription `json:"value"` +} + +type subscription struct { + ActionDescription string `json:"actionDescription"` + ConsumerActionID string `json:"consumerActionId"` + ConsumerID string `json:"consumerId"` + ConsumerInputs struct { + AccountName string `json:"accountName,omitempty"` + AcceptUntrustedCerts string `json:"acceptUntrustedCerts,omitempty"` + AddToTop string `json:"addToTop,omitempty"` + APIToken string `json:"apiToken,omitempty"` + BoardID string `json:"boardId,omitempty"` + BuildName string `json:"buildName,omitempty"` + BuildParameterized string `json:"buildParameterized,omitempty"` + FeedID string `json:"feedId,omitempty"` + ListID string `json:"listId,omitempty"` + PackageSourceID string `json:"packageSourceId,omitempty"` + Password string `json:"password,omitempty"` + ServerBaseURL string `json:"serverBaseUrl,omitempty"` + URL string `json:"url,omitempty"` + UserToken string `json:"userToken,omitempty"` + Username string `json:"username,omitempty"` + } `json:"consumerInputs"` + CreatedBy struct { + ID string `json:"id"` + } `json:"createdBy"` + CreatedDate string `json:"createdDate"` + EventDescription string `json:"eventDescription"` + EventType string `json:"eventType"` + ID string `json:"id"` + ModifiedBy struct { + ID string `json:"id"` + } `json:"modifiedBy"` + ModifiedDate string `json:"modifiedDate"` + ProbationRetries int64 `json:"probationRetries"` + PublisherID string `json:"publisherId"` + PublisherInputs struct { + AreaPath string `json:"areaPath,omitempty"` + Branch string `json:"branch,omitempty"` + BuildStatus string `json:"buildStatus,omitempty"` + ChangedFields string `json:"changedFields,omitempty"` + CommentPattern string `json:"commentPattern,omitempty"` + DefinitionName string `json:"definitionName,omitempty"` + HostID string `json:"hostId,omitempty"` + Path string `json:"path,omitempty"` + ProjectID string `json:"projectId,omitempty"` + Repository string `json:"repository,omitempty"` + TfsSubscriptionID string `json:"tfsSubscriptionId,omitempty"` + WorkItemType string `json:"workItemType,omitempty"` + } `json:"publisherInputs"` + ResourceVersion string `json:"resourceVersion"` + Status string `json:"status"` + URL string `json:"url"` +} + +// helper function to convert from the azure devops repository list to +// the common repository structure. +func convertRepositoryList(from *repositories, owner string) []*scm.Repository { + to := []*scm.Repository{} + for _, v := range from.Value { + to = append(to, convertRepository(v, owner)) + } + return to +} + +// helper function to convert from the azure devops repository structure +// to the common repository structure. +func convertRepository(from *repository, owner string) *scm.Repository { + namespace := []string{owner, from.Project.Name} + return &scm.Repository{ + 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, projectFilter string, repositoryFilter string) []*scm.Hook { + to := []*scm.Hook{} + for _, v := range from { + if repositoryFilter != "" && projectFilter == v.PublisherInputs.ProjectID && repositoryFilter == v.PublisherInputs.Repository { + to = append(to, convertHook(v)) + } + } + return to +} + +func convertHook(from *subscription) *scm.Hook { + returnVal := &scm.Hook{ + ID: from.ID, + + Active: from.Status == "enabled", + Target: from.ConsumerInputs.URL, + Events: []string{from.EventType}, + SkipVerify: from.ConsumerInputs.AcceptUntrustedCerts == "true", + } + + return returnVal +} diff --git a/scm/driver/azure/repo_test.go b/scm/driver/azure/repo_test.go new file mode 100644 index 000000000..f2bd509db --- /dev/null +++ b/scm/driver/azure/repo_test.go @@ -0,0 +1,172 @@ +// 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 azure + +import ( + "context" + "encoding/json" + "io/ioutil" + "testing" + + "github.com/drone/go-scm/scm" + + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestRepositoryList(t *testing.T) { + defer gock.Off() + + gock.New("https:/dev.azure.com/"). + Get("/ORG/PROJ/_apis/git/repositories"). + Reply(200). + Type("application/json"). + File("testdata/repos.json") + + client := NewDefault("ORG", "PROJ") + got, _, err := client.Repositories.List(context.Background(), scm.ListOptions{}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Repository{} + raw, _ := ioutil.ReadFile("testdata/repos.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 TestRepositoryHookCreate(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/"). + Post("/ORG/_apis/hooks/subscriptions"). + Reply(201). + Type("application/json"). + File("testdata/hook.json") + + in := &scm.HookInput{ + Name: "web", + NativeEvents: []string{"git.push"}, + Target: "http://www.example.com/webhook", + } + + client := NewDefault("ORG", "test_project") + got, _, err := client.Repositories.CreateHook(context.Background(), "test_project", in) + 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 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() + + gock.New("https:/dev.azure.com/"). + Delete("/ORG/_apis/hooks/subscriptions"). + Reply(204). + Type("application/json") + + client := NewDefault("ORG", "PROJ") + res, err := client.Repositories.DeleteHook(context.Background(), "", "test-project") + if err != nil { + t.Error(err) + return + } + + if got, want := res.Status, 204; got != want { + t.Errorf("Want response status %d, got %d", want, got) + } + +} + +func TestRepositoryFind(t *testing.T) { + defer gock.Off() + + gock.New("https:/dev.azure.com/"). + Get("/ORG/PROJ/_apis/git/repositories/test_project"). + Reply(200). + Type("application/json"). + File("testdata/repo.json") + + client := NewDefault("ORG", "PROJ") + got, _, err := client.Repositories.Find(context.Background(), "test_project") + if err != nil { + t.Error(err) + return + } + + want := new(scm.Repository) + raw, _ := ioutil.ReadFile("testdata/repo.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) + } + +} diff --git a/scm/driver/azure/review.go b/scm/driver/azure/review.go new file mode 100644 index 000000000..f93a1f2b8 --- /dev/null +++ b/scm/driver/azure/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 azure + +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/azure/testdata/branch_create.json b/scm/driver/azure/testdata/branch_create.json new file mode 100644 index 000000000..6a6700ae4 --- /dev/null +++ b/scm/driver/azure/testdata/branch_create.json @@ -0,0 +1,14 @@ +{ + "value": [ + { + "repositoryId": "d3d1760b-311c-4175-a726-20dfc6a7f885", + "name": "refs/heads/vsts-api-sample/answer-woman-flame", + "oldObjectId": "0000000000000000000000000000000000000000", + "newObjectId": "ffe9cba521f00d7f60e322845072238635edb451", + "isLocked": false, + "updateStatus": "succeeded", + "success": true + } + ], + "count": 1 + } \ No newline at end of file diff --git a/scm/driver/azure/testdata/branches.json b/scm/driver/azure/testdata/branches.json new file mode 100644 index 000000000..8f804ee43 --- /dev/null +++ b/scm/driver/azure/testdata/branches.json @@ -0,0 +1,77 @@ +{ + "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/pr_branch", + "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" + }, + { + "name": "refs/heads/test_branch", + "objectId": "d2036abdecd80290e971e263fe668ca87608f8d1", + "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%2Ftest_branch" + }, + { + "name": "refs/pull/1/merge", + "objectId": "e29c0a25614589e1310574b42f799101903b7e30", + "creator": { + "displayName": "Microsoft.VisualStudio.Services.TFS", + "url": "https://spsproduks1.vssps.visualstudio.com/A93f74f38-2b8d-42d4-a5cb-74646f46666e/_apis/Identities/00000002-0000-8888-8000-000000000000", + "_links": { + "avatar": { + "href": "https://dev.azure.com/tphoney/_apis/GraphProfile/MemberAvatars/s2s.MDAwMDAwMDItMDAwMC04ODg4LTgwMDAtMDAwMDAwMDAwMDAwQDJjODk1OTA4LTA0ZTAtNDk1Mi04OWZkLTU0YjAwNDZkNjI4OA" + } + }, + "id": "00000002-0000-8888-8000-000000000000", + "uniqueName": "00000002-0000-8888-8000-000000000000@2c895908-04e0-4952-89fd-54b0046d6288", + "imageUrl": "https://dev.azure.com/tphoney/_api/_common/identityImage?id=00000002-0000-8888-8000-000000000000", + "descriptor": "s2s.MDAwMDAwMDItMDAwMC04ODg4LTgwMDAtMDAwMDAwMDAwMDAwQDJjODk1OTA4LTA0ZTAtNDk1Mi04OWZkLTU0YjAwNDZkNjI4OA" + }, + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/refs?filter=pull%2F1%2Fmerge" + } + ], + "count": 4 +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/branches.json.golden b/scm/driver/azure/testdata/branches.json.golden new file mode 100644 index 000000000..6bfe635cb --- /dev/null +++ b/scm/driver/azure/testdata/branches.json.golden @@ -0,0 +1,22 @@ +[ + { + "Name": "main", + "Path": "refs/heads/main", + "Sha": "e0aee6aa543294d62520fb906689da6710af149c" + }, + { + "Name": "pr_branch", + "Path": "refs/heads/pr_branch", + "Sha": "01768d964c03e97260af0bd8cd9e5cd1f9ac6356" + }, + { + "Name": "test_branch", + "Path": "refs/heads/test_branch", + "Sha": "d2036abdecd80290e971e263fe668ca87608f8d1" + }, + { + "Name": "refs/pull/1/merge", + "Path": "refs/pull/1/merge", + "Sha": "e29c0a25614589e1310574b42f799101903b7e30" + } +] \ No newline at end of file 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 b/scm/driver/azure/testdata/commit.json new file mode 100644 index 000000000..ea37dc05b --- /dev/null +++ b/scm/driver/azure/testdata/commit.json @@ -0,0 +1,53 @@ +{ + "treeId": "efbaf98cd9984e7480f600f8c4b592432a428518", + "commitId": "14897f4465d2d63508242b5cbf68aa2865f693e7", + "author": { + "name": "tp", + "email": "tp@harness.io", + "date": "2022-03-15T17:08:22Z", + "imageUrl": "https://dev.azure.com/tphoney/_apis/GraphProfile/MemberAvatars/msa.M2ZmNGEyMGYtMzA2ZS03NzdlLThhMDEtNTdmMzVlNzFmMTA5" + }, + "committer": { + "name": "tp", + "email": "tp@harness.io", + "date": "2022-03-15T17:08:22Z", + "imageUrl": "https://dev.azure.com/tphoney/_apis/GraphProfile/MemberAvatars/msa.M2ZmNGEyMGYtMzA2ZS03NzdlLThhMDEtNTdmMzVlNzFmMTA5" + }, + "comment": "update CRUD", + "parents": [ + "0e969a16c531c2a6961e5dcf9f82f4456c7bbe68" + ], + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/14897f4465d2d63508242b5cbf68aa2865f693e7", + "remoteUrl": "https://dev.azure.com/tphoney/test_project/_git/test_repo2/commit/14897f4465d2d63508242b5cbf68aa2865f693e7", + "_links": { + "self": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/14897f4465d2d63508242b5cbf68aa2865f693e7" + }, + "repository": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a" + }, + "web": { + "href": "https://dev.azure.com/tphoney/test_project/_git/test_repo2/commit/14897f4465d2d63508242b5cbf68aa2865f693e7" + }, + "changes": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/14897f4465d2d63508242b5cbf68aa2865f693e7/changes" + } + }, + "push": { + "pushedBy": { + "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" + }, + "pushId": 296, + "date": "2022-03-15T17:08:22.7905002Z" + } +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/commit.json.golden b/scm/driver/azure/testdata/commit.json.golden new file mode 100644 index 000000000..1659822a9 --- /dev/null +++ b/scm/driver/azure/testdata/commit.json.golden @@ -0,0 +1,19 @@ +{ + "Sha": "14897f4465d2d63508242b5cbf68aa2865f693e7", + "Message": "update CRUD", + "Author": { + "Name": "tp", + "Email": "tp@harness.io", + "Date": "2022-03-15T17:08:22Z", + "Login": "tp", + "Avatar": "" + }, + "Committer": { + "Name": "tp", + "Email": "tp@harness.io", + "Date": "2022-03-15T17:08:22Z", + "Login": "tp", + "Avatar": "" + }, + "Link": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/14897f4465d2d63508242b5cbf68aa2865f693e7" +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/commits.json b/scm/driver/azure/testdata/commits.json new file mode 100644 index 000000000..4f4748d75 --- /dev/null +++ b/scm/driver/azure/testdata/commits.json @@ -0,0 +1,71 @@ +{ + "value": [ + { + "commitId": "e0aee6aa543294d62520fb906689da6710af149c", + "author": { + "name": "tp", + "email": "tp@harness.io", + "date": "2022-03-04T12:19:58Z" + }, + "committer": { + "name": "tp", + "email": "tp@harness.io", + "date": "2022-03-04T12:19:58Z" + }, + "comment": "go-scm delete crud file", + "commentTruncated": false, + "changeCounts": { + "Add": 0, + "Edit": 0, + "Delete": 1 + }, + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/e0aee6aa543294d62520fb906689da6710af149c", + "remoteUrl": "https://dev.azure.com/tphoney/test_project/_git/test_repo2/commit/e0aee6aa543294d62520fb906689da6710af149c" + }, + { + "commitId": "1fe456794debece7c4125b9e283b601c974977a9", + "author": { + "name": "tp", + "email": "tp@harness.io", + "date": "2022-03-04T12:19:57Z" + }, + "committer": { + "name": "tp", + "email": "tp@harness.io", + "date": "2022-03-04T12:19:57Z" + }, + "comment": "go-scm update crud file", + "commentTruncated": false, + "changeCounts": { + "Add": 0, + "Edit": 1, + "Delete": 0 + }, + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/1fe456794debece7c4125b9e283b601c974977a9", + "remoteUrl": "https://dev.azure.com/tphoney/test_project/_git/test_repo2/commit/1fe456794debece7c4125b9e283b601c974977a9" + }, + { + "commitId": "dc49e8e6e22bb3456366a09365ce9e72912f26b5", + "author": { + "name": "tp", + "email": "tp@harness.io", + "date": "2022-03-04T12:19:56Z" + }, + "committer": { + "name": "tp", + "email": "tp@harness.io", + "date": "2022-03-04T12:19:56Z" + }, + "comment": "go-scm create crud file", + "commentTruncated": false, + "changeCounts": { + "Add": 1, + "Edit": 0, + "Delete": 0 + }, + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/dc49e8e6e22bb3456366a09365ce9e72912f26b5", + "remoteUrl": "https://dev.azure.com/tphoney/test_project/_git/test_repo2/commit/dc49e8e6e22bb3456366a09365ce9e72912f26b5" + } + ], + "count": 3 +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/commits.json.golden b/scm/driver/azure/testdata/commits.json.golden new file mode 100644 index 000000000..a42699cf2 --- /dev/null +++ b/scm/driver/azure/testdata/commits.json.golden @@ -0,0 +1,59 @@ +[ + { + "Sha": "e0aee6aa543294d62520fb906689da6710af149c", + "Message": "go-scm delete crud file", + "Author": { + "Name": "tp", + "Email": "tp@harness.io", + "Date": "2022-03-04T12:19:58Z", + "Login": "tp", + "Avatar": "" + }, + "Committer": { + "Name": "tp", + "Email": "tp@harness.io", + "Date": "2022-03-04T12:19:58Z", + "Login": "tp", + "Avatar": "" + }, + "Link": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/e0aee6aa543294d62520fb906689da6710af149c" + }, + { + "Sha": "1fe456794debece7c4125b9e283b601c974977a9", + "Message": "go-scm update crud file", + "Author": { + "Name": "tp", + "Email": "tp@harness.io", + "Date": "2022-03-04T12:19:57Z", + "Login": "tp", + "Avatar": "" + }, + "Committer": { + "Name": "tp", + "Email": "tp@harness.io", + "Date": "2022-03-04T12:19:57Z", + "Login": "tp", + "Avatar": "" + }, + "Link": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/1fe456794debece7c4125b9e283b601c974977a9" + }, + { + "Sha": "dc49e8e6e22bb3456366a09365ce9e72912f26b5", + "Message": "go-scm create crud file", + "Author": { + "Name": "tp", + "Email": "tp@harness.io", + "Date": "2022-03-04T12:19:56Z", + "Login": "tp", + "Avatar": "" + }, + "Committer": { + "Name": "tp", + "Email": "tp@harness.io", + "Date": "2022-03-04T12:19:56Z", + "Login": "tp", + "Avatar": "" + }, + "Link": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/dc49e8e6e22bb3456366a09365ce9e72912f26b5" + } +] \ No newline at end of file diff --git a/scm/driver/azure/testdata/compare.json b/scm/driver/azure/testdata/compare.json new file mode 100644 index 000000000..7e23610f0 --- /dev/null +++ b/scm/driver/azure/testdata/compare.json @@ -0,0 +1,24 @@ +{ + "allChangesIncluded": true, + "changeCounts": { + "Edit": 1 + }, + "changes": [ + { + "item": { + "objectId": "a493dad221fb22ff4c35ff89f112a61f8c39e924", + "originalObjectId": "c42585a91aea68fcdd2f06508f7073983689aa5f", + "gitObjectType": "blob", + "commitId": "66df312dad61e84dd896d1e8d14ee3dce53b62f0", + "path": "/testfile", + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/items/testfile?versionType=Commit&version=66df312dad61e84dd896d1e8d14ee3dce53b62f0" + }, + "changeType": "edit" + } + ], + "commonCommit": "9788e5ddf8b387cb79228628f34d8dc18582d606", + "baseCommit": "9788e5ddf8b387cb79228628f34d8dc18582d606", + "targetCommit": "66df312dad61e84dd896d1e8d14ee3dce53b62f0", + "aheadCount": 10, + "behindCount": 0 +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/compare.json.golden b/scm/driver/azure/testdata/compare.json.golden new file mode 100644 index 000000000..adbdcb42a --- /dev/null +++ b/scm/driver/azure/testdata/compare.json.golden @@ -0,0 +1,9 @@ +[ + { + "Path": "/testfile", + "Added": false, + "Renamed": false, + "Deleted": false, + "BlobID": "" + } +] diff --git a/scm/driver/azure/testdata/content.json b/scm/driver/azure/testdata/content.json new file mode 100644 index 000000000..34dc1a328 --- /dev/null +++ b/scm/driver/azure/testdata/content.json @@ -0,0 +1,19 @@ +{ + "objectId": "0ca446aab9d09eac8625b53e3df8da661976c458", + "gitObjectType": "blob", + "commitId": "2c0c712b26c3328ed66d5771213360812be9d035", + "path": "/README.md", + "content": "Hello World!\n", + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/items?path=%2FREADME.md&versionType=Branch&versionOptions=None", + "_links": { + "self": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/items?path=%2FREADME.md&versionType=Branch&versionOptions=None" + }, + "repository": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a" + }, + "blob": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/blobs/0ca446aab9d09eac8625b53e3df8da661976c458" + } + } +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/content.json.golden b/scm/driver/azure/testdata/content.json.golden new file mode 100644 index 000000000..d5e39f579 --- /dev/null +++ b/scm/driver/azure/testdata/content.json.golden @@ -0,0 +1,6 @@ +{ + "Path": "/README.md", + "Data": "SGVsbG8gV29ybGQhCg==", + "Sha": "2c0c712b26c3328ed66d5771213360812be9d035", + "BlobID": "0ca446aab9d09eac8625b53e3df8da661976c458" +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/content_create.json b/scm/driver/azure/testdata/content_create.json new file mode 100644 index 000000000..e1bf88fc5 --- /dev/null +++ b/scm/driver/azure/testdata/content_create.json @@ -0,0 +1,83 @@ +{ + "commits": [ + { + "treeId": "175455a66a5fee6f99aeed0c75b4716835d22c64", + "commitId": "aa97ef963bff4dd90dde7456d503dd6ba8a28703", + "author": { + "name": "tp", + "email": "tp@harness.io", + "date": "2022-03-01T14:40:55Z" + }, + "committer": { + "name": "tp", + "email": "tp@harness.io", + "date": "2022-03-01T14:40:55Z" + }, + "comment": "test message create tickles", + "parents": [ + "2c0c712b26c3328ed66d5771213360812be9d035" + ], + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/aa97ef963bff4dd90dde7456d503dd6ba8a28703" + } + ], + "refUpdates": [ + { + "repositoryId": "fde2d21f-13b9-4864-a995-83329045289a", + "name": "refs/heads/main", + "oldObjectId": "2c0c712b26c3328ed66d5771213360812be9d035", + "newObjectId": "aa97ef963bff4dd90dde7456d503dd6ba8a28703" + } + ], + "repository": { + "id": "fde2d21f-13b9-4864-a995-83329045289a", + "name": "test_repo2", + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a", + "project": { + "id": "d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "name": "test_project", + "url": "https://dev.azure.com/tphoney/_apis/projects/d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "state": "wellFormed", + "revision": 11, + "visibility": "private", + "lastUpdateTime": "2022-02-24T15:31:27.89Z" + }, + "size": 713, + "remoteUrl": "https://tphoney@dev.azure.com/tphoney/test_project/_git/test_repo2", + "sshUrl": "git@ssh.dev.azure.com:v3/tphoney/test_project/test_repo2", + "webUrl": "https://dev.azure.com/tphoney/test_project/_git/test_repo2", + "isDisabled": false + }, + "pushedBy": { + "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" + }, + "pushId": 11, + "date": "2022-03-01T14:40:55.3379799Z", + "url": "https://dev.azure.com/tphoney/test_project/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/pushes/11", + "_links": { + "self": { + "href": "https://dev.azure.com/tphoney/test_project/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/pushes/11" + }, + "repository": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a" + }, + "commits": { + "href": "https://dev.azure.com/tphoney/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/pushes/11/commits" + }, + "pusher": { + "href": "https://spsproduks1.vssps.visualstudio.com/A93f74f38-2b8d-42d4-a5cb-74646f46666e/_apis/Identities/3ff4a20f-306e-677e-8a01-57f35e71f109" + }, + "refs": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/refs/heads/main" + } + } +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/content_delete.json b/scm/driver/azure/testdata/content_delete.json new file mode 100644 index 000000000..68eff44ed --- /dev/null +++ b/scm/driver/azure/testdata/content_delete.json @@ -0,0 +1,83 @@ +{ + "commits": [ + { + "treeId": "9804b758e84cac41a6acc4d011f57310a1f63102", + "commitId": "e25d5d5f8dba6a25d5d66c020b101278d818a8b8", + "author": { + "name": "tp", + "email": "tp@harness.io", + "date": "2022-03-01T14:54:53Z" + }, + "committer": { + "name": "tp", + "email": "tp@harness.io", + "date": "2022-03-01T14:54:53Z" + }, + "comment": "test delete message", + "parents": [ + "86260582b1ace66941ea2d1230ac083b68eb95cc" + ], + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/e25d5d5f8dba6a25d5d66c020b101278d818a8b8" + } + ], + "refUpdates": [ + { + "repositoryId": "fde2d21f-13b9-4864-a995-83329045289a", + "name": "refs/heads/main", + "oldObjectId": "86260582b1ace66941ea2d1230ac083b68eb95cc", + "newObjectId": "e25d5d5f8dba6a25d5d66c020b101278d818a8b8" + } + ], + "repository": { + "id": "fde2d21f-13b9-4864-a995-83329045289a", + "name": "test_repo2", + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a", + "project": { + "id": "d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "name": "test_project", + "url": "https://dev.azure.com/tphoney/_apis/projects/d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "state": "wellFormed", + "revision": 11, + "visibility": "private", + "lastUpdateTime": "2022-02-24T15:31:27.89Z" + }, + "size": 713, + "remoteUrl": "https://tphoney@dev.azure.com/tphoney/test_project/_git/test_repo2", + "sshUrl": "git@ssh.dev.azure.com:v3/tphoney/test_project/test_repo2", + "webUrl": "https://dev.azure.com/tphoney/test_project/_git/test_repo2", + "isDisabled": false + }, + "pushedBy": { + "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" + }, + "pushId": 13, + "date": "2022-03-01T14:54:54.0241357Z", + "url": "https://dev.azure.com/tphoney/test_project/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/pushes/13", + "_links": { + "self": { + "href": "https://dev.azure.com/tphoney/test_project/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/pushes/13" + }, + "repository": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a" + }, + "commits": { + "href": "https://dev.azure.com/tphoney/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/pushes/13/commits" + }, + "pusher": { + "href": "https://spsproduks1.vssps.visualstudio.com/A93f74f38-2b8d-42d4-a5cb-74646f46666e/_apis/Identities/3ff4a20f-306e-677e-8a01-57f35e71f109" + }, + "refs": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/refs/heads/main" + } + } +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/content_list.json b/scm/driver/azure/testdata/content_list.json new file mode 100644 index 000000000..00e9899bf --- /dev/null +++ b/scm/driver/azure/testdata/content_list.json @@ -0,0 +1,20 @@ +{ + "count": 2, + "value": [ + { + "objectId": "9804b758e84cac41a6acc4d011f57310a1f63102", + "gitObjectType": "tree", + "commitId": "e25d5d5f8dba6a25d5d66c020b101278d818a8b8", + "path": "/", + "isFolder": true, + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/items?path=%2F&versionType=Branch&versionOptions=None" + }, + { + "objectId": "0ca446aab9d09eac8625b53e3df8da661976c458", + "gitObjectType": "blob", + "commitId": "e25d5d5f8dba6a25d5d66c020b101278d818a8b8", + "path": "/README.md", + "url": "https://dev.azure.com/tphoney/test_project/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/items//README.md?versionType=Branch&versionOptions=None" + } + ] +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/content_list.json.golden b/scm/driver/azure/testdata/content_list.json.golden new file mode 100644 index 000000000..b5644b732 --- /dev/null +++ b/scm/driver/azure/testdata/content_list.json.golden @@ -0,0 +1,14 @@ +[ + { + "path": "/", + "kind": "directory", + "Sha": "e25d5d5f8dba6a25d5d66c020b101278d818a8b8", + "BlobID": "9804b758e84cac41a6acc4d011f57310a1f63102" + }, + { + "path": "/README.md", + "kind": "file", + "Sha": "e25d5d5f8dba6a25d5d66c020b101278d818a8b8", + "BlobID": "0ca446aab9d09eac8625b53e3df8da661976c458" + } +] \ No newline at end of file diff --git a/scm/driver/azure/testdata/content_update.json b/scm/driver/azure/testdata/content_update.json new file mode 100644 index 000000000..c9ebc450e --- /dev/null +++ b/scm/driver/azure/testdata/content_update.json @@ -0,0 +1,83 @@ +{ + "commits": [ + { + "treeId": "8c48e1f820617b4d33efb453feef450f4252a8b0", + "commitId": "86260582b1ace66941ea2d1230ac083b68eb95cc", + "author": { + "name": "tp", + "email": "tp@harness.io", + "date": "2022-03-01T14:50:23Z" + }, + "committer": { + "name": "tp", + "email": "tp@harness.io", + "date": "2022-03-01T14:50:23Z" + }, + "comment": "test message update tickles", + "parents": [ + "aa97ef963bff4dd90dde7456d503dd6ba8a28703" + ], + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/86260582b1ace66941ea2d1230ac083b68eb95cc" + } + ], + "refUpdates": [ + { + "repositoryId": "fde2d21f-13b9-4864-a995-83329045289a", + "name": "refs/heads/main", + "oldObjectId": "aa97ef963bff4dd90dde7456d503dd6ba8a28703", + "newObjectId": "86260582b1ace66941ea2d1230ac083b68eb95cc" + } + ], + "repository": { + "id": "fde2d21f-13b9-4864-a995-83329045289a", + "name": "test_repo2", + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a", + "project": { + "id": "d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "name": "test_project", + "url": "https://dev.azure.com/tphoney/_apis/projects/d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "state": "wellFormed", + "revision": 11, + "visibility": "private", + "lastUpdateTime": "2022-02-24T15:31:27.89Z" + }, + "size": 713, + "remoteUrl": "https://tphoney@dev.azure.com/tphoney/test_project/_git/test_repo2", + "sshUrl": "git@ssh.dev.azure.com:v3/tphoney/test_project/test_repo2", + "webUrl": "https://dev.azure.com/tphoney/test_project/_git/test_repo2", + "isDisabled": false + }, + "pushedBy": { + "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" + }, + "pushId": 12, + "date": "2022-03-01T14:50:23.2995Z", + "url": "https://dev.azure.com/tphoney/test_project/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/pushes/12", + "_links": { + "self": { + "href": "https://dev.azure.com/tphoney/test_project/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/pushes/12" + }, + "repository": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a" + }, + "commits": { + "href": "https://dev.azure.com/tphoney/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/pushes/12/commits" + }, + "pusher": { + "href": "https://spsproduks1.vssps.visualstudio.com/A93f74f38-2b8d-42d4-a5cb-74646f46666e/_apis/Identities/3ff4a20f-306e-677e-8a01-57f35e71f109" + }, + "refs": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/refs/heads/main" + } + } +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/hook.json b/scm/driver/azure/testdata/hook.json new file mode 100644 index 000000000..ff8a2daea --- /dev/null +++ b/scm/driver/azure/testdata/hook.json @@ -0,0 +1,58 @@ +{ + "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" + } + } +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/hook.json.golden b/scm/driver/azure/testdata/hook.json.golden new file mode 100644 index 000000000..927ae8496 --- /dev/null +++ b/scm/driver/azure/testdata/hook.json.golden @@ -0,0 +1,10 @@ +{ + "ID": "d455cb11-20a0-4b15-b546-7e9fb9973cc6", + "Name": "", + "Target": "http://www.bla.com", + "Events": [ + "git.pullrequest.created" + ], + "Active": true, + "SkipVerify": true +} \ No newline at end of file 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 new file mode 100644 index 000000000..01c08b31e --- /dev/null +++ b/scm/driver/azure/testdata/pr.json @@ -0,0 +1,76 @@ +{ + "repository": { + "id": "fde2d21f-13b9-4864-a995-83329045289a", + "name": "test_repo2", + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a", + "project": { + "id": "d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "name": "test_project", + "description": "", + "url": "https://dev.azure.com/tphoney/_apis/projects/d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "state": "wellFormed", + "revision": 11 + }, + "remoteUrl": "https://tphoney@dev.azure.com/tphoney/test_project/_git/test_repo2" + }, + "pullRequestId": 19, + "codeReviewId": 19, + "status": "completed", + "createdBy": { + "id": "3ff4a20f-306e-677e-8a01-57f35e71f109", + "displayName": "tp", + "uniqueName": "tp@harness.io", + "url": "https://spsproduks1.vssps.visualstudio.com/A93f74f38-2b8d-42d4-a5cb-74646f46666e/_apis/Identities/3ff4a20f-306e-677e-8a01-57f35e71f109", + "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", + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/01768d964c03e97260af0bd8cd9e5cd1f9ac6356" + }, + "lastMergeTargetCommit": { + "commitId": "b748ab7eb49b8627214f22f631f878c4af9893b5", + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/b748ab7eb49b8627214f22f631f878c4af9893b5" + }, + "reviewers": [], + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/pullRequests/19", + "_links": { + "self": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/pullRequests/19" + }, + "repository": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a" + }, + "workItems": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/pullRequests/19/workitems" + }, + "sourceBranch": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/refs/heads/pr_branch" + }, + "targetBranch": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/refs/heads/main" + }, + "sourceCommit": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/01768d964c03e97260af0bd8cd9e5cd1f9ac6356" + }, + "targetCommit": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/commits/b748ab7eb49b8627214f22f631f878c4af9893b5" + }, + "createdBy": { + "href": "https://spsproduks1.vssps.visualstudio.com/A93f74f38-2b8d-42d4-a5cb-74646f46666e/_apis/Identities/3ff4a20f-306e-677e-8a01-57f35e71f109" + }, + "iterations": { + "href": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a/pullRequests/19/iterations" + } + }, + "supportsIterations": true, + "artifactId": "vstfs:///Git/PullRequestId/d350c9c0-7749-4ff8-a78f-f9c1f0e56729%2ffde2d21f-13b9-4864-a995-83329045289a%2f19" +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/pr.json.golden b/scm/driver/azure/testdata/pr.json.golden new file mode 100644 index 000000000..23330a15e --- /dev/null +++ b/scm/driver/azure/testdata/pr.json.golden @@ -0,0 +1,37 @@ +{ + "Number": 19, + "Title": "test_pr", + "Body": "test_pr_body", + "Sha": "01768d964c03e97260af0bd8cd9e5cd1f9ac6356", + "Ref": "", + "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": "", + "Draft": false, + "Closed": true, + "Merged": true, + "Base": { + "Name": "", + "Path": "", + "Sha": "b748ab7eb49b8627214f22f631f878c4af9893b5" + }, + "Head": { + "Name": "", + "Path": "", + "Sha": "01768d964c03e97260af0bd8cd9e5cd1f9ac6356" + }, + "Author": { + "Login": "tp@harness.io", + "Name": "", + "Email": "", + "Avatar": "https://dev.azure.com/tphoney/_api/_common/identityImage?id=3ff4a20f-306e-677e-8a01-57f35e71f109", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "Created": "2022-03-04T13:34:54.3177724Z", + "Updated": "0001-01-01T00:00:00Z", + "Labels": null +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/projects.json b/scm/driver/azure/testdata/projects.json new file mode 100644 index 000000000..933b642be --- /dev/null +++ b/scm/driver/azure/testdata/projects.json @@ -0,0 +1,14 @@ +{ + "count": 1, + "value": [ + { + "id": "d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "name": "test_project", + "url": "https://dev.azure.com/tphoney/_apis/projects/d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "state": "wellFormed", + "revision": 11, + "visibility": "private", + "lastUpdateTime": "2022-02-24T15:31:27.89Z" + } + ] +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/repo.json b/scm/driver/azure/testdata/repo.json new file mode 100644 index 000000000..c21fec46a --- /dev/null +++ b/scm/driver/azure/testdata/repo.json @@ -0,0 +1,20 @@ +{ + "id": "91f0d4cb-4c36-49a5-b28d-2d72da089c4d", + "name": "test_project", + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/91f0d4cb-4c36-49a5-b28d-2d72da089c4d", + "project": { + "id": "d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "name": "test_project", + "url": "https://dev.azure.com/tphoney/_apis/projects/d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "state": "wellFormed", + "revision": 11, + "visibility": "private", + "lastUpdateTime": "2022-02-24T15:31:27.89Z" + }, + "defaultBranch": "refs/heads/main", + "size": 1232, + "remoteUrl": "https://tphoney@dev.azure.com/tphoney/test_project/_git/test_project", + "sshUrl": "git@ssh.dev.azure.com:v3/tphoney/test_project/test_project", + "webUrl": "https://dev.azure.com/tphoney/test_project/_git/test_project", + "isDisabled": false +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/repo.json.golden b/scm/driver/azure/testdata/repo.json.golden new file mode 100644 index 000000000..c65a2d23d --- /dev/null +++ b/scm/driver/azure/testdata/repo.json.golden @@ -0,0 +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", + "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 new file mode 100644 index 000000000..e5d7c6a23 --- /dev/null +++ b/scm/driver/azure/testdata/repos.json @@ -0,0 +1,45 @@ +{ + "value": [ + { + "id": "91f0d4cb-4c36-49a5-b28d-2d72da089c4d", + "name": "test_project", + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/91f0d4cb-4c36-49a5-b28d-2d72da089c4d", + "project": { + "id": "d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "name": "test_project", + "url": "https://dev.azure.com/tphoney/_apis/projects/d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "state": "wellFormed", + "revision": 11, + "visibility": "private", + "lastUpdateTime": "2022-02-24T15:31:27.89Z" + }, + "defaultBranch": "refs/heads/main", + "size": 1232, + "remoteUrl": "https://tphoney@dev.azure.com/tphoney/test_project/_git/test_project", + "sshUrl": "git@ssh.dev.azure.com:v3/tphoney/test_project/test_project", + "webUrl": "https://dev.azure.com/tphoney/test_project/_git/test_project", + "isDisabled": false + }, + { + "id": "fde2d21f-13b9-4864-a995-83329045289a", + "name": "test_repo2", + "url": "https://dev.azure.com/tphoney/d350c9c0-7749-4ff8-a78f-f9c1f0e56729/_apis/git/repositories/fde2d21f-13b9-4864-a995-83329045289a", + "project": { + "id": "d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "name": "test_project", + "url": "https://dev.azure.com/tphoney/_apis/projects/d350c9c0-7749-4ff8-a78f-f9c1f0e56729", + "state": "wellFormed", + "revision": 11, + "visibility": "public", + "lastUpdateTime": "2022-02-24T15:31:27.89Z" + }, + "defaultBranch": "refs/heads/main", + "size": 37687, + "remoteUrl": "https://tphoney@dev.azure.com/tphoney/test_project/_git/test_repo2", + "sshUrl": "git@ssh.dev.azure.com:v3/tphoney/test_project/test_repo2", + "webUrl": "https://dev.azure.com/tphoney/test_project/_git/test_repo2", + "isDisabled": false + } + ], + "count": 2 +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/repos.json.golden b/scm/driver/azure/testdata/repos.json.golden new file mode 100644 index 000000000..137b73660 --- /dev/null +++ b/scm/driver/azure/testdata/repos.json.golden @@ -0,0 +1,22 @@ +[ + { + "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", + "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", + "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/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 new file mode 100644 index 000000000..9b544c962 --- /dev/null +++ b/scm/driver/azure/testdata/webhooks/pr_created.json @@ -0,0 +1,86 @@ +{ + "id": "2ab4e3d3-b7a6-425e-92b1-5a9982c1269e", + "eventType": "git.pullrequest.created", + "publisherId": "tfs", + "scope": "all", + "message": { + "text": "Jamal Hartnett created a new pull request", + "html": "Jamal Hartnett created a new pull request", + "markdown": "Jamal Hartnett created a new pull request" + }, + "detailedMessage": { + "text": "Jamal Hartnett created a new pull request\r\n\r\n- Merge status: Succeeded\r\n- Merge commit: eef717(https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72)\r\n", + "html": "Jamal Hartnett created a new pull request\r\n", + "markdown": "Jamal Hartnett created a new pull request\r\n\r\n+ Merge status: Succeeded\r\n+ Merge commit: [eef717](https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72)\r\n" + }, + "resource": { + "repository": { + "id": "4bc14d40-c903-45e2-872e-0462c7748079", + "name": "Fabrikam", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079", + "project": { + "id": "6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "name": "Fabrikam", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/projects/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "state": "wellFormed" + }, + "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, + "status": "active", + "createdBy": { + "id": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "displayName": "Jamal Hartnett", + "uniqueName": "fabrikamfiber4@hotmail.com", + "url": "https://vssps.dev.azure.com/fabrikam/_apis/Identities/54d125f7-69f7-4191-904f-c5b96b6261c8", + "imageUrl": "https://dev.azure.com/fabrikam/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://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/53d54ac915144006c2c9e90d2c7d3880920db49c" + }, + "lastMergeTargetCommit": { + "commitId": "a511f535b1ea495ee0c903badb68fbc83772c882", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/a511f535b1ea495ee0c903badb68fbc83772c882" + }, + "lastMergeCommit": { + "commitId": "eef717f69257a6333f221566c1c987dc94cc0d72", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72" + }, + "reviewers": [ + { + "reviewerUrl": null, + "vote": 0, + "id": "2ea2d095-48f9-4cd6-9966-62f6f574096c", + "displayName": "[Mobile]\\Mobile Team", + "uniqueName": "vstfs:///Classification/TeamProject/f0811a3b-8c8a-4e43-a3bf-9a049b4835bd\\Mobile Team", + "url": "https://vssps.dev.azure.com/fabrikam/_apis/Identities/2ea2d095-48f9-4cd6-9966-62f6f574096c", + "imageUrl": "https://dev.azure.com/fabrikam/DefaultCollection/_api/_common/identityImage?id=2ea2d095-48f9-4cd6-9966-62f6f574096c", + "isContainer": true + } + ], + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1" + }, + "resourceVersion": "1.0", + "resourceContainers": { + "collection": { + "id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2" + }, + "account": { + "id": "f844ec47-a9db-4511-8281-8b63f4eaf94e" + }, + "project": { + "id": "be9b3917-87e6-42a4-a549-2bc06a7a878f" + } + }, + "createdDate": "2016-09-19T13:03:27.2879096Z" +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/webhooks/pr_created.json.golden b/scm/driver/azure/testdata/webhooks/pr_created.json.golden new file mode 100644 index 000000000..e081e85fa --- /dev/null +++ b/scm/driver/azure/testdata/webhooks/pr_created.json.golden @@ -0,0 +1,61 @@ +{ + "Action": "created", + "Repo": { + "ID": "4bc14d40-c903-45e2-872e-0462c7748079", + "Namespace": "Fabrikam", + "Name": "Fabrikam", + "Perm": null, + "Branch": "", + "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" + }, + "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://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/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://dev.azure.com/fabrikam/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 + }, + "Sender": { + "Login": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "Name": "Jamal Hartnett", + "Email": "fabrikamfiber4@hotmail.com", + "Avatar": "https://dev.azure.com/fabrikam/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8", + "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_merged.json b/scm/driver/azure/testdata/webhooks/pr_merged.json new file mode 100644 index 000000000..15537ac3e --- /dev/null +++ b/scm/driver/azure/testdata/webhooks/pr_merged.json @@ -0,0 +1,87 @@ +{ + "id": "6872ee8c-b333-4eff-bfb9-0d5274943566", + "eventType": "git.pullrequest.merged", + "publisherId": "tfs", + "scope": "all", + "message": { + "text": "Jamal Hartnett has created a pull request merge commit", + "html": "Jamal Hartnett has created a pull request merge commit", + "markdown": "Jamal Hartnett has created a pull request merge commit" + }, + "detailedMessage": { + "text": "Jamal Hartnett has created a pull request merge commit\r\n\r\n- Merge status: Succeeded\r\n- Merge commit: eef717(https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72)\r\n", + "html": "Jamal Hartnett has created a pull request merge commit\r\n", + "markdown": "Jamal Hartnett has created a pull request merge commit\r\n\r\n+ Merge status: Succeeded\r\n+ Merge commit: [eef717](https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72)\r\n" + }, + "resource": { + "repository": { + "id": "4bc14d40-c903-45e2-872e-0462c7748079", + "name": "Fabrikam", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079", + "project": { + "id": "6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "name": "Fabrikam", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/projects/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "state": "wellFormed" + }, + "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, + "status": "completed", + "createdBy": { + "id": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "displayName": "Jamal Hartnett", + "uniqueName": "fabrikamfiber4@hotmail.com", + "url": "https://vssps.dev.azure.com/fabrikam/_apis/Identities/54d125f7-69f7-4191-904f-c5b96b6261c8", + "imageUrl": "https://dev.azure.com/fabrikam/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8" + }, + "creationDate": "2014-06-17T16:55:46.589889Z", + "closedDate": "2014-06-30T18:59:12.3660573Z", + "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://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/53d54ac915144006c2c9e90d2c7d3880920db49c" + }, + "lastMergeTargetCommit": { + "commitId": "a511f535b1ea495ee0c903badb68fbc83772c882", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/a511f535b1ea495ee0c903badb68fbc83772c882" + }, + "lastMergeCommit": { + "commitId": "eef717f69257a6333f221566c1c987dc94cc0d72", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72" + }, + "reviewers": [ + { + "reviewerUrl": null, + "vote": 0, + "id": "2ea2d095-48f9-4cd6-9966-62f6f574096c", + "displayName": "[Mobile]\\Mobile Team", + "uniqueName": "vstfs:///Classification/TeamProject/f0811a3b-8c8a-4e43-a3bf-9a049b4835bd\\Mobile Team", + "url": "https://vssps.dev.azure.com/fabrikam/_apis/Identities/2ea2d095-48f9-4cd6-9966-62f6f574096c", + "imageUrl": "https://dev.azure.com/fabrikam/DefaultCollection/_api/_common/identityImage?id=2ea2d095-48f9-4cd6-9966-62f6f574096c", + "isContainer": true + } + ], + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1" + }, + "resourceVersion": "1.0", + "resourceContainers": { + "collection": { + "id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2" + }, + "account": { + "id": "f844ec47-a9db-4511-8281-8b63f4eaf94e" + }, + "project": { + "id": "be9b3917-87e6-42a4-a549-2bc06a7a878f" + } + }, + "createdDate": "2016-09-19T13:03:27.3156388Z" + } \ No newline at end of file diff --git a/scm/driver/azure/testdata/webhooks/pr_merged.json.golden b/scm/driver/azure/testdata/webhooks/pr_merged.json.golden new file mode 100644 index 000000000..844d14542 --- /dev/null +++ b/scm/driver/azure/testdata/webhooks/pr_merged.json.golden @@ -0,0 +1,61 @@ +{ + "Action": "merged", + "Repo": { + "ID": "4bc14d40-c903-45e2-872e-0462c7748079", + "Namespace": "Fabrikam", + "Name": "Fabrikam", + "Perm": null, + "Branch": "", + "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" + }, + "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://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1", + "Diff": "", + "Closed": false, + "Merged": true, + "Base": { + "Name": "", + "Path": "", + "Sha": "" + }, + "Head": { + "Name": "", + "Path": "", + "Sha": "" + }, + "Author": { + "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", + "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 + }, + "Sender": { + "Login": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "Name": "Jamal Hartnett", + "Email": "fabrikamfiber4@hotmail.com", + "Avatar": "https://dev.azure.com/fabrikam/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8", + "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_updated.json b/scm/driver/azure/testdata/webhooks/pr_updated.json new file mode 100644 index 000000000..ac0f7f1ac --- /dev/null +++ b/scm/driver/azure/testdata/webhooks/pr_updated.json @@ -0,0 +1,93 @@ +{ + "id": "af07be1b-f3ad-44c8-a7f1-c4835f2df06b", + "eventType": "git.pullrequest.updated", + "publisherId": "tfs", + "scope": "all", + "message": { + "text": "Jamal Hartnett marked the pull request as completed", + "html": "Jamal Hartnett marked the pull request as completed", + "markdown": "Jamal Hartnett marked the pull request as completed" + }, + "detailedMessage": { + "text": "Jamal Hartnett marked the pull request as completed\r\n\r\n- Merge status: Succeeded\r\n- Merge commit: eef717(https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72)\r\n", + "html": "Jamal Hartnett marked the pull request as completed\r\n", + "markdown": "Jamal Hartnett marked the pull request as completed\r\n\r\n+ Merge status: Succeeded\r\n+ Merge commit: [eef717](https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72)\r\n" + }, + "resource": { + "repository": { + "id": "4bc14d40-c903-45e2-872e-0462c7748079", + "name": "Fabrikam", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079", + "project": { + "id": "6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "name": "Fabrikam", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/projects/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "state": "wellFormed" + }, + "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, + "status": "completed", + "createdBy": { + "id": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "displayName": "Jamal Hartnett", + "uniqueName": "fabrikamfiber4@hotmail.com", + "url": "https://vssps.dev.azure.com/fabrikam/_apis/Identities/54d125f7-69f7-4191-904f-c5b96b6261c8", + "imageUrl": "https://dev.azure.com/fabrikam/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8" + }, + "creationDate": "2014-06-17T16:55:46.589889Z", + "closedDate": "2014-06-30T18:59:12.3660573Z", + "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://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/53d54ac915144006c2c9e90d2c7d3880920db49c" + }, + "lastMergeTargetCommit": { + "commitId": "a511f535b1ea495ee0c903badb68fbc83772c882", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/a511f535b1ea495ee0c903badb68fbc83772c882" + }, + "lastMergeCommit": { + "commitId": "eef717f69257a6333f221566c1c987dc94cc0d72", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72" + }, + "reviewers": [ + { + "reviewerUrl": null, + "vote": 0, + "id": "2ea2d095-48f9-4cd6-9966-62f6f574096c", + "displayName": "[Mobile]\\Mobile Team", + "uniqueName": "vstfs:///Classification/TeamProject/f0811a3b-8c8a-4e43-a3bf-9a049b4835bd\\Mobile Team", + "url": "https://vssps.dev.azure.com/fabrikam/_apis/Identities/2ea2d095-48f9-4cd6-9966-62f6f574096c", + "imageUrl": "https://dev.azure.com/fabrikam/DefaultCollection/_api/_common/identityImage?id=2ea2d095-48f9-4cd6-9966-62f6f574096c", + "isContainer": true + } + ], + "commits": [ + { + "commitId": "53d54ac915144006c2c9e90d2c7d3880920db49c", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/53d54ac915144006c2c9e90d2c7d3880920db49c" + } + ], + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1" + }, + "resourceVersion": "1.0", + "resourceContainers": { + "collection": { + "id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2" + }, + "account": { + "id": "f844ec47-a9db-4511-8281-8b63f4eaf94e" + }, + "project": { + "id": "be9b3917-87e6-42a4-a549-2bc06a7a878f" + } + }, + "createdDate": "2016-09-19T13:03:27.2813828Z" +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/webhooks/pr_updated.json.golden b/scm/driver/azure/testdata/webhooks/pr_updated.json.golden new file mode 100644 index 000000000..ae36b5d5b --- /dev/null +++ b/scm/driver/azure/testdata/webhooks/pr_updated.json.golden @@ -0,0 +1,61 @@ +{ + "Action": "updated", + "Repo": { + "ID": "4bc14d40-c903-45e2-872e-0462c7748079", + "Namespace": "Fabrikam", + "Name": "Fabrikam", + "Perm": null, + "Branch": "", + "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" + }, + "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://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1", + "Diff": "", + "Closed": true, + "Merged": false, + "Base": { + "Name": "", + "Path": "", + "Sha": "" + }, + "Head": { + "Name": "", + "Path": "", + "Sha": "" + }, + "Author": { + "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", + "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 + }, + "Sender": { + "Login": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "Name": "Jamal Hartnett", + "Email": "fabrikamfiber4@hotmail.com", + "Avatar": "https://dev.azure.com/fabrikam/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8", + "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/push.json b/scm/driver/azure/testdata/webhooks/push.json new file mode 100644 index 000000000..a5fc4d254 --- /dev/null +++ b/scm/driver/azure/testdata/webhooks/push.json @@ -0,0 +1,76 @@ +{ + "id": "03c164c2-8912-4d5e-8009-3707d5f83734", + "eventType": "git.push", + "publisherId": "tfs", + "scope": "all", + "message": { + "text": "Jamal Hartnett pushed updates to branch master of repository Fabrikam-Fiber-Git.", + "html": "Jamal Hartnett pushed updates to branch master of repository Fabrikam-Fiber-Git.", + "markdown": "Jamal Hartnett pushed updates to branch `master` of repository `Fabrikam-Fiber-Git`." + }, + "detailedMessage": { + "text": "Jamal Hartnett pushed 1 commit to branch master of repository Fabrikam-Fiber-Git.\n - Fixed bug in web.config file 33b55f7c", + "html": "Jamal Hartnett pushed 1 commit to branch master of repository Fabrikam-Fiber-Git.\n", + "markdown": "Jamal Hartnett pushed 1 commit to branch [master](https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git/#version=GBmaster) of repository [Fabrikam-Fiber-Git](https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git/).\n* Fixed bug in web.config file [33b55f7c](https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git/commit/33b55f7cb7e7e245323987634f960cf4a6e6bc74)" + }, + "resource": { + "commits": [ + { + "commitId": "33b55f7cb7e7e245323987634f960cf4a6e6bc74", + "author": { + "name": "Jamal Hartnett", + "email": "fabrikamfiber4@hotmail.com", + "date": "2015-02-25T19:01:00Z" + }, + "committer": { + "name": "Jamal Hartnett", + "email": "fabrikamfiber4@hotmail.com", + "date": "2015-02-25T19:01:00Z" + }, + "comment": "Fixed bug in web.config file", + "url": "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git/commit/33b55f7cb7e7e245323987634f960cf4a6e6bc74" + } + ], + "refUpdates": [ + { + "name": "refs/heads/master", + "oldObjectId": "aad331d8d3b131fa9ae03cf5e53965b51942618a", + "newObjectId": "33b55f7cb7e7e245323987634f960cf4a6e6bc74" + } + ], + "repository": { + "id": "278d5cd2-584d-4b63-824a-2ba458937249", + "name": "Fabrikam-Fiber-Git", + "url": "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_apis/repos/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249", + "project": { + "id": "6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "name": "Fabrikam-Fiber-Git", + "url": "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_apis/projects/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "state": "wellFormed" + }, + "defaultBranch": "refs/heads/master", + "remoteUrl": "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git" + }, + "pushedBy": { + "id": "00067FFED5C7AF52@Live.com", + "displayName": "Jamal Hartnett", + "uniqueName": "Windows Live ID\\fabrikamfiber4@hotmail.com" + }, + "pushId": 14, + "date": "2014-05-02T19:17:13.3309587Z", + "url": "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_apis/repos/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249/pushes/14" + }, + "resourceVersion": "1.0", + "resourceContainers": { + "collection": { + "id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2" + }, + "account": { + "id": "f844ec47-a9db-4511-8281-8b63f4eaf94e" + }, + "project": { + "id": "be9b3917-87e6-42a4-a549-2bc06a7a878f" + } + }, + "createdDate": "2016-09-19T13:03:27.0379153Z" +} \ No newline at end of file diff --git a/scm/driver/azure/testdata/webhooks/push.json.golden b/scm/driver/azure/testdata/webhooks/push.json.golden new file mode 100644 index 000000000..59fae065b --- /dev/null +++ b/scm/driver/azure/testdata/webhooks/push.json.golden @@ -0,0 +1,62 @@ +{ + "Ref": "refs/heads/master", + "Before": "aad331d8d3b131fa9ae03cf5e53965b51942618a", + "After": "33b55f7cb7e7e245323987634f960cf4a6e6bc74", + "Repo": { + "ID": "278d5cd2-584d-4b63-824a-2ba458937249", + "Namespace": "Fabrikam-Fiber-Git", + "Name": "Fabrikam-Fiber-Git", + "Perm": null, + "Branch": "master", + "Private": false, + "Clone": "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git", + "CloneSSH": "", + "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" + }, + "Commits": [ + { + "Sha": "33b55f7cb7e7e245323987634f960cf4a6e6bc74", + "Message": "Fixed bug in web.config file", + "Author": { + "Name": "Jamal Hartnett", + "Email": "fabrikamfiber4@hotmail.com", + "Date": "2015-02-25T19:01:00-00:00", + "Login": "Jamal Hartnett", + "Avatar": "" + }, + "Committer": { + "Name": "Jamal Hartnett", + "Email": "fabrikamfiber4@hotmail.com", + "Date": "2015-02-25T19:01:00-00:00", + "Login": "Jamal Hartnett", + "Avatar": "" + }, + "Link": "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git/commit/33b55f7cb7e7e245323987634f960cf4a6e6bc74" + } + ], + "Sender": { + "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/user.go b/scm/driver/azure/user.go new file mode 100644 index 000000000..711edd848 --- /dev/null +++ b/scm/driver/azure/user.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 azure + +import ( + "context" + + "github.com/drone/go-scm/scm" +) + +type userService struct { + client *wrapper +} + +func (s *userService) Find(ctx context.Context) (*scm.User, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +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 +} diff --git a/scm/driver/azure/util.go b/scm/driver/azure/util.go new file mode 100644 index 000000000..d9f74acdd --- /dev/null +++ b/scm/driver/azure/util.go @@ -0,0 +1,23 @@ +// 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 azure + +import ( + "net/url" + "strconv" + + "github.com/drone/go-scm/scm" +) + +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("per_page", strconv.Itoa(opts.Size)) + } + return params.Encode() +} diff --git a/scm/driver/azure/webhook.go b/scm/driver/azure/webhook.go new file mode 100644 index 000000000..9e17da18f --- /dev/null +++ b/scm/driver/azure/webhook.go @@ -0,0 +1,790 @@ +// 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 azure + +import ( + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "time" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/internal/null" +) + +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 + } + // we need to read the json data then look at the eventType + var unstructuredJSON map[string]interface{} + jsonErr := json.Unmarshal([]byte(data), &unstructuredJSON) + if jsonErr != nil { + return nil, fmt.Errorf("Error parsing JSON from webhook: %s", jsonErr) + } + eventType := unstructuredJSON["eventType"].(string) + + switch eventType { + case "git.push": + // https://docs.microsoft.com/en-us/azure/devops/service-hooks/events?view=azure-devops#git.push + src := new(pushHook) + err := json.Unmarshal(data, src) + if err != nil { + return nil, err + } + dst := convertPushHook(src) + return dst, nil + case "git.pullrequest.created": + // https://docs.microsoft.com/en-us/azure/devops/service-hooks/events?view=azure-devops#git.pullrequest.created + src := new(createPullRequestHook) + err := json.Unmarshal(data, src) + if err != nil { + return nil, err + } + dst := convertCreatePullRequestHook(src) + 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 + src := new(updatePullRequestHook) + err := json.Unmarshal(data, src) + if err != nil { + return nil, err + } + dst := convertUpdatePullRequestHook(src) + dst.Action = scm.ActionUpdate + return dst, nil + case "git.pullrequest.merged": + // https://docs.microsoft.com/en-us/azure/devops/service-hooks/events?view=azure-devops#git.pullrequest.merged + src := new(mergePullRequestHook) + err := json.Unmarshal(data, src) + if err != nil { + return nil, err + } + 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 { + commits = append(commits, + scm.Commit{ + Sha: c.CommitID, + Message: c.Comment, + Link: c.URL, + Author: scm.Signature{ + Login: c.Author.Name, + Email: c.Author.Email, + Name: c.Author.Name, + Date: c.Author.Date, + }, + Committer: scm.Signature{ + Login: c.Committer.Name, + Email: c.Committer.Email, + Name: c.Committer.Name, + Date: c.Committer.Date, + }, + }) + } + 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, + 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, + } + return dst +} + +func convertCreatePullRequestHook(src *createPullRequestHook) (returnVal *scm.PullRequestHook) { + returnVal = &scm.PullRequestHook{ + PullRequest: scm.PullRequest{ + Number: src.Resource.PullRequestID, + Title: src.Resource.Title, + Body: src.Resource.Description, + Sha: src.Resource.LastMergeSourceCommit.CommitID, + Ref: src.Resource.SourceRefName, + 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.DisplayName, + Name: src.Resource.CreatedBy.DisplayName, + Email: src.Resource.CreatedBy.UniqueName, + Avatar: src.Resource.CreatedBy.ImageURL, + }, + Created: src.Resource.CreationDate, + }, + Repo: scm.Repository{ + ID: src.Resource.Repository.ID, + 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, + Name: src.Resource.CreatedBy.DisplayName, + Email: src.Resource.CreatedBy.UniqueName, + Avatar: src.Resource.CreatedBy.ImageURL, + }, + } + return returnVal +} + +func convertUpdatePullRequestHook(src *updatePullRequestHook) (returnVal *scm.PullRequestHook) { + returnVal = &scm.PullRequestHook{ + PullRequest: scm.PullRequest{ + Number: src.Resource.PullRequestID, + Title: src.Resource.Title, + Body: src.Resource.Description, + Sha: src.Resource.LastMergeSourceCommit.CommitID, + Ref: src.Resource.SourceRefName, + 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.DisplayName, + Name: src.Resource.CreatedBy.DisplayName, + Email: src.Resource.CreatedBy.UniqueName, + Avatar: src.Resource.CreatedBy.ImageURL, + }, + Created: src.Resource.CreationDate, + }, + Repo: scm.Repository{ + ID: src.Resource.Repository.ID, + 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, + Name: src.Resource.CreatedBy.DisplayName, + Email: src.Resource.CreatedBy.UniqueName, + Avatar: src.Resource.CreatedBy.ImageURL, + }, + } + return returnVal +} + +func convertMergePullRequestHook(src *mergePullRequestHook) (returnVal *scm.PullRequestHook) { + returnVal = &scm.PullRequestHook{ + PullRequest: scm.PullRequest{ + Number: src.Resource.PullRequestID, + Title: src.Resource.Title, + Body: src.Resource.Description, + Sha: src.Resource.LastMergeSourceCommit.CommitID, + Ref: src.Resource.SourceRefName, + 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.DisplayName, + Name: src.Resource.CreatedBy.DisplayName, + Email: src.Resource.CreatedBy.UniqueName, + Avatar: src.Resource.CreatedBy.ImageURL, + }, + Created: src.Resource.CreationDate, + }, + Repo: scm.Repository{ + ID: src.Resource.Repository.ID, + 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, + Name: src.Resource.CreatedBy.DisplayName, + Email: src.Resource.CreatedBy.UniqueName, + Avatar: src.Resource.CreatedBy.ImageURL, + }, + } + 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 { + 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 { + Commits []struct { + Author struct { + Date time.Time `json:"date"` + Email string `json:"email"` + Name string `json:"name"` + } `json:"author"` + Comment string `json:"comment"` + CommitID string `json:"commitId"` + Committer struct { + Date time.Time `json:"date"` + Email string `json:"email"` + Name string `json:"name"` + } `json:"committer"` + URL string `json:"url"` + } `json:"commits"` + Date string `json:"date"` + PushID int64 `json:"pushId"` + PushedBy 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"` + NewObjectID string `json:"newObjectId"` + OldObjectID string `json:"oldObjectId"` + } `json:"refUpdates"` + Repository struct { + DefaultBranch string `json:"defaultBranch"` + 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"` + } `json:"repository"` + URL string `json:"url"` + } `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"` +} + +type createPullRequestHook struct { + ID string `json:"id"` + EventType string `json:"eventType"` + PublisherID string `json:"publisherId"` + Scope string `json:"scope"` + Message struct { + Text string `json:"text"` + HTML string `json:"html"` + Markdown string `json:"markdown"` + } `json:"message"` + DetailedMessage struct { + Text string `json:"text"` + HTML string `json:"html"` + Markdown string `json:"markdown"` + } `json:"detailedMessage"` + Resource struct { + Repository 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"` + URL string `json:"url"` + State string `json:"state"` + } `json:"project"` + DefaultBranch string `json:"defaultBranch"` + RemoteURL string `json:"remoteUrl"` + } `json:"repository"` + PullRequestID int `json:"pullRequestId"` + Status string `json:"status"` + CreatedBy struct { + ID string `json:"id"` + DisplayName string `json:"displayName"` + UniqueName string `json:"uniqueName"` + 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"` + LastMergeSourceCommit struct { + CommitID string `json:"commitId"` + URL string `json:"url"` + } `json:"lastMergeSourceCommit"` + LastMergeTargetCommit struct { + CommitID string `json:"commitId"` + URL string `json:"url"` + } `json:"lastMergeTargetCommit"` + LastMergeCommit struct { + CommitID string `json:"commitId"` + URL string `json:"url"` + } `json:"lastMergeCommit"` + Reviewers []struct { + ReviewerURL interface{} `json:"reviewerUrl"` + Vote int `json:"vote"` + ID string `json:"id"` + DisplayName string `json:"displayName"` + UniqueName string `json:"uniqueName"` + URL string `json:"url"` + ImageURL string `json:"imageUrl"` + IsContainer bool `json:"isContainer"` + } `json:"reviewers"` + URL string `json:"url"` + } `json:"resource"` + ResourceVersion string `json:"resourceVersion"` + ResourceContainers struct { + Collection struct { + ID string `json:"id"` + } `json:"collection"` + Account struct { + ID string `json:"id"` + } `json:"account"` + Project struct { + ID string `json:"id"` + } `json:"project"` + } `json:"resourceContainers"` + CreatedDate time.Time `json:"createdDate"` +} + +type updatePullRequestHook 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 { + ClosedDate null.String `json:"closedDate"` + Commits []struct { + CommitID string `json:"commitId"` + URL string `json:"url"` + } `json:"commits"` + 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"` + 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 { + DefaultBranch string `json:"defaultBranch"` + 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:"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"` +} + +type mergePullRequestHook 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 { + ClosedDate string `json:"closedDate"` + 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"` + 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 { + DefaultBranch string `json:"defaultBranch"` + 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:"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"` +} + +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 new file mode 100644 index 000000000..d4024c2f8 --- /dev/null +++ b/scm/driver/azure/webhook_test.go @@ -0,0 +1,125 @@ +// 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 azure + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "net/http" + "strings" + "testing" + + "github.com/drone/go-scm/scm" + "github.com/google/go-cmp/cmp" +) + +func TestWebhooks(t *testing.T) { + tests := []struct { + before string + after string + obj interface{} + }{ + // push hook + { + before: "testdata/webhooks/push.json", + after: "testdata/webhooks/push.json.golden", + obj: new(scm.PushHook), + }, + // pull request events + // pull request created + { + before: "testdata/webhooks/pr_created.json", + after: "testdata/webhooks/pr_created.json.golden", + obj: new(scm.PullRequestHook), + }, + // pull request updated + { + before: "testdata/webhooks/pr_updated.json", + after: "testdata/webhooks/pr_updated.json.golden", + obj: new(scm.PullRequestHook), + }, + // pull request merged + { + before: "testdata/webhooks/pr_merged.json", + 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 { + 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", "/?secret=71295b197fa25f4356d2fb9965df3f2379d903d7", buf) + + s := new(webhookService) + o, err := s.Parse(r, secretFunc) + if err != nil { + 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 "71295b197fa25f4356d2fb9965df3f2379d903d7", nil +} diff --git a/scm/driver/bitbucket/bitbucket.go b/scm/driver/bitbucket/bitbucket.go index 8aaa9ae74..f05ab670e 100644 --- a/scm/driver/bitbucket/bitbucket.go +++ b/scm/driver/bitbucket/bitbucket.go @@ -10,6 +10,7 @@ import ( "context" "encoding/json" "io" + "mime/multipart" "net/url" "strings" @@ -33,9 +34,11 @@ func New(uri string) (*scm.Client, error) { client.Contents = &contentService{client} client.Git = &gitService{client} 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} client.Users = &userService{client} client.Webhooks = &webhookService{client} @@ -65,12 +68,74 @@ func (c *wrapper) do(ctx context.Context, method, path string, in, out interface // 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"}, + // create or update content + switch content := in.(type) { + case *contentCreateUpdate: + // add the content to the multipart + myReader := strings.NewReader(string(content.Content)) + var b bytes.Buffer + w := multipart.NewWriter(&b) + var fw io.Writer + fw, _ = w.CreateFormFile(content.Files, "") + _, _ = io.Copy(fw, myReader) + // add the other fields + if content.Message != "" { + _ = w.WriteField("message", content.Message) + } + if content.Branch != "" { + _ = w.WriteField("branch", content.Branch) + } + if content.Sha != "" { + _ = w.WriteField("parents", content.Sha) + } + if content.Author != "" { + _ = w.WriteField("author", content.Author) + } + w.Close() + // write the multipart response to the body + req.Body = &b + // write the content type that contains the length of the multipart + req.Header = map[string][]string{ + "Content-Type": {w.FormDataContentType()}, + } + case *contentDelete: + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + fw, err := writer.CreateFormField("files") + _, err = io.Copy(fw, strings.NewReader(content.File)) + if err != nil { + return nil, err + } + fw, err = writer.CreateFormField("message") + _, err = io.Copy(fw, strings.NewReader(content.Message)) + if err != nil { + return nil, err + } + fw, err = writer.CreateFormField("author") + _, err = io.Copy(fw, strings.NewReader(content.Author)) + if err != nil { + return nil, err + } + if content.Branch != "" { + fw, err = writer.CreateFormField("branch") + _, err = io.Copy(fw, strings.NewReader(content.Branch)) + if err != nil { + return nil, err + } + } + writer.Close() + req.Body = bytes.NewReader(body.Bytes()) + req.Header = map[string][]string{ + "Content-Type": {writer.FormDataContentType()}, + } + default: + buf := new(bytes.Buffer) + json.NewEncoder(buf).Encode(in) + req.Header = map[string][]string{ + "Content-Type": {"application/json"}, + } + req.Body = buf } - req.Body = buf } // execute the http request diff --git a/scm/driver/bitbucket/content.go b/scm/driver/bitbucket/content.go index 079b67439..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,29 +18,77 @@ 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) - return &scm.Content{ + content := &scm.Content{ Path: path, Data: out.Bytes(), - }, res, err + } + if err != nil { + return content, res, err + } + 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 { + content.Sha = metaOut.Commit.Hash + return content, metaRes, metaErr + } else { + // do not risk that returning an error if getting the meta fails. + return content, res, err + } } func (s *contentService) Create(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { - return nil, scm.ErrNotSupported + endpoint := fmt.Sprintf("/2.0/repositories/%s/src", repo) + in := &contentCreateUpdate{ + Files: path, + Message: params.Message, + Branch: params.Branch, + Content: params.Data, + Author: fmt.Sprintf("%s <%s>", params.Signature.Name, 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) { - return nil, scm.ErrNotSupported + // https://jira.atlassian.com/browse/BCLOUD-20424?error=login_required&error_description=Login+required&state=196d85f7-a181-4b63-babe-0b567858d8f5 ugh :( + endpoint := fmt.Sprintf("/2.0/repositories/%s/src", repo) + in := &contentCreateUpdate{ + Files: path, + Message: params.Message, + Branch: params.Branch, + Content: params.Data, + Sha: params.Sha, + Author: fmt.Sprintf("%s <%s>", params.Signature.Name, 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, ref string) (*scm.Response, error) { - return nil, scm.ErrNotSupported +func (s *contentService) Delete(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { + author := fmt.Sprintf("%s <%s>", params.Signature.Name, params.Signature.Email) + endpoint := fmt.Sprintf("/2.0/repositories/%s/src", repo) + in := &contentDelete{ + File: path, + Branch: params.Branch, + Message: params.Message, + Sha: params.Sha, + Author: author, + } + res, err := s.client.do(ctx, "POST", endpoint, in, nil) + return res, err } func (s *contentService) List(ctx context.Context, repo, path, ref string, opts scm.ListOptions) ([]*scm.ContentInfo, *scm.Response, error) { endpoint := fmt.Sprintf("/2.0/repositories/%s/src/%s/%s?%s", repo, ref, path, encodeListOptions(opts)) + if opts.URL != "" { + endpoint = opts.URL + } + out := new(contents) res, err := s.client.do(ctx, "GET", endpoint, nil, out) copyPagination(out.pagination, res) @@ -52,11 +101,38 @@ type contents struct { } type content struct { - Path string `json:"path"` - Type string `json:"type"` + Path string `json:"path"` + Type string `json:"type"` + Commit struct { + Hash string `json:"hash"` + } `json:"commit"` Attributes []string `json:"attributes"` } +type metaContent struct { + Path string `json:"path"` + Commit struct { + Hash string `json:"hash"` + } `json:"commit"` +} + +type contentCreateUpdate struct { + Files string `json:"files"` + Branch string `json:"branch"` + Message string `json:"message"` + Content []byte `json:"content"` + Sha string `json:"sha"` + Author string `json:"author"` +} + +type contentDelete struct { + File string `json:"file"` + Branch string `json:"branch"` + Message string `json:"message"` + Sha string `json:"sha"` + Author string `json:"author"` +} + func convertContentInfoList(from *contents) []*scm.ContentInfo { to := []*scm.ContentInfo{} for _, v := range from.Values { @@ -66,7 +142,10 @@ func convertContentInfoList(from *contents) []*scm.ContentInfo { } func convertContentInfo(from *content) *scm.ContentInfo { - to := &scm.ContentInfo{Path: from.Path} + to := &scm.ContentInfo{ + Path: from.Path, + Sha: from.Commit.Hash, + } switch from.Type { case "commit_file": to.Kind = func() scm.ContentKind { diff --git a/scm/driver/bitbucket/content_test.go b/scm/driver/bitbucket/content_test.go index d6a87da01..7c16f4e7e 100644 --- a/scm/driver/bitbucket/content_test.go +++ b/scm/driver/bitbucket/content_test.go @@ -25,6 +25,13 @@ func TestContentFind(t *testing.T) { Type("text/plain"). File("testdata/content.txt") + gock.New("https://api.bitbucket.org"). + MatchParam("format", "meta"). + Get("/2.0/repositories/atlassian/atlaskit/src/425863f9dbe56d70c8dcdbf2e4e0805e85591fcc/README"). + Reply(200). + Type("application/json"). + File("testdata/content.json") + client, _ := New("https://api.bitbucket.org") got, _, err := client.Contents.Find(context.Background(), "atlassian/atlaskit", "README", "425863f9dbe56d70c8dcdbf2e4e0805e85591fcc") if err != nil { @@ -41,27 +48,171 @@ func TestContentFind(t *testing.T) { } } +func TestContentFindNoMeta(t *testing.T) { + defer gock.Off() + + gock.New("https://api.bitbucket.org"). + Get("/2.0/repositories/atlassian/atlaskit/src/425863f9dbe56d70c8dcdbf2e4e0805e85591fcc/README"). + Reply(200). + Type("text/plain"). + File("testdata/content.txt") + + gock.New("https://api.bitbucket.org"). + MatchParam("format", "meta"). + Get("/2.0/repositories/atlassian/atlaskit/src/425863f9dbe56d70c8dcdbf2e4e0805e85591fcc/README"). + Reply(404). + Type("application/json"). + File("testdata/content_fail.json") + + client, _ := New("https://api.bitbucket.org") + got, _, err := client.Contents.Find(context.Background(), "atlassian/atlaskit", "README", "425863f9dbe56d70c8dcdbf2e4e0805e85591fcc") + if err != nil { + t.Error(err) + } + + want := new(scm.Content) + raw, _ := ioutil.ReadFile("testdata/content.json.fail") + json.Unmarshal(raw, want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + func TestContentCreate(t *testing.T) { - content := new(contentService) - _, err := content.Create(context.Background(), "atlassian/atlaskit", "README", nil) - if err != scm.ErrNotSupported { - t.Errorf("Expect Not Supported error") + defer gock.Off() + + gock.New("https://api.bitbucket.org"). + Post("/2.0/repositories/atlassian/atlaskit/src"). + Reply(201). + Type("application/json") + + params := &scm.ContentParams{ + Message: "my commit message", + Data: []byte("bXkgbmV3IGZpbGUgY29udGVudHM="), + Signature: scm.Signature{ + Name: "Monalisa Octocat", + Email: "octocat@github.com", + }, } + + client := NewDefault() + res, err := client.Contents.Create( + context.Background(), + "atlassian/atlaskit", + "test/hello", + params, + ) + + if err != nil { + t.Error(err) + return + } + + if res.Status != 201 { + t.Errorf("Unexpected Results") + } + } func TestContentUpdate(t *testing.T) { - content := new(contentService) - _, err := content.Update(context.Background(), "atlassian/atlaskit", "README", nil) - if err != scm.ErrNotSupported { - t.Errorf("Expect Not Supported error") + defer gock.Off() + + gock.New("https://api.bitbucket.org"). + Post("/2.0/repositories/atlassian/atlaskit/src"). + Reply(201). + Type("application/json") + + params := &scm.ContentParams{ + Message: "my commit message", + Data: []byte("bXkgbmV3IGZpbGUgY29udGVudHM="), + Signature: scm.Signature{ + Name: "Monalisa Octocat", + Email: "octocat@github.com", + }, + } + + client := NewDefault() + res, err := client.Contents.Update( + context.Background(), + "atlassian/atlaskit", + "test/hello", + params, + ) + + if err != nil { + t.Error(err) + return + } + + if res.Status != 201 { + t.Errorf("Unexpected Results") + } +} + +func TestContentUpdateBadCommitID(t *testing.T) { + defer gock.Off() + + gock.New("https://api.bitbucket.org"). + Post("/2.0/repositories/atlassian/atlaskit/src"). + Reply(400). + Type("application/json"). + File("testdata/content_update.json.fail") + + params := &scm.ContentParams{ + Message: "my commit message", + Data: []byte("bXkgbmV3IGZpbGUgY29udGVudHM="), + Sha: "bad commit", + Signature: scm.Signature{ + Name: "Monalisa Octocat", + Email: "octocat@github.com", + }, + } + + client := NewDefault() + _, err := client.Contents.Update( + context.Background(), + "atlassian/atlaskit", + "test/hello", + params, + ) + if err.Error() != "parents: Commit not found: 1a7eba6c-d4fe-47b7-b767-859abc660efc" { + t.Errorf("Expecting 'parents: Commit not found: 1a7eba6c-d4fe-47b7-b767-859abc660efc'") } } func TestContentDelete(t *testing.T) { - content := new(contentService) - _, err := content.Delete(context.Background(), "atlassian/atlaskit", "README", "master") - if err != scm.ErrNotSupported { - t.Errorf("Expect Not Supported error") + defer gock.Off() + + gock.New("https://api.bitbucket.org"). + Post("/2.0/repositories/atlassian/atlaskit/src"). + Reply(201). + Type("application/json") + + params := &scm.ContentParams{ + Message: "my commit message", + Signature: scm.Signature{ + Name: "Monalisa Octocat", + Email: "octocat@github.com", + }, + } + + client := NewDefault() + res, err := client.Contents.Update( + context.Background(), + "atlassian/atlaskit", + "test/hello", + params, + ) + + if err != nil { + t.Error(err) + return + } + + if res.Status != 201 { + t.Errorf("Unexpected Results") } } @@ -89,3 +240,29 @@ func TestContentList(t *testing.T) { t.Log(diff) } } + +func TestContentListWithUrlInput(t *testing.T) { + defer gock.Off() + + mockNextPageUri := "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/master/packages/activity?pageLen=3&page=RPfL" + + gock.New(mockNextPageUri). + Reply(200). + Type("application/json"). + File("testdata/content_list.json") + + client, _ := New("https://api.bitbucket.org") + got, _, err := client.Contents.List(context.Background(), "atlassian/atlaskit", "packages/activity", "master", scm.ListOptions{URL: mockNextPageUri}) + 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/bitbucket/git.go b/scm/driver/bitbucket/git.go index 79b6cae29..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,6 +17,17 @@ type gitService struct { client *wrapper } +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, + Target: target{ + Hash: params.Sha, + }, + } + return s.client.do(ctx, "POST", path, in, nil) +} + func (s *gitService) FindBranch(ctx context.Context, repo, name string) (*scm.Reference, *scm.Response, error) { path := fmt.Sprintf("2.0/repositories/%s/refs/branches/%s", repo, name) out := new(branch) @@ -24,7 +36,21 @@ 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) { - path := fmt.Sprintf("2.0/repositories/%s/commit/%s", repo, ref) + // github and gitlab permit fetching a commit by sha + // or branch. This code emulates the github and gitlab + // behavior for bitbucket 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 + } + } + 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 @@ -44,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)) @@ -54,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 } @@ -70,7 +112,7 @@ func (s *gitService) ListChanges(ctx context.Context, repo, ref string, opts scm } func (s *gitService) CompareChanges(ctx context.Context, repo, source, target string, opts scm.ListOptions) ([]*scm.Change, *scm.Response, error) { - path := fmt.Sprintf("2.0/repositories/%s/diffstat/%s..%s?%s", repo, source, target, encodeListOptions(opts)) + path := fmt.Sprintf("2.0/repositories/%s/diffstat/%s..%s?%s", repo, target, source, encodeListOptions(opts)) out := new(diffstats) res, err := s.client.do(ctx, "GET", path, nil, &out) copyPagination(out.pagination, res) @@ -85,6 +127,15 @@ type branch struct { } `json:"target"` } +type createBranch struct { + Name string `json:"name"` + Target target `json:"target"` +} + +type target struct { + Hash string `json:"hash"` +} + type commits struct { pagination Values []*commit `json:"values"` @@ -190,12 +241,20 @@ func convertDiffstats(from *diffstats) []*scm.Change { } func convertDiffstat(from *diffstat) *scm.Change { - return &scm.Change{ + response := &scm.Change{ Path: from.New.Path, Added: from.Status == "added", Renamed: from.Status == "renamed", Deleted: from.Status == "removed", } + + if response.Renamed { + response.PrevFilePath = from.Old.Path + } else if response.Deleted { + response.Path = from.Old.Path + } + + return response } func convertCommitList(from *commits) []*scm.Commit { diff --git a/scm/driver/bitbucket/git_test.go b/scm/driver/bitbucket/git_test.go index 7a15e8a83..912434bf1 100644 --- a/scm/driver/bitbucket/git_test.go +++ b/scm/driver/bitbucket/git_test.go @@ -41,6 +41,88 @@ 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() + + gock.New("https://api.bitbucket.org"). + Get("/2.0/repositories/atlassian/stash-example-plugin/commit/a6e5e7d797edf751cbd839d6bd4aef86c941eec9"). + Reply(200). + Type("application/json"). + File("testdata/commit.json") + + gock.New("https://api.bitbucket.org"). + Get("/2.0/repositories/atlassian/stash-example-plugin/refs/branches/master"). + Reply(200). + Type("application/json"). + File("testdata/branch.json") + + client, _ := New("https://api.bitbucket.org") + got, _, err := client.Git.FindCommit(context.Background(), "atlassian/stash-example-plugin", "master") + 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 TestGitCreateBranch(t *testing.T) { + defer gock.Off() + + gock.New("https://api.bitbucket.org"). + Post("/2.0/repositories/atlassian/stash-example-plugin/refs/branches"). + Reply(201). + Type("application/json"). + File("testdata/branch_create.json") + + params := &scm.ReferenceInput{ + Name: "yooo", + Sha: "2e684d13a43afd86cb48ea36d9f40f43e791fae9", + } + client, _ := New("https://api.bitbucket.org") + res, err := client.Git.CreateBranch(context.Background(), "atlassian/stash-example-plugin", params) + + if err != nil { + t.Error(err) + return + } + + if res.Status != 201 { + t.Errorf("Unexpected Results") + } +} func TestGitFindBranch(t *testing.T) { defer gock.Off() @@ -98,12 +180,13 @@ func TestGitListCommits(t *testing.T) { Get("/2.0/repositories/atlassian/stash-example-plugin/commits/master"). MatchParam("page", "1"). MatchParam("pagelen", "30"). + MatchParam("path", "LICENSE"). Reply(200). Type("application/json"). File("testdata/commits.json") client, _ := New("https://api.bitbucket.org") - got, res, err := client.Git.ListCommits(context.Background(), "atlassian/stash-example-plugin", scm.CommitListOptions{Ref: "master", Page: 1, Size: 30}) + got, res, err := client.Git.ListCommits(context.Background(), "atlassian/stash-example-plugin", scm.CommitListOptions{Ref: "master", Page: 1, Size: 30, Path: "LICENSE"}) if err != nil { t.Error(err) } @@ -149,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) } @@ -175,7 +290,6 @@ func TestGitListTags(t *testing.T) { t.Log(diff) } - t.Run("Page", testPage(res)) } func TestGitListChanges(t *testing.T) { @@ -208,7 +322,7 @@ func TestGitCompareChanges(t *testing.T) { defer gock.Off() gock.New("https://api.bitbucket.org"). - Get("/2.0/repositories/atlassian/atlaskit/diffstat/dec26e0fe887167743c2b7e36531dedfeb6cd478..425863f9dbe56d70c8dcdbf2e4e0805e85591fcc"). + Get("/2.0/repositories/atlassian/atlaskit/diffstat/425863f9dbe56d70c8dcdbf2e4e0805e85591fcc..dec26e0fe887167743c2b7e36531dedfeb6cd478"). MatchParam("page", "1"). MatchParam("pagelen", "30"). Reply(200). diff --git a/scm/driver/bitbucket/milestone.go b/scm/driver/bitbucket/milestone.go new file mode 100644 index 000000000..7c2624dc6 --- /dev/null +++ b/scm/driver/bitbucket/milestone.go @@ -0,0 +1,31 @@ +package bitbucket + +import ( + "context" + + "github.com/drone/go-scm/scm" +) + +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 +} diff --git a/scm/driver/bitbucket/org.go b/scm/driver/bitbucket/org.go index e14ba594c..7efd0e2a3 100644 --- a/scm/driver/bitbucket/org.go +++ b/scm/driver/bitbucket/org.go @@ -16,7 +16,7 @@ type organizationService struct { } func (s *organizationService) Find(ctx context.Context, name string) (*scm.Organization, *scm.Response, error) { - path := fmt.Sprintf("2.0/teams/%s", name) + path := fmt.Sprintf("2.0/workspaces/%s", name) out := new(organization) res, err := s.client.do(ctx, "GET", path, nil, out) return convertOrganization(out), res, err @@ -27,7 +27,7 @@ func (s *organizationService) FindMembership(ctx context.Context, name, username } func (s *organizationService) List(ctx context.Context, opts scm.ListOptions) ([]*scm.Organization, *scm.Response, error) { - path := fmt.Sprintf("2.0/teams?%s", encodeListRoleOptions(opts)) + path := fmt.Sprintf("2.0/workspaces?%s", encodeListRoleOptions(opts)) out := new(organizationList) res, err := s.client.do(ctx, "GET", path, nil, out) copyPagination(out.pagination, res) @@ -48,7 +48,7 @@ type organizationList struct { } type organization struct { - Login string `json:"username"` + Login string `json:"slug"` } func convertOrganization(from *organization) *scm.Organization { diff --git a/scm/driver/bitbucket/org_test.go b/scm/driver/bitbucket/org_test.go index 0868f7b34..62f19c7df 100644 --- a/scm/driver/bitbucket/org_test.go +++ b/scm/driver/bitbucket/org_test.go @@ -20,7 +20,7 @@ func TestOrganizationFind(t *testing.T) { defer gock.Off() gock.New("https://api.bitbucket.org"). - Get("/2.0/teams/atlassian"). + Get("/2.0/workspaces/atlassian"). Reply(200). Type("application/json"). File("testdata/team.json") @@ -45,7 +45,7 @@ func TestOrganizationList(t *testing.T) { defer gock.Off() gock.New("https://api.bitbucket.org"). - Get("/2.0/teams"). + Get("/2.0/workspaces"). MatchParam("pagelen", "30"). MatchParam("page", "1"). Reply(200). diff --git a/scm/driver/bitbucket/pr.go b/scm/driver/bitbucket/pr.go index 854fa0803..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) { @@ -39,6 +39,14 @@ func (s *pullService) ListChanges(ctx context.Context, repo string, number int, return convertDiffstats(out), res, err } +func (s *pullService) ListCommits(ctx context.Context, repo string, number int, opts scm.ListOptions) ([]*scm.Commit, *scm.Response, error) { + path := fmt.Sprintf("2.0/repositories/%s/pullrequests/%d/commits?%s", repo, number, encodeListOptions(opts)) + out := new(commits) + res, err := s.client.do(ctx, "GET", path, nil, &out) + copyPagination(out.pagination, res) + return convertCommitList(out), res, err +} + func (s *pullService) Merge(ctx context.Context, repo string, number int) (*scm.Response, error) { path := fmt.Sprintf("2.0/repositories/%s/pullrequests/%d/merge", repo, number) res, err := s.client.do(ctx, "POST", path, nil, nil) @@ -61,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"` @@ -100,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"` @@ -141,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, @@ -159,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, }, @@ -167,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 90d8648d6..038ec1952 100644 --- a/scm/driver/bitbucket/pr_test.go +++ b/scm/driver/bitbucket/pr_test.go @@ -149,3 +149,79 @@ func TestPullCreate(t *testing.T) { t.Log(diff) } } +func TestPullListCommits(t *testing.T) { + defer gock.Off() + + gock.New("https://api.bitbucket.org"). + Get("/2.0/repositories/atlassian/atlaskit/pullrequests/1/commits"). + MatchParam("pagelen", "30"). + MatchParam("page", "1"). + Reply(200). + Type("application/json"). + File("testdata/commits.json") + + client, _ := New("https://api.bitbucket.org") + got, _, err := client.PullRequests.ListCommits(context.Background(), "atlassian/atlaskit", 1, scm.ListOptions{Size: 30, Page: 1}) + if err != nil { + t.Error(err) + } + + 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) + } +} + +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/release.go b/scm/driver/bitbucket/release.go new file mode 100644 index 000000000..c38d0b40a --- /dev/null +++ b/scm/driver/bitbucket/release.go @@ -0,0 +1,43 @@ +package bitbucket + +import ( + "context" + + "github.com/drone/go-scm/scm" +) + +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 +} diff --git a/scm/driver/bitbucket/repo.go b/scm/driver/bitbucket/repo.go index cccae00d5..cc942c49a 100644 --- a/scm/driver/bitbucket/repo.go +++ b/scm/driver/bitbucket/repo.go @@ -105,6 +105,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 +} + // ListHooks returns a list or repository hooks. func (s *repositoryService) ListHooks(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Hook, *scm.Response, error) { path := fmt.Sprintf("2.0/repositories/%s/hooks?%s", repo, encodeListOptions(opts)) diff --git a/scm/driver/bitbucket/repo_test.go b/scm/driver/bitbucket/repo_test.go index 8b8efd79d..6c1f02b1b 100644 --- a/scm/driver/bitbucket/repo_test.go +++ b/scm/driver/bitbucket/repo_test.go @@ -136,6 +136,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 TestStatusList(t *testing.T) { defer gock.Off() diff --git a/scm/driver/bitbucket/testdata/branch_create.json b/scm/driver/bitbucket/testdata/branch_create.json new file mode 100644 index 000000000..ec47672a5 --- /dev/null +++ b/scm/driver/bitbucket/testdata/branch_create.json @@ -0,0 +1,103 @@ +{ + "name": "yooo", + "links": { + "commits": { + "href": "https://api.bitbucket.org/2.0/repositories/tphoney/scm-test/commits/yooo" + }, + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/tphoney/scm-test/refs/branches/yooo" + }, + "html": { + "href": "https://bitbucket.org/tphoney/scm-test/branch/yooo" + } + }, + "default_merge_strategy": "merge_commit", + "merge_strategies": [ + "merge_commit", + "squash", + "fast_forward" + ], + "type": "branch", + "target": { + "hash": "2e684d13a43afd86cb48ea36d9f40f43e791fae9", + "repository": { + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/tphoney/scm-test" + }, + "html": { + "href": "https://bitbucket.org/tphoney/scm-test" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7Bb918ca22-3472-4053-b234-c61deee57314%7D?ts=default" + } + }, + "type": "repository", + "name": "scm-test", + "full_name": "tphoney/scm-test", + "uuid": "{b918ca22-3472-4053-b234-c61deee57314}" + }, + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/tphoney/scm-test/commit/2e684d13a43afd86cb48ea36d9f40f43e791fae9" + }, + "comments": { + "href": "https://api.bitbucket.org/2.0/repositories/tphoney/scm-test/commit/2e684d13a43afd86cb48ea36d9f40f43e791fae9/comments" + }, + "patch": { + "href": "https://api.bitbucket.org/2.0/repositories/tphoney/scm-test/patch/2e684d13a43afd86cb48ea36d9f40f43e791fae9" + }, + "html": { + "href": "https://bitbucket.org/tphoney/scm-test/commits/2e684d13a43afd86cb48ea36d9f40f43e791fae9" + }, + "diff": { + "href": "https://api.bitbucket.org/2.0/repositories/tphoney/scm-test/diff/2e684d13a43afd86cb48ea36d9f40f43e791fae9" + }, + "approve": { + "href": "https://api.bitbucket.org/2.0/repositories/tphoney/scm-test/commit/2e684d13a43afd86cb48ea36d9f40f43e791fae9/approve" + }, + "statuses": { + "href": "https://api.bitbucket.org/2.0/repositories/tphoney/scm-test/commit/2e684d13a43afd86cb48ea36d9f40f43e791fae9/statuses" + } + }, + "author": { + "raw": "TP Honey ", + "type": "author", + "user": { + "display_name": "TP Honey", + "uuid": "{1d020398-429a-4fb3-9339-7e2096b1ecaf}", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7B1d020398-429a-4fb3-9339-7e2096b1ecaf%7D" + }, + "html": { + "href": "https://bitbucket.org/%7B1d020398-429a-4fb3-9339-7e2096b1ecaf%7D/" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/cb9ef853b678d8a34ce0734e57a24f2f?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTH-3.png" + } + }, + "nickname": "thomas.honey", + "type": "user", + "account_id": "60259ce77db80e006a2e0935" + } + }, + "parents": [ + { + "hash": "ba88d4dd3c98b442a77588ff1e623a16f2656a63", + "type": "commit", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/tphoney/scm-test/commit/ba88d4dd3c98b442a77588ff1e623a16f2656a63" + }, + "html": { + "href": "https://bitbucket.org/tphoney/scm-test/commits/ba88d4dd3c98b442a77588ff1e623a16f2656a63" + } + } + } + ], + "date": "2021-04-01T10:38:26+00:00", + "message": "asdasd created online with Bitbucket", + "type": "commit" + } +} \ No newline at end of file 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/content.json b/scm/driver/bitbucket/testdata/content.json new file mode 100644 index 000000000..8a4d8820e --- /dev/null +++ b/scm/driver/bitbucket/testdata/content.json @@ -0,0 +1,31 @@ +{ + "mimetype": null, + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/tphoney/scm-test/src/0846a192175701903ddd9264ece31922d8437c1a/README.md" + }, + "meta": { + "href": "https://api.bitbucket.org/2.0/repositories/tphoney/scm-test/src/0846a192175701903ddd9264ece31922d8437c1a/README.md?format=meta" + }, + "history": { + "href": "https://api.bitbucket.org/2.0/repositories/tphoney/scm-test/filehistory/0846a192175701903ddd9264ece31922d8437c1a/README.md" + } + }, + "escaped_path": "README.md", + "path": "README.md", + "commit": { + "type": "commit", + "hash": "0846a192175701903ddd9264ece31922d8437c1a", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/tphoney/scm-test/commit/0846a192175701903ddd9264ece31922d8437c1a" + }, + "html": { + "href": "https://bitbucket.org/tphoney/scm-test/commits/0846a192175701903ddd9264ece31922d8437c1a" + } + } + }, + "attributes": [], + "type": "commit_file", + "size": 39 +} \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/content.json.fail b/scm/driver/bitbucket/testdata/content.json.fail new file mode 100644 index 000000000..5c12f59e2 --- /dev/null +++ b/scm/driver/bitbucket/testdata/content.json.fail @@ -0,0 +1,4 @@ +{ + "Path": "README", + "Data": "SEVMTE8gV09STEQK" +} diff --git a/scm/driver/bitbucket/testdata/content.json.golden b/scm/driver/bitbucket/testdata/content.json.golden index b31f9dcdc..f7e307b61 100644 --- a/scm/driver/bitbucket/testdata/content.json.golden +++ b/scm/driver/bitbucket/testdata/content.json.golden @@ -1,4 +1,5 @@ { "Path": "README", - "Data": "SEVMTE8gV09STEQK" -} \ No newline at end of file + "Data": "SEVMTE8gV09STEQK", + "Sha": "0846a192175701903ddd9264ece31922d8437c1a" +} diff --git a/scm/driver/bitbucket/testdata/content_fail.json b/scm/driver/bitbucket/testdata/content_fail.json new file mode 100644 index 000000000..d8bf6879d --- /dev/null +++ b/scm/driver/bitbucket/testdata/content_fail.json @@ -0,0 +1,6 @@ +{ + "type": "error", + "error": { + "message": "No such file or directory: README.md.asdas" + } +} \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/content_list.json b/scm/driver/bitbucket/testdata/content_list.json index 7d3e5b2ed..9ea2f3523 100644 --- a/scm/driver/bitbucket/testdata/content_list.json +++ b/scm/driver/bitbucket/testdata/content_list.json @@ -1 +1,277 @@ -{"pagelen":10,"values":[{"path":"packages/activity/build","type":"commit_directory","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/build/"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/build/?format=meta"}},"commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}}},{"path":"packages/activity/dist","type":"commit_directory","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/dist/"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/dist/?format=meta"}},"commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}}},{"path":"packages/activity/docs","type":"commit_directory","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/docs/"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/docs/?format=meta"}},"commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}}},{"path":"packages/activity/src","type":"commit_directory","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/src/"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/src/?format=meta"}},"commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}}},{"path":"packages/activity/test","type":"commit_directory","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/test/"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/test/?format=meta"}},"commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}}},{"mimetype":null,"links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/.npmignore"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/.npmignore?format=meta"},"history":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/filehistory/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/.npmignore"}},"path":"packages/activity/.npmignore","commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}},"attributes":[],"type":"commit_file","size":10},{"mimetype":null,"links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/LICENSE"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/LICENSE?format=meta"},"history":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/filehistory/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/LICENSE"}},"path":"packages/activity/LICENSE","commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}},"attributes":[],"type":"commit_file","size":558},{"mimetype":"text/vnd.trolltech.linguist","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/index.ts"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/index.ts?format=meta"},"history":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/filehistory/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/index.ts"}},"path":"packages/activity/index.ts","commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}},"attributes":[],"type":"commit_file","size":494},{"mimetype":"application/json","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json?format=meta"},"history":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/filehistory/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json"}},"path":"packages/activity/package.json","commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}},"attributes":[],"type":"commit_file","size":1914},{"mimetype":"text/vnd.trolltech.linguist","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json.d.ts"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json.d.ts?format=meta"},"history":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/filehistory/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json.d.ts"}},"path":"packages/activity/package.json.d.ts","commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}},"attributes":[],"type":"commit_file","size":61}],"page":1,"next":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/master/packages/activity?page=8xhd"} \ No newline at end of file +{ + "pagelen": 10, + "values": [ + { + "path": "packages/activity/build", + "type": "commit_directory", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/build/" + }, + "meta": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/build/?format=meta" + } + }, + "commit": { + "type": "commit", + "hash": "710db794f15bd187db9e7a7b952aac48ebac08bb", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb" + }, + "html": { + "href": "https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb" + } + } + } + }, + { + "path": "packages/activity/dist", + "type": "commit_directory", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/dist/" + }, + "meta": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/dist/?format=meta" + } + }, + "commit": { + "type": "commit", + "hash": "710db794f15bd187db9e7a7b952aac48ebac08bb", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb" + }, + "html": { + "href": "https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb" + } + } + } + }, + { + "path": "packages/activity/docs", + "type": "commit_directory", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/docs/" + }, + "meta": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/docs/?format=meta" + } + }, + "commit": { + "type": "commit", + "hash": "710db794f15bd187db9e7a7b952aac48ebac08bb", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb" + }, + "html": { + "href": "https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb" + } + } + } + }, + { + "path": "packages/activity/src", + "type": "commit_directory", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/src/" + }, + "meta": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/src/?format=meta" + } + }, + "commit": { + "type": "commit", + "hash": "710db794f15bd187db9e7a7b952aac48ebac08bb", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb" + }, + "html": { + "href": "https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb" + } + } + } + }, + { + "path": "packages/activity/test", + "type": "commit_directory", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/test/" + }, + "meta": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/test/?format=meta" + } + }, + "commit": { + "type": "commit", + "hash": "710db794f15bd187db9e7a7b952aac48ebac08bb", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb" + }, + "html": { + "href": "https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb" + } + } + } + }, + { + "mimetype": null, + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/.npmignore" + }, + "meta": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/.npmignore?format=meta" + }, + "history": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/filehistory/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/.npmignore" + } + }, + "path": "packages/activity/.npmignore", + "commit": { + "type": "commit", + "hash": "710db794f15bd187db9e7a7b952aac48ebac08bb", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb" + }, + "html": { + "href": "https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb" + } + } + }, + "attributes": [], + "type": "commit_file", + "size": 10 + }, + { + "mimetype": null, + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/LICENSE" + }, + "meta": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/LICENSE?format=meta" + }, + "history": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/filehistory/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/LICENSE" + } + }, + "path": "packages/activity/LICENSE", + "commit": { + "type": "commit", + "hash": "710db794f15bd187db9e7a7b952aac48ebac08bb", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb" + }, + "html": { + "href": "https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb" + } + } + }, + "attributes": [], + "type": "commit_file", + "size": 558 + }, + { + "mimetype": "text/vnd.trolltech.linguist", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/index.ts" + }, + "meta": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/index.ts?format=meta" + }, + "history": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/filehistory/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/index.ts" + } + }, + "path": "packages/activity/index.ts", + "commit": { + "type": "commit", + "hash": "710db794f15bd187db9e7a7b952aac48ebac08bb", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb" + }, + "html": { + "href": "https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb" + } + } + }, + "attributes": [], + "type": "commit_file", + "size": 494 + }, + { + "mimetype": "application/json", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json" + }, + "meta": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json?format=meta" + }, + "history": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/filehistory/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json" + } + }, + "path": "packages/activity/package.json", + "commit": { + "type": "commit", + "hash": "710db794f15bd187db9e7a7b952aac48ebac08bb", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb" + }, + "html": { + "href": "https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb" + } + } + }, + "attributes": [], + "type": "commit_file", + "size": 1914 + }, + { + "mimetype": "text/vnd.trolltech.linguist", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json.d.ts" + }, + "meta": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json.d.ts?format=meta" + }, + "history": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/filehistory/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json.d.ts" + } + }, + "path": "packages/activity/package.json.d.ts", + "commit": { + "type": "commit", + "hash": "710db794f15bd187db9e7a7b952aac48ebac08bb", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb" + }, + "html": { + "href": "https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb" + } + } + }, + "attributes": [], + "type": "commit_file", + "size": 61 + } + ], + "page": 1, + "next": "https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/master/packages/activity?page=8xhd" +} \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/content_list.json.golden b/scm/driver/bitbucket/testdata/content_list.json.golden index c0dc728b1..6ec39c44e 100644 --- a/scm/driver/bitbucket/testdata/content_list.json.golden +++ b/scm/driver/bitbucket/testdata/content_list.json.golden @@ -1,42 +1,52 @@ [ { "path": "packages/activity/build", - "kind": "directory" + "kind": "directory", + "Sha": "710db794f15bd187db9e7a7b952aac48ebac08bb" }, { "path": "packages/activity/dist", - "kind": "directory" + "kind": "directory", + "Sha": "710db794f15bd187db9e7a7b952aac48ebac08bb" }, { "path": "packages/activity/docs", - "kind": "directory" + "kind": "directory", + "Sha": "710db794f15bd187db9e7a7b952aac48ebac08bb" }, { "path": "packages/activity/src", - "kind": "directory" + "kind": "directory", + "Sha": "710db794f15bd187db9e7a7b952aac48ebac08bb" }, { "path": "packages/activity/test", - "kind": "directory" + "kind": "directory", + "Sha": "710db794f15bd187db9e7a7b952aac48ebac08bb" }, { "path": "packages/activity/.npmignore", - "kind": "file" + "kind": "file", + "Sha": "710db794f15bd187db9e7a7b952aac48ebac08bb" }, { "path": "packages/activity/LICENSE", - "kind": "file" + "kind": "file", + "Sha": "710db794f15bd187db9e7a7b952aac48ebac08bb" }, { "path": "packages/activity/index.ts", - "kind": "file" + "kind": "file", + "Sha": "710db794f15bd187db9e7a7b952aac48ebac08bb" }, { "path": "packages/activity/package.json", - "kind": "file" + "kind": "file", + "Sha": "710db794f15bd187db9e7a7b952aac48ebac08bb" }, { "path": "packages/activity/package.json.d.ts", - "kind": "file" + "kind": "file", + "Sha": "710db794f15bd187db9e7a7b952aac48ebac08bb" } ] diff --git a/scm/driver/bitbucket/testdata/content_update.json.fail b/scm/driver/bitbucket/testdata/content_update.json.fail new file mode 100644 index 000000000..085a52569 --- /dev/null +++ b/scm/driver/bitbucket/testdata/content_update.json.fail @@ -0,0 +1,9 @@ +{ + "type": "error", + "error": { + "fields": { + "parents": [] + }, + "message": "parents: Commit not found: 1a7eba6c-d4fe-47b7-b767-859abc660efc" + } +} \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/diffstat.json b/scm/driver/bitbucket/testdata/diffstat.json index 6d6030ad5..97a36f5bf 100644 --- a/scm/driver/bitbucket/testdata/diffstat.json +++ b/scm/driver/bitbucket/testdata/diffstat.json @@ -24,6 +24,54 @@ } }, "type": "diffstat" + }, + { + "status": "renamed", + "old": { + "path": "old-folder/CONTRIBUTING.md", + "type": "commit_file", + "links": { + "self": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/atlaskit\/src\/dec26e0fe887167743c2b7e36531dedfeb6cd478\/CONTRIBUTING.md" + } + } + }, + "lines_removed": 0, + "lines_added": 0, + "new": { + "path": "new-folder/CONTRIBUTING.md", + "type": "commit_file", + "links": { + "self": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/atlaskit\/src\/425863f9dbe56d70c8dcdbf2e4e0805e85591fcc\/CONTRIBUTING.md" + } + } + }, + "type": "diffstat" + }, + { + "status": "removed", + "old": { + "path": "CONTRIBUTING.md", + "type": "commit_file", + "links": { + "self": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/atlaskit\/src\/dec26e0fe887167743c2b7e36531dedfeb6cd478\/CONTRIBUTING.md" + } + } + }, + "lines_removed": 15, + "lines_added": 0, + "new": { + "path": "", + "type": "commit_file", + "links": { + "self": { + "href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/atlaskit\/src\/425863f9dbe56d70c8dcdbf2e4e0805e85591fcc\/CONTRIBUTING.md" + } + } + }, + "type": "diffstat" } ], "page": 1, diff --git a/scm/driver/bitbucket/testdata/diffstat.json.golden b/scm/driver/bitbucket/testdata/diffstat.json.golden index 168e87d94..03fecb3ff 100644 --- a/scm/driver/bitbucket/testdata/diffstat.json.golden +++ b/scm/driver/bitbucket/testdata/diffstat.json.golden @@ -4,5 +4,18 @@ "Added": false, "Renamed": false, "Deleted": false + }, + { + "Path": "new-folder/CONTRIBUTING.md", + "Added": false, + "Renamed": true, + "Deleted": false, + "PrevFilePath": "old-folder/CONTRIBUTING.md" + }, + { + "Path": "CONTRIBUTING.md", + "Added": false, + "Renamed": false, + "Deleted": true } ] \ 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/team.json b/scm/driver/bitbucket/testdata/team.json index 929b2595f..97a446fad 100644 --- a/scm/driver/bitbucket/testdata/team.json +++ b/scm/driver/bitbucket/testdata/team.json @@ -1,17 +1,37 @@ { - "username": "atlassian", - "type": "team", - "display_name": "Atlassian", "uuid": "{02b941e3-cfaa-40f9-9a58-cec53e20bdc3}", "links": { + "owners": { + "href": "https://api.bitbucket.org/2.0/workspaces/atlassian/members?q=permission%3D%22owner%22" + }, + "hooks": { + "href": "https://api.bitbucket.org/2.0/workspaces/atlassian/hooks" + }, "self": { - "href": "https:\/\/api.bitbucket.org\/2.0\/teams\/atlassian" + "href": "https://api.bitbucket.org/2.0/workspaces/atlassian" + }, + "repositories": { + "href": "https://api.bitbucket.org/2.0/repositories/atlassian" }, "html": { - "href": "https:\/\/bitbucket.org\/atlassian\/" + "href": "https://bitbucket.org/atlassian/" }, "avatar": { - "href": "https:\/\/bitbucket.org\/account\/atlassian\/avatar\/32\/" + "href": "https://bitbucket.org/workspaces/atlassian/avatar/?ts=1612327398" + }, + "members": { + "href": "https://api.bitbucket.org/2.0/workspaces/atlassian/members" + }, + "projects": { + "href": "https://api.bitbucket.org/2.0/workspaces/atlassian/projects" + }, + "snippets": { + "href": "https://api.bitbucket.org/2.0/snippets/atlassian" } - } + }, + "created_on": "2018-11-29T02:26:39.297476+00:00", + "type": "workspace", + "slug": "atlassian", + "is_private": true, + "name": "Atlassian" } \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/teams.json b/scm/driver/bitbucket/testdata/teams.json index b767565d1..3b47bbf52 100644 --- a/scm/driver/bitbucket/testdata/teams.json +++ b/scm/driver/bitbucket/testdata/teams.json @@ -2,9 +2,10 @@ "pagelen": 30, "values": [ { - "username": "atlassian", + "slug": "atlassian", "website": null, - "display_name": "Atlassian", + "is_private": false, + "name": "Atlassian", "uuid": "{d5bb8c49-f033-4498-910e-7e4b546b04ee}", "links": { "hooks": { @@ -39,8 +40,7 @@ } }, "created_on": "2012-11-08T19:05:39.080491+00:00", - "location": null, - "type": "team" + "type": "workspace" } ], "page": 1, 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/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 0797aae42..d8986b55a 100644 --- a/scm/driver/bitbucket/testdata/webhooks/push_branch_create.json.golden +++ b/scm/driver/bitbucket/testdata/webhooks/push_branch_create.json.golden @@ -74,6 +74,7 @@ } ], "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 322223a56..688fff348 100644 --- a/scm/driver/bitbucket/testdata/webhooks/push_tag_create.json.golden +++ b/scm/driver/bitbucket/testdata/webhooks/push_tag_create.json.golden @@ -34,6 +34,7 @@ "Link": "https://bitbucket.org/brydzewski/foo/commits/141977fedf5cf35aa290ac87d4b5177ac4cd9de1" }, "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 d5ad1e4b8..eba34f022 100644 --- a/scm/driver/bitbucket/user.go +++ b/scm/driver/bitbucket/user.go @@ -29,7 +29,22 @@ func (s *userService) FindLogin(ctx context.Context, login string) (*scm.User, * } func (s *userService) FindEmail(ctx context.Context) (string, *scm.Response, error) { - return "", nil, scm.ErrNotSupported + out := new(emails) + 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 { @@ -49,6 +64,15 @@ type user struct { UUID string `json:"uuid"` } +type email struct { + Email string `json:"email"` + IsPrimary bool `json:"is_primary"` +} + +type emails struct { + Values []*email `json:"values"` +} + func convertUser(from *user) *scm.User { return &scm.User{ Avatar: fmt.Sprintf("https://bitbucket.org/account/%s/avatar/32/", from.Username), diff --git a/scm/driver/bitbucket/user_test.go b/scm/driver/bitbucket/user_test.go index aa3b4e947..4e6b3c9f4 100644 --- a/scm/driver/bitbucket/user_test.go +++ b/scm/driver/bitbucket/user_test.go @@ -67,9 +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"). + Reply(200). + Type("application/json"). + File("testdata/userEmail.json") + client, _ := New("https://api.bitbucket.org") - _, _, err := client.Users.FindEmail(context.Background()) - if err != scm.ErrNotSupported { - t.Errorf("Expect Not Supported error") + got, _, err := client.Users.FindEmail(context.Background()) + if err != nil { + t.Error(err) + } + + 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 38314c051..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 { @@ -55,6 +97,9 @@ func encodeCommitListOptions(opts scm.CommitListOptions) string { if opts.Size != 0 { params.Set("pagelen", strconv.Itoa(opts.Size)) } + if opts.Path != "" { + params.Set("path", opts.Path) + } return params.Encode() } diff --git a/scm/driver/bitbucket/webhook.go b/scm/driver/bitbucket/webhook.go index da62ba876..d254bba54 100644 --- a/scm/driver/bitbucket/webhook.go +++ b/scm/driver/bitbucket/webhook.go @@ -53,6 +53,23 @@ 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 + } } if err != nil { return nil, err @@ -78,6 +95,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) @@ -381,6 +404,200 @@ 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"` + } ) // @@ -446,6 +663,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 +696,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 +724,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 +752,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 +780,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 +801,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 +827,78 @@ 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 } diff --git a/scm/driver/bitbucket/webhook_test.go b/scm/driver/bitbucket/webhook_test.go index 9e633ed23..e72e096ff 100644 --- a/scm/driver/bitbucket/webhook_test.go +++ b/scm/driver/bitbucket/webhook_test.go @@ -132,6 +132,20 @@ 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), + }, } for _, test := range tests { diff --git a/scm/driver/gitea/content.go b/scm/driver/gitea/content.go index 07945a48a..d0c73ad5c 100644 --- a/scm/driver/gitea/content.go +++ b/scm/driver/gitea/content.go @@ -34,7 +34,7 @@ func (s *contentService) Update(ctx context.Context, repo, path string, params * return nil, scm.ErrNotSupported } -func (s *contentService) Delete(ctx context.Context, repo, path, ref string) (*scm.Response, error) { +func (s *contentService) Delete(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { return nil, scm.ErrNotSupported } @@ -48,6 +48,7 @@ func (s *contentService) List(ctx context.Context, repo, path, ref string, _ scm type content struct { Path string `json:"path"` Type string `json:"type"` + Sha string `json:"sha"` } func convertContentInfoList(from []*content) []*scm.ContentInfo { @@ -59,7 +60,7 @@ func convertContentInfoList(from []*content) []*scm.ContentInfo { } func convertContentInfo(from *content) *scm.ContentInfo { - to := &scm.ContentInfo{Path: from.Path} + to := &scm.ContentInfo{Path: from.Path, BlobID: from.Sha} switch from.Type { case "file": to.Kind = scm.ContentKindFile diff --git a/scm/driver/gitea/content_test.go b/scm/driver/gitea/content_test.go index 4e73acfc5..5a276da4c 100644 --- a/scm/driver/gitea/content_test.go +++ b/scm/driver/gitea/content_test.go @@ -61,7 +61,7 @@ func TestContentUpdate(t *testing.T) { func TestContentDelete(t *testing.T) { client, _ := New("https://try.gitea.io") - _, err := client.Contents.Delete(context.Background(), "go-gitea/gitea", "README.md", "master") + _, err := client.Contents.Delete(context.Background(), "go-gitea/gitea", "README.md", &scm.ContentParams{}) if err != scm.ErrNotSupported { t.Errorf("Expect Not Supported error") } diff --git a/scm/driver/gitea/git.go b/scm/driver/gitea/git.go index d20580561..aaa58134f 100644 --- a/scm/driver/gitea/git.go +++ b/scm/driver/gitea/git.go @@ -17,6 +17,10 @@ type gitService struct { client *wrapper } +func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.ReferenceInput) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + func (s *gitService) FindBranch(ctx context.Context, repo, name string) (*scm.Reference, *scm.Response, error) { path := fmt.Sprintf("api/v1/repos/%s/branches/%s", repo, name) out := new(branch) @@ -25,6 +29,7 @@ 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) { + ref = scm.TrimRef(ref) path := fmt.Sprintf("api/v1/repos/%s/git/commits/%s", repo, url.PathEscape(ref)) out := new(commitInfo) res, err := s.client.do(ctx, "GET", path, nil, out) @@ -54,8 +59,17 @@ 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) { - return nil, nil, scm.ErrNotSupported + path := fmt.Sprintf("api/v1/repos/%s/commits", repo) + out := []*commitInfo{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertCommitList(out), res, err } func (s *gitService) ListTags(ctx context.Context, repo string, _ scm.ListOptions) ([]*scm.Reference, *scm.Response, error) { @@ -142,13 +156,13 @@ func convertBranch(src *branch) *scm.Reference { } } -// func convertCommitList(src []*commit) []*scm.Commit { -// dst := []*scm.Commit{} -// for _, v := range src { -// dst = append(dst, convertCommitInfo(v)) -// } -// return dst -// } +func convertCommitList(src []*commitInfo) []*scm.Commit { + dst := []*scm.Commit{} + for _, v := range src { + dst = append(dst, convertCommitInfo(v)) + } + return dst +} func convertCommitInfo(src *commitInfo) *scm.Commit { return &scm.Commit{ diff --git a/scm/driver/gitea/git_test.go b/scm/driver/gitea/git_test.go index 65f139bea..de91410ce 100644 --- a/scm/driver/gitea/git_test.go +++ b/scm/driver/gitea/git_test.go @@ -24,7 +24,7 @@ func TestGitFindCommit(t *testing.T) { Get("/api/v1/repos/gitea/gitea/git/commits/c43399cad8766ee521b873a32c1652407c5a4630"). Reply(200). Type("application/json"). - File("testdata/commits.json") + File("testdata/commit.json") client, _ := New("https://try.gitea.io") got, _, err := client.Git.FindCommit( @@ -37,7 +37,7 @@ func TestGitFindCommit(t *testing.T) { } want := new(scm.Commit) - raw, _ := ioutil.ReadFile("testdata/commits.json.golden") + raw, _ := ioutil.ReadFile("testdata/commit.json.golden") json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { @@ -47,10 +47,25 @@ func TestGitFindCommit(t *testing.T) { } func TestGitListCommits(t *testing.T) { + gock.New("https://try.gitea.io"). + Get("/api/v1/repos/go-gitea/gitea/commits"). + Reply(200). + Type("application/json"). + File("testdata/commits.json") + client, _ := New("https://try.gitea.io") - _, _, err := client.Git.ListCommits(context.Background(), "go-gitea/gitea", scm.CommitListOptions{}) - if err != scm.ErrNotSupported { - t.Errorf("Expect Not Supported error") + got, _, err := client.Git.ListCommits(context.Background(), "go-gitea/gitea", scm.CommitListOptions{}) + if err != nil { + t.Error(err) + } + + 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/gitea/gitea.go b/scm/driver/gitea/gitea.go index e52900189..3e8031cbd 100644 --- a/scm/driver/gitea/gitea.go +++ b/scm/driver/gitea/gitea.go @@ -35,9 +35,11 @@ func New(uri string) (*scm.Client, error) { 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} diff --git a/scm/driver/gitea/gitea_test.go b/scm/driver/gitea/gitea_test.go index 79f0573da..658aef0c5 100644 --- a/scm/driver/gitea/gitea_test.go +++ b/scm/driver/gitea/gitea_test.go @@ -5,7 +5,10 @@ // package gitea implements a Gogs client. package gitea -import "testing" +import ( + "github.com/drone/go-scm/scm" + "testing" +) func TestClient(t *testing.T) { client, err := New("https://try.gitea.io") @@ -33,3 +36,20 @@ func TestClient_Error(t *testing.T) { 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) + } + } +} \ No newline at end of file diff --git a/scm/driver/gitea/milestone.go b/scm/driver/gitea/milestone.go new file mode 100644 index 000000000..73c69bccd --- /dev/null +++ b/scm/driver/gitea/milestone.go @@ -0,0 +1,130 @@ +package gitea + +import ( + "context" + "fmt" + + "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) { + namespace, name := scm.Split(repo) + path := fmt.Sprintf("api/v1/repos/%s/%s/milestones/%d", namespace, name, id) + out := new(milestone) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertMilestone(out), res, err +} + +func (s *milestoneService) List(ctx context.Context, repo string, opts scm.MilestoneListOptions) ([]*scm.Milestone, *scm.Response, error) { + namespace, name := scm.Split(repo) + path := fmt.Sprintf("api/v1/repos/%s/%s/milestones%s", namespace, name, encodeMilestoneListOptions(opts)) + out := []*milestone{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertMilestoneList(out), res, err +} + +func (s *milestoneService) Create(ctx context.Context, repo string, input *scm.MilestoneInput) (*scm.Milestone, *scm.Response, error) { + namespace, name := scm.Split(repo) + path := fmt.Sprintf("api/v1/repos/%s/%s/milestones", namespace, name) + in := &milestoneInput{ + Title: input.Title, + Description: input.Description, + State: stateOpen, + Deadline: null.TimeFrom(input.DueDate), + } + if input.State == "closed" { + in.State = stateClosed + } + out := new(milestone) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertMilestone(out), res, err +} + +func (s *milestoneService) Delete(ctx context.Context, repo string, id int) (*scm.Response, error) { + namespace, name := scm.Split(repo) + path := fmt.Sprintf("api/v1/repos/%s/%s/milestones/%d", namespace, name, id) + return s.client.do(ctx, "DELETE", path, nil, nil) +} + +func (s *milestoneService) Update(ctx context.Context, repo string, id int, input *scm.MilestoneInput) (*scm.Milestone, *scm.Response, error) { + namespace, name := scm.Split(repo) + path := fmt.Sprintf("api/v1/repos/%s/%s/milestones/%d", namespace, name, id) + in := milestoneInput{} + if input.Title != "" { + in.Title = input.Title + } + switch input.State { + case "open": + in.State = stateOpen + case "close", "closed": + in.State = stateClosed + } + if input.Description != "" { + in.Description = input.Description + } + if !input.DueDate.IsZero() { + in.Deadline = null.TimeFrom(input.DueDate) + } + out := new(milestone) + res, err := s.client.do(ctx, "PATCH", path, in, out) + return convertMilestone(out), res, err +} + +// 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/gitea/milestone_test.go b/scm/driver/gitea/milestone_test.go new file mode 100644 index 000000000..93d9f185e --- /dev/null +++ b/scm/driver/gitea/milestone_test.go @@ -0,0 +1,185 @@ +package gitea + +import ( + "context" + "encoding/json" + "io/ioutil" + "testing" + "time" + + "github.com/drone/go-scm/scm" + + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestMilestoneFind(t *testing.T) { + defer gock.Off() + + mockServerVersion() + + gock.New("https://try.gitea.io"). + Get("/api/v1/repos/jcitizen/my-repo/milestones/1"). + Reply(200). + Type("application/json"). + File("testdata/milestone.json") + + client, _ := New("https://try.gitea.io") + got, _, err := client.Milestones.Find(context.Background(), "jcitizen/my-repo", 1) + if err != nil { + t.Error(err) + } + + want := new(scm.Milestone) + raw, _ := ioutil.ReadFile("testdata/milestone.json.golden") + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestMilestoneList(t *testing.T) { + defer gock.Off() + + mockServerVersion() + + gock.New("https://try.gitea.io"). + Get("/api/v1/repos/jcitizen/my-repo/milestones"). + Reply(200). + Type("application/json"). + SetHeaders(mockPageHeaders). + File("testdata/milestones.json") + + client, _ := New("https://try.gitea.io") + got, res, err := client.Milestones.List(context.Background(), "jcitizen/my-repo", scm.MilestoneListOptions{}) + if err != nil { + t.Error(err) + } + + want := []*scm.Milestone{} + raw, _ := ioutil.ReadFile("testdata/milestones.json.golden") + err = json.Unmarshal(raw, &want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + t.Run("Page", testPage(res)) +} + +func TestMilestoneCreate(t *testing.T) { + defer gock.Off() + + mockServerVersion() + + gock.New("https://try.gitea.io"). + Post("/api/v1/repos/jcitizen/my-repo/milestones"). + File("testdata/milestone_create.json"). + Reply(200). + Type("application/json"). + File("testdata/milestone.json") + + client, _ := New("https://try.gitea.io") + dueDate, _ := time.Parse(scm.SearchTimeFormat, "2012-10-09T23:39:01Z") + input := &scm.MilestoneInput{ + Title: "v1.0", + Description: "Tracking milestone for version 1.0", + State: "open", + DueDate: dueDate, + } + got, _, err := client.Milestones.Create(context.Background(), "jcitizen/my-repo", input) + if err != nil { + t.Error(err) + } + + want := new(scm.Milestone) + raw, _ := ioutil.ReadFile("testdata/milestone.json.golden") + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestMilestoneUpdate(t *testing.T) { + defer gock.Off() + + mockServerVersion() + + gock.New("https://try.gitea.io"). + Patch("/api/v1/repos/jcitizen/my-repo/milestones"). + File("testdata/milestone_create.json"). + Reply(200). + Type("application/json"). + File("testdata/milestone.json") + + client, _ := New("https://try.gitea.io") + dueDate, _ := time.Parse(scm.SearchTimeFormat, "2012-10-09T23:39:01Z") + input := &scm.MilestoneInput{ + Title: "v1.0", + Description: "Tracking milestone for version 1.0", + State: "open", + DueDate: dueDate, + } + got, _, err := client.Milestones.Update(context.Background(), "jcitizen/my-repo", 1, input) + if err != nil { + t.Error(err) + } + + want := new(scm.Milestone) + raw, _ := ioutil.ReadFile("testdata/milestone.json.golden") + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestMilestoneDelete(t *testing.T) { + defer gock.Off() + + mockServerVersion() + + gock.New("https://try.gitea.io"). + Delete("/api/v1/repos/jcitizen/my-repo/milestones/1"). + Reply(200). + Type("application/json") + + client, _ := New("https://try.gitea.io") + _, err := client.Milestones.Delete(context.Background(), "jcitizen/my-repo", 1) + if err != nil { + t.Error(err) + } +} + +var mockPageHeaders = map[string]string{ + "Link": `; rel="next",` + + `; rel="prev",` + + `; rel="first",` + + `; rel="last"`, +} + +func mockServerVersion() { + gock.New("https://try.gitea.io"). + Get("/api/v1/version"). + Reply(200). + Type("application/json"). + File("testdata/version.json") +} diff --git a/scm/driver/gitea/org.go b/scm/driver/gitea/org.go index c7c7efc03..6ca8ec7ea 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) List(ctx context.Context, opts scm.ListOptions) ([]*scm.Organization, *scm.Response, error) { @@ -33,6 +39,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 // @@ -60,3 +78,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/pr.go b/scm/driver/gitea/pr.go index ab7fc4142..754f46240 100644 --- a/scm/driver/gitea/pr.go +++ b/scm/driver/gitea/pr.go @@ -38,6 +38,10 @@ func (s *pullService) ListComments(context.Context, string, int, scm.ListOptions return nil, nil, scm.ErrNotSupported } +func (s *pullService) ListCommits(context.Context, string, int, scm.ListOptions) ([]*scm.Commit, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + func (s *pullService) ListChanges(context.Context, string, int, scm.ListOptions) ([]*scm.Change, *scm.Response, error) { return nil, nil, scm.ErrNotSupported } diff --git a/scm/driver/gitea/pr_test.go b/scm/driver/gitea/pr_test.go index 6bff3bb3c..fc2d88e97 100644 --- a/scm/driver/gitea/pr_test.go +++ b/scm/driver/gitea/pr_test.go @@ -171,3 +171,11 @@ func TestPullRequestCommentDelete(t *testing.T) { t.Errorf("Expect Not Supported error") } } + +func TestPullListCommits(t *testing.T) { + client, _ := New("https://try.gitea.io") + _, _, err := client.PullRequests.ListCommits(context.Background(), "go-gitea/gitea", 1, scm.ListOptions{}) + if err != scm.ErrNotSupported { + t.Errorf("Expect Not Supported error") + } +} diff --git a/scm/driver/gitea/release.go b/scm/driver/gitea/release.go new file mode 100644 index 000000000..f64eab834 --- /dev/null +++ b/scm/driver/gitea/release.go @@ -0,0 +1,157 @@ +package gitea + +import ( + "context" + "fmt" + + "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) { + namespace, name := scm.Split(repo) + path := fmt.Sprintf("api/v1/repos/%s/%s/releases/%d", namespace, name, id) + out := new(release) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertRelease(out), res, err +} + +func (s *releaseService) FindByTag(ctx context.Context, repo string, tag string) (*scm.Release, *scm.Response, error) { + namespace, name := scm.Split(repo) + path := fmt.Sprintf("api/v1/repos/%s/%s/releases/tags/%s", namespace, name, tag) + out := new(release) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertRelease(out), res, err +} + +func (s *releaseService) List(ctx context.Context, repo string, opts scm.ReleaseListOptions) ([]*scm.Release, *scm.Response, error) { + namespace, name := scm.Split(repo) + path := fmt.Sprintf("api/v1/repos/%s/%s/releases?%s", namespace, name, encodeReleaseListOptions(releaseListOptionsToGiteaListOptions(opts))) + out := []*release{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertReleaseList(out), res, err +} + +func (s *releaseService) Create(ctx context.Context, repo string, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + namespace, name := scm.Split(repo) + path := fmt.Sprintf("api/v1/repos/%s/%s/releases", namespace, name) + in := &ReleaseInput{ + TagName: input.Tag, + Target: input.Commitish, + Title: input.Title, + Note: input.Description, + IsDraft: input.Draft, + IsPrerelease: input.Prerelease, + } + out := new(release) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertRelease(out), res, err +} + +func (s *releaseService) Delete(ctx context.Context, repo string, id int) (*scm.Response, error) { + namespace, name := scm.Split(repo) + path := fmt.Sprintf("api/v1/repos/%s/%s/releases/%d", namespace, name, id) + return s.client.do(ctx, "DELETE", path, nil, nil) +} + +func (s *releaseService) DeleteByTag(ctx context.Context, repo string, tag string) (*scm.Response, error) { + namespace, name := scm.Split(repo) + path := fmt.Sprintf("api/v1/repos/%s/%s/releases/tags/%s", namespace, name, tag) + return s.client.do(ctx, "DELETE", path, nil, nil) +} + +func (s *releaseService) Update(ctx context.Context, repo string, id int, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + namespace, name := scm.Split(repo) + path := fmt.Sprintf("api/v1/repos/%s/%s/releases/%d", namespace, name, id) + in := &ReleaseInput{ + TagName: input.Tag, + Target: input.Commitish, + Title: input.Title, + Note: input.Description, + IsDraft: input.Draft, + IsPrerelease: input.Prerelease, + } + out := new(release) + res, err := s.client.do(ctx, "PATCH", path, in, out) + return convertRelease(out), res, err +} + +func (s *releaseService) UpdateByTag(ctx context.Context, repo string, tag string, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + rel, _, err := s.FindByTag(ctx, repo, tag) + if err != nil { + return nil, nil, err + } + return s.Update(ctx, repo, rel.ID, input) +} + +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 *user `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/gitea/release_test.go b/scm/driver/gitea/release_test.go new file mode 100644 index 000000000..4cf491890 --- /dev/null +++ b/scm/driver/gitea/release_test.go @@ -0,0 +1,352 @@ +package gitea + +import ( + "context" + "encoding/json" + "io/ioutil" + "testing" + + "github.com/drone/go-scm/scm" + + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestConvertAPIURLToHTMLURL(t *testing.T) { + + got := convertAPIURLToHTMLURL("https://try.gitea.com/api/v1/repos/octocat/Hello-World/123", "v1.0.0") + want := "https://try.gitea.com/octocat/Hello-World/releases/tag/v1.0.0" + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + + t.Log("got:") + t.Log(string(got)) + } + +} + +func TestConvertAPIURLToHTMLURLEmptyLinkWhenURLParseFails(t *testing.T) { + + broken := []string{"http s://try.gitea.com/api/v1/repos/octocat/Hello-World/123", "https://try.gitea.com/api/v1/repos/octocat/Hello-World"} + for _, url := range broken { + + got := convertAPIURLToHTMLURL(url, "v1.0.0") + want := "" + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + + t.Log("got:") + t.Log(string(got)) + } + } + +} + +func TestReleaseFind(t *testing.T) { + defer gock.Off() + + mockServerVersion() + + gock.New("https://try.gitea.io"). + Get("/repos/octocat/hello-world/releases/1"). + Reply(200). + Type("application/json"). + File("testdata/release.json") + + client, err := New("https://try.gitea.io") + if err != nil { + t.Error(err) + return + } + got, _, err := client.Releases.Find(context.Background(), "octocat/hello-world", 1) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Release) + raw, _ := ioutil.ReadFile("testdata/release.json.golden") + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + + data, _ := json.Marshal(got) + t.Log("got JSON:") + t.Log(string(data)) + } +} + +func TestReleaseFindByTag(t *testing.T) { + defer gock.Off() + + mockServerVersion() + + gock.New("https://try.gitea.io"). + Get("/repos/octocat/hello-world/releases/tags/v1.0.0"). + Reply(200). + Type("application/json"). + File("testdata/release.json") + + client, err := New("https://try.gitea.io") + if err != nil { + t.Error(err) + return + } + got, _, err := client.Releases.FindByTag(context.Background(), "octocat/hello-world", "v1.0.0") + if err != nil { + t.Error(err) + return + } + + want := new(scm.Release) + raw, _ := ioutil.ReadFile("testdata/release.json.golden") + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + + data, _ := json.Marshal(got) + t.Log("got JSON:") + t.Log(string(data)) + } +} + +func TestReleaseList(t *testing.T) { + defer gock.Off() + + mockServerVersion() + + gock.New("https://try.gitea.io"). + Get("/repos/octocat/hello-world/releases"). + MatchParam("page", "1"). + MatchParam("limit", "30"). + Reply(200). + Type("application/json"). + File("testdata/releases.json") + + client, err := New("https://try.gitea.io") + if err != nil { + t.Error(err) + return + } + + got, _, err := client.Releases.List(context.Background(), "octocat/hello-world", scm.ReleaseListOptions{Page: 1, Size: 30, Open: true, Closed: true}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Release{} + raw, _ := ioutil.ReadFile("testdata/releases.json.golden") + err = json.Unmarshal(raw, &want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + + data, _ := json.Marshal(got) + t.Log("got JSON:") + t.Log(string(data)) + } + +} + +func TestReleaseCreate(t *testing.T) { + defer gock.Off() + + mockServerVersion() + + gock.New("https://try.gitea.io"). + Post("/repos/octocat/hello-world/releases"). + File("testdata/release_create.json"). + Reply(200). + Type("application/json"). + File("testdata/release.json") + + client, err := New("https://try.gitea.io") + if err != nil { + t.Error(err) + return + } + input := &scm.ReleaseInput{ + Title: "v1.0.0", + Description: "Description of the release", + Tag: "v1.0.0", + Commitish: "master", + Draft: false, + Prerelease: false, + } + + got, _, err := client.Releases.Create(context.Background(), "octocat/hello-world", input) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Release) + raw, _ := ioutil.ReadFile("testdata/release.json.golden") + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + + data, _ := json.Marshal(got) + t.Log("got JSON:") + t.Log(string(data)) + } + +} + +func TestReleaseUpdate(t *testing.T) { + defer gock.Off() + + mockServerVersion() + + gock.New("https://try.gitea.io"). + Patch("/repos/octocat/hello-world/releases/1"). + File("testdata/release_update.json"). + Reply(200). + Type("application/json"). + File("testdata/release.json") + + client, err := New("https://try.gitea.io") + if err != nil { + t.Error(err) + return + } + input := &scm.ReleaseInput{ + Title: "v1.0.0", + Description: "Description of the release", + Tag: "v1.0.0", + Commitish: "master", + Draft: false, + Prerelease: false, + } + got, _, err := client.Releases.Update(context.Background(), "octocat/hello-world", 1, input) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Release) + raw, _ := ioutil.ReadFile("testdata/release.json.golden") + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + +} + +func TestReleaseUpdateByTag(t *testing.T) { + defer gock.Off() + + mockServerVersion() + + gock.New("https://try.gitea.io"). + Get("/repos/octocat/hello-world/releases/tags/v1.0.0"). + Reply(200). + Type("application/json"). + File("testdata/release.json") + + gock.New("https://try.gitea.io"). + Patch("/repos/octocat/hello-world/releases/1"). + File("testdata/release_update.json"). + Reply(200). + Type("application/json"). + File("testdata/release.json") + + client, err := New("https://try.gitea.io") + if err != nil { + t.Error(err) + return + } + input := &scm.ReleaseInput{ + Title: "v1.0.0", + Description: "Description of the release", + Tag: "v1.0.0", + Commitish: "master", + Draft: false, + Prerelease: false, + } + got, _, err := client.Releases.UpdateByTag(context.Background(), "octocat/hello-world", "v1.0.0", input) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Release) + raw, _ := ioutil.ReadFile("testdata/release.json.golden") + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + +} + +func TestReleaseDelete(t *testing.T) { + defer gock.Off() + + mockServerVersion() + + gock.New("https://try.gitea.io"). + Delete("/repos/octocat/hello-world/releases/1"). + Reply(200). + Type("application/json") + + client, err := New("https://try.gitea.io") + _, err = client.Releases.Delete(context.Background(), "octocat/hello-world", 1) + if err != nil { + t.Error(err) + return + } + +} + +func TestReleaseDeleteByTag(t *testing.T) { + defer gock.Off() + + mockServerVersion() + + gock.New("https://try.gitea.io"). + Delete("/repos/octocat/hello-world/releases/tags/v1.0.0"). + Reply(200). + Type("application/json") + + client, err := New("https://try.gitea.io") + _, err = client.Releases.DeleteByTag(context.Background(), "octocat/hello-world", "v1.0.0") + if err != nil { + t.Error(err) + return + } + +} diff --git a/scm/driver/gitea/repo.go b/scm/driver/gitea/repo.go index 154c7f322..81d92a5f5 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) ListHooks(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Hook, *scm.Response, error) { path := fmt.Sprintf("api/v1/repos/%s/hooks?%s", repo, encodeListOptions(opts)) out := []*hook{} @@ -148,6 +160,7 @@ type ( CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` Permissions perm `json:"permissions"` + Archived bool `json:"archived"` } // gitea permissions details. @@ -215,6 +228,7 @@ func convertRepository(src *repository) *scm.Repository { Clone: src.CloneURL, CloneSSH: src.SSHURL, Link: src.HTMLURL, + Archived: src.Archived, } } diff --git a/scm/driver/gitea/testdata/commit.json b/scm/driver/gitea/testdata/commit.json new file mode 100644 index 000000000..d43d473de --- /dev/null +++ b/scm/driver/gitea/testdata/commit.json @@ -0,0 +1,39 @@ +{ + "url": "https://try.gitea.io/api/v1/repos/gitea/gitea/git/commits/c43399cad8766ee521b873a32c1652407c5a4630", + "sha": "c43399cad8766ee521b873a32c1652407c5a4630", + "html_url": "https://try.gitea.io/gitea/gitea/commits/c43399cad8766ee521b873a32c1652407c5a4630", + "commit": { + "url": "https://try.gitea.io/api/v1/repos/gitea/gitea/git/commits/c43399cad8766ee521b873a32c1652407c5a4630", + "author": { + "name": "Lewis Cowles", + "email": "lewiscowles@me.com", + "date": "2018-09-09T03:36:08Z" + }, + "committer": { + "name": "Lunny Xiao", + "email": "xiaolunwen@gmail.com", + "date": "2018-09-09T03:36:08Z" + }, + "message": "Fixes repo branch endpoint summary (#4893)", + "tree": { + "url": "https://try.gitea.io/api/v1/repos/gitea/gitea/trees/c43399cad8766ee521b873a32c1652407c5a4630", + "sha": "c43399cad8766ee521b873a32c1652407c5a4630" + } + }, + "author": null, + "committer": { + "id": 3, + "login": "lunny", + "full_name": "Lunny Xiao", + "email": "xiaolunwen@gmail.com", + "avatar_url": "https://secure.gravatar.com/avatar/271fc56bcea89c6f69ab0024b59b3f81?d=identicon", + "language": "zh-CN", + "username": "lunny" + }, + "parents": [ + { + "url": "https://try.gitea.io/api/v1/repos/gitea/gitea/git/commits/d293a2b9d6722dffde7998c953c3087e47a38a83", + "sha": "d293a2b9d6722dffde7998c953c3087e47a38a83" + } + ] +} \ No newline at end of file diff --git a/scm/driver/gitea/testdata/commit.json.golden b/scm/driver/gitea/testdata/commit.json.golden new file mode 100644 index 000000000..da61dbddd --- /dev/null +++ b/scm/driver/gitea/testdata/commit.json.golden @@ -0,0 +1,11 @@ +{ + "committer": { + "name": "Lunny Xiao", + "login": "lunny", + "email": "xiaolunwen@gmail.com", + "avatar": "https://secure.gravatar.com/avatar/271fc56bcea89c6f69ab0024b59b3f81?d=identicon" + }, + "link": "https://try.gitea.io/api/v1/repos/gitea/gitea/git/commits/c43399cad8766ee521b873a32c1652407c5a4630", + "sha": "c43399cad8766ee521b873a32c1652407c5a4630", + "message": "Fixes repo branch endpoint summary (#4893)" +} \ No newline at end of file diff --git a/scm/driver/gitea/testdata/commits.json b/scm/driver/gitea/testdata/commits.json index 1478fa4be..936a6029d 100644 --- a/scm/driver/gitea/testdata/commits.json +++ b/scm/driver/gitea/testdata/commits.json @@ -1 +1,41 @@ -{"url":"https://try.gitea.io/api/v1/repos/gitea/gitea/git/commits/c43399cad8766ee521b873a32c1652407c5a4630","sha":"c43399cad8766ee521b873a32c1652407c5a4630","html_url":"https://try.gitea.io/gitea/gitea/commits/c43399cad8766ee521b873a32c1652407c5a4630","commit":{"url":"https://try.gitea.io/api/v1/repos/gitea/gitea/git/commits/c43399cad8766ee521b873a32c1652407c5a4630","author":{"name":"Lewis Cowles","email":"lewiscowles@me.com","date":"2018-09-09T03:36:08Z"},"committer":{"name":"Lunny Xiao","email":"xiaolunwen@gmail.com","date":"2018-09-09T03:36:08Z"},"message":"Fixes repo branch endpoint summary (#4893)","tree":{"url":"https://try.gitea.io/api/v1/repos/gitea/gitea/trees/c43399cad8766ee521b873a32c1652407c5a4630","sha":"c43399cad8766ee521b873a32c1652407c5a4630"}},"author":null,"committer":{"id":3,"login":"lunny","full_name":"Lunny Xiao","email":"xiaolunwen@gmail.com","avatar_url":"https://secure.gravatar.com/avatar/271fc56bcea89c6f69ab0024b59b3f81?d=identicon","language":"zh-CN","username":"lunny"},"parents":[{"url":"https://try.gitea.io/api/v1/repos/gitea/gitea/git/commits/d293a2b9d6722dffde7998c953c3087e47a38a83","sha":"d293a2b9d6722dffde7998c953c3087e47a38a83"}]} \ No newline at end of file +[ + { + "url": "https://try.gitea.io/api/v1/repos/gitea/gitea/git/commits/c43399cad8766ee521b873a32c1652407c5a4630", + "sha": "c43399cad8766ee521b873a32c1652407c5a4630", + "html_url": "https://try.gitea.io/gitea/gitea/commits/c43399cad8766ee521b873a32c1652407c5a4630", + "commit": { + "url": "https://try.gitea.io/api/v1/repos/gitea/gitea/git/commits/c43399cad8766ee521b873a32c1652407c5a4630", + "author": { + "name": "Lewis Cowles", + "email": "lewiscowles@me.com", + "date": "2018-09-09T03:36:08Z" + }, + "committer": { + "name": "Lunny Xiao", + "email": "xiaolunwen@gmail.com", + "date": "2018-09-09T03:36:08Z" + }, + "message": "Fixes repo branch endpoint summary (#4893)", + "tree": { + "url": "https://try.gitea.io/api/v1/repos/gitea/gitea/trees/c43399cad8766ee521b873a32c1652407c5a4630", + "sha": "c43399cad8766ee521b873a32c1652407c5a4630" + } + }, + "author": null, + "committer": { + "id": 3, + "login": "lunny", + "full_name": "Lunny Xiao", + "email": "xiaolunwen@gmail.com", + "avatar_url": "https://secure.gravatar.com/avatar/271fc56bcea89c6f69ab0024b59b3f81?d=identicon", + "language": "zh-CN", + "username": "lunny" + }, + "parents": [ + { + "url": "https://try.gitea.io/api/v1/repos/gitea/gitea/git/commits/d293a2b9d6722dffde7998c953c3087e47a38a83", + "sha": "d293a2b9d6722dffde7998c953c3087e47a38a83" + } + ] + } +] \ No newline at end of file diff --git a/scm/driver/gitea/testdata/commits.json.golden b/scm/driver/gitea/testdata/commits.json.golden index da61dbddd..bb9d78ed4 100644 --- a/scm/driver/gitea/testdata/commits.json.golden +++ b/scm/driver/gitea/testdata/commits.json.golden @@ -1,11 +1,13 @@ -{ - "committer": { - "name": "Lunny Xiao", - "login": "lunny", - "email": "xiaolunwen@gmail.com", - "avatar": "https://secure.gravatar.com/avatar/271fc56bcea89c6f69ab0024b59b3f81?d=identicon" - }, - "link": "https://try.gitea.io/api/v1/repos/gitea/gitea/git/commits/c43399cad8766ee521b873a32c1652407c5a4630", - "sha": "c43399cad8766ee521b873a32c1652407c5a4630", - "message": "Fixes repo branch endpoint summary (#4893)" -} \ No newline at end of file +[ + { + "committer": { + "name": "Lunny Xiao", + "login": "lunny", + "email": "xiaolunwen@gmail.com", + "avatar": "https://secure.gravatar.com/avatar/271fc56bcea89c6f69ab0024b59b3f81?d=identicon" + }, + "link": "https://try.gitea.io/api/v1/repos/gitea/gitea/git/commits/c43399cad8766ee521b873a32c1652407c5a4630", + "sha": "c43399cad8766ee521b873a32c1652407c5a4630", + "message": "Fixes repo branch endpoint summary (#4893)" + } +] \ No newline at end of file diff --git a/scm/driver/gitea/testdata/content_list.json b/scm/driver/gitea/testdata/content_list.json index 72efd49f6..b7b2871a4 100644 --- a/scm/driver/gitea/testdata/content_list.json +++ b/scm/driver/gitea/testdata/content_list.json @@ -1 +1,82 @@ -[{"name":"advanced.en-us.md","path":"docs/content/doc/advanced.en-us.md","sha":"de2bfeed6f2d3ea1d2f91e457e9450efc582bb31","type":"file","size":192,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/advanced.en-us.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/advanced.en-us.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/de2bfeed6f2d3ea1d2f91e457e9450efc582bb31","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/advanced.en-us.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/advanced.en-us.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/de2bfeed6f2d3ea1d2f91e457e9450efc582bb31","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/advanced.en-us.md"}},{"name":"advanced.fr-fr.md","path":"docs/content/doc/advanced.fr-fr.md","sha":"04734a8f81f5641de2b6d738bc9b777c2cc541c6","type":"file","size":190,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/advanced.fr-fr.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/advanced.fr-fr.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/04734a8f81f5641de2b6d738bc9b777c2cc541c6","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/advanced.fr-fr.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/advanced.fr-fr.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/04734a8f81f5641de2b6d738bc9b777c2cc541c6","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/advanced.fr-fr.md"}},{"name":"advanced.zh-cn.md","path":"docs/content/doc/advanced.zh-cn.md","sha":"1f7ebf81e723a0ba82a89eec18a2706ac1b0dace","type":"file","size":188,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/advanced.zh-cn.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/advanced.zh-cn.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/1f7ebf81e723a0ba82a89eec18a2706ac1b0dace","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/advanced.zh-cn.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/advanced.zh-cn.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/1f7ebf81e723a0ba82a89eec18a2706ac1b0dace","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/advanced.zh-cn.md"}},{"name":"advanced","path":"docs/content/doc/advanced","sha":"8c43a4fb023735dfd026014bae92ad91414b88bd","type":"dir","size":0,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/advanced?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/advanced","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/8c43a4fb023735dfd026014bae92ad91414b88bd","download_url":null,"submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/advanced?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/8c43a4fb023735dfd026014bae92ad91414b88bd","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/advanced"}},{"name":"features.en-us.md","path":"docs/content/doc/features.en-us.md","sha":"9cc90b46a0d17864e5ce1749dbd1609a0921f8f7","type":"file","size":192,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/features.en-us.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/features.en-us.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/9cc90b46a0d17864e5ce1749dbd1609a0921f8f7","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/features.en-us.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/features.en-us.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/9cc90b46a0d17864e5ce1749dbd1609a0921f8f7","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/features.en-us.md"}},{"name":"features.zh-cn.md","path":"docs/content/doc/features.zh-cn.md","sha":"68d2f71b11f6bb5b1ca31adad00bc0f6ed3e94d8","type":"file","size":188,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/features.zh-cn.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/features.zh-cn.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/68d2f71b11f6bb5b1ca31adad00bc0f6ed3e94d8","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/features.zh-cn.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/features.zh-cn.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/68d2f71b11f6bb5b1ca31adad00bc0f6ed3e94d8","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/features.zh-cn.md"}},{"name":"features.zh-tw.md","path":"docs/content/doc/features.zh-tw.md","sha":"889e0df88213a937914ba43bb52956d0e54b1c98","type":"file","size":188,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/features.zh-tw.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/features.zh-tw.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/889e0df88213a937914ba43bb52956d0e54b1c98","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/features.zh-tw.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/features.zh-tw.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/889e0df88213a937914ba43bb52956d0e54b1c98","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/features.zh-tw.md"}},{"name":"features","path":"docs/content/doc/features","sha":"e212486606cf756b3b626f0a5bb1dd386b83b698","type":"dir","size":0,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/features?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/features","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/e212486606cf756b3b626f0a5bb1dd386b83b698","download_url":null,"submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/features?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/e212486606cf756b3b626f0a5bb1dd386b83b698","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/features"}},{"name":"help.en-us.md","path":"docs/content/doc/help.en-us.md","sha":"5ad1dd7f1edb3b78a3e3fba2113ecd5b10625dc4","type":"file","size":176,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/help.en-us.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/help.en-us.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/5ad1dd7f1edb3b78a3e3fba2113ecd5b10625dc4","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/help.en-us.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/help.en-us.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/5ad1dd7f1edb3b78a3e3fba2113ecd5b10625dc4","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/help.en-us.md"}},{"name":"help.zh-cn.md","path":"docs/content/doc/help.zh-cn.md","sha":"6af7aa1719b99e35874b76911aff29b9ad4bbc68","type":"file","size":180,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/help.zh-cn.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/help.zh-cn.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/6af7aa1719b99e35874b76911aff29b9ad4bbc68","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/help.zh-cn.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/help.zh-cn.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/6af7aa1719b99e35874b76911aff29b9ad4bbc68","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/help.zh-cn.md"}},{"name":"help","path":"docs/content/doc/help","sha":"91adc879a877f6c44aab1f27453bfa2679e4c3a0","type":"dir","size":0,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/help?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/help","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/91adc879a877f6c44aab1f27453bfa2679e4c3a0","download_url":null,"submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/help?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/91adc879a877f6c44aab1f27453bfa2679e4c3a0","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/help"}},{"name":"installation.en-us.md","path":"docs/content/doc/installation.en-us.md","sha":"4257521d973b0d28a7040f9030f701bbd1bf7bef","type":"file","size":208,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/installation.en-us.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/installation.en-us.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/4257521d973b0d28a7040f9030f701bbd1bf7bef","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/installation.en-us.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/installation.en-us.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/4257521d973b0d28a7040f9030f701bbd1bf7bef","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/installation.en-us.md"}},{"name":"installation.fr-fr.md","path":"docs/content/doc/installation.fr-fr.md","sha":"55b48bda3eca4e459c12e44d54de9c4573d9b0b7","type":"file","size":208,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/installation.fr-fr.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/installation.fr-fr.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/55b48bda3eca4e459c12e44d54de9c4573d9b0b7","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/installation.fr-fr.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/installation.fr-fr.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/55b48bda3eca4e459c12e44d54de9c4573d9b0b7","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/installation.fr-fr.md"}},{"name":"installation.zh-cn.md","path":"docs/content/doc/installation.zh-cn.md","sha":"8f57e0f00c273619c1ce66f04f7536f62d830e88","type":"file","size":196,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/installation.zh-cn.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/installation.zh-cn.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/8f57e0f00c273619c1ce66f04f7536f62d830e88","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/installation.zh-cn.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/installation.zh-cn.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/8f57e0f00c273619c1ce66f04f7536f62d830e88","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/installation.zh-cn.md"}},{"name":"installation.zh-tw.md","path":"docs/content/doc/installation.zh-tw.md","sha":"f955e994ac09834f546212a6ec494978a4d10039","type":"file","size":196,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/installation.zh-tw.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/installation.zh-tw.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/f955e994ac09834f546212a6ec494978a4d10039","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/installation.zh-tw.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/installation.zh-tw.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/f955e994ac09834f546212a6ec494978a4d10039","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/installation.zh-tw.md"}},{"name":"installation","path":"docs/content/doc/installation","sha":"2a3ff66218ae980c07444b8c97b710b3d7b5b846","type":"dir","size":0,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/installation?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/installation","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/2a3ff66218ae980c07444b8c97b710b3d7b5b846","download_url":null,"submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/installation?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/2a3ff66218ae980c07444b8c97b710b3d7b5b846","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/installation"}},{"name":"upgrade.en-us.md","path":"docs/content/doc/upgrade.en-us.md","sha":"9623ff9f1eaf74e9ebc03f5869bc0b9d2b3372d3","type":"file","size":188,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/upgrade.en-us.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/upgrade.en-us.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/9623ff9f1eaf74e9ebc03f5869bc0b9d2b3372d3","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/upgrade.en-us.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/upgrade.en-us.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/9623ff9f1eaf74e9ebc03f5869bc0b9d2b3372d3","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/upgrade.en-us.md"}},{"name":"upgrade.fr-fr.md","path":"docs/content/doc/upgrade.fr-fr.md","sha":"ca08daf9c096bf027ba95a13b44c5fe4d0a47afe","type":"file","size":198,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/upgrade.fr-fr.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/upgrade.fr-fr.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/ca08daf9c096bf027ba95a13b44c5fe4d0a47afe","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/upgrade.fr-fr.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/upgrade.fr-fr.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/ca08daf9c096bf027ba95a13b44c5fe4d0a47afe","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/upgrade.fr-fr.md"}},{"name":"upgrade.zh-cn.md","path":"docs/content/doc/upgrade.zh-cn.md","sha":"d12e150b9cbce2c26acb64c724914cec8667bb5d","type":"file","size":186,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/upgrade.zh-cn.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/upgrade.zh-cn.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/d12e150b9cbce2c26acb64c724914cec8667bb5d","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/upgrade.zh-cn.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/upgrade.zh-cn.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/d12e150b9cbce2c26acb64c724914cec8667bb5d","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/upgrade.zh-cn.md"}},{"name":"upgrade.zh-tw.md","path":"docs/content/doc/upgrade.zh-tw.md","sha":"b57fccbdd578e9c981171838a9dd1e152f69bce9","type":"file","size":186,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/upgrade.zh-tw.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/upgrade.zh-tw.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/b57fccbdd578e9c981171838a9dd1e152f69bce9","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/upgrade.zh-tw.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/upgrade.zh-tw.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/b57fccbdd578e9c981171838a9dd1e152f69bce9","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/upgrade.zh-tw.md"}},{"name":"upgrade","path":"docs/content/doc/upgrade","sha":"ff064862ee6ca9aa7bfda908c5354c83fbac25a4","type":"dir","size":0,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/upgrade?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/upgrade","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/ff064862ee6ca9aa7bfda908c5354c83fbac25a4","download_url":null,"submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/upgrade?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/ff064862ee6ca9aa7bfda908c5354c83fbac25a4","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/upgrade"}},{"name":"usage.en-us.md","path":"docs/content/doc/usage.en-us.md","sha":"6be9769d64603f93e05e099a8b2dcbceae1e98df","type":"file","size":180,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/usage.en-us.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/usage.en-us.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/6be9769d64603f93e05e099a8b2dcbceae1e98df","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/usage.en-us.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/usage.en-us.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/6be9769d64603f93e05e099a8b2dcbceae1e98df","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/usage.en-us.md"}},{"name":"usage.zh-cn.md","path":"docs/content/doc/usage.zh-cn.md","sha":"c533df662481ea381cba02f0cb7996a3c1b377fd","type":"file","size":194,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/usage.zh-cn.md?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/usage.zh-cn.md","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/c533df662481ea381cba02f0cb7996a3c1b377fd","download_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/usage.zh-cn.md","submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/usage.zh-cn.md?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/c533df662481ea381cba02f0cb7996a3c1b377fd","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/usage.zh-cn.md"}},{"name":"usage","path":"docs/content/doc/usage","sha":"ac7d00a3401c3299068e09da540badfaf29d5e58","type":"dir","size":0,"encoding":null,"content":null,"target":null,"url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/usage?ref=master","html_url":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/usage","git_url":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/ac7d00a3401c3299068e09da540badfaf29d5e58","download_url":null,"submodule_git_url":null,"_links":{"self":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/usage?ref=master","git":"https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/ac7d00a3401c3299068e09da540badfaf29d5e58","html":"https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/usage"}}] \ No newline at end of file +[ + { + "name": "advanced.en-us.md", + "path": "docs/content/doc/advanced.en-us.md", + "sha": "de2bfeed6f2d3ea1d2f91e457e9450efc582bb31", + "type": "file", + "size": 192, + "encoding": null, + "content": null, + "target": null, + "url": "https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/advanced.en-us.md?ref=master", + "html_url": "https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/advanced.en-us.md", + "git_url": "https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/de2bfeed6f2d3ea1d2f91e457e9450efc582bb31", + "download_url": "https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/advanced.en-us.md", + "submodule_git_url": null, + "_links": { + "self": "https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/advanced.en-us.md?ref=master", + "git": "https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/de2bfeed6f2d3ea1d2f91e457e9450efc582bb31", + "html": "https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/advanced.en-us.md" + } + }, + { + "name": "advanced.fr-fr.md", + "path": "docs/content/doc/advanced.fr-fr.md", + "sha": "04734a8f81f5641de2b6d738bc9b777c2cc541c6", + "type": "file", + "size": 190, + "encoding": null, + "content": null, + "target": null, + "url": "https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/advanced.fr-fr.md?ref=master", + "html_url": "https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/advanced.fr-fr.md", + "git_url": "https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/04734a8f81f5641de2b6d738bc9b777c2cc541c6", + "download_url": "https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/advanced.fr-fr.md", + "submodule_git_url": null, + "_links": { + "self": "https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/advanced.fr-fr.md?ref=master", + "git": "https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/04734a8f81f5641de2b6d738bc9b777c2cc541c6", + "html": "https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/advanced.fr-fr.md" + } + }, + { + "name": "advanced.zh-cn.md", + "path": "docs/content/doc/advanced.zh-cn.md", + "sha": "1f7ebf81e723a0ba82a89eec18a2706ac1b0dace", + "type": "file", + "size": 188, + "encoding": null, + "content": null, + "target": null, + "url": "https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/advanced.zh-cn.md?ref=master", + "html_url": "https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/advanced.zh-cn.md", + "git_url": "https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/1f7ebf81e723a0ba82a89eec18a2706ac1b0dace", + "download_url": "https://try.gitea.io/aaaaaz/go-gitea.gitea/raw/branch/master/docs/content/doc/advanced.zh-cn.md", + "submodule_git_url": null, + "_links": { + "self": "https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/advanced.zh-cn.md?ref=master", + "git": "https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/1f7ebf81e723a0ba82a89eec18a2706ac1b0dace", + "html": "https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/advanced.zh-cn.md" + } + }, + { + "name": "advanced", + "path": "docs/content/doc/advanced", + "sha": "8c43a4fb023735dfd026014bae92ad91414b88bd", + "type": "dir", + "size": 0, + "encoding": null, + "content": null, + "target": null, + "url": "https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/advanced?ref=master", + "html_url": "https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/advanced", + "git_url": "https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/8c43a4fb023735dfd026014bae92ad91414b88bd", + "download_url": null, + "submodule_git_url": null, + "_links": { + "self": "https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/contents/docs/content/doc/advanced?ref=master", + "git": "https://try.gitea.io/api/v1/repos/aaaaaz/go-gitea.gitea/git/blobs/8c43a4fb023735dfd026014bae92ad91414b88bd", + "html": "https://try.gitea.io/aaaaaz/go-gitea.gitea/src/branch/master/docs/content/doc/advanced" + } + } +] \ No newline at end of file diff --git a/scm/driver/gitea/testdata/content_list.json.golden b/scm/driver/gitea/testdata/content_list.json.golden index cc23f85ff..7b6547bab 100644 --- a/scm/driver/gitea/testdata/content_list.json.golden +++ b/scm/driver/gitea/testdata/content_list.json.golden @@ -1,98 +1,22 @@ [ { "path": "docs/content/doc/advanced.en-us.md", - "kind": "file" + "kind": "file", + "blobid": "de2bfeed6f2d3ea1d2f91e457e9450efc582bb31" }, { "path": "docs/content/doc/advanced.fr-fr.md", - "kind": "file" + "kind": "file", + "blobid": "04734a8f81f5641de2b6d738bc9b777c2cc541c6" }, { "path": "docs/content/doc/advanced.zh-cn.md", - "kind": "file" + "kind": "file", + "blobid": "1f7ebf81e723a0ba82a89eec18a2706ac1b0dace" }, { "path": "docs/content/doc/advanced", - "kind": "directory" - }, - { - "path": "docs/content/doc/features.en-us.md", - "kind": "file" - }, - { - "path": "docs/content/doc/features.zh-cn.md", - "kind": "file" - }, - { - "path": "docs/content/doc/features.zh-tw.md", - "kind": "file" - }, - { - "path": "docs/content/doc/features", - "kind": "directory" - }, - { - "path": "docs/content/doc/help.en-us.md", - "kind": "file" - }, - { - "path": "docs/content/doc/help.zh-cn.md", - "kind": "file" - }, - { - "path": "docs/content/doc/help", - "kind": "directory" - }, - { - "path": "docs/content/doc/installation.en-us.md", - "kind": "file" - }, - { - "path": "docs/content/doc/installation.fr-fr.md", - "kind": "file" - }, - { - "path": "docs/content/doc/installation.zh-cn.md", - "kind": "file" - }, - { - "path": "docs/content/doc/installation.zh-tw.md", - "kind": "file" - }, - { - "path": "docs/content/doc/installation", - "kind": "directory" - }, - { - "path": "docs/content/doc/upgrade.en-us.md", - "kind": "file" - }, - { - "path": "docs/content/doc/upgrade.fr-fr.md", - "kind": "file" - }, - { - "path": "docs/content/doc/upgrade.zh-cn.md", - "kind": "file" - }, - { - "path": "docs/content/doc/upgrade.zh-tw.md", - "kind": "file" - }, - { - "path": "docs/content/doc/upgrade", - "kind": "directory" - }, - { - "path": "docs/content/doc/usage.en-us.md", - "kind": "file" - }, - { - "path": "docs/content/doc/usage.zh-cn.md", - "kind": "file" - }, - { - "path": "docs/content/doc/usage", - "kind": "directory" + "kind": "directory", + "blobid": "8c43a4fb023735dfd026014bae92ad91414b88bd" } ] 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/milestone.json b/scm/driver/gitea/testdata/milestone.json new file mode 100644 index 000000000..9d69fb31c --- /dev/null +++ b/scm/driver/gitea/testdata/milestone.json @@ -0,0 +1,12 @@ +{ + "closed_at": "2020-09-11T19:32:38.046Z", + "closed_issues": 0, + "created_at": "2020-09-11T19:32:38.046Z", + "description": "string", + "due_on": "2020-09-11T19:32:38.046Z", + "id": 1, + "open_issues": 0, + "state": "open", + "title": "string", + "updated_at": "2020-09-11T19:32:38.046Z" +} diff --git a/scm/driver/gitea/testdata/milestone.json.golden b/scm/driver/gitea/testdata/milestone.json.golden new file mode 100644 index 000000000..be885236a --- /dev/null +++ b/scm/driver/gitea/testdata/milestone.json.golden @@ -0,0 +1,8 @@ +{ + "Description": "string", + "DueDate": "2020-09-11T19:32:38.046Z", + "ID": 1, + "Number": 1, + "State": "open", + "Title": "string" +} diff --git a/scm/driver/gitea/testdata/milestone_create.json b/scm/driver/gitea/testdata/milestone_create.json new file mode 100644 index 000000000..ca4130241 --- /dev/null +++ b/scm/driver/gitea/testdata/milestone_create.json @@ -0,0 +1,6 @@ +{ + "title": "v1.0", + "description": "Tracking milestone for version 1.0", + "state": "open", + "due_on": "2012-10-09T23:39:01Z" +} diff --git a/scm/driver/gitea/testdata/milestones.json b/scm/driver/gitea/testdata/milestones.json new file mode 100644 index 000000000..90cb3ed92 --- /dev/null +++ b/scm/driver/gitea/testdata/milestones.json @@ -0,0 +1,14 @@ +[ + { + "closed_at": "2020-09-11T19:32:38.046Z", + "closed_issues": 0, + "created_at": "2020-09-11T19:32:38.046Z", + "description": "string", + "due_on": "2020-09-11T19:32:38.046Z", + "id": 1, + "open_issues": 0, + "state": "open", + "title": "string", + "updated_at": "2020-09-11T19:32:38.046Z" + } +] diff --git a/scm/driver/gitea/testdata/milestones.json.golden b/scm/driver/gitea/testdata/milestones.json.golden new file mode 100644 index 000000000..23ce5fd75 --- /dev/null +++ b/scm/driver/gitea/testdata/milestones.json.golden @@ -0,0 +1,10 @@ +[ + { + "Description": "string", + "DueDate": "2020-09-11T19:32:38.046Z", + "ID": 1, + "Number": 1, + "State": "open", + "Title": "string" + } +] 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/gitea/testdata/release.json b/scm/driver/gitea/testdata/release.json new file mode 100644 index 000000000..02eeed341 --- /dev/null +++ b/scm/driver/gitea/testdata/release.json @@ -0,0 +1,10 @@ +{ + "id": 1, + "name": "v1.0.0", + "body": "Description of the release", + "url": "https://try.gitea.com/api/v1/repos/octocat/Hello-World/123", + "tag_name": "v1.0.0", + "target_commitish": "master", + "draft": false, + "prerelease": false +} \ No newline at end of file diff --git a/scm/driver/gitea/testdata/release.json.golden b/scm/driver/gitea/testdata/release.json.golden new file mode 100644 index 000000000..5ebc0ddf8 --- /dev/null +++ b/scm/driver/gitea/testdata/release.json.golden @@ -0,0 +1,10 @@ +{ + "ID": 1, + "Title": "v1.0.0", + "Description": "Description of the release", + "Link": "https://try.gitea.com/octocat/Hello-World/releases/tag/v1.0.0", + "Tag": "v1.0.0", + "Commitish": "master", + "Draft": false, + "Prerelease": false +} \ No newline at end of file diff --git a/scm/driver/gitea/testdata/release_create.json b/scm/driver/gitea/testdata/release_create.json new file mode 100644 index 000000000..37e53d251 --- /dev/null +++ b/scm/driver/gitea/testdata/release_create.json @@ -0,0 +1,8 @@ +{ + "tag_name": "v1.0.0", + "target_commitish": "master", + "name": "v1.0.0", + "body": "Description of the release", + "draft": false, + "prerelease": false +} \ No newline at end of file diff --git a/scm/driver/gitea/testdata/release_update.json b/scm/driver/gitea/testdata/release_update.json new file mode 100644 index 000000000..37e53d251 --- /dev/null +++ b/scm/driver/gitea/testdata/release_update.json @@ -0,0 +1,8 @@ +{ + "tag_name": "v1.0.0", + "target_commitish": "master", + "name": "v1.0.0", + "body": "Description of the release", + "draft": false, + "prerelease": false +} \ No newline at end of file diff --git a/scm/driver/gitea/testdata/releases.json b/scm/driver/gitea/testdata/releases.json new file mode 100644 index 000000000..252ace560 --- /dev/null +++ b/scm/driver/gitea/testdata/releases.json @@ -0,0 +1,12 @@ +[ + { + "id": 1, + "name": "v1.0.0", + "body": "Description of the release", + "url": "https://try.gitea.com/api/v1/repos/octocat/Hello-World/123", + "tag_name": "v1.0.0", + "target_commitish": "master", + "draft": false, + "prerelease": false + } +] \ No newline at end of file diff --git a/scm/driver/gitea/testdata/releases.json.golden b/scm/driver/gitea/testdata/releases.json.golden new file mode 100644 index 000000000..51a6b244a --- /dev/null +++ b/scm/driver/gitea/testdata/releases.json.golden @@ -0,0 +1,12 @@ +[ + { + "ID": 1, + "Title": "v1.0.0", + "Description": "Description of the release", + "Link": "https://try.gitea.com/octocat/Hello-World/releases/tag/v1.0.0", + "Tag": "v1.0.0", + "Commitish": "master", + "Draft": false, + "Prerelease": false + } +] \ No newline at end of file diff --git a/scm/driver/gitea/testdata/repo.json b/scm/driver/gitea/testdata/repo.json index 536d5f238..2f1756fb5 100644 --- a/scm/driver/gitea/testdata/repo.json +++ b/scm/driver/gitea/testdata/repo.json @@ -32,5 +32,6 @@ "admin": true, "push": true, "pull": true - } + }, + "archived": false } \ No newline at end of file diff --git a/scm/driver/gitea/testdata/repo.json.golden b/scm/driver/gitea/testdata/repo.json.golden index 15fc567c1..62aee5e3c 100644 --- a/scm/driver/gitea/testdata/repo.json.golden +++ b/scm/driver/gitea/testdata/repo.json.golden @@ -13,5 +13,6 @@ "CloneSSH": "git@try.gitea.io:go-gitea/gitea.git", "Link": "https://try.gitea.io/go-gitea/gitea", "Created": "0001-01-01T00:00:00Z", - "Updated": "0001-01-01T00:00:00Z" + "Updated": "0001-01-01T00:00:00Z", + "Archived": false } \ No newline at end of file diff --git a/scm/driver/gitea/testdata/repos.json b/scm/driver/gitea/testdata/repos.json index 89e446201..8576aaeab 100644 --- a/scm/driver/gitea/testdata/repos.json +++ b/scm/driver/gitea/testdata/repos.json @@ -33,6 +33,7 @@ "admin": true, "push": true, "pull": true - } + }, + "archived": false } ] diff --git a/scm/driver/gitea/testdata/repos.json.golden b/scm/driver/gitea/testdata/repos.json.golden index 620565c96..35314d2ac 100644 --- a/scm/driver/gitea/testdata/repos.json.golden +++ b/scm/driver/gitea/testdata/repos.json.golden @@ -14,6 +14,7 @@ "CloneSSH": "git@try.gitea.io:go-gitea/gitea.git", "Link": "https://try.gitea.io/go-gitea/gitea", "Created": "0001-01-01T00:00:00Z", - "Updated": "0001-01-01T00:00:00Z" + "Updated": "0001-01-01T00:00:00Z", + "Archived": false } ] \ No newline at end of file diff --git a/scm/driver/gitea/user.go b/scm/driver/gitea/user.go index 09b9e9399..38ab64acc 100644 --- a/scm/driver/gitea/user.go +++ b/scm/driver/gitea/user.go @@ -33,6 +33,10 @@ func (s *userService) FindEmail(ctx context.Context) (string, *scm.Response, err return user.Email, res, err } +func (s *userService) ListEmail(context.Context, scm.ListOptions) ([]*scm.Email, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + // // native data structures // diff --git a/scm/driver/gitea/util.go b/scm/driver/gitea/util.go index 1179ddaeb..29915e910 100644 --- a/scm/driver/gitea/util.go +++ b/scm/driver/gitea/util.go @@ -5,8 +5,10 @@ package gitea import ( + "fmt" "net/url" "strconv" + "strings" "github.com/drone/go-scm/scm" ) @@ -53,3 +55,49 @@ func encodePullRequestListOptions(opts scm.PullRequestListOptions) string { } 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() +} \ No newline at end of file diff --git a/scm/driver/gitee/content.go b/scm/driver/gitee/content.go new file mode 100644 index 000000000..7ac8d6445 --- /dev/null +++ b/scm/driver/gitee/content.go @@ -0,0 +1,142 @@ +// 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 gitee + +import ( + "context" + "encoding/base64" + "fmt" + + "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) { + endpoint := fmt.Sprintf("repos/%s/contents/%s?ref=%s", repo, path, ref) + out := new(content) + res, err := s.client.do(ctx, "GET", endpoint, nil, out) + raw, _ := base64.StdEncoding.DecodeString(out.Content) + return &scm.Content{ + Path: out.Path, + Data: raw, + Sha: out.Sha, + }, res, err +} + +func (s *contentService) Create(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { + endpoint := fmt.Sprintf("repos/%s/contents/%s", repo, path) + in := &contentCreateUpdate{ + Message: params.Message, + Branch: params.Branch, + Content: params.Data, + Committer: commitAuthor{ + Name: params.Signature.Name, + Email: params.Signature.Email, + }, + Author: commitAuthor{ + 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) { + endpoint := fmt.Sprintf("repos/%s/contents/%s", repo, path) + in := &contentCreateUpdate{ + Message: params.Message, + Branch: params.Branch, + Content: params.Data, + Sha: params.Sha, + Committer: commitAuthor{ + Name: params.Signature.Name, + Email: params.Signature.Email, + }, + Author: commitAuthor{ + Name: params.Signature.Name, + Email: params.Signature.Email, + }, + } + res, err := s.client.do(ctx, "PUT", endpoint, in, nil) + return res, err +} + +func (s *contentService) Delete(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { + endpoint := fmt.Sprintf("repos/%s/contents/%s", repo, path) + in := &contentCreateUpdate{ + Message: params.Message, + Branch: params.Branch, + Sha: params.Sha, + Committer: commitAuthor{ + Name: params.Signature.Name, + Email: params.Signature.Email, + }, + Author: commitAuthor{ + Name: params.Signature.Name, + Email: params.Signature.Email, + }, + } + res, err := s.client.do(ctx, "DELETE", endpoint, in, nil) + return res, err +} + +func (s *contentService) List(ctx context.Context, repo, path, ref string, _ scm.ListOptions) ([]*scm.ContentInfo, *scm.Response, error) { + endpoint := fmt.Sprintf("repos/%s/contents/%s?ref=%s", repo, path, ref) + out := []*content{} + res, err := s.client.do(ctx, "GET", endpoint, nil, &out) + return convertContentInfoList(out), res, err +} + +type content struct { + Name string `json:"name"` + Path string `json:"path"` + Sha string `json:"sha"` + Content string `json:"content"` + Type string `json:"type"` +} + +type contentCreateUpdate struct { + Branch string `json:"branch"` + Message string `json:"message"` + Content []byte `json:"content"` + Sha string `json:"sha"` + Author commitAuthor `json:"author"` + Committer commitAuthor `json:"committer"` +} + +type commitAuthor struct { + Name string `json:"name"` + Date string `json:"date"` + Email string `json:"email"` +} + +func convertContentInfoList(from []*content) []*scm.ContentInfo { + to := []*scm.ContentInfo{} + for _, v := range from { + to = append(to, convertContentInfo(v)) + } + return to +} +func convertContentInfo(from *content) *scm.ContentInfo { + to := &scm.ContentInfo{Path: from.Path} + switch from.Type { + case "file": + to.Kind = scm.ContentKindFile + case "dir": + to.Kind = scm.ContentKindDirectory + case "symlink": + to.Kind = scm.ContentKindSymlink + case "submodule": + to.Kind = scm.ContentKindGitlink + default: + to.Kind = scm.ContentKindUnsupported + } + return to +} diff --git a/scm/driver/gitee/content_test.go b/scm/driver/gitee/content_test.go new file mode 100644 index 000000000..0ded74af6 --- /dev/null +++ b/scm/driver/gitee/content_test.go @@ -0,0 +1,200 @@ +// 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 gitee + +import ( + "context" + "encoding/json" + "io/ioutil" + "testing" + + "github.com/drone/go-scm/scm" + + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestContentFind(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/contents/README.md"). + MatchParam("ref", "d295a4c616d46fbcdfa3dfd1473c1337a1ec6f83"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/content.json") + + client := NewDefault() + got, res, err := client.Contents.Find( + context.Background(), + "kit101/drone-yml-test", + "README.md", + "d295a4c616d46fbcdfa3dfd1473c1337a1ec6f83", + ) + 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)) +} + +func TestContentCreate(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Post("/repos/kit101/drone-yml-test/contents/apitest/CreateByDroneGiteeProvider.md"). + Reply(201). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/content_create.json") + + params := &scm.ContentParams{ + Message: "my commit message", + Data: []byte("bY3JlYXRlIGJ5IGRyb25lLXNjbSBnaXRlZSBwcm92aWRlci4gMjAyMS0wOC0xNyAyMzowNToxNi4="), + Signature: scm.Signature{ + Name: "kit101", + Email: "kit101@gitee.com", + }, + } + + client := NewDefault() + res, err := client.Contents.Create( + context.Background(), + "kit101/drone-yml-test", + "apitest/CreateByDroneGiteeProvider.md", + params, + ) + + if err != nil { + t.Error(err) + return + } + + if res.Status != 201 { + t.Errorf("Unexpected Results") + } +} + +func TestContentUpdate(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Put("/repos/kit101/drone-yml-test/contents/apitest/UpdateByDroneGiteeProvider.md"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/content_update.json") + + params := &scm.ContentParams{ + Message: "my commit message by update", + Data: []byte("bdXBkYXRlIGJ5IGRyb25lLXNjbSBnaXRlZSBwcm92aWRlci4gMjAyMS0wOC0xNyAyMzozMDozNy4="), + Sha: "9de0cf94e1e3c1cbe0a25c3865de4cc9ede7ad3e", + Signature: scm.Signature{ + Name: "kit101", + Email: "kit101@gitee.com", + }, + } + + client := NewDefault() + res, err := client.Contents.Update( + context.Background(), + "kit101/drone-yml-test", + "apitest/UpdateByDroneGiteeProvider.md", + params, + ) + + if err != nil { + t.Error(err) + return + } + + if res.Status != 200 { + t.Errorf("Unexpected Results") + } +} + +func TestContentDelete(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Delete("/repos/kit101/drone-yml-test/contents/apitest/DeleteByDroneGiteeProvider.md"). + Reply(204). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/content_delete.json") + + contentParams := scm.ContentParams{ + Branch: "master", + Sha: "ae0653e4ab697cd77fc559cd798bdb30e8bb4d7e", + Message: "delete commit message", + Signature: scm.Signature{ + Name: "kit101", + Email: "kit101@gitee.com", + }, + } + client := NewDefault() + res, err := client.Contents.Delete( + context.Background(), + "kit101/drone-yml-test", + "apitest/DeleteByDroneGiteeProvider.md", + &contentParams, + ) + if err != nil { + t.Error(err) + return + } + + if got, want := res.Status, 204; got != want { + t.Errorf("Want response status %d, got %d", want, got) + } + t.Run("Request", testRequest(res)) +} + +func TestContentList(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/contents/apitest"). + MatchParam("ref", "master"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/content_list.json") + + client := NewDefault() + got, res, err := client.Contents.List( + context.Background(), + "kit101/drone-yml-test", + "apitest", + "master", + scm.ListOptions{}, + ) + if err != nil { + t.Error(err) + return + } + + 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) + } + + t.Run("Request", testRequest(res)) +} diff --git a/scm/driver/gitee/git.go b/scm/driver/gitee/git.go new file mode 100644 index 000000000..b3377a43c --- /dev/null +++ b/scm/driver/gitee/git.go @@ -0,0 +1,308 @@ +// 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 gitee + +import ( + "context" + "fmt" + "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) { + path := fmt.Sprintf("repos/%s/branches", repo) + in := &branchCreate{ + Refs: params.Sha, + BranchName: params.Name, + } + res, err := s.client.do(ctx, "POST", path, in, nil) + return res, err +} + +func (s *gitService) FindBranch(ctx context.Context, repo, name string) (*scm.Reference, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/branches/%s", repo, name) + out := new(branch) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertBranch(out), res, err +} + +func (s *gitService) FindCommit(ctx context.Context, repo, ref string) (*scm.Commit, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/commits/%s", repo, ref) + out := new(commit) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertCommit(out), res, err +} + +func (s *gitService) FindTag(ctx context.Context, repo, name string) (*scm.Reference, *scm.Response, error) { + tags, res, err := s.ListTags(ctx, repo, scm.ListOptions{}) + if err != nil { + return nil, nil, err + } + for _, tag := range tags { + if tag.Name == name { + return tag, res, err + } + } + return nil, res, err +} + +func (s *gitService) ListBranches(ctx context.Context, repo string, _ scm.ListOptions) ([]*scm.Reference, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/branches", repo) + 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) { + // 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{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertCommitList(out), res, err +} + +func (s *gitService) ListTags(ctx context.Context, repo string, _ scm.ListOptions) ([]*scm.Reference, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/tags", repo) + out := []*releasesTags{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertTagList(out), res, err +} + +func (s *gitService) ListChanges(ctx context.Context, repo, ref string, _ scm.ListOptions) ([]*scm.Change, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/commits/%s", repo, ref) + out := new(commit) + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertChangeList(out.Files), res, err +} + +func (s *gitService) CompareChanges(ctx context.Context, repo, source, target string, _ scm.ListOptions) ([]*scm.Change, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/compare/%s...%s", repo, source, target) + out := new(compare) + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertChangeList(out.Files), res, err +} + +type branchCreate struct { + Refs string `json:"refs"` + BranchName string `json:"branch_name"` +} + +type branch struct { + //Links string `json:"_links"` + Name string `json:"name"` + Commit tree `json:"commit"` + Protected bool `json:"protected"` + ProtectionURL string `json:"protection_url"` +} + +type commit struct { + URL string `json:"url"` + Sha string `json:"sha"` + HtmlURL string `json:"html_url"` + CommentsURL string `json:"comments_url"` + Commit struct { + Author committer `json:"author"` + Committer committer `json:"committer"` + Message string `json:"message"` + Tree tree `json:"tree"` + } `json:"commit"` + Author author `json:"author"` + Committer author `json:"committer"` + Parents []tree `json:"parents"` + Stats struct { + ID string `json:"id"` + Additions int64 `json:"additions"` + Deletions int64 `json:"deletions"` + Total int64 `json:"total"` + } `json:"stats"` + Files []*file `json:"files"` +} + +type committer struct { + Name string `json:"name"` + Date time.Time `json:"date"` + Email string `json:"email"` +} + +type tree struct { + Sha string `json:"sha"` + URL string `json:"url"` +} + +type file struct { + SHA string `json:"sha"` + Filename string `json:"filename"` + Status string `json:"status"` + Additions int64 `json:"additions"` + Deletions int64 `json:"deletions"` + Changes int64 `json:"changes"` + BlobURL string `json:"blob_url"` + RawURL string `json:"raw_url"` + ContentURL string `json:"content_url"` + Patch string `json:"patch"` +} + +type compare struct { + BaseCommit struct { + URL string `json:"url"` + Sha string `json:"sha"` + HTMLURL string `json:"html_url"` + CommentsURL string `json:"comments_url"` + Commit compareCommit `json:"commit"` + Author compareAuthor `json:"author"` + Committer committer `json:"committer"` + Parents []tree `json:"parents"` + } `json:"base_commit"` + MergeBaseCommit struct { + URL string `json:"url"` + Sha string `json:"sha"` + HTMLURL string `json:"html_url"` + CommentsURL string `json:"comments_url"` + Commit compareCommit `json:"commit"` + Author compareAuthor `json:"author"` + Committer committer `json:"committer"` + Parents []tree `json:"parents"` + } `json:"merge_base_commit"` + Commits []struct { + URL string `json:"url"` + Sha string `json:"sha"` + HTMLURL string `json:"html_url"` + CommentsURL string `json:"comments_url"` + Commit compareCommit `json:"commit"` + Author compareAuthor `json:"author"` + Committer committer `json:"committer"` + Parents []tree `json:"parents"` + } `json:"commits"` + Files []*file `json:"files"` +} +type compareAuthor struct { + Name string `json:"name"` + Date time.Time `json:"date"` + Email string `json:"email"` +} +type compareCommit struct { + Author compareAuthor `json:"author"` + Committer committer `json:"committer"` + Message string `json:"message"` + Tree tree `json:"tree"` +} + +type releasesTags struct { + Name string `json:"name"` + Message string `json:"message"` + Commit struct { + Sha string `json:"sha"` + Date time.Time `json:"date"` + } `json:"commit"` +} + +type author struct { + ID int `json:"id"` + Login string `json:"login"` + Name string `json:"name"` + AvatarURL string `json:"avatar_url"` + URL string `json:"url"` + HTMLURL string `json:"html_url"` + FollowersURL string `json:"followers_url"` + FollowingURL string `json:"following_url"` + GistsURL string `json:"gists_url"` + StarredURL string `json:"starred_url"` + SubscriptionsURL string `json:"subscriptions_url"` + OrganizationsURL string `json:"organizations_url"` + ReposURL string `json:"repos_url"` + EventsURL string `json:"events_url"` + ReceivedEventsURL string `json:"received_events_url"` + Type string `json:"type"` +} + +func convertCommitList(from []*commit) []*scm.Commit { + to := []*scm.Commit{} + for _, v := range from { + to = append(to, convertCommit(v)) + } + return to +} + +func convertCommit(from *commit) *scm.Commit { + return &scm.Commit{ + Message: from.Commit.Message, + Sha: from.Sha, + Link: from.HtmlURL, + Author: scm.Signature{ + Name: from.Commit.Author.Name, + Email: from.Commit.Author.Email, + Date: from.Commit.Author.Date, + Login: from.Author.Login, + Avatar: from.Author.AvatarURL, + }, + Committer: scm.Signature{ + Name: from.Commit.Committer.Name, + Email: from.Commit.Committer.Email, + Date: from.Commit.Committer.Date, + Login: from.Committer.Login, + Avatar: from.Committer.AvatarURL, + }, + } +} + +func convertBranchList(from []*branch) []*scm.Reference { + to := []*scm.Reference{} + for _, v := range from { + to = append(to, convertBranch(v)) + } + return to +} + +func convertBranch(from *branch) *scm.Reference { + return &scm.Reference{ + Name: scm.TrimRef(from.Name), + Path: scm.ExpandRef(from.Name, "refs/heads/"), + Sha: from.Commit.Sha, + } +} + +func convertTagList(from []*releasesTags) []*scm.Reference { + to := []*scm.Reference{} + for _, v := range from { + to = append(to, convertTag(v)) + } + return to +} + +func convertTag(from *releasesTags) *scm.Reference { + return &scm.Reference{ + Name: scm.TrimRef(from.Name), + Path: scm.ExpandRef(from.Name, "refs/tags/"), + Sha: from.Commit.Sha, + } +} + +func convertChangeList(from []*file) []*scm.Change { + to := []*scm.Change{} + for _, v := range from { + to = append(to, convertChange(v)) + } + return to +} + +func convertChange(from *file) *scm.Change { + return &scm.Change{ + Path: from.Filename, + Added: from.Status == "added", + Deleted: from.Status == "removed", + Renamed: from.Status == "modified" && from.Additions == 0 && from.Deletions == 0 && from.Changes == 0, + BlobID: from.SHA, + } +} diff --git a/scm/driver/gitee/git_test.go b/scm/driver/gitee/git_test.go new file mode 100644 index 000000000..bdceb7634 --- /dev/null +++ b/scm/driver/gitee/git_test.go @@ -0,0 +1,279 @@ +// 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 gitee + +import ( + "context" + "encoding/json" + "io/ioutil" + "testing" + + "github.com/drone/go-scm/scm" + + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestGitCreateBranch(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Post("/repos/kit101/drone-yml-test/branches"). + Reply(201). + Type("application/json"). + SetHeaders(mockHeaders) + + client := NewDefault() + input := scm.ReferenceInput{ + Name: "create-by-api", + Sha: "b72a4c4a2d838d96a545a42d41d7776ae5566f4a", + } + res, err := client.Git.CreateBranch(context.Background(), "kit101/drone-yml-test", &input) + if err != nil { + t.Error(err) + return + } + + if got, want := res.Status, 201; got != want { + t.Errorf("Want response status %d, got %d", want, got) + } + t.Run("Request", testRequest(res)) +} + +func TestGitFindBranch(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/branches/master"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/branch.json") + + client := NewDefault() + got, res, err := client.Git.FindBranch(context.Background(), "kit101/drone-yml-test", "master") + if err != nil { + t.Error(err) + return + } + + want := new(scm.Reference) + raw, _ := ioutil.ReadFile("testdata/branch.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)) +} + +func TestGitFindCommit(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/commits/e3c0ff4d5cef439ea11b30866fb1ed79b420801d"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/commit.json") + + client := NewDefault() + got, res, err := client.Git.FindCommit(context.Background(), "kit101/drone-yml-test", "e3c0ff4d5cef439ea11b30866fb1ed79b420801d") + if err != nil { + t.Error(err) + return + } + + 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) + } + + t.Run("Request", testRequest(res)) +} + +func TestGitFindTag(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/tags"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/tags.json") + + client := NewDefault() + got, res, err := client.Git.FindTag(context.Background(), "kit101/drone-yml-test", "1.0") + if err != nil { + t.Error(err) + return + } + + want := new(scm.Reference) + raw, _ := ioutil.ReadFile("testdata/tag.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)) +} + +func TestGitListBranches(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/branches"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/branches.json") + + client := NewDefault() + got, res, err := client.Git.ListBranches(context.Background(), "kit101/drone-yml-test", scm.ListOptions{}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Reference{} + raw, _ := ioutil.ReadFile("testdata/branches.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)) +} + +func TestGitListCommits(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/commits"). + MatchParam("sha", "master"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/commits.json") + + client := NewDefault() + got, res, err := client.Git.ListCommits(context.Background(), "kit101/drone-yml-test", + scm.CommitListOptions{Ref: "master", Page: 1, Size: 3}) + 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) + } + + t.Run("Request", testRequest(res)) + t.Run("Page", testPage(res)) +} + +func TestGitListTags(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/tags"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/tags.json") + + client := NewDefault() + got, res, err := client.Git.ListTags(context.Background(), "kit101/drone-yml-test", 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) + } + + t.Run("Request", testRequest(res)) +} + +func TestGitListChanges(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com"). + Get("/repos/kit101/drone-yml-test/commits/7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/changes.json") + + client := NewDefault() + got, res, err := client.Git.ListChanges(context.Background(), "kit101/drone-yml-test", "7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51", scm.ListOptions{}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Change{} + raw, _ := ioutil.ReadFile("testdata/changes.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)) +} + +func TestGitCompareChanges(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/compare/e3c0ff4d5cef439ea11b30866fb1ed79b420801d...2700445cd84c08546f4d003f8aa54d2099a006b7"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/compare.json") + + client := NewDefault() + got, res, err := client.Git.CompareChanges(context.Background(), "kit101/drone-yml-test", "e3c0ff4d5cef439ea11b30866fb1ed79b420801d", "2700445cd84c08546f4d003f8aa54d2099a006b7", scm.ListOptions{}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Change{} + raw, _ := ioutil.ReadFile("testdata/compare.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)) +} diff --git a/scm/driver/gitee/gitee.go b/scm/driver/gitee/gitee.go new file mode 100644 index 000000000..9bf40fd29 --- /dev/null +++ b/scm/driver/gitee/gitee.go @@ -0,0 +1,167 @@ +// 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 gitee implements a Gitee client. +package gitee + +import ( + "bytes" + "context" + "encoding/json" + "net/url" + "strconv" + "strings" + + "github.com/drone/go-scm/scm" +) + +// New returns a new Gitee API client. +func New(uri 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)} + client.BaseURL = base + // initialize services + client.Driver = scm.DriverGitee + client.Linker = &linker{websiteAddress(base)} + client.Contents = &contentService{client} + client.Git = &gitService{client} + client.Issues = &issueService{client} + client.Organizations = &organizationService{client} + client.PullRequests = &pullService{client} + client.Repositories = &RepositoryService{client} + client.Reviews = &reviewService{client} + client.Users = &userService{client} + client.Webhooks = &webhookService{client} + return client.Client, nil +} + +// NewDefault returns a new Gitee API client using the +// default gitee.com/api/v5 address. +func NewDefault() *scm.Client { + client, _ := New("https://gitee.com/api/v5") + return client +} + +// wrapper wraps the Client to provide high level helper functions +// for making http requests and unmarshaling the response. +type wrapper struct { + *scm.Client +} + +// 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() + // parse the gitee request id. + res.ID = res.Header.Get("X-Request-Id") + + // gitee pageValues + populatePageValues(req, res) + + // 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 a json response is expected, parse and return + // the json response. + return res, json.NewDecoder(res.Body).Decode(out) +} + +// Error represents a Gitee error. +type Error struct { + Message string `json:"message"` +} + +func (e *Error) Error() string { + return e.Message +} + +// helper function converts the Gitee API url to +// the website url. +func websiteAddress(u *url.URL) string { + host, proto := u.Host, u.Scheme + switch host { + case "gitee.com/api/v5": + return "https://gitee.com/" + } + return proto + "://" + host + "/" +} + +// populatePageValues parses the HTTP Link response headers +// and populates the various pagination link values in the +// Response. +// response header: total_page, total_count +func populatePageValues(req *scm.Request, resp *scm.Response) { + // get last + last, totalError := strconv.Atoi(resp.Header.Get("total_page")) + if totalError != nil { + return + } + // get curren page + reqURL, err := url.Parse(req.Path) + if err != nil { + return + } + currentPageStr := reqURL.Query().Get("page") + var current int + if currentPageStr == "" { + current = 1 + } else { + currentPage, currentError := strconv.Atoi(currentPageStr) + if currentError != nil { + return + } + current = currentPage + } + + // first, prev + if current <= 1 { + resp.Page.First = 0 + resp.Page.Prev = 0 + } else { + resp.Page.First = 1 + resp.Page.Prev = current - 1 + } + // last, next + if current >= last { + resp.Page.Last = 0 + resp.Page.Next = 0 + } else { + resp.Page.Last = last + resp.Page.Next = current + 1 + } +} diff --git a/scm/driver/gitee/gitee_test.go b/scm/driver/gitee/gitee_test.go new file mode 100644 index 000000000..7547de351 --- /dev/null +++ b/scm/driver/gitee/gitee_test.go @@ -0,0 +1,97 @@ +// 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 gitee + +import ( + "net/url" + "testing" + + "github.com/drone/go-scm/scm" +) + +var mockHeaders = map[string]string{ + "X-Request-Id": "7cb049dbf1fafae67b4f0aa81ca7e870", +} + +var mockPageHeaders = map[string]string{ + "total_page": `3`, +} + +func TestClient(t *testing.T) { + client, err := New("https://gitee.com/api/v5") + if err != nil { + t.Error(err) + } + if got, want := client.BaseURL.String(), "https://gitee.com/api/v5/"; got != want { + t.Errorf("Want Client URL %q, got %q", want, got) + } +} + +func TestClient_Base(t *testing.T) { + client, err := New("https://gitee.com/api/v5") + if err != nil { + t.Error(err) + } + got, want := client.BaseURL.String(), "https://gitee.com/api/v5/" + if got != want { + t.Errorf("Want Client URL %q, got %q", want, got) + } +} + +func TestClient_Default(t *testing.T) { + client := NewDefault() + if got, want := client.BaseURL.String(), "https://gitee.com/api/v5/"; 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.Prev, 0; got != want { + t.Errorf("Want prev page %d, got %d", want, got) + } + if got, want := res.Page.Next, 2; got != want { + t.Errorf("Want next page %d, got %d", want, got) + } + if got, want := res.Page.Last, 3; got != want { + t.Errorf("Want last page %d, got %d", want, got) + } + if got, want := res.Page.First, 0; got != want { + t.Errorf("Want first page %d, got %d", want, got) + } + } +} + +func testRequest(res *scm.Response) func(t *testing.T) { + return func(t *testing.T) { + if got, want := res.ID, "7cb049dbf1fafae67b4f0aa81ca7e870"; got != want { + t.Errorf("Want X-Request-Id %q, got %q", want, got) + } + } +} + +func TestWebsiteAddress(t *testing.T) { + tests := []struct { + api string + web string + }{ + {"https://gitee.com/api/v5/", "https://gitee.com/"}, + } + + for _, test := range tests { + parsed, _ := url.Parse(test.api) + got, want := websiteAddress(parsed), test.web + if got != want { + t.Errorf("Want website address %q, got %q", want, got) + } + } +} diff --git a/scm/driver/gitee/integration/content_test.go b/scm/driver/gitee/integration/content_test.go new file mode 100644 index 000000000..8e0404906 --- /dev/null +++ b/scm/driver/gitee/integration/content_test.go @@ -0,0 +1,54 @@ +// 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 integration + +import ( + "context" + "testing" + + "github.com/drone/go-scm/scm" +) + +func testContents(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + t.Run("Find", testContentFind(client)) + t.Run("Find/Branch", testContentFindBranch(client)) + } +} + +func testContentFind(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + result, _, err := client.Contents.Find(context.Background(), "kit101/drone-yml-test", "main.py", "5e7876efb3468ff679410b82a72f7c002382d41e") + if err != nil { + t.Error(err) + return + } + if got, want := result.Path, "main.py"; got != want { + t.Errorf("Got file path %q, want %q", got, want) + } + if got, want := string(result.Data), "if __name__ == '__main__':\r\n print('Hello world.')"; got != want { + t.Errorf("Got file data %q, want %q", got, want) + } + } +} + +func testContentFindBranch(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + result, _, err := client.Contents.Find(context.Background(), "kit101/drone-yml-test", "main.py", "feat-4") + if err != nil { + t.Error(err) + return + } + if got, want := result.Path, "main.py"; got != want { + t.Errorf("Got file path %q, want %q", got, want) + } + if got, want := string(result.Data), "if __name__ == '__main__':\r\n print('Hello world.')"; got != want { + t.Errorf("Got file data %q, want %q", got, want) + } + } +} diff --git a/scm/driver/gitee/integration/git_test.go b/scm/driver/gitee/integration/git_test.go new file mode 100644 index 000000000..d7267fc60 --- /dev/null +++ b/scm/driver/gitee/integration/git_test.go @@ -0,0 +1,214 @@ +// 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 integration + +import ( + "context" + "testing" + + "github.com/drone/go-scm/scm" +) + +// +// git sub-tests +// + +func testGit(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + t.Run("Branches", testBranches(client)) + t.Run("Commits", testCommits(client)) + t.Run("Tags", testTags(client)) + } +} + +// +// branch sub-tests +// + +func testBranches(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + t.Run("Find", testBranchFind(client)) + t.Run("List", testBranchList(client)) + } +} + +func testBranchFind(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + result, _, err := client.Git.FindBranch(context.Background(), "kit101/drone-yml-test", "feat-4") + if err != nil { + t.Error(err) + return + } + t.Run("Branch", testBranch(result)) + } +} + +func testBranchList(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + opts := scm.ListOptions{} + result, _, err := client.Git.ListBranches(context.Background(), "kit101/drone-yml-test", opts) + if err != nil { + t.Error(err) + return + } + if len(result) == 0 { + t.Errorf("Want a non-empty branch list") + } + for _, branch := range result { + if branch.Name == "feat-4" { + t.Run("Branch", testBranch(branch)) + } + } + } +} + +// +// branch sub-tests +// + +func testTags(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + t.Run("Find", testTagFind(client)) + t.Run("List", testTagList(client)) + } +} + +func testTagFind(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + tag, _, err := client.Git.FindTag(context.Background(), "kit101/drone-yml-test", "1.1") + if err != nil { + t.Error(err) + return + } + t.Run("Tag", testTag(tag)) + } +} + +func testTagList(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + opts := scm.ListOptions{} + result, _, err := client.Git.ListTags(context.Background(), "kit101/drone-yml-test", opts) + if err != nil { + t.Error(err) + return + } + if len(result) == 0 { + t.Errorf("Want a non-empty tag list") + } + for _, tag := range result { + if tag.Name == "1.1" { + t.Run("Tag", testTag(tag)) + } + } + } +} + +// +// commit sub-tests +// + +func testCommits(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + t.Run("Find", testCommitFind(client)) + t.Run("List", testCommitList(client)) + } +} + +func testCommitFind(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + result, _, err := client.Git.FindCommit(context.Background(), "kit101/drone-yml-test", "e3c0ff4d5cef439ea11b30866fb1ed79b420801d") + if err != nil { + t.Error(err) + return + } + t.Run("Commit", testCommit(result)) + } +} + +func testCommitList(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + opts := scm.CommitListOptions{ + Ref: "feat-4", + } + result, _, err := client.Git.ListCommits(context.Background(), "kit101/drone-yml-test", opts) + if err != nil { + t.Error(err) + return + } + if len(result) == 0 { + t.Errorf("Want a non-empty commit list") + } + for _, commit := range result { + if commit.Sha == "e3c0ff4d5cef439ea11b30866fb1ed79b420801d" { + t.Run("Commit", testCommit(commit)) + } + } + } +} + +// +// struct sub-tests +// + +func testBranch(branch *scm.Reference) func(t *testing.T) { + return func(t *testing.T) { + if got, want := branch.Name, "feat-4"; got != want { + t.Errorf("Want branch Name %q, got %q", want, got) + } + if got, want := branch.Sha, "2eac1cac02c325058cf959725c45b0612d3e8177"; got != want { + t.Errorf("Want branch Avatar %q, got %q", want, got) + } + } +} + +func testTag(tag *scm.Reference) func(t *testing.T) { + return func(t *testing.T) { + if got, want := tag.Name, "1.1"; got != want { + t.Errorf("Want tag Name %q, got %q", want, got) + } + if got, want := tag.Sha, "5e7876efb3468ff679410b82a72f7c002382d41e"; got != want { + t.Errorf("Want tag Avatar %q, got %q", want, got) + } + } +} + +func testCommit(commit *scm.Commit) func(t *testing.T) { + return func(t *testing.T) { + if got, want := commit.Message, "add/update/delete/rename\n"; got != want { + t.Errorf("Want commit Message %q, got %q", want, got) + } + if got, want := commit.Sha, "e3c0ff4d5cef439ea11b30866fb1ed79b420801d"; got != want { + t.Errorf("Want commit Sha %q, got %q", want, got) + } + if got, want := commit.Author.Name, "kit101"; got != want { + t.Errorf("Want commit author Name %q, got %q", want, got) + } + if got, want := commit.Author.Email, "qkssk1711@163.com"; got != want { + t.Errorf("Want commit author Email %q, got %q", want, got) + } + if got, want := commit.Author.Date.Unix(), int64(1629733553); got != want { + t.Errorf("Want commit author Date %d, got %d", want, got) + } + if got, want := commit.Committer.Name, "kit101"; got != want { + t.Errorf("Want commit author Name %q, got %q", want, got) + } + if got, want := commit.Committer.Email, "qkssk1711@163.com"; got != want { + t.Errorf("Want commit author Email %q, got %q", want, got) + } + if got, want := commit.Committer.Date.Unix(), int64(1629733553); got != want { + t.Errorf("Want commit author Date %d, got %d", want, got) + } + } +} diff --git a/scm/driver/gitee/integration/gitee_test.go b/scm/driver/gitee/integration/gitee_test.go new file mode 100644 index 000000000..cb9918130 --- /dev/null +++ b/scm/driver/gitee/integration/gitee_test.go @@ -0,0 +1,37 @@ +// 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 integration + +import ( + "net/http" + "os" + "testing" + + "github.com/drone/go-scm/scm/driver/gitee" + "github.com/drone/go-scm/scm/transport" +) + +func TestGitee(t *testing.T) { + accessToken := os.Getenv("GITEE_TOKEN") + if accessToken == "" { + t.Skipf("missing GITEE_TOKEN environment variable") + return + } + + client := gitee.NewDefault() + client.Client = &http.Client{ + Transport: &transport.BearerToken{ + Token: accessToken, + }, + } + + t.Run("Contents", testContents(client)) + t.Run("Git", testGit(client)) + t.Run("Issues", testIssues(client)) + t.Run("Organizations", testOrgs(client)) + t.Run("PullRequests", testPullRequests(client)) + t.Run("Repositories", testRepos(client)) + t.Run("Users", testUsers(client)) +} diff --git a/scm/driver/gitee/integration/integration.go b/scm/driver/gitee/integration/integration.go new file mode 100644 index 000000000..acc0ad401 --- /dev/null +++ b/scm/driver/gitee/integration/integration.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 integration diff --git a/scm/driver/gitee/integration/issue_test.go b/scm/driver/gitee/integration/issue_test.go new file mode 100644 index 000000000..f2d6ca846 --- /dev/null +++ b/scm/driver/gitee/integration/issue_test.go @@ -0,0 +1,145 @@ +// 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 integration + +import ( + "context" + "testing" + + "github.com/drone/go-scm/scm" +) + +// +// issue sub-tests +// + +func testIssues(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + t.Run("List", testIssueList(client)) + t.Run("Find", testIssueFind(client)) + t.Run("Comments", testIssueComments(client)) + } +} + +func testIssueList(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + opts := scm.IssueListOptions{ + Open: true, + Closed: true, + } + result, _, err := client.Issues.List(context.Background(), "kit101/drone-yml-test", opts) + if err != nil { + t.Error(err) + } + if len(result) == 0 { + t.Errorf("Got empty issue list") + } + } +} + +func testIssueFind(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + result, _, err := client.Issues.Find(context.Background(), "kit101/drone-yml-test", 735267685380) + if err != nil { + t.Error(err) + } + t.Run("Issue", testIssue(result)) + } +} + +// +// issue comment sub-tests +// + +func testIssueComments(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Run("List", testIssueCommentList(client)) + t.Run("Find", testIssueCommentFind(client)) + } +} + +func testIssueCommentList(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + opts := scm.ListOptions{} + result, _, err := client.Issues.ListComments(context.Background(), "kit101/drone-yml-test", 735267685380, opts) + if err != nil { + t.Error(err) + } + if len(result) == 0 { + t.Errorf("Want a non-empty issue comment list") + } + for _, comment := range result { + if comment.ID == 6877445 { + t.Run("Comment", testIssueComment(comment)) + } + } + } +} + +func testIssueCommentFind(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + result, _, err := client.Issues.FindComment(context.Background(), "kit101/drone-yml-test", 735267685380, 6877445) + if err != nil { + t.Error(err) + } + t.Run("Comment", testIssueComment(result)) + } +} + +// +// struct sub-tests +// + +func testIssue(issue *scm.Issue) func(t *testing.T) { + return func(t *testing.T) { + if got, want := issue.Number, 735267685380; got != want { + t.Errorf("Want issue Number %d, got %d", want, got) + } + if got, want := issue.Title, "test issue 1"; got != want { + t.Errorf("Want issue Title %q, got %q", want, got) + } + if got, want := issue.Body, "test issue 1"; got != want { + t.Errorf("Want issue Body %q, got %q", want, got) + } + if got, want := issue.Link, "https://gitee.com/kit101/drone-yml-test/issues/I4CD5P"; got != want { + t.Errorf("Want issue Link %q, got %q", want, got) + } + if got, want := issue.Author.Login, "kit101"; got != want { + t.Errorf("Want issue Author Login %q, got %q", want, got) + } + if got, want := issue.Author.Avatar, "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png"; got != want { + t.Errorf("Want issue Author Avatar %q, got %q", want, got) + } + if got, want := issue.Closed, true; got != want { + t.Errorf("Want issue Closed %v, got %v", want, got) + } + if got, want := issue.Created.Unix(), int64(1632878488); got != want { + t.Errorf("Want issue Created %d, got %d", want, got) + } + } +} + +func testIssueComment(comment *scm.Comment) func(t *testing.T) { + return func(t *testing.T) { + if got, want := comment.ID, 6877445; got != want { + t.Errorf("Want issue comment ID %d, got %d", want, got) + } + if got, want := comment.Body, "it's ok."; got != want { + t.Errorf("Want issue comment Body %q, got %q", want, got) + } + if got, want := comment.Author.Login, "kit101"; got != want { + t.Errorf("Want issue comment Author Login %q, got %q", want, got) + } + if got, want := comment.Created.Unix(), int64(1632884450); got != want { + t.Errorf("Want issue comment Created %d, got %d", want, got) + } + if got, want := comment.Updated.Unix(), int64(1632884450); got != want { + t.Errorf("Want issue comment Updated %d, got %d", want, got) + } + } +} diff --git a/scm/driver/gitee/integration/org_test.go b/scm/driver/gitee/integration/org_test.go new file mode 100644 index 000000000..e25590a19 --- /dev/null +++ b/scm/driver/gitee/integration/org_test.go @@ -0,0 +1,51 @@ +// 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 integration + +import ( + "context" + "testing" + + "github.com/drone/go-scm/scm" +) + +// +// organization sub-tests +// + +func testOrgs(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + t.Run("Find", testOrgFind(client)) + } +} + +func testOrgFind(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + result, _, err := client.Organizations.Find(context.Background(), "gitee-community") + if err != nil { + t.Error(err) + return + } + t.Run("Organization", testOrg(result)) + } +} + +// +// struct sub-tests +// + +func testOrg(organization *scm.Organization) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + if got, want := organization.Name, "gitee-community"; got != want { + t.Errorf("Want organization Name %q, got %q", want, got) + } + if got, want := organization.Avatar, "https://portrait.gitee.com/uploads/avatars/namespace/1715/5146011_gitee-community_1607593452.png?is_link=true"; got != want { + t.Errorf("Want organization Avatar %q, got %q", want, got) + } + } +} diff --git a/scm/driver/gitee/integration/pr_test.go b/scm/driver/gitee/integration/pr_test.go new file mode 100644 index 000000000..99caee142 --- /dev/null +++ b/scm/driver/gitee/integration/pr_test.go @@ -0,0 +1,212 @@ +// 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 integration + +import ( + "context" + "testing" + + "github.com/drone/go-scm/scm" +) + +// +// pull request sub-tests +// + +func testPullRequests(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + t.Run("List", testPullRequestList(client)) + t.Run("Find", testPullRequestFind(client)) + t.Run("Changes", testPullRequestChanges(client)) + t.Run("Comments", testPullRequestComments(client)) + } +} + +func testPullRequestList(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + opts := scm.PullRequestListOptions{ + Open: true, + Closed: true, + } + result, _, err := client.PullRequests.List(context.Background(), "kit101/drone-yml-test", opts) + if err != nil { + t.Error(err) + } + if len(result) == 0 { + t.Errorf("Got empty pull request list") + } + for _, pr := range result { + if pr.Number == 7 { + t.Run("PullRequest", testPullRequest(pr)) + } + } + } +} + +func testPullRequestFind(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + result, _, err := client.PullRequests.Find(context.Background(), "kit101/drone-yml-test", 7) + if err != nil { + t.Error(err) + } + t.Run("PullRequest", testPullRequest(result)) + } +} + +// +// pull request comment sub-tests +// + +func testPullRequestComments(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + t.Run("List", testPullRequestCommentFind(client)) + t.Run("Find", testPullRequestCommentList(client)) + } +} + +func testPullRequestCommentFind(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + result, _, err := client.PullRequests.FindComment(context.Background(), "kit101/drone-yml-test", 7, 6922557) + if err != nil { + t.Error(err) + } + t.Run("Comment", testPullRequestComment(result)) + } +} + +func testPullRequestCommentList(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + opts := scm.ListOptions{} + result, _, err := client.PullRequests.ListComments(context.Background(), "kit101/drone-yml-test", 7, opts) + if err != nil { + t.Error(err) + } + if len(result) == 0 { + t.Errorf("Got empty pull request comment list") + } + for _, comment := range result { + if comment.ID == 6922557 { + t.Run("Comment", testPullRequestComment(comment)) + } + } + } +} + +// +// pull request changes sub-tests +// + +func testPullRequestChanges(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + opts := scm.ListOptions{} + result, _, err := client.PullRequests.ListChanges(context.Background(), "kit101/drone-yml-test", 7, opts) + if err != nil { + t.Error(err) + } + if len(result) == 0 { + t.Errorf("Got empty pull request change list") + return + } + t.Run("File", testChange(result[0])) + } +} + +// +// struct sub-tests +// + +func testPullRequest(pr *scm.PullRequest) func(t *testing.T) { + return func(t *testing.T) { + if got, want := pr.Number, 7; got != want { + t.Errorf("Want pr Number %d, got %d", want, got) + } + if got, want := pr.Title, "feat add 3"; got != want { + t.Errorf("Want pr Title %q, got %q", want, got) + } + if got, want := pr.Body, ""; got != want { + t.Errorf("Want pr Body %q, got %q", want, got) + } + if got, want := pr.Source, "feat-2"; got != want { + t.Errorf("Want pr Source %q, got %q", want, got) + } + if got, want := pr.Target, "master"; got != want { + t.Errorf("Want pr Target %q, got %q", want, got) + } + if got, want := pr.Ref, "refs/pull/7/head"; got != want { + t.Errorf("Want pr Ref %q, got %q", want, got) + } + if got, want := pr.Sha, "6168d9dae737b47f00c59fafca10c913a6850c3a"; got != want { + t.Errorf("Want pr Sha %q, got %q", want, got) + } + if got, want := pr.Link, "https://gitee.com/kit101/drone-yml-test/pulls/7"; got != want { + t.Errorf("Want pr Link %q, got %q", want, got) + } + if got, want := pr.Diff, "https://gitee.com/kit101/drone-yml-test/pulls/7.diff"; got != want { + t.Errorf("Want pr Diff %q, got %q", want, got) + } + if got, want := pr.Author.Login, "kit101"; got != want { + t.Errorf("Want pr Author Login %q, got %q", want, got) + } + if got, want := pr.Author.Avatar, "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png"; got != want { + t.Errorf("Want pr Author Avatar %q, got %q", want, got) + } + if got, want := pr.Closed, false; got != want { + t.Errorf("Want pr Closed %v, got %v", want, got) + } + if got, want := pr.Merged, false; got != want { + t.Errorf("Want pr Merged %v, got %v", want, got) + } + if got, want := pr.Created.Unix(), int64(1632996627); got != want { + t.Errorf("Want pr Created %d, got %d", want, got) + } + } +} + +func testPullRequestComment(comment *scm.Comment) func(t *testing.T) { + return func(t *testing.T) { + if got, want := comment.ID, 6922557; got != want { + t.Errorf("Want pr comment ID %d, got %d", want, got) + } + if got, want := comment.Body, "test comment 1"; got != want { + t.Errorf("Want pr comment Body %q, got %q", want, got) + } + if got, want := comment.Author.Login, "kit101"; got != want { + t.Errorf("Want pr comment Author Login %q, got %q", want, got) + } + if got, want := comment.Author.Name, "kit101"; got != want { + t.Errorf("Want pr comment Author Name %q, got %q", want, got) + } + if got, want := comment.Created.Unix(), int64(1633570005); got != want { + t.Errorf("Want pr comment Created %d, got %d", want, got) + } + if got, want := comment.Updated.Unix(), int64(1633570005); got != want { + t.Errorf("Want pr comment Updated %d, got %d", want, got) + } + } +} + +func testChange(change *scm.Change) func(t *testing.T) { + return func(t *testing.T) { + if got, want := change.Path, "change/add3.txt"; got != want { + t.Errorf("Want file change Path %q, got %q", want, got) + } + if got, want := change.Added, true; got != want { + t.Errorf("Want file Added %v, got %v", want, got) + } + if got, want := change.Deleted, false; got != want { + t.Errorf("Want file Deleted %v, got %v", want, got) + } + if got, want := change.Renamed, false; got != want { + t.Errorf("Want file Renamed %v, got %v", want, got) + } + } +} diff --git a/scm/driver/gitee/integration/repo_test.go b/scm/driver/gitee/integration/repo_test.go new file mode 100644 index 000000000..5ff0cef15 --- /dev/null +++ b/scm/driver/gitee/integration/repo_test.go @@ -0,0 +1,85 @@ +// 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 integration + +import ( + "context" + "testing" + + "github.com/drone/go-scm/scm" +) + +// +// repository sub-tests +// + +func testRepos(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + t.Run("Find", testRepoFind(client)) + } +} + +func testRepoFind(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + result, _, err := client.Repositories.Find(context.Background(), "kit101/drone-yml-test") + if err != nil { + t.Error(err) + return + } + t.Run("Repository", testRepo(result)) + t.Run("Permissions", testPerm(result.Perm)) + } +} + +// +// struct sub-tests +// + +func testRepo(repository *scm.Repository) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + if got, want := repository.Name, "drone-yml-test"; got != want { + t.Errorf("Want repository Name %q, got %q", want, got) + } + if got, want := repository.Namespace, "kit101"; got != want { + t.Errorf("Want repository Namespace %q, got %q", want, got) + } + if got, want := repository.Branch, "master"; got != want { + t.Errorf("Want repository Branch %q, got %q", want, got) + } + if got, want := repository.Clone, "https://gitee.com/kit101/drone-yml-test.git"; got != want { + t.Errorf("Want repository Clone URL %q, got %q", want, got) + } + if got, want := repository.CloneSSH, "git@gitee.com:kit101/drone-yml-test.git"; got != want { + t.Errorf("Want repository SSH URL %q, got %q", want, got) + } + if got, want := repository.Link, "https://gitee.com/kit101/drone-yml-test.git"; got != want { + t.Errorf("Want repository Link %q, got %q", want, got) + } + if got, want := repository.Created.Unix(), int64(1616556274); got != want { + t.Errorf("Want repository Created %d, got %d", want, got) + } + if got, want := repository.Private, false; got != want { + t.Errorf("Want repository Private %v, got %v", want, got) + } + } +} + +func testPerm(perms *scm.Perm) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + if got, want := perms.Pull, true; got != want { + t.Errorf("Want permission Pull %v, got %v", want, got) + } + if got, want := perms.Push, false; got != want { + t.Errorf("Want permission Push %v, got %v", want, got) + } + if got, want := perms.Admin, false; got != want { + t.Errorf("Want permission Admin %v, got %v", want, got) + } + } +} diff --git a/scm/driver/gitee/integration/user_test.go b/scm/driver/gitee/integration/user_test.go new file mode 100644 index 000000000..26c731e12 --- /dev/null +++ b/scm/driver/gitee/integration/user_test.go @@ -0,0 +1,54 @@ +// 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 integration + +import ( + "context" + "testing" + + "github.com/drone/go-scm/scm" +) + +// +// user sub-tests +// + +func testUsers(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + t.Run("Find", testUserFind(client)) + } +} + +func testUserFind(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + result, _, err := client.Users.FindLogin(context.Background(), "kit101") + if err != nil { + t.Error(err) + return + } + t.Run("User", testUser(result)) + } +} + +// +// struct sub-tests +// + +func testUser(user *scm.User) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + if got, want := user.Login, "kit101"; got != want { + t.Errorf("Want user Login %q, got %q", want, got) + } + if got, want := user.Name, "kit101"; got != want { + t.Errorf("Want user Name %q, got %q", want, got) + } + if got, want := user.Avatar, "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png"; got != want { + t.Errorf("Want user Avatar %q, got %q", want, got) + } + } +} diff --git a/scm/driver/gitee/issue.go b/scm/driver/gitee/issue.go new file mode 100644 index 000000000..4d06350a6 --- /dev/null +++ b/scm/driver/gitee/issue.go @@ -0,0 +1,319 @@ +// 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 gitee + +import ( + "context" + "fmt" + "strconv" + "time" + + "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) { + path := fmt.Sprintf("repos/%s/issues/%s", repo, decodeNumber(number)) + out := new(issue) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertIssue(out), res, err +} + +func (s *issueService) FindComment(ctx context.Context, repo string, number, id int) (*scm.Comment, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/issues/comments/%d", repo, id) + out := new(issueComment) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertIssueComment(out), res, err +} + +func (s *issueService) List(ctx context.Context, repo string, opts scm.IssueListOptions) ([]*scm.Issue, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/issues?%s", repo, encodeIssueListOptions(opts)) + out := []*issue{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertIssueList(out), res, err +} + +func (s *issueService) ListComments(ctx context.Context, repo string, number int, opts scm.ListOptions) ([]*scm.Comment, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/issues/%s/comments?%s", repo, decodeNumber(number), encodeListOptions(opts)) + out := []*issueComment{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertIssueCommentList(out), res, err +} + +func (s *issueService) Create(ctx context.Context, repo string, input *scm.IssueInput) (*scm.Issue, *scm.Response, error) { + owner, repoName := scm.Split(repo) + path := fmt.Sprintf("repos/%s/issues", owner) + in := &issueInput{ + Repo: repoName, + Title: input.Title, + Body: input.Body, + } + out := new(issue) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertIssue(out), res, err +} + +func (s *issueService) CreateComment(ctx context.Context, repo string, number int, input *scm.CommentInput) (*scm.Comment, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/issues/%s/comments", repo, decodeNumber(number)) + in := &issueCommentInput{ + Body: input.Body, + } + out := new(issueComment) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertIssueComment(out), res, err +} + +func (s *issueService) DeleteComment(ctx context.Context, repo string, number, id int) (*scm.Response, error) { + path := fmt.Sprintf("repos/%s/issues/comments/%d", repo, id) + return s.client.do(ctx, "DELETE", path, nil, nil) +} + +func (s *issueService) Close(ctx context.Context, repo string, number int) (*scm.Response, error) { + owner, repoName := scm.Split(repo) + path := fmt.Sprintf("repos/%s/issues/%s", owner, decodeNumber(number)) + data := map[string]string{ + "repo": repoName, + "state": "closed", + } + out := new(issue) + res, err := s.client.do(ctx, "PATCH", path, &data, out) + return res, err +} + +func (s *issueService) Lock(context.Context, string, int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + +func (s *issueService) Unlock(context.Context, string, int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + +type issue struct { + ID int `json:"id"` + URL string `json:"url"` + RepositoryURL string `json:"repository_url"` + LabelsURL string `json:"labels_url"` + CommentsURL string `json:"comments_url"` + HtmlURL string `json:"html_url"` + ParentURL interface{} `json:"parent_url"` + Number string `json:"number"` + ParentID int `json:"parent_id"` + Depth int `json:"depth"` + State string `json:"state"` + Title string `json:"title"` + Body string `json:"body"` + User user `json:"user"` + Labels []label `json:"labels"` + Assignee assignee `json:"assignee"` + Collaborators []interface{} `json:"collaborators"` + Repository issueRepository `json:"repository"` + Milestone milestone `json:"milestone"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + PlanStartedAt interface{} `json:"plan_started_at"` + Deadline interface{} `json:"deadline"` + FinishedAt interface{} `json:"finished_at"` + ScheduledTime float64 `json:"scheduled_time"` + Comments int `json:"comments"` + Priority int `json:"priority"` + IssueType string `json:"issue_type"` + SecurityHole bool `json:"security_hole"` + IssueState string `json:"issue_state"` + IssueTypeDetail issueTypeDetail `json:"issue_type_detail"` + IssueStateDetail issueStateDetail `json:"issue_state_detail"` +} +type issueRepository struct { + ID int `json:"id"` + FullName string `json:"full_name"` + HumanName string `json:"human_name"` + URL string `json:"url"` + Namespace namespace `json:"namespace"` + Path string `json:"path"` + Name string `json:"name"` + Owner user `json:"owner"` + Assigner assignee `json:"assigner"` + Description string `json:"description"` + Private bool `json:"private"` + Public bool `json:"public"` + Internal bool `json:"internal"` + Fork bool `json:"fork"` + HTMLURL string `json:"html_url"` + SSHURL string `json:"ssh_url"` + ForksURL string `json:"forks_url"` + KeysURL string `json:"keys_url"` + CollaboratorsURL string `json:"collaborators_url"` + HooksURL string `json:"hooks_url"` + BranchesURL string `json:"branches_url"` + TagsURL string `json:"tags_url"` + BlobsURL string `json:"blobs_url"` + StargazersURL string `json:"stargazers_url"` + ContributorsURL string `json:"contributors_url"` + CommitsURL string `json:"commits_url"` + CommentsURL string `json:"comments_url"` + IssueCommentURL string `json:"issue_comment_url"` + IssuesURL string `json:"issues_url"` + PullsURL string `json:"pulls_url"` + MilestonesURL string `json:"milestones_url"` + NotificationsURL string `json:"notifications_url"` + LabelsURL string `json:"labels_url"` + ReleasesURL string `json:"releases_url"` + Recommend bool `json:"recommend"` + Gvp bool `json:"gvp"` + Homepage string `json:"homepage"` + Language interface{} `json:"language"` + ForksCount int `json:"forks_count"` + StargazersCount int `json:"stargazers_count"` + WatchersCount int `json:"watchers_count"` + DefaultBranch string `json:"default_branch"` + OpenIssuesCount int `json:"open_issues_count"` + HasIssues bool `json:"has_issues"` + HasWiki bool `json:"has_wiki"` + IssueComment bool `json:"issue_comment"` + CanComment bool `json:"can_comment"` + PullRequestsEnabled bool `json:"pull_requests_enabled"` + HasPage bool `json:"has_page"` + License interface{} `json:"license"` + Outsourced bool `json:"outsourced"` + ProjectCreator string `json:"project_creator"` + Members []string `json:"members"` + PushedAt time.Time `json:"pushed_at"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Parent interface{} `json:"parent"` + Paas interface{} `json:"paas"` + AssigneesNumber int `json:"assignees_number"` + TestersNumber int `json:"testers_number"` + Assignee []assignee `json:"assignee"` + Testers []tester `json:"testers"` + Status string `json:"status"` + EmptyRepo bool `json:"empty_repo"` + Programs []interface{} `json:"programs"` + Enterprise interface{} `json:"enterprise"` +} +type issueTypeDetail struct { + ID int `json:"id"` + Title string `json:"title"` + Template interface{} `json:"template"` + Ident string `json:"ident"` + Color string `json:"color"` + IsSystem bool `json:"is_system"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} +type issueStateDetail struct { + ID int `json:"id"` + Title string `json:"title"` + Color string `json:"color"` + Icon string `json:"icon"` + Command interface{} `json:"command"` + Serial int `json:"serial"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +type issueInput struct { + Repo string `json:"repo"` + Title string `json:"title"` + Body string `json:"body"` +} + +type issueComment struct { + ID int `json:"id"` + HTMLURL string `json:"html_url"` + User struct { + ID int `json:"id"` + Login string `json:"login"` + AvatarURL string `json:"avatar_url"` + } `json:"user"` + Body string `json:"body"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +type issueCommentInput struct { + Body string `json:"body"` +} + +func convertIssueList(from []*issue) []*scm.Issue { + to := []*scm.Issue{} + for _, v := range from { + to = append(to, convertIssue(v)) + } + return to +} +func convertIssue(from *issue) *scm.Issue { + return &scm.Issue{ + Number: encodeNumber(from.Number), + Title: from.Title, + Body: from.Body, + Link: from.HtmlURL, + Labels: convertLabels(from), + Closed: from.State == "closed", + Author: scm.User{ + Login: from.User.Login, + Avatar: from.User.AvatarURL, + }, + Created: from.CreatedAt, + Updated: from.UpdatedAt, + } +} + +func convertIssueCommentList(from []*issueComment) []*scm.Comment { + to := []*scm.Comment{} + for _, v := range from { + to = append(to, convertIssueComment(v)) + } + return to +} +func convertIssueComment(from *issueComment) *scm.Comment { + return &scm.Comment{ + ID: from.ID, + Body: from.Body, + Author: scm.User{ + Login: from.User.Login, + Avatar: from.User.AvatarURL, + }, + Created: from.CreatedAt, + Updated: from.UpdatedAt, + } +} + +func convertLabels(from *issue) []string { + var labels []string + for _, label := range from.Labels { + labels = append(labels, label.Name) + } + return labels +} + +// The issue number of gitee consists of 6 uppercase letters or numbers. +// The ASCII of uppercase letters or numbers is between 48 and 90, so encoded issue number(max:9090909090) less than the maximum value of int. +func encodeNumber(giteeIssueNumber string) int { + runes := []rune(giteeIssueNumber) + encodedNumber := "" + for i := 0; i < len(runes); i++ { + encodedNumber += strconv.Itoa(int(runes[i])) + } + scmNumber, err := strconv.Atoi(encodedNumber) + if err != nil { + return 0 + } + return scmNumber +} +func decodeNumber(scmIssueNumber int) string { + issueNumberStr := strconv.Itoa(scmIssueNumber) + giteeNumber := "" + for i := 0; i < len(issueNumberStr)-1; i += 2 { + numberStr, err := strconv.Atoi(issueNumberStr[i : i+2]) + if err != nil { + return "" + } + giteeNumber += string(rune(numberStr)) + } + return giteeNumber +} diff --git a/scm/driver/gitee/issue_test.go b/scm/driver/gitee/issue_test.go new file mode 100644 index 000000000..a59ea6b29 --- /dev/null +++ b/scm/driver/gitee/issue_test.go @@ -0,0 +1,280 @@ +// 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 gitee + +import ( + "context" + "encoding/json" + "io/ioutil" + "testing" + + "github.com/drone/go-scm/scm" + + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestEncodeAndDecodeIssueNumber(t *testing.T) { + giteeIssueNumber := "I4CD5P" + scmIssueNumber := 735267685380 + encodedScmIssueNumber := encodeNumber(giteeIssueNumber) + if diff := cmp.Diff(encodedScmIssueNumber, scmIssueNumber); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + encodedGiteeIssueNumber := decodeNumber(scmIssueNumber) + if diff := cmp.Diff(encodedGiteeIssueNumber, giteeIssueNumber); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestIssueFind(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/issues/I4CD5P"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/issue.json") + + client := NewDefault() + got, res, err := client.Issues.Find(context.Background(), "kit101/drone-yml-test", 735267685380) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Issue) + raw, _ := ioutil.ReadFile("testdata/issue.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)) +} + +func TestIssueFindComment(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/issues/comments/6877445"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/issue_comment.json") + + client := NewDefault() + got, res, err := client.Issues.FindComment(context.Background(), "kit101/drone-yml-test", 735267685380, 6877445) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Comment) + raw, _ := ioutil.ReadFile("testdata/issue_comment.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)) +} + +func TestIssueList(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/issues"). + MatchParam("page", "1"). + MatchParam("per_page", "3"). + MatchParam("state", "all"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/issues.json") + + client := NewDefault() + got, res, err := client.Issues.List(context.Background(), "kit101/drone-yml-test", scm.IssueListOptions{Page: 1, Size: 3, Open: true, Closed: true}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Issue{} + raw, _ := ioutil.ReadFile("testdata/issues.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("Page", testPage(res)) +} + +func TestIssueListComments(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml/issues/I4CD5P/comments"). + MatchParam("page", "1"). + MatchParam("per_page", "3"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/issue_comments.json") + + client := NewDefault() + got, res, err := client.Issues.ListComments(context.Background(), "kit101/drone-yml", 735267685380, scm.ListOptions{Size: 3, Page: 1}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Comment{} + raw, _ := ioutil.ReadFile("testdata/issue_comments.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("Page", testPage(res)) +} + +func TestIssueCreate(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Post("/repos/kit101/issues"). + Reply(201). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/issue.json") + + input := scm.IssueInput{ + Title: "test issue 1", + Body: "test issue 1", + } + + client := NewDefault() + got, res, err := client.Issues.Create(context.Background(), "kit101/drone-yml-test", &input) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Issue) + raw, _ := ioutil.ReadFile("testdata/issue.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)) +} + +func TestIssueCreateComment(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com"). + Post("/repos/kit101/drone-yml-test/issues/I4CD5P/comments"). + Reply(201). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/issue_comment.json") + + input := &scm.CommentInput{ + Body: "it's ok.", + } + + client := NewDefault() + got, res, err := client.Issues.CreateComment(context.Background(), "kit101/drone-yml-test", 735267685380, input) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Comment) + raw, _ := ioutil.ReadFile("testdata/issue_comment.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)) +} + +func TestIssueDeleteComment(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Delete("/repos/kit101/drone-yml-test/issues/comments/6879139"). + Reply(204). + Type("application/json"). + SetHeaders(mockHeaders) + + client := NewDefault() + res, err := client.Issues.DeleteComment(context.Background(), "kit101/drone-yml-test", 735267685380, 6879139) + if err != nil { + t.Error(err) + return + } + + if got, want := res.Status, 204; got != want { + t.Errorf("Want response status %d, got %d", want, got) + } + t.Run("Request", testRequest(res)) +} + +func TestIssueClose(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Patch("/repos/kit101/issues/I4CD5P"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/issue.json") + + client := NewDefault() + res, err := client.Issues.Close(context.Background(), "kit101/drone-yml-test", 735267685380) + if err != nil { + t.Error(err) + return + } + + t.Run("Request", testRequest(res)) +} + +func TestIssueLock(t *testing.T) { + _, err := NewDefault().Issues.Lock(context.Background(), "kit101/drone-yml-test", 735267685380) + if err != scm.ErrNotSupported { + t.Errorf("Expect Not Supported error") + } +} + +func TestIssueUnlock(t *testing.T) { + _, err := NewDefault().Issues.Unlock(context.Background(), "kit101/drone-yml-test", 735267685380) + if err != scm.ErrNotSupported { + t.Errorf("Expect Not Supported error") + } +} diff --git a/scm/driver/gitee/linker.go b/scm/driver/gitee/linker.go new file mode 100644 index 000000000..79b0beac5 --- /dev/null +++ b/scm/driver/gitee/linker.go @@ -0,0 +1,50 @@ +// 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 gitee + +import ( + "context" + "fmt" + + "github.com/drone/go-scm/scm" +) + +type linker struct { + base string +} + +func (l *linker) Resource(ctx context.Context, repo string, ref scm.Reference) (string, error) { + switch { + case scm.IsTag(ref.Path): + t := scm.TrimRef(ref.Path) + return fmt.Sprintf("%s%s/tree/%s", l.base, repo, t), nil + case scm.IsPullRequest(ref.Path): + d := scm.ExtractPullRequest(ref.Path) + return fmt.Sprintf("%s%s/pulls/%d", l.base, repo, d), nil + case ref.Sha == "": + t := scm.TrimRef(ref.Path) + return fmt.Sprintf("%s%s/tree/%s", l.base, repo, t), nil + default: + return fmt.Sprintf("%s%s/commit/%s", l.base, repo, ref.Sha), nil + } +} + +func (l *linker) Diff(ctx context.Context, repo string, source, target scm.Reference) (string, error) { + if scm.IsPullRequest(target.Path) { + pullRequestID := scm.ExtractPullRequest(target.Path) + return fmt.Sprintf("%s%s/pulls/%d/files", l.base, repo, pullRequestID), nil + } + + s := source.Sha + t := target.Sha + if s == "" { + s = scm.TrimRef(source.Path) + } + if t == "" { + t = scm.TrimRef(target.Path) + } + + return fmt.Sprintf("%s%s/compare/%s...%s", l.base, repo, s, t), nil +} diff --git a/scm/driver/gitee/linker_test.go b/scm/driver/gitee/linker_test.go new file mode 100644 index 000000000..55c9a84f2 --- /dev/null +++ b/scm/driver/gitee/linker_test.go @@ -0,0 +1,103 @@ +// 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 gitee + +import ( + "context" + "testing" + + "github.com/drone/go-scm/scm" +) + +func TestLink(t *testing.T) { + tests := []struct { + path string + sha string + want string + }{ + { + path: "refs/heads/master", + sha: "2eac1cac02c325058cf959725c45b0612d3e8177", + want: "https://gitee.com/kit101/drone-yml-test/commit/2eac1cac02c325058cf959725c45b0612d3e8177", + }, + { + path: "refs/pull/7/head", + sha: "00b76e8abd51ae6a96318b3450944b32995f9158", + want: "https://gitee.com/kit101/drone-yml-test/pulls/7", + }, + { + path: "refs/tags/1.1", + want: "https://gitee.com/kit101/drone-yml-test/tree/1.1", + }, + { + path: "refs/heads/master", + want: "https://gitee.com/kit101/drone-yml-test/tree/master", + }, + } + + for _, test := range tests { + client := NewDefault() + ref := scm.Reference{ + Path: test.path, + Sha: test.sha, + } + got, err := client.Linker.Resource(context.Background(), "kit101/drone-yml-test", ref) + if err != nil { + t.Error(err) + return + } + want := test.want + if got != want { + t.Errorf("Want link %q, got %q", want, got) + } + } +} + +func TestDiff(t *testing.T) { + tests := []struct { + source scm.Reference + target scm.Reference + want string + }{ + { + source: scm.Reference{Sha: "2eac1cac02c325058cf959725c45b0612d3e8177"}, + target: scm.Reference{Sha: "00b76e8abd51ae6a96318b3450944b32995f9158"}, + want: "https://gitee.com/kit101/drone-yml-test/compare/2eac1cac02c325058cf959725c45b0612d3e8177...00b76e8abd51ae6a96318b3450944b32995f9158", + }, + { + source: scm.Reference{Path: "refs/heads/master"}, + target: scm.Reference{Sha: "00b76e8abd51ae6a96318b3450944b32995f9158"}, + want: "https://gitee.com/kit101/drone-yml-test/compare/master...00b76e8abd51ae6a96318b3450944b32995f9158", + }, + { + source: scm.Reference{Sha: "00b76e8abd51ae6a96318b3450944b32995f9158"}, + target: scm.Reference{Path: "refs/heads/master"}, + want: "https://gitee.com/kit101/drone-yml-test/compare/00b76e8abd51ae6a96318b3450944b32995f9158...master", + }, + { + target: scm.Reference{Path: "refs/pull/7/head"}, + want: "https://gitee.com/kit101/drone-yml-test/pulls/7/files", + }, + } + + for _, test := range tests { + client := NewDefault() + got, err := client.Linker.Diff(context.Background(), "kit101/drone-yml-test", test.source, test.target) + if err != nil { + t.Error(err) + return + } + want := test.want + if got != want { + t.Errorf("Want link %q, got %q", want, got) + } + } +} + +func TestLinkBase(t *testing.T) { + if got, want := NewDefault().Linker.(*linker).base, "https://gitee.com/"; got != want { + t.Errorf("Want url %s, got %s", want, got) + } +} diff --git a/scm/driver/gitee/org.go b/scm/driver/gitee/org.go new file mode 100644 index 000000000..1a9e66947 --- /dev/null +++ b/scm/driver/gitee/org.go @@ -0,0 +1,97 @@ +// 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 gitee + +import ( + "context" + "fmt" + + "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) { + path := fmt.Sprintf("orgs/%s", name) + out := new(organization) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertOrganization(out), res, err +} + +func (s *organizationService) FindMembership(ctx context.Context, name, username string) (*scm.Membership, *scm.Response, error) { + path := fmt.Sprintf("orgs/%s/memberships/%s", name, username) + out := new(membership) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertMembership(out), res, err +} + +func (s *organizationService) List(ctx context.Context, opts scm.ListOptions) ([]*scm.Organization, *scm.Response, error) { + path := fmt.Sprintf("user/orgs?%s", encodeListOptions(opts)) + out := []*organization{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertOrganizationList(out), res, err +} + +type organization struct { + ID int `json:"id"` + Login string `json:"login"` + Name string `json:"name"` + URL string `json:"url"` + AvatarURL string `json:"avatar_url"` + ReposURL string `json:"repos_url"` + EventsURL string `json:"events_url"` + MembersURL string `json:"members_url"` + Description string `json:"description"` + FollowCount int `json:"follow_count"` +} + +type membership struct { + URL string `json:"url"` + Active bool `json:"active"` + Remark string `json:"remark"` + Role string `json:"role"` + OrganizationURL string `json:"organization_url"` + Organization organization `json:"organization"` + User struct { + ID int `json:"id"` + Login string `json:"login"` + Name string `json:"name"` + AvatarURL string `json:"avatar_url"` + URL string `json:"url"` + HtmlURL string `json:"html_url"` + Remark string `json:"remark"` + } `json:"user"` +} + +func convertOrganizationList(from []*organization) []*scm.Organization { + to := []*scm.Organization{} + for _, v := range from { + to = append(to, convertOrganization(v)) + } + return to +} + +func convertOrganization(from *organization) *scm.Organization { + return &scm.Organization{ + Name: from.Login, + Avatar: from.AvatarURL, + } +} + +func convertMembership(from *membership) *scm.Membership { + to := new(scm.Membership) + to.Active = from.Active + switch from.Role { + case "admin": + to.Role = scm.RoleAdmin + case "member": + to.Role = scm.RoleMember + default: + to.Role = scm.RoleUndefined + } + return to +} diff --git a/scm/driver/gitee/org_test.go b/scm/driver/gitee/org_test.go new file mode 100644 index 000000000..fa08e8927 --- /dev/null +++ b/scm/driver/gitee/org_test.go @@ -0,0 +1,108 @@ +// 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 gitee + +import ( + "context" + "encoding/json" + "io/ioutil" + "testing" + + "github.com/drone/go-scm/scm" + + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestOrganizationFind(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/orgs/kit101-personal"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/org.json") + + client := NewDefault() + got, res, err := client.Organizations.Find(context.Background(), "kit101-personal") + if err != nil { + t.Error(err) + return + } + + want := new(scm.Organization) + raw, _ := ioutil.ReadFile("testdata/org.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)) +} + +func TestOrganizationFindMembership(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/orgs/kit101-personal/memberships/kit101"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/membership.json") + + client := NewDefault() + got, res, err := client.Organizations.FindMembership(context.Background(), "kit101-personal", "kit101") + if err != nil { + t.Error(err) + return + } + + 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) + } + + t.Run("Request", testRequest(res)) +} + +func TestOrganizationList(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/user/orgs"). + MatchParam("page", "1"). + MatchParam("per_page", "3"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/orgs.json") + + client := NewDefault() + got, res, err := client.Organizations.List(context.Background(), scm.ListOptions{Size: 3, Page: 1}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Organization{} + raw, _ := ioutil.ReadFile("testdata/orgs.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("Page", testPage(res)) +} diff --git a/scm/driver/gitee/pr.go b/scm/driver/gitee/pr.go new file mode 100644 index 000000000..7a35768f9 --- /dev/null +++ b/scm/driver/gitee/pr.go @@ -0,0 +1,413 @@ +// 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 gitee + +import ( + "context" + "fmt" + "time" + + "github.com/drone/go-scm/scm" +) + +type pullService struct { + client *wrapper +} + +func (s *pullService) Find(ctx context.Context, repo string, number int) (*scm.PullRequest, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/pulls/%d", repo, number) + out := new(pr) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertPullRequest(out), res, err +} + +func (s *pullService) FindComment(ctx context.Context, repo string, _ int, id int) (*scm.Comment, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/pulls/comments/%d", repo, id) + out := new(prComment) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertPullRequestComment(out), res, err +} + +func (s *pullService) List(ctx context.Context, repo string, opts scm.PullRequestListOptions) ([]*scm.PullRequest, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/pulls?%s", repo, encodePullRequestListOptions(opts)) + out := []*pr{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertPullRequestList(out), res, err +} + +func (s *pullService) ListChanges(ctx context.Context, repo string, number int, _ scm.ListOptions) ([]*scm.Change, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/pulls/%d/files", repo, number) + out := []*prFile{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertPrChangeList(out), res, err +} + +func (s *pullService) ListComments(ctx context.Context, repo string, number int, opts scm.ListOptions) ([]*scm.Comment, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/pulls/%d/comments/?%s", repo, number, encodeListOptions(opts)) + out := []*prComment{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertPullRequestComments(out), res, err +} + +func (s *pullService) ListCommits(ctx context.Context, repo string, number int, _ scm.ListOptions) ([]*scm.Commit, *scm.Response, error) { + path := fmt.Sprintf("/repos/%s/pulls/%d/commits", repo, number) + out := []*prCommit{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertPrCommitList(out), res, err +} + +func (s *pullService) Merge(ctx context.Context, repo string, number int) (*scm.Response, error) { + path := fmt.Sprintf("repos/%s/pulls/%d/merge", repo, number) + res, err := s.client.do(ctx, "PUT", path, nil, nil) + return res, err +} + +func (s *pullService) Close(ctx context.Context, repo string, number int) (*scm.Response, error) { + path := fmt.Sprintf("repos/%s/pulls/%d", repo, number) + data := map[string]string{"state": "closed"} + res, err := s.client.do(ctx, "PATCH", path, &data, nil) + return res, err +} + +func (s *pullService) Create(ctx context.Context, repo string, input *scm.PullRequestInput) (*scm.PullRequest, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/pulls", repo) + in := &prInput{ + Title: input.Title, + Body: input.Body, + Head: input.Source, + Base: 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, number int, input *scm.CommentInput) (*scm.Comment, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/pulls/%d/comments", repo, number) + in := &prCommentInput{ + Body: 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, _ int, id int) (*scm.Response, error) { + path := fmt.Sprintf("repos/%s/pulls/comments/%d", repo, id) + res, err := s.client.do(ctx, "DELETE", path, nil, nil) + return res, err +} + +type ( + pr struct { + ID int `json:"id"` + URL string `json:"url"` + HtmlURL string `json:"html_url"` + DiffURL string `json:"diff_url"` + PatchURL string `json:"patch_url"` + IssueURL string `json:"issue_url"` + CommitsURL string `json:"commits_url"` + ReviewCommentsURL string `json:"review_comments_url"` + ReviewCommentURL string `json:"review_comment_url"` + CommentsURL string `json:"comments_url"` + Number int `json:"number"` + State string `json:"state"` + Title string `json:"title"` + Body string `json:"body"` + AssigneesNumber int `json:"assignees_number"` + TestersNumber int `json:"testers_number"` + Assignees []assignee `json:"assignees"` + Testers []tester `json:"testers"` + Milestone milestone `json:"milestone"` + Labels []label `json:"labels"` + Locked bool `json:"locked"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + ClosedAt time.Time `json:"closed_at"` + MergedAt time.Time `json:"merged_at"` + Mergeable bool `json:"mergeable"` + CanMergeCheck bool `json:"can_merge_check"` + Head headOrBase `json:"head"` + Base headOrBase `json:"base"` + User user `json:"user"` + } + assignee struct { + ID int `json:"id"` + Login string `json:"login"` + Name string `json:"name"` + AvatarURL string `json:"avatar_url"` + URL string `json:"url"` + HtmlURL string `json:"html_url"` + Remark string `json:"remark"` + FollowersURL string `json:"followers_url"` + FollowingURL string `json:"following_url"` + GistsURL string `json:"gists_url"` + StarredURL string `json:"starred_url"` + SubscriptionsURL string `json:"subscriptions_url"` + OrganizationsURL string `json:"organizations_url"` + ReposURL string `json:"repos_url"` + EventsURL string `json:"events_url"` + ReceivedEventsURL string `json:"received_events_url"` + Type string `json:"type"` + } + tester struct { + ID int `json:"id"` + Login string `json:"login"` + Name string `json:"name"` + AvatarURL string `json:"avatar_url"` + URL string `json:"url"` + HtmlURL string `json:"html_url"` + Remark string `json:"remark"` + FollowersURL string `json:"followers_url"` + FollowingURL string `json:"following_url"` + GistsURL string `json:"gists_url"` + StarredURL string `json:"starred_url"` + SubscriptionsURL string `json:"subscriptions_url"` + OrganizationsURL string `json:"organizations_url"` + ReposURL string `json:"repos_url"` + EventsURL string `json:"events_url"` + ReceivedEventsURL string `json:"received_events_url"` + Type string `json:"type"` + } + milestone struct { + URL string `json:"url"` + HtmlURL string `json:"html_url"` + ID int `json:"id"` + Number int `json:"number"` + RepositoryID interface{} `json:"repository_id"` + State string `json:"state"` + Title string `json:"title"` + Description string `json:"description"` + UpdatedAt time.Time `json:"updated_at"` + CreatedAt time.Time `json:"created_at"` + OpenIssues int `json:"open_issues"` + ClosedIssues int `json:"closed_issues"` + DueOn string `json:"due_on"` + } + label struct { + ID int `json:"id"` + Name string `json:"name"` + Color string `json:"color"` + RepositoryID int `json:"repository_id"` + URL string `json:"url"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + } + prRepo struct { + ID int `json:"id"` + FullName string `json:"full_name"` + HumanName string `json:"human_name"` + URL string `json:"url"` + //Namespace namespace `json:"namespace"` + Path string `json:"path"` + Name string `json:"name"` + Owner user `json:"owner"` + Assigner assignee `json:"assigner"` + Description string `json:"description"` + Private bool `json:"private"` + Public bool `json:"public"` + Internal bool `json:"internal"` + Fork bool `json:"fork"` + HtmlURL string `json:"html_url"` + SshURL string `json:"ssh_url"` + } + headOrBase struct { + Label string `json:"label"` + Ref string `json:"ref"` + Sha string `json:"sha"` + User user `json:"user"` + Repo prRepo `json:"repo"` + } + + prComment struct { + URL string `json:"url"` + ID int `json:"id"` + User user `json:"user"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Body string `json:"body"` + HtmlURL string `json:"html_url"` + PullRequestURL string `json:"pull_request_url"` + } + + prFile struct { + Sha string `json:"sha"` + Filename string `json:"filename"` + Status string `json:"status"` + Additions string `json:"additions"` + Deletions string `json:"deletions"` + BlobURL string `json:"blob_url"` + RawURL string `json:"raw_url"` + Patch struct { + Diff string `json:"diff"` + NewPath string `json:"new_path"` + OldPath string `json:"old_path"` + AMode string `json:"a_mode"` + BMode string `json:"b_mode"` + NewFile bool `json:"new_file"` + RenamedFile bool `json:"renamed_file"` + DeletedFile bool `json:"deleted_file"` + TooLarge bool `json:"too_large"` + } `json:"patch"` + } + + prCommit struct { + URL string `json:"url"` + Sha string `json:"sha"` + HtmlURL string `json:"html_url"` + CommentsURL string `json:"comments_url"` + Commit struct { + URL string `json:"url"` + Author struct { + Name string `json:"name"` + Date time.Time `json:"date"` + Email string `json:"email"` + } `json:"author"` + Committer struct { + Name string `json:"name"` + Date time.Time `json:"date"` + Email string `json:"email"` + } `json:"committer"` + Message string `json:"message"` + CommentCount int `json:"comment_count"` + } `json:"commit"` + Author author `json:"author"` + Committer author `json:"committer"` + Parents struct { + URL string `json:"url"` + Sha string `json:"sha"` + } `json:"parents"` + } +) + +type prInput struct { + Title string `json:"title"` + Body string `json:"body"` + Head string `json:"head"` + Base string `json:"base"` +} +type prCommentInput struct { + Body string `json:"body"` +} + +func convertPullRequestList(from []*pr) []*scm.PullRequest { + to := []*scm.PullRequest{} + for _, v := range from { + to = append(to, convertPullRequest(v)) + } + return to +} +func convertPullRequest(from *pr) *scm.PullRequest { + var labels []scm.Label + for _, label := range from.Labels { + labels = append(labels, scm.Label{ + Name: label.Name, + Color: label.Color, + }) + } + merged := from.State == "merged" + closed := from.State == "closed" + if merged { + closed = true + } + return &scm.PullRequest{ + Number: from.Number, + Title: from.Title, + Body: from.Body, + Sha: from.Head.Sha, + Ref: fmt.Sprintf("refs/pull/%d/head", from.Number), + Source: from.Head.Ref, + Target: from.Base.Ref, + Fork: from.Head.Repo.FullName, + Link: from.HtmlURL, + Diff: from.DiffURL, + Closed: closed, + Merged: merged, + Head: scm.Reference{ + Name: from.Head.Ref, + Path: scm.ExpandRef(from.Head.Ref, "refs/heads"), + Sha: from.Head.Sha, + }, + Base: scm.Reference{ + Name: from.Base.Ref, + Path: scm.ExpandRef(from.Base.Ref, "refs/heads"), + Sha: from.Base.Sha, + }, + Author: scm.User{ + Login: from.User.Login, + Avatar: from.User.AvatarURL, + }, + Created: from.CreatedAt, + Updated: from.UpdatedAt, + Labels: labels, + } +} + +func convertPullRequestComments(from []*prComment) []*scm.Comment { + to := []*scm.Comment{} + for _, v := range from { + to = append(to, convertPullRequestComment(v)) + } + return to +} +func convertPullRequestComment(from *prComment) *scm.Comment { + return &scm.Comment{ + ID: from.ID, + Body: from.Body, + Author: scm.User{ + Login: from.User.Login, + Name: from.User.Name, + Avatar: from.User.AvatarURL, + }, + Created: from.CreatedAt, + Updated: from.UpdatedAt, + } +} + +func convertPrChangeList(from []*prFile) []*scm.Change { + to := []*scm.Change{} + for _, v := range from { + to = append(to, convertPrChange(v)) + } + return to +} +func convertPrChange(from *prFile) *scm.Change { + return &scm.Change{ + Path: from.Filename, + Added: from.Status == "added", + Deleted: from.Status == "deleted", + Renamed: from.Status == "renamed", + BlobID: from.Sha, + } +} + +func convertPrCommitList(from []*prCommit) []*scm.Commit { + to := []*scm.Commit{} + for _, v := range from { + to = append(to, convertPrCommit(v)) + } + return to +} +func convertPrCommit(from *prCommit) *scm.Commit { + return &scm.Commit{ + Message: from.Commit.Message, + Sha: from.Sha, + Link: from.HtmlURL, + Author: scm.Signature{ + Name: from.Commit.Author.Name, + Email: from.Commit.Author.Email, + Date: from.Commit.Author.Date, + Login: from.Author.Login, + Avatar: from.Author.AvatarURL, + }, + Committer: scm.Signature{ + Name: from.Commit.Committer.Name, + Email: from.Commit.Committer.Email, + Date: from.Commit.Committer.Date, + Login: from.Committer.Login, + Avatar: from.Committer.AvatarURL, + }, + } +} diff --git a/scm/driver/gitee/pr_test.go b/scm/driver/gitee/pr_test.go new file mode 100644 index 000000000..bc20d30b5 --- /dev/null +++ b/scm/driver/gitee/pr_test.go @@ -0,0 +1,320 @@ +// 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 gitee + +import ( + "context" + "encoding/json" + "io/ioutil" + "testing" + + "github.com/drone/go-scm/scm" + + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestPullFind(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/pulls/6"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/pr.json") + + client := NewDefault() + got, res, err := client.PullRequests.Find(context.Background(), "kit101/drone-yml-test", 6) + 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) + } + + t.Run("Request", testRequest(res)) +} + +func TestPullFindComment(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/pulls/comments/6922557"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/pr_comment.json") + + client := NewDefault() + got, res, err := client.PullRequests.FindComment(context.Background(), "kit101/drone-yml-test", 7, 6922557) + if err != nil { + t.Error(err) + return + } + want := new(scm.Comment) + raw, _ := ioutil.ReadFile("testdata/pr_comment.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)) +} + +func TestPullList(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/pulls"). + MatchParam("page", "1"). + MatchParam("per_page", "3"). + MatchParam("state", "all"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/pulls.json") + + client := NewDefault() + got, res, err := client.PullRequests.List(context.Background(), "kit101/drone-yml-test", scm.PullRequestListOptions{Page: 1, Size: 3, Open: true, Closed: true}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.PullRequest{} + raw, _ := ioutil.ReadFile("testdata/pulls.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("Page", testPage(res)) +} + +func TestPullListChanges(t *testing.T) { + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/pulls/6/files"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/pr_files.json") + + client := NewDefault() + got, res, err := client.PullRequests.ListChanges(context.Background(), "kit101/drone-yml-test", 6, scm.ListOptions{}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Change{} + raw, _ := ioutil.ReadFile("testdata/pr_files.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)) +} + +func TestPullListComments(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/pulls/7/comments"). + MatchParam("page", "1"). + MatchParam("per_page", "3"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/pr_comments.json") + + client := NewDefault() + got, res, err := client.PullRequests.ListComments(context.Background(), "kit101/drone-yml-test", 7, scm.ListOptions{Page: 1, Size: 3}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Comment{} + raw, _ := ioutil.ReadFile("testdata/pr_comments.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("Page", testPage(res)) +} + +func TestPullListCommits(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/pulls/7/commits"). + Reply(200). + Type("application/json"). + File("testdata/pr_commits.json") + + client := NewDefault() + got, _, err := client.PullRequests.ListCommits(context.Background(), "kit101/drone-yml-test", 7, scm.ListOptions{}) + if err != nil { + t.Error(err) + } + + want := []*scm.Commit{} + raw, _ := ioutil.ReadFile("testdata/pr_commits.json.golden") + json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +func TestPullMerge(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Put("/repos/kit101/drone-yml-test/pulls/6/merge"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders) + + client := NewDefault() + res, err := client.PullRequests.Merge(context.Background(), "kit101/drone-yml-test", 6) + if err != nil { + t.Error(err) + return + } + + t.Run("Request", testRequest(res)) +} + +func TestPullClose(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Patch("/repos/kit101/drone-yml-test/pulls/6"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders) + + client := NewDefault() + res, err := client.PullRequests.Close(context.Background(), "kit101/drone-yml-test", 6) + if err != nil { + t.Error(err) + return + } + + t.Run("Request", testRequest(res)) +} + +func TestPullCreate(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Post("/repos/kit101/drone-yml-test/pulls"). + Reply(201). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/pr.json") + + input := scm.PullRequestInput{ + Title: "new-feature", + Body: "Please pull these awesome changes", + Source: "crud", + Target: "master", + } + + client := NewDefault() + got, res, err := client.PullRequests.Create(context.Background(), "kit101/drone-yml-test", &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) + } + + t.Run("Request", testRequest(res)) +} + +func TestPullCommentCreate(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Post("/repos/kit101/drone-yml-test/pulls/7/comments"). + Reply(201). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/pr_comment.json") + + client := NewDefault() + input := scm.CommentInput{ + Body: "test comment 1", + } + got, res, err := client.PullRequests.CreateComment(context.Background(), "kit101/drone-yml-test", 7, &input) + if err != nil { + t.Error(err) + return + } + want := new(scm.Comment) + raw, _ := ioutil.ReadFile("testdata/pr_comment.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)) +} + +func TestPullCommentDelete(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Delete("/repos/kit101/drone-yml-test/pulls/comments/6990588"). + Reply(204). + SetHeaders(mockHeaders) + + client := NewDefault() + res, err := client.PullRequests.DeleteComment(context.Background(), "kit101/drone-yml-test", 7, 6990588) + if err != nil { + t.Error(err) + return + } + + if got, want := res.Status, 204; got != want { + t.Errorf("Want response status %d, got %d", want, got) + } + t.Run("Request", testRequest(res)) +} diff --git a/scm/driver/gitee/repo.go b/scm/driver/gitee/repo.go new file mode 100644 index 000000000..967ab4f59 --- /dev/null +++ b/scm/driver/gitee/repo.go @@ -0,0 +1,241 @@ +// 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 gitee + +import ( + "context" + "fmt" + "strconv" + "time" + + "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) { + path := fmt.Sprintf("repos/%s", repo) + out := new(repository) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertRepository(out), res, err +} + +func (s *RepositoryService) FindHook(ctx context.Context, repo string, id string) (*scm.Hook, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/hooks/%s", repo, id) + 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) { + repos, res, err := s.Find(ctx, repo) + if err == nil { + return repos.Perm, res, err + } + return nil, res, err +} + +func (s *RepositoryService) List(ctx context.Context, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) { + path := fmt.Sprintf("user/repos?%s", encodeListOptions(opts)) + 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) { + // 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) ListHooks(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Hook, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/hooks?%s", repo, encodeListOptions(opts)) + out := []*hook{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertHookList(out), res, err +} + +func (s *RepositoryService) ListStatus(context.Context, string, string, 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) { + path := fmt.Sprintf("repos/%s/hooks", repo) + in := new(hook) + // 1: signature + in.EncryptionType = 1 + in.Password = input.Secret + in.URL = input.Target + convertFromHookEvents(input.Events, in) + + out := new(hook) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertHook(out), res, err +} + +func (s *RepositoryService) CreateStatus(context.Context, string, string, *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) { + path := fmt.Sprintf("repos/%s/hooks/%s", repo, id) + in := new(hook) + // 1: signature + in.EncryptionType = 1 + in.Password = input.Secret + in.URL = input.Target + convertFromHookEvents(input.Events, in) + + out := new(hook) + res, err := s.client.do(ctx, "PATCH", path, in, out) + return convertHook(out), res, err +} + +func (s *RepositoryService) DeleteHook(ctx context.Context, repo, id string) (*scm.Response, error) { + path := fmt.Sprintf("repos/%s/hooks/%s", repo, id) + return s.client.do(ctx, "DELETE", path, nil, nil) +} + +type repository struct { + ID int `json:"id"` + Owner struct { + ID int `json:"id"` + Login string `json:"login"` + Name string `json:"name"` + AvatarURL string `json:"avatar_url"` + } `json:"owner"` + Namespace namespace `json:"namespace"` + Name string `json:"name"` + FullName string `json:"full_name"` + HumanName string `json:"human_name"` + Path string `json:"path"` + Public bool `json:"public"` + Private bool `json:"private"` + Internal bool `json:"internal"` + Fork bool `json:"fork"` + URL string `json:"url"` + HtmlURL string `json:"html_url"` + SshURL string `json:"ssh_url"` + DefaultBranch string `json:"default_branch"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Permission struct { + Admin bool `json:"admin"` + Push bool `json:"push"` + Pull bool `json:"pull"` + } `json:"permission"` +} + +type hook struct { + ID int `json:"id"` + URL string `json:"url"` + CreatedAt time.Time `json:"created_at"` + // password encryption type, 0: password, 1: signature + EncryptionType int `json:"encryption_type"` + Password string `json:"password"` + ProjectID int `json:"project_id"` + Result string `json:"result"` + ResultCode int `json:"result_code"` + PushEvents bool `json:"push_events"` + TagPushEvents bool `json:"tag_push_events"` + IssuesEvents bool `json:"issues_events"` + NoteEvents bool `json:"note_events"` + MergeRequestsEvents bool `json:"merge_requests_events"` +} + +type namespace struct { + ID int `json:"id"` + Type string `json:"type"` + Name string `json:"name"` + Path string `json:"path"` + HtmlURL string `json:"html_url"` +} + +func convertRepositoryList(from []*repository) []*scm.Repository { + to := []*scm.Repository{} + for _, v := range from { + to = append(to, convertRepository(v)) + } + return to +} +func convertRepository(from *repository) *scm.Repository { + return &scm.Repository{ + ID: strconv.Itoa(from.ID), + Name: from.Path, + Namespace: from.Namespace.Path, + Perm: &scm.Perm{ + Push: from.Permission.Push, + Pull: from.Permission.Pull, + Admin: from.Permission.Admin, + }, + Link: from.HtmlURL, + Branch: from.DefaultBranch, + Private: from.Private, + Clone: from.HtmlURL, + CloneSSH: from.SshURL, + Created: from.CreatedAt, + Updated: from.UpdatedAt, + } +} + +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{ + ID: strconv.Itoa(from.ID), + Active: true, + Target: from.URL, + Events: convertHookEvent(from), + SkipVerify: true, + } +} + +func convertHookEvent(from *hook) []string { + var events []string + if from.PushEvents { + events = append(events, "push") + } + if from.TagPushEvents { + events = append(events, "tag_push") + } + if from.IssuesEvents { + events = append(events, "issues") + } + if from.NoteEvents { + events = append(events, "note") + } + if from.MergeRequestsEvents { + events = append(events, "merge_requests") + } + return events +} + +// convertFromHookEvents not support: Branch, Deployment +func convertFromHookEvents(from scm.HookEvents, to *hook) { + if from.Push { + to.PushEvents = true + } + if from.PullRequest { + to.MergeRequestsEvents = true + } + if from.Issue { + to.IssuesEvents = true + } + if from.IssueComment || from.PullRequestComment || from.ReviewComment { + to.NoteEvents = true + } + if from.Tag { + to.TagPushEvents = true + } +} diff --git a/scm/driver/gitee/repo_test.go b/scm/driver/gitee/repo_test.go new file mode 100644 index 000000000..1e3459ad9 --- /dev/null +++ b/scm/driver/gitee/repo_test.go @@ -0,0 +1,359 @@ +// 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 gitee + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "testing" + + "github.com/drone/go-scm/scm" + + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestRepositoryFind(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/repo.json") + + client := NewDefault() + got, res, err := client.Repositories.Find(context.Background(), "kit101/drone-yml-test") + 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) + } + + t.Run("Request", testRequest(res)) +} + +func TestRepositoryHookFind(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/hooks/787341"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/hook.json") + + client := NewDefault() + got, res, err := client.Repositories.FindHook(context.Background(), "kit101/drone-yml-test", "787341") + 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) + } + + t.Run("Request", testRequest(res)) +} + +func TestRepositoryPerms(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/repo.json") + + client := NewDefault() + got, res, err := client.Repositories.FindPerms(context.Background(), "kit101/drone-yml-test") + 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.Perm); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + t.Run("Request", testRequest(res)) +} + +func TestRepositoryList(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/user/repos"). + MatchParam("page", "1"). + MatchParam("per_page", "3"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/repos.json") + + client := NewDefault() + got, res, err := client.Repositories.List(context.Background(), scm.ListOptions{Page: 1, Size: 3}) + 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("Page", testPage(res)) +} + +func TestRepositoryListHook(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/kit101/drone-yml-test/hooks"). + MatchParam("page", "1"). + MatchParam("per_page", "3"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/hooks.json") + + client := NewDefault() + got, res, err := client.Repositories.ListHooks(context.Background(), "kit101/drone-yml-test", scm.ListOptions{Page: 1, Size: 3}) + 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) + } + + t.Run("Request", testRequest(res)) + t.Run("Page", testPage(res)) +} + +func TestRepositoryListStatus(t *testing.T) { + _, _, err := NewDefault().Repositories.ListStatus(context.Background(), "", "", scm.ListOptions{}) + if err != scm.ErrNotSupported { + t.Errorf("Expect Not Supported error") + } +} + +func TestRepositoryCreateHook(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Post("/repos/kit101/drone-yml-test/hooks"). + Reply(201). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/hook.json") + + in := &scm.HookInput{ + Target: "http://test.kit101.com/webhook", + Secret: "123asdas123", + } + + client := NewDefault() + got, res, err := client.Repositories.CreateHook(context.Background(), "kit101/drone-yml-test", in) + 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) + } + + t.Run("Request", testRequest(res)) +} + +func TestRepositoryCreateStatus(t *testing.T) { + _, _, err := NewDefault().Repositories.CreateStatus(context.Background(), "", "", &scm.StatusInput{}) + if err != scm.ErrNotSupported { + t.Errorf("Expect Not Supported error") + } +} + +func TestRepositoryUpdateHook(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Patch("/repos/kit101/drone-yml-test/hooks/787341"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/hook.json") + + in := &scm.HookInput{ + Target: "http://test.kit101.com/webhook", + Secret: "123asdas123", + } + + client := NewDefault() + got, res, err := client.Repositories.UpdateHook(context.Background(), "kit101/drone-yml-test", "787341", in) + 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) + } + + t.Run("Request", testRequest(res)) +} + +func TestRepositoryDeleteHook(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Delete("/repos/kit101/drone-yml-test/hooks/787341"). + Reply(204). + Type("application/json"). + SetHeaders(mockHeaders) + + client := NewDefault() + res, err := client.Repositories.DeleteHook(context.Background(), "kit101/drone-yml-test", "787341") + if err != nil { + t.Error(err) + return + } + + if got, want := res.Status, 204; got != want { + t.Errorf("Want response status %d, got %d", want, got) + } + t.Run("Request", testRequest(res)) +} + +func TestRepositoryNotFound(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/repos/dev/null"). + Reply(404). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/error.json") + + client := NewDefault() + _, _, err := client.Repositories.Find(context.Background(), "dev/null") + if err == nil { + t.Errorf("Expect Not Found error") + return + } + if got, want := err.Error(), "404 Project Not Found"; got != want { + t.Errorf("Want error %q, got %q", want, got) + } +} + +func TestHookEvents(t *testing.T) { + tests := []struct { + in scm.HookEvents + out *hook + }{ + { + in: scm.HookEvents{Push: true}, + out: &hook{PushEvents: true}, + }, + { + in: scm.HookEvents{Branch: true}, + out: &hook{}, + }, + { + in: scm.HookEvents{IssueComment: true}, + out: &hook{NoteEvents: true}, + }, + { + in: scm.HookEvents{PullRequestComment: true}, + out: &hook{NoteEvents: true}, + }, + { + in: scm.HookEvents{Issue: true}, + out: &hook{IssuesEvents: true}, + }, + { + in: scm.HookEvents{PullRequest: true}, + out: &hook{MergeRequestsEvents: true}, + }, + { + in: scm.HookEvents{ + Branch: true, + Deployment: true, + Issue: true, + IssueComment: true, + PullRequest: true, + PullRequestComment: true, + Push: true, + ReviewComment: true, + Tag: true, + }, + out: &hook{ + IssuesEvents: true, + MergeRequestsEvents: true, + NoteEvents: true, + PushEvents: true, + TagPushEvents: true, + }, + }, + } + + for i, test := range tests { + fmt.Println(test, i) + got := new(hook) + convertFromHookEvents(test.in, got) + want := test.out + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results at index %d", i) + t.Log(diff) + } + } +} diff --git a/scm/driver/gitee/review.go b/scm/driver/gitee/review.go new file mode 100644 index 000000000..95749db1a --- /dev/null +++ b/scm/driver/gitee/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 gitee + +import ( + "context" + + "github.com/drone/go-scm/scm" +) + +type reviewService struct { + client *wrapper +} + +func (s *reviewService) Find(context.Context, string, int, int) (*scm.Review, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *reviewService) List(context.Context, string, int, scm.ListOptions) ([]*scm.Review, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *reviewService) Create(context.Context, string, int, *scm.ReviewInput) (*scm.Review, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *reviewService) Delete(context.Context, string, int, int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} diff --git a/scm/driver/gitee/review_test.go b/scm/driver/gitee/review_test.go new file mode 100644 index 000000000..28b2fd775 --- /dev/null +++ b/scm/driver/gitee/review_test.go @@ -0,0 +1,44 @@ +// 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 gitee + +import ( + "context" + "testing" + + "github.com/drone/go-scm/scm" +) + +func TestReviewFind(t *testing.T) { + service := new(reviewService) + _, _, err := service.Find(context.Background(), "kit101/drone-yml-test", 1, 1) + if err != scm.ErrNotSupported { + t.Errorf("Expect Not Supported error") + } +} + +func TestReviewList(t *testing.T) { + service := new(reviewService) + _, _, err := service.List(context.Background(), "kit101/drone-yml-test", 1, scm.ListOptions{}) + if err != scm.ErrNotSupported { + t.Errorf("Expect Not Supported error") + } +} + +func TestReviewCreate(t *testing.T) { + service := new(reviewService) + _, _, err := service.Create(context.Background(), "kit101/drone-yml-test", 1, nil) + if err != scm.ErrNotSupported { + t.Errorf("Expect Not Supported error") + } +} + +func TestReviewDelete(t *testing.T) { + service := new(reviewService) + _, err := service.Delete(context.Background(), "kit101/drone-yml-test", 1, 1) + if err != scm.ErrNotSupported { + t.Errorf("Expect Not Supported error") + } +} diff --git a/scm/driver/gitee/testdata/branch.json b/scm/driver/gitee/testdata/branch.json new file mode 100644 index 000000000..ae0ad3dd7 --- /dev/null +++ b/scm/driver/gitee/testdata/branch.json @@ -0,0 +1,49 @@ +{ + "name": "master", + "commit": { + "sha": "e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "commit": { + "author": { + "name": "kit101", + "date": "2021-08-23T23:45:53+08:00", + "email": "qkssk1711@163.com" + }, + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/git/commits/e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "message": "add/update/delete/rename\n", + "tree": { + "sha": "55d4c682f3e2b276cc40c70e59cebb17dcb1273a", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/git/trees/55d4c682f3e2b276cc40c70e59cebb17dcb1273a" + }, + "committer": { + "name": "kit101", + "date": "2021-08-23T23:45:53+08:00", + "email": "qkssk1711@163.com" + } + }, + "author": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "id": 1535738, + "login": "kit101" + }, + "parents": [ + { + "sha": "537575f44a09c57dfc472e26fe067754fd2f9374", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/537575f44a09c57dfc472e26fe067754fd2f9374" + } + ], + "committer": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "id": 1535738, + "login": "kit101" + } + }, + "_links": { + "html": "https://gitee.com/kit101/drone-yml-test/tree/master", + "self": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/branches/master" + }, + "protected": false, + "protection_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/branches/master/protection" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/branch.json.golden b/scm/driver/gitee/testdata/branch.json.golden new file mode 100644 index 000000000..ec8a3ea78 --- /dev/null +++ b/scm/driver/gitee/testdata/branch.json.golden @@ -0,0 +1,5 @@ +{ + "Name": "master", + "Path": "refs/heads/master", + "Sha": "e3c0ff4d5cef439ea11b30866fb1ed79b420801d" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/branches.json b/scm/driver/gitee/testdata/branches.json new file mode 100644 index 000000000..7f49be0af --- /dev/null +++ b/scm/driver/gitee/testdata/branches.json @@ -0,0 +1,11 @@ +[ + { + "name": "master", + "commit": { + "sha": "e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/e3c0ff4d5cef439ea11b30866fb1ed79b420801d" + }, + "protected": false, + "protection_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/branches/master/protection" + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/branches.json.golden b/scm/driver/gitee/testdata/branches.json.golden new file mode 100644 index 000000000..161b33c27 --- /dev/null +++ b/scm/driver/gitee/testdata/branches.json.golden @@ -0,0 +1,7 @@ +[ + { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "e3c0ff4d5cef439ea11b30866fb1ed79b420801d" + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/changes.json b/scm/driver/gitee/testdata/changes.json new file mode 100644 index 000000000..73aa16994 --- /dev/null +++ b/scm/driver/gitee/testdata/changes.json @@ -0,0 +1,87 @@ +{ + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51", + "sha": "7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51", + "html_url": "https://gitee.com/kit101/drone-yml-test/commit/7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51/comments", + "commit": { + "author": { + "name": "kit101", + "date": "2021-08-23T23:41:22+08:00", + "email": "qkssk1711@163.com" + }, + "committer": { + "name": "kit101", + "date": "2021-08-23T23:41:22+08:00", + "email": "qkssk1711@163.com" + }, + "message": "rename\n", + "tree": { + "sha": "3dd0fe5f5bcde3966871c8eb2c91d55554dab80f", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/git/trees/3dd0fe5f5bcde3966871c8eb2c91d55554dab80f" + } + }, + "author": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "committer": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "parents": [ + { + "sha": "f87d3cca9d85a7e52bb9dadac176817812b76fbd", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/f87d3cca9d85a7e52bb9dadac176817812b76fbd" + } + ], + "stats": { + "id": "7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51", + "additions": 3, + "deletions": 3, + "total": 6 + }, + "files": [ + { + "sha": "b748919728ba7080c9e41e2b888872b09d246d90", + "filename": "rename.4.txt", + "status": "modified", + "additions": 0, + "deletions": 0, + "changes": 0, + "blob_url": "https://gitee.com/kit101/drone-yml-test/blob/7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51/rename.4.txt", + "raw_url": "https://gitee.com/kit101/drone-yml-test/raw/7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51/rename.4.txt", + "content_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/rename.4.txt?ref=7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51", + "patch": "" + } + ] +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/changes.json.golden b/scm/driver/gitee/testdata/changes.json.golden new file mode 100644 index 000000000..859972e23 --- /dev/null +++ b/scm/driver/gitee/testdata/changes.json.golden @@ -0,0 +1,9 @@ +[ + { + "Path": "rename.4.txt", + "Added": false, + "Renamed": true, + "Deleted": false, + "BlobID": "b748919728ba7080c9e41e2b888872b09d246d90" + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/commit.json b/scm/driver/gitee/testdata/commit.json new file mode 100644 index 000000000..c40d2ee30 --- /dev/null +++ b/scm/driver/gitee/testdata/commit.json @@ -0,0 +1,123 @@ +{ + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "sha": "e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "html_url": "https://gitee.com/kit101/drone-yml-test/commit/e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/e3c0ff4d5cef439ea11b30866fb1ed79b420801d/comments", + "commit": { + "author": { + "name": "kit101", + "date": "2021-08-23T23:45:53+08:00", + "email": "qkssk1711@163.com" + }, + "committer": { + "name": "kit101", + "date": "2021-08-23T23:45:53+08:00", + "email": "qkssk1711@163.com" + }, + "message": "add/update/delete/rename\n", + "tree": { + "sha": "55d4c682f3e2b276cc40c70e59cebb17dcb1273a", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/git/trees/55d4c682f3e2b276cc40c70e59cebb17dcb1273a" + } + }, + "author": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "committer": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "parents": [ + { + "sha": "537575f44a09c57dfc472e26fe067754fd2f9374", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/537575f44a09c57dfc472e26fe067754fd2f9374" + } + ], + "stats": { + "id": "e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "additions": 4, + "deletions": 3, + "total": 7 + }, + "files": [ + { + "sha": "d28d40b18823a27071d0e9ce89c149adb3f9c4ee", + "filename": "change/add.txt", + "status": "added", + "additions": 1, + "deletions": 0, + "changes": 1, + "blob_url": "https://gitee.com/kit101/drone-yml-test/blob/e3c0ff4d5cef439ea11b30866fb1ed79b420801d/change/add.txt", + "raw_url": "https://gitee.com/kit101/drone-yml-test/raw/e3c0ff4d5cef439ea11b30866fb1ed79b420801d/change/add.txt", + "content_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/change/add.txt?ref=e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "patch": "@@ -0,0 +1 @@\n+add\n\\ No newline at end of file\n" + }, + { + "sha": "41f6d1ab2598013cc08173771d81f67106bd15fc", + "filename": "change/modified.txt", + "status": "modified", + "additions": 2, + "deletions": 1, + "changes": 3, + "blob_url": "https://gitee.com/kit101/drone-yml-test/blob/e3c0ff4d5cef439ea11b30866fb1ed79b420801d/change/modified.txt", + "raw_url": "https://gitee.com/kit101/drone-yml-test/raw/e3c0ff4d5cef439ea11b30866fb1ed79b420801d/change/modified.txt", + "content_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/change/modified.txt?ref=e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "patch": "@@ -1 +1,2 @@\n-will be modified\n\\ No newline at end of file\n+will be modified\n+modified\n\\ No newline at end of file\n" + }, + { + "sha": "026c61940bebac2bd51a709af499db11a62b9beb", + "filename": "change/remove.txt", + "status": "removed", + "additions": 0, + "deletions": 1, + "changes": 1, + "blob_url": "https://gitee.com/kit101/drone-yml-test/blob/537575f44a09c57dfc472e26fe067754fd2f9374/change/remove.txt", + "raw_url": "https://gitee.com/kit101/drone-yml-test/raw/537575f44a09c57dfc472e26fe067754fd2f9374/change/remove.txt", + "content_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/change/remove.txt?ref=537575f44a09c57dfc472e26fe067754fd2f9374", + "patch": "@@ -1 +0,0 @@\n-will be removed\n\\ No newline at end of file\n" + }, + { + "sha": "b5442782c85d797e70d7bcd14abab49fd8c40b5b", + "filename": "change/rename.1.txt", + "status": "modified", + "additions": 0, + "deletions": 0, + "changes": 0, + "blob_url": "https://gitee.com/kit101/drone-yml-test/blob/e3c0ff4d5cef439ea11b30866fb1ed79b420801d/change/rename.1.txt", + "raw_url": "https://gitee.com/kit101/drone-yml-test/raw/e3c0ff4d5cef439ea11b30866fb1ed79b420801d/change/rename.1.txt", + "content_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/change/rename.1.txt?ref=e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "patch": "" + } + ] +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/commit.json.golden b/scm/driver/gitee/testdata/commit.json.golden new file mode 100644 index 000000000..4ee12ddcb --- /dev/null +++ b/scm/driver/gitee/testdata/commit.json.golden @@ -0,0 +1,19 @@ +{ + "Sha": "e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "Message": "add/update/delete/rename\n", + "Author": { + "Name": "kit101", + "Date": "2021-08-23T23:45:53+08:00", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Committer": { + "Name": "kit101", + "Date": "2021-08-23T23:45:53+08:00", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Link": "https://gitee.com/kit101/drone-yml-test/commit/e3c0ff4d5cef439ea11b30866fb1ed79b420801d" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/commits.json b/scm/driver/gitee/testdata/commits.json new file mode 100644 index 000000000..a4cb29163 --- /dev/null +++ b/scm/driver/gitee/testdata/commits.json @@ -0,0 +1,203 @@ +[ + { + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "sha": "e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "html_url": "https://gitee.com/kit101/drone-yml-test/commit/e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/e3c0ff4d5cef439ea11b30866fb1ed79b420801d/comments", + "commit": { + "author": { + "name": "kit101", + "date": "2021-08-23T23:45:53+08:00", + "email": "qkssk1711@163.com" + }, + "committer": { + "name": "kit101", + "date": "2021-08-23T23:45:53+08:00", + "email": "qkssk1711@163.com" + }, + "message": "add/update/delete/rename\n", + "tree": { + "sha": "55d4c682f3e2b276cc40c70e59cebb17dcb1273a", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/git/trees/55d4c682f3e2b276cc40c70e59cebb17dcb1273a" + } + }, + "author": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "committer": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "parents": [ + { + "sha": "537575f44a09c57dfc472e26fe067754fd2f9374", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/537575f44a09c57dfc472e26fe067754fd2f9374" + } + ] + }, + { + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/537575f44a09c57dfc472e26fe067754fd2f9374", + "sha": "537575f44a09c57dfc472e26fe067754fd2f9374", + "html_url": "https://gitee.com/kit101/drone-yml-test/commit/537575f44a09c57dfc472e26fe067754fd2f9374", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/537575f44a09c57dfc472e26fe067754fd2f9374/comments", + "commit": { + "author": { + "name": "kit101", + "date": "2021-08-23T23:45:04+08:00", + "email": "qkssk1711@163.com" + }, + "committer": { + "name": "kit101", + "date": "2021-08-23T23:45:04+08:00", + "email": "qkssk1711@163.com" + }, + "message": "change ready\n", + "tree": { + "sha": "c5851e358f5c1950ce15772b0cf05941470793bc", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/git/trees/c5851e358f5c1950ce15772b0cf05941470793bc" + } + }, + "author": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "committer": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "parents": [ + { + "sha": "7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51" + } + ] + }, + { + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51", + "sha": "7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51", + "html_url": "https://gitee.com/kit101/drone-yml-test/commit/7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51/comments", + "commit": { + "author": { + "name": "kit101", + "date": "2021-08-23T23:41:22+08:00", + "email": "qkssk1711@163.com" + }, + "committer": { + "name": "kit101", + "date": "2021-08-23T23:41:22+08:00", + "email": "qkssk1711@163.com" + }, + "message": "rename\n", + "tree": { + "sha": "3dd0fe5f5bcde3966871c8eb2c91d55554dab80f", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/git/trees/3dd0fe5f5bcde3966871c8eb2c91d55554dab80f" + } + }, + "author": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "committer": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "parents": [ + { + "sha": "f87d3cca9d85a7e52bb9dadac176817812b76fbd", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/f87d3cca9d85a7e52bb9dadac176817812b76fbd" + } + ] + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/commits.json.golden b/scm/driver/gitee/testdata/commits.json.golden new file mode 100644 index 000000000..91c30b1f4 --- /dev/null +++ b/scm/driver/gitee/testdata/commits.json.golden @@ -0,0 +1,59 @@ +[ + { + "Sha": "e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "Message": "add/update/delete/rename\n", + "Author": { + "Name": "kit101", + "Email": "qkssk1711@163.com", + "Date": "2021-08-23T23:45:53+08:00", + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Committer": { + "Name": "kit101", + "Email": "qkssk1711@163.com", + "Date": "2021-08-23T23:45:53+08:00", + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Link": "https://gitee.com/kit101/drone-yml-test/commit/e3c0ff4d5cef439ea11b30866fb1ed79b420801d" + }, + { + "Sha": "537575f44a09c57dfc472e26fe067754fd2f9374", + "Message": "change ready\n", + "Author": { + "Name": "kit101", + "Email": "qkssk1711@163.com", + "Date": "2021-08-23T23:45:04+08:00", + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Committer": { + "Name": "kit101", + "Email": "qkssk1711@163.com", + "Date": "2021-08-23T23:45:04+08:00", + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Link": "https://gitee.com/kit101/drone-yml-test/commit/537575f44a09c57dfc472e26fe067754fd2f9374" + }, + { + "Sha": "7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51", + "Message": "rename\n", + "Author": { + "Name": "kit101", + "Email": "qkssk1711@163.com", + "Date": "2021-08-23T23:41:22+08:00", + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Committer": { + "Name": "kit101", + "Email": "qkssk1711@163.com", + "Date": "2021-08-23T23:41:22+08:00", + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Link": "https://gitee.com/kit101/drone-yml-test/commit/7e84b6f94b8d4bfaa051910cc4ce16b73bcffd51" + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/compare.json b/scm/driver/gitee/testdata/compare.json new file mode 100644 index 000000000..24451e9c3 --- /dev/null +++ b/scm/driver/gitee/testdata/compare.json @@ -0,0 +1,201 @@ +{ + "base_commit": { + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "sha": "e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "html_url": "https://gitee.com/kit101/drone-yml-test/commit/e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/e3c0ff4d5cef439ea11b30866fb1ed79b420801d/comments", + "commit": { + "author": { + "name": "kit101", + "date": "2021-08-23T23:45:53+08:00", + "email": "qkssk1711@163.com" + }, + "committer": { + "name": "kit101", + "date": "2021-08-23T23:45:53+08:00", + "email": "qkssk1711@163.com" + }, + "message": "add/update/delete/rename\n", + "tree": { + "sha": "55d4c682f3e2b276cc40c70e59cebb17dcb1273a", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/git/trees/55d4c682f3e2b276cc40c70e59cebb17dcb1273a" + } + }, + "author": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "committer": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "parents": [ + { + "sha": "537575f44a09c57dfc472e26fe067754fd2f9374", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/537575f44a09c57dfc472e26fe067754fd2f9374" + } + ] + }, + "merge_base_commit": { + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "sha": "e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "html_url": "https://gitee.com/kit101/drone-yml-test/commit/e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/e3c0ff4d5cef439ea11b30866fb1ed79b420801d/comments", + "commit": { + "author": { + "name": "kit101", + "date": "2021-08-23T23:45:53+08:00", + "email": "qkssk1711@163.com" + }, + "committer": { + "name": "kit101", + "date": "2021-08-23T23:45:53+08:00", + "email": "qkssk1711@163.com" + }, + "message": "add/update/delete/rename\n", + "tree": { + "sha": "55d4c682f3e2b276cc40c70e59cebb17dcb1273a", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/git/trees/55d4c682f3e2b276cc40c70e59cebb17dcb1273a" + } + }, + "author": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "committer": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "parents": [ + { + "sha": "537575f44a09c57dfc472e26fe067754fd2f9374", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/537575f44a09c57dfc472e26fe067754fd2f9374" + } + ] + }, + "commits": [ + { + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/2700445cd84c08546f4d003f8aa54d2099a006b7", + "sha": "2700445cd84c08546f4d003f8aa54d2099a006b7", + "html_url": "https://gitee.com/kit101/drone-yml-test/commit/2700445cd84c08546f4d003f8aa54d2099a006b7", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/2700445cd84c08546f4d003f8aa54d2099a006b7/comments", + "commit": { + "author": { + "name": "kit101", + "date": "2021-09-28T16:45:33+00:00", + "email": "qkssk1711@163.com" + }, + "committer": { + "name": "Gitee", + "date": "2021-09-28T16:45:33+00:00", + "email": "noreply@gitee.com" + }, + "message": "add feat-compare.txt.\n", + "tree": { + "sha": "3743833f1906b6343c0e373e9d5c5c02bb793f4d", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/git/trees/3743833f1906b6343c0e373e9d5c5c02bb793f4d" + } + }, + "author": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "committer": null, + "parents": [ + { + "sha": "e3c0ff4d5cef439ea11b30866fb1ed79b420801d", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/e3c0ff4d5cef439ea11b30866fb1ed79b420801d" + } + ] + } + ], + "files": [ + { + "sha": "b3a3b1dc93cb4323ef918aa742227356e91ddf1e", + "filename": "feat-compare.txt", + "status": "added", + "additions": 1, + "deletions": 0, + "changes": 1, + "blob_url": "https://gitee.com/kit101/drone-yml-test/blob/2700445cd84c08546f4d003f8aa54d2099a006b7/feat-compare.txt", + "raw_url": "https://gitee.com/kit101/drone-yml-test/raw/2700445cd84c08546f4d003f8aa54d2099a006b7/feat-compare.txt", + "content_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/feat-compare.txt?ref=2700445cd84c08546f4d003f8aa54d2099a006b7", + "patch": "@@ -0,0 +1 @@\n+feat-compare\n\\ No newline at end of file\n" + } + ] +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/compare.json.golden b/scm/driver/gitee/testdata/compare.json.golden new file mode 100644 index 000000000..06be5bbcd --- /dev/null +++ b/scm/driver/gitee/testdata/compare.json.golden @@ -0,0 +1,9 @@ +[ + { + "Path": "feat-compare.txt", + "Added": true, + "Renamed": false, + "Deleted": false, + "BlobID": "b3a3b1dc93cb4323ef918aa742227356e91ddf1e" + } +] diff --git a/scm/driver/gitee/testdata/content.json b/scm/driver/gitee/testdata/content.json new file mode 100644 index 000000000..1f9136c8a --- /dev/null +++ b/scm/driver/gitee/testdata/content.json @@ -0,0 +1,16 @@ +{ + "type": "file", + "encoding": "base64", + "size": 22, + "name": "README.md", + "path": "README.md", + "content": "IyBkcm9uZS15bWwtdGVzdAoKdGVzdA==", + "sha": "1563ebda9da15e6a7753431774920c62b168e5bb", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/README.md", + "html_url": "https://gitee.com/kit101/drone-yml-test/blob/d295a4c616d46fbcdfa3dfd1473c1337a1ec6f83/README.md", + "download_url": "https://gitee.com/kit101/drone-yml-test/raw/d295a4c616d46fbcdfa3dfd1473c1337a1ec6f83/README.md", + "_links": { + "self": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/README.md", + "html": "https://gitee.com/kit101/drone-yml-test/blob/d295a4c616d46fbcdfa3dfd1473c1337a1ec6f83/README.md" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/content.json.golden b/scm/driver/gitee/testdata/content.json.golden new file mode 100644 index 000000000..8f970cd12 --- /dev/null +++ b/scm/driver/gitee/testdata/content.json.golden @@ -0,0 +1,5 @@ +{ + "Path": "README.md", + "Data": "IyBkcm9uZS15bWwtdGVzdAoKdGVzdA==", + "Sha": "1563ebda9da15e6a7753431774920c62b168e5bb" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/content_create.json b/scm/driver/gitee/testdata/content_create.json new file mode 100644 index 000000000..fe60e5d3b --- /dev/null +++ b/scm/driver/gitee/testdata/content_create.json @@ -0,0 +1,40 @@ +{ + "content": { + "name": "CreateByDroneGiteeProvider.md", + "path": "apitest/CreateByDroneGiteeProvider.md", + "size": 56, + "sha": "9de0cf94e1e3c1cbe0a25c3865de4cc9ede7ad3e", + "type": "file", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/apitest/CreateByDroneGiteeProvider.md", + "html_url": "https://gitee.com/kit101/drone-yml-test/blob/master/apitest/CreateByDroneGiteeProvider.md", + "download_url": "https://gitee.com/kit101/drone-yml-test/raw/master/apitest/CreateByDroneGiteeProvider.md", + "_links": { + "self": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/apitest/CreateByDroneGiteeProvider.md", + "html": "https://gitee.com/kit101/drone-yml-test/blob/master/apitest/CreateByDroneGiteeProvider.md" + } + }, + "commit": { + "sha": "261b772064f5aed55d626799417ec31b1c48080b", + "author": { + "name": "kit101", + "date": "2021-08-17T15:16:26+00:00", + "email": "kit101@gitee.com" + }, + "committer": { + "name": "Gitee", + "date": "2021-08-17T15:16:26+00:00", + "email": "noreply@gitee.com" + }, + "message": "my commit message", + "tree": { + "sha": "3830427494001c27ed6a9711a823a4fc6af836af", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/git/trees/3830427494001c27ed6a9711a823a4fc6af836af" + }, + "parents": [ + { + "sha": "d295a4c616d46fbcdfa3dfd1473c1337a1ec6f83", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/d295a4c616d46fbcdfa3dfd1473c1337a1ec6f83" + } + ] + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/content_delete.json b/scm/driver/gitee/testdata/content_delete.json new file mode 100644 index 000000000..3cfd6c802 --- /dev/null +++ b/scm/driver/gitee/testdata/content_delete.json @@ -0,0 +1,27 @@ +{ + "content": null, + "commit": { + "sha": "bdce92fc3e96f54d7e918c7f2b6e61053366da5e", + "author": { + "name": "kit101", + "date": "2021-08-17T15:49:36+00:00", + "email": "kit101@gitee.com" + }, + "committer": { + "name": "Gitee", + "date": "2021-08-17T15:49:36+00:00", + "email": "noreply@gitee.com" + }, + "message": "delete commit message", + "tree": { + "sha": "4de6efba7063724cb20ab9135be309db0477c186", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/git/trees/4de6efba7063724cb20ab9135be309db0477c186" + }, + "parents": [ + { + "sha": "56b7c68eea99df8469f819fca08ca71c2d942d8d", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/56b7c68eea99df8469f819fca08ca71c2d942d8d" + } + ] + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/content_list.json b/scm/driver/gitee/testdata/content_list.json new file mode 100644 index 000000000..64274caaf --- /dev/null +++ b/scm/driver/gitee/testdata/content_list.json @@ -0,0 +1,44 @@ +[ + { + "type": "file", + "size": null, + "name": "CreateByDroneGiteeProvider.md", + "path": "apitest/CreateByDroneGiteeProvider.md", + "sha": "9de0cf94e1e3c1cbe0a25c3865de4cc9ede7ad3e", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/apitest/CreateByDroneGiteeProvider.md", + "html_url": "https://gitee.com/kit101/drone-yml-test/blob/master/apitest/CreateByDroneGiteeProvider.md", + "download_url": "https://gitee.com/kit101/drone-yml-test/raw/master/apitest/CreateByDroneGiteeProvider.md", + "_links": { + "self": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/apitest/CreateByDroneGiteeProvider.md", + "html": "https://gitee.com/kit101/drone-yml-test/blob/master/apitest/CreateByDroneGiteeProvider.md" + } + }, + { + "type": "file", + "size": null, + "name": "UpdateByDroneGiteeProvider.md", + "path": "apitest/UpdateByDroneGiteeProvider.md", + "sha": "480a4b3865989bfa78d8f249b124716dda1581d7", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/apitest/UpdateByDroneGiteeProvider.md", + "html_url": "https://gitee.com/kit101/drone-yml-test/blob/master/apitest/UpdateByDroneGiteeProvider.md", + "download_url": "https://gitee.com/kit101/drone-yml-test/raw/master/apitest/UpdateByDroneGiteeProvider.md", + "_links": { + "self": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/apitest/UpdateByDroneGiteeProvider.md", + "html": "https://gitee.com/kit101/drone-yml-test/blob/master/apitest/UpdateByDroneGiteeProvider.md" + } + }, + { + "type": "dir", + "size": null, + "name": "newdir", + "path": "apitest/newdir", + "sha": "2f5fb87ae0d8b8a5f78b4dbfefc1fd70b356bdc4", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/apitest/newdir", + "html_url": "https://gitee.com/kit101/drone-yml-test/blob/master/apitest/newdir", + "download_url": "https://gitee.com/kit101/drone-yml-test/raw/master/apitest/newdir", + "_links": { + "self": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/apitest/newdir", + "html": "https://gitee.com/kit101/drone-yml-test/blob/master/apitest/newdir" + } + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/content_list.json.golden b/scm/driver/gitee/testdata/content_list.json.golden new file mode 100644 index 000000000..7fcd66370 --- /dev/null +++ b/scm/driver/gitee/testdata/content_list.json.golden @@ -0,0 +1,14 @@ +[ + { + "kind": "file", + "path": "apitest/CreateByDroneGiteeProvider.md" + }, + { + "kind": "file", + "path": "apitest/UpdateByDroneGiteeProvider.md" + }, + { + "kind": "directory", + "path": "apitest/newdir" + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/content_update.json b/scm/driver/gitee/testdata/content_update.json new file mode 100644 index 000000000..9ddbbd6ed --- /dev/null +++ b/scm/driver/gitee/testdata/content_update.json @@ -0,0 +1,40 @@ +{ + "content": { + "name": "UpdateByDroneGiteeProvider.md", + "path": "apitest/UpdateByDroneGiteeProvider.md", + "size": 56, + "sha": "480a4b3865989bfa78d8f249b124716dda1581d7", + "type": "file", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/apitest/UpdateByDroneGiteeProvider.md", + "html_url": "https://gitee.com/kit101/drone-yml-test/blob/master/apitest/UpdateByDroneGiteeProvider.md", + "download_url": "https://gitee.com/kit101/drone-yml-test/raw/master/apitest/UpdateByDroneGiteeProvider.md", + "_links": { + "self": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contents/apitest/UpdateByDroneGiteeProvider.md", + "html": "https://gitee.com/kit101/drone-yml-test/blob/master/apitest/UpdateByDroneGiteeProvider.md" + } + }, + "commit": { + "sha": "b280133ab20a219027584bd69671230503c916de", + "author": { + "name": "kit101", + "date": "2021-08-17T15:33:48+00:00", + "email": "kit101@gitee.com" + }, + "committer": { + "name": "Gitee", + "date": "2021-08-17T15:33:48+00:00", + "email": "noreply@gitee.com" + }, + "message": "my commit message by update", + "tree": { + "sha": "4de6efba7063724cb20ab9135be309db0477c186", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/git/trees/4de6efba7063724cb20ab9135be309db0477c186" + }, + "parents": [ + { + "sha": "f24c34e8d884b294c9f197460fc0840d9582220b", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/f24c34e8d884b294c9f197460fc0840d9582220b" + } + ] + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/error.json b/scm/driver/gitee/testdata/error.json new file mode 100644 index 000000000..74392666a --- /dev/null +++ b/scm/driver/gitee/testdata/error.json @@ -0,0 +1,3 @@ +{ + "message": "404 Project Not Found" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/hook.json b/scm/driver/gitee/testdata/hook.json new file mode 100644 index 000000000..b5c6184ac --- /dev/null +++ b/scm/driver/gitee/testdata/hook.json @@ -0,0 +1,14 @@ +{ + "id": 787341, + "url": "http://test.kit101.com/webhook", + "created_at": "2021-10-07T10:27:26+08:00", + "password": "123asdas123", + "project_id": 14836026, + "result": "\u003Chtml\u003E \u003Chead\u003E\u003Ctitle\u003E403 Forbidden\u003C/title\u003E\u003C/head\u003E \u003Cbody\u003E \u003Ccenter\u003E\u003Ch1\u003E403 Forbidden\u003C/h1\u003E\u003C/center\u003E \u003C/body\u003E \u003C/html\u003E", + "result_code": 403, + "push_events": true, + "tag_push_events": true, + "issues_events": true, + "note_events": true, + "merge_requests_events": true +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/hook.json.golden b/scm/driver/gitee/testdata/hook.json.golden new file mode 100644 index 000000000..0deb616ec --- /dev/null +++ b/scm/driver/gitee/testdata/hook.json.golden @@ -0,0 +1,14 @@ +{ + "ID": "787341", + "Name": "", + "Target": "http://test.kit101.com/webhook", + "Events": [ + "push", + "tag_push", + "issues", + "note", + "merge_requests" + ], + "Active": true, + "SkipVerify": true +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/hooks.json b/scm/driver/gitee/testdata/hooks.json new file mode 100644 index 000000000..cd8fa4164 --- /dev/null +++ b/scm/driver/gitee/testdata/hooks.json @@ -0,0 +1,16 @@ +[ + { + "id": 787341, + "url": "http://test.kit101.com/webhook", + "created_at": "2021-10-07T10:27:26+08:00", + "password": "123asdas123", + "project_id": 14836026, + "result": "\u003Chtml\u003E \u003Chead\u003E\u003Ctitle\u003E403 Forbidden\u003C/title\u003E\u003C/head\u003E \u003Cbody\u003E \u003Ccenter\u003E\u003Ch1\u003E403 Forbidden\u003C/h1\u003E\u003C/center\u003E \u003C/body\u003E \u003C/html\u003E", + "result_code": 403, + "push_events": true, + "tag_push_events": true, + "issues_events": true, + "note_events": true, + "merge_requests_events": true + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/hooks.json.golden b/scm/driver/gitee/testdata/hooks.json.golden new file mode 100644 index 000000000..ce6a0d17c --- /dev/null +++ b/scm/driver/gitee/testdata/hooks.json.golden @@ -0,0 +1,16 @@ +[ + { + "ID": "787341", + "Name": "", + "Target": "http://test.kit101.com/webhook", + "Events": [ + "push", + "tag_push", + "issues", + "note", + "merge_requests" + ], + "Active": true, + "SkipVerify": true + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/issue.json b/scm/driver/gitee/testdata/issue.json new file mode 100644 index 000000000..a93370864 --- /dev/null +++ b/scm/driver/gitee/testdata/issue.json @@ -0,0 +1,235 @@ +{ + "id": 7295389, + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues/I4CD5P", + "repository_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test", + "labels_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues/I4CD5P/labels", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues/I4CD5P/comments", + "html_url": "https://gitee.com/kit101/drone-yml-test/issues/I4CD5P", + "parent_url": null, + "number": "I4CD5P", + "parent_id": 0, + "depth": 0, + "state": "open", + "title": "test issue 1", + "body": "test issue 1", + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "labels": [ + { + "id": 102145592, + "name": "feature", + "color": "B5CC18", + "repository_id": 14836026, + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/labels/feature", + "created_at": "2021-03-24T11:24:34+08:00", + "updated_at": "2021-09-29T09:55:42+08:00" + } + ], + "assignee": null, + "collaborators": [ + ], + "repository": { + "id": 14836026, + "full_name": "kit101/drone-yml-test", + "human_name": "kit101/drone-yml-test", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test", + "namespace": { + "id": 1576684, + "type": "personal", + "name": "kit101", + "path": "kit101", + "html_url": "https://gitee.com/kit101" + }, + "path": "drone-yml-test", + "name": "drone-yml-test", + "owner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "assigner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "description": "", + "private": false, + "public": true, + "internal": false, + "fork": false, + "html_url": "https://gitee.com/kit101/drone-yml-test.git", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "forks_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/forks", + "keys_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/keys{/key_id}", + "collaborators_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/collaborators{/collaborator}", + "hooks_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/hooks", + "branches_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/branches{/branch}", + "tags_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/tags", + "blobs_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/blobs{/sha}", + "stargazers_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/stargazers", + "contributors_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contributors", + "commits_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits{/sha}", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/comments{/number}", + "issue_comment_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues/comments{/number}", + "issues_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues{/number}", + "pulls_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls{/number}", + "milestones_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/milestones{/number}", + "notifications_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/notifications{?since,all,participating}", + "labels_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/labels{/name}", + "releases_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/releases{/id}", + "recommend": false, + "gvp": false, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "language": null, + "forks_count": 0, + "stargazers_count": 0, + "watchers_count": 1, + "default_branch": "master", + "open_issues_count": 1, + "has_issues": true, + "has_wiki": true, + "issue_comment": false, + "can_comment": true, + "pull_requests_enabled": true, + "has_page": false, + "license": null, + "outsourced": false, + "project_creator": "kit101", + "members": [ + "kit101" + ], + "pushed_at": "2021-09-29T00:46:59+08:00", + "created_at": "2021-03-24T11:24:34+08:00", + "updated_at": "2021-09-29T09:21:28+08:00", + "parent": null, + "paas": null, + "assignees_number": 1, + "testers_number": 1, + "assignee": [ + { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + ], + "testers": [ + { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + ], + "status": "开始", + "empty_repo": false, + "programs": [ + ], + "enterprise": null + }, + "milestone": null, + "created_at": "2021-09-29T09:21:28+08:00", + "updated_at": "2021-09-29T09:55:42+08:00", + "plan_started_at": null, + "deadline": null, + "finished_at": null, + "scheduled_time": 0.0, + "comments": 0, + "priority": 0, + "issue_type": "任务", + "program": null, + "security_hole": false, + "issue_state": "待办的", + "branch": null, + "issue_type_detail": { + "id": 1, + "title": "任务", + "template": null, + "ident": "task", + "color": "#0086D6", + "is_system": true, + "created_at": "2017-09-01T03:09:12+08:00", + "updated_at": "2017-09-01T03:09:12+08:00" + }, + "issue_state_detail": { + "id": 1, + "title": "待办的", + "color": "#8c92a4", + "icon": "icon-task-state-21", + "command": null, + "serial": 1, + "created_at": "2017-09-01T03:09:13+08:00", + "updated_at": "2017-09-01T03:09:13+08:00" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/issue.json.golden b/scm/driver/gitee/testdata/issue.json.golden new file mode 100644 index 000000000..6075529d9 --- /dev/null +++ b/scm/driver/gitee/testdata/issue.json.golden @@ -0,0 +1,16 @@ +{ + "Number": 735267685380, + "Title": "test issue 1", + "Body": "test issue 1", + "Link": "https://gitee.com/kit101/drone-yml-test/issues/I4CD5P", + "Labels": [ + "feature" + ], + "Closed": false, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-09-29T09:21:28+08:00", + "Updated": "2021-09-29T09:55:42+08:00" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/issue_comment.json b/scm/driver/gitee/testdata/issue_comment.json new file mode 100644 index 000000000..09e3a289a --- /dev/null +++ b/scm/driver/gitee/testdata/issue_comment.json @@ -0,0 +1,34 @@ +{ + "id": 6877445, + "body": "it's ok.", + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "source": null, + "target": { + "issue": { + "id": 7295389, + "title": "test issue 1", + "number": "I4CD5P" + }, + "pull_request": null + }, + "created_at": "2021-09-29T11:00:50+08:00", + "updated_at": "2021-09-29T11:00:50+08:00" +} diff --git a/scm/driver/gitee/testdata/issue_comment.json.golden b/scm/driver/gitee/testdata/issue_comment.json.golden new file mode 100644 index 000000000..283c558a7 --- /dev/null +++ b/scm/driver/gitee/testdata/issue_comment.json.golden @@ -0,0 +1,10 @@ +{ + "ID": 6877445, + "Body": "it's ok.", + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-09-29T11:00:50+08:00", + "Updated": "2021-09-29T11:00:50+08:00" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/issue_comments.json b/scm/driver/gitee/testdata/issue_comments.json new file mode 100644 index 000000000..c310a4348 --- /dev/null +++ b/scm/driver/gitee/testdata/issue_comments.json @@ -0,0 +1,36 @@ +[ + { + "id": 6877445, + "body": "it's ok.", + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "source": null, + "target": { + "issue": { + "id": 7295389, + "title": "test issue 1", + "number": "I4CD5P" + }, + "pull_request": null + }, + "created_at": "2021-09-29T11:00:50+08:00", + "updated_at": "2021-09-29T11:00:50+08:00" + } +] diff --git a/scm/driver/gitee/testdata/issue_comments.json.golden b/scm/driver/gitee/testdata/issue_comments.json.golden new file mode 100644 index 000000000..ea7200e52 --- /dev/null +++ b/scm/driver/gitee/testdata/issue_comments.json.golden @@ -0,0 +1,12 @@ +[ + { + "ID": 6877445, + "Body": "it's ok.", + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-09-29T11:00:50+08:00", + "Updated": "2021-09-29T11:00:50+08:00" + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/issues.json b/scm/driver/gitee/testdata/issues.json new file mode 100644 index 000000000..ca238cbb4 --- /dev/null +++ b/scm/driver/gitee/testdata/issues.json @@ -0,0 +1,468 @@ +[ + { + "id": 7296764, + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues/I4CE7W", + "repository_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test", + "labels_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues/I4CE7W/labels", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues/I4CE7W/comments", + "html_url": "https://gitee.com/kit101/drone-yml-test/issues/I4CE7W", + "parent_url": null, + "number": "I4CE7W", + "parent_id": 0, + "depth": 0, + "state": "closed", + "title": "close issue test", + "body": "close issue test", + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "labels": [ + { + "id": 102145594, + "name": "invalid", + "color": "1B1C1D", + "repository_id": 14836026, + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/labels/invalid", + "created_at": "2021-03-24T11:24:34+08:00", + "updated_at": "2021-09-29T11:05:30+08:00" + } + ], + "assignee": null, + "collaborators": [], + "repository": { + "id": 14836026, + "full_name": "kit101/drone-yml-test", + "human_name": "kit101/drone-yml-test", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test", + "namespace": { + "id": 1576684, + "type": "personal", + "name": "kit101", + "path": "kit101", + "html_url": "https://gitee.com/kit101" + }, + "path": "drone-yml-test", + "name": "drone-yml-test", + "owner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "assigner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "description": "", + "private": false, + "public": true, + "internal": false, + "fork": false, + "html_url": "https://gitee.com/kit101/drone-yml-test.git", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "forks_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/forks", + "keys_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/keys{/key_id}", + "collaborators_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/collaborators{/collaborator}", + "hooks_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/hooks", + "branches_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/branches{/branch}", + "tags_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/tags", + "blobs_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/blobs{/sha}", + "stargazers_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/stargazers", + "contributors_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contributors", + "commits_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits{/sha}", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/comments{/number}", + "issue_comment_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues/comments{/number}", + "issues_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues{/number}", + "pulls_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls{/number}", + "milestones_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/milestones{/number}", + "notifications_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/notifications{?since,all,participating}", + "labels_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/labels{/name}", + "releases_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/releases{/id}", + "recommend": false, + "gvp": false, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "language": null, + "forks_count": 0, + "stargazers_count": 0, + "watchers_count": 1, + "default_branch": "master", + "open_issues_count": 1, + "has_issues": true, + "has_wiki": true, + "issue_comment": false, + "can_comment": true, + "pull_requests_enabled": true, + "has_page": false, + "license": null, + "outsourced": false, + "project_creator": "kit101", + "members": [ + "kit101" + ], + "pushed_at": "2021-09-29T00:46:59+08:00", + "created_at": "2021-03-24T11:24:34+08:00", + "updated_at": "2021-09-29T11:05:49+08:00", + "parent": null, + "paas": null, + "assignees_number": 1, + "testers_number": 1, + "assignee": [ + { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + ], + "testers": [ + { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + ], + "status": "开始", + "empty_repo": false, + "programs": [], + "enterprise": null + }, + "milestone": null, + "created_at": "2021-09-29T11:05:30+08:00", + "updated_at": "2021-09-29T11:05:49+08:00", + "plan_started_at": null, + "deadline": null, + "finished_at": "2021-09-29T11:05:49+08:00", + "scheduled_time": 0.0, + "comments": 0, + "priority": 0, + "issue_type": "任务", + "program": null, + "security_hole": false, + "issue_state": "已完成", + "branch": null, + "issue_type_detail": { + "id": 1, + "title": "任务", + "template": null, + "ident": "task", + "color": "#0086D6", + "is_system": true, + "created_at": "2017-09-01T03:09:12+08:00", + "updated_at": "2017-09-01T03:09:12+08:00" + }, + "issue_state_detail": { + "id": 3, + "title": "已完成", + "color": "#4baf50", + "icon": "icon-task-state-24", + "command": null, + "serial": 3, + "created_at": "2017-09-01T03:09:13+08:00", + "updated_at": "2017-09-01T03:09:13+08:00" + } + }, + { + "id": 7295389, + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues/I4CD5P", + "repository_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test", + "labels_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues/I4CD5P/labels", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues/I4CD5P/comments", + "html_url": "https://gitee.com/kit101/drone-yml-test/issues/I4CD5P", + "parent_url": null, + "number": "I4CD5P", + "parent_id": 0, + "depth": 0, + "state": "open", + "title": "test issue 1", + "body": "test issue 1", + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "labels": [ + { + "id": 102145592, + "name": "feature", + "color": "B5CC18", + "repository_id": 14836026, + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/labels/feature", + "created_at": "2021-03-24T11:24:34+08:00", + "updated_at": "2021-09-29T09:55:42+08:00" + } + ], + "assignee": null, + "collaborators": [], + "repository": { + "id": 14836026, + "full_name": "kit101/drone-yml-test", + "human_name": "kit101/drone-yml-test", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test", + "namespace": { + "id": 1576684, + "type": "personal", + "name": "kit101", + "path": "kit101", + "html_url": "https://gitee.com/kit101" + }, + "path": "drone-yml-test", + "name": "drone-yml-test", + "owner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "assigner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "description": "", + "private": false, + "public": true, + "internal": false, + "fork": false, + "html_url": "https://gitee.com/kit101/drone-yml-test.git", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "forks_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/forks", + "keys_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/keys{/key_id}", + "collaborators_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/collaborators{/collaborator}", + "hooks_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/hooks", + "branches_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/branches{/branch}", + "tags_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/tags", + "blobs_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/blobs{/sha}", + "stargazers_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/stargazers", + "contributors_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contributors", + "commits_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits{/sha}", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/comments{/number}", + "issue_comment_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues/comments{/number}", + "issues_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues{/number}", + "pulls_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls{/number}", + "milestones_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/milestones{/number}", + "notifications_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/notifications{?since,all,participating}", + "labels_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/labels{/name}", + "releases_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/releases{/id}", + "recommend": false, + "gvp": false, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "language": null, + "forks_count": 0, + "stargazers_count": 0, + "watchers_count": 1, + "default_branch": "master", + "open_issues_count": 1, + "has_issues": true, + "has_wiki": true, + "issue_comment": false, + "can_comment": true, + "pull_requests_enabled": true, + "has_page": false, + "license": null, + "outsourced": false, + "project_creator": "kit101", + "members": [ + "kit101" + ], + "pushed_at": "2021-09-29T00:46:59+08:00", + "created_at": "2021-03-24T11:24:34+08:00", + "updated_at": "2021-09-29T11:05:49+08:00", + "parent": null, + "paas": null, + "assignees_number": 1, + "testers_number": 1, + "assignee": [ + { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + ], + "testers": [ + { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + ], + "status": "开始", + "empty_repo": false, + "programs": [], + "enterprise": null + }, + "milestone": null, + "created_at": "2021-09-29T09:21:28+08:00", + "updated_at": "2021-09-29T11:00:50+08:00", + "plan_started_at": null, + "deadline": null, + "finished_at": null, + "scheduled_time": 0.0, + "comments": 1, + "priority": 0, + "issue_type": "任务", + "program": null, + "security_hole": false, + "issue_state": "待办的", + "branch": null, + "issue_type_detail": { + "id": 1, + "title": "任务", + "template": null, + "ident": "task", + "color": "#0086D6", + "is_system": true, + "created_at": "2017-09-01T03:09:12+08:00", + "updated_at": "2017-09-01T03:09:12+08:00" + }, + "issue_state_detail": { + "id": 1, + "title": "待办的", + "color": "#8c92a4", + "icon": "icon-task-state-21", + "command": null, + "serial": 1, + "created_at": "2017-09-01T03:09:13+08:00", + "updated_at": "2017-09-01T03:09:13+08:00" + } + } +] diff --git a/scm/driver/gitee/testdata/issues.json.golden b/scm/driver/gitee/testdata/issues.json.golden new file mode 100644 index 000000000..b9daeccaf --- /dev/null +++ b/scm/driver/gitee/testdata/issues.json.golden @@ -0,0 +1,34 @@ +[ + { + "Number": 735267695587, + "Title": "close issue test", + "Body": "close issue test", + "Link": "https://gitee.com/kit101/drone-yml-test/issues/I4CE7W", + "Labels": [ + "invalid" + ], + "Closed": true, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-09-29T11:05:30+08:00", + "Updated": "2021-09-29T11:05:49+08:00" + }, + { + "Number": 735267685380, + "Title": "test issue 1", + "Body": "test issue 1", + "Link": "https://gitee.com/kit101/drone-yml-test/issues/I4CD5P", + "Labels": [ + "feature" + ], + "Closed": false, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-09-29T09:21:28+08:00", + "Updated": "2021-09-29T11:00:50+08:00" + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/membership.json b/scm/driver/gitee/testdata/membership.json new file mode 100644 index 000000000..e6edce7dd --- /dev/null +++ b/scm/driver/gitee/testdata/membership.json @@ -0,0 +1,28 @@ +{ + "url": "https://gitee.com/api/v5/orgs/kit101-personal/memberships/kit101", + "active": true, + "remark": null, + "role": "admin", + "organization_url": "https://gitee.com/api/v5/orgs/kit101-personal", + "organization": { + "id": 8538153, + "login": "kit101-personal", + "name": "kit101-personal", + "url": "https://gitee.com/api/v5/orgs/kit101-personal", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/namespace/2846/8538153_kit101-personal_1632964073.png?is_link=true", + "repos_url": "https://gitee.com/api/v5/orgs/kit101-personal/repos", + "events_url": "https://gitee.com/api/v5/orgs/kit101-personal/events", + "members_url": "https://gitee.com/api/v5/orgs/kit101-personal/members{/member}", + "description": "", + "follow_count": 1 + }, + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/membership.json.golden b/scm/driver/gitee/testdata/membership.json.golden new file mode 100644 index 000000000..96ec5685e --- /dev/null +++ b/scm/driver/gitee/testdata/membership.json.golden @@ -0,0 +1,4 @@ +{ + "Active": true, + "Role": 2 +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/org.json b/scm/driver/gitee/testdata/org.json new file mode 100644 index 000000000..30389776c --- /dev/null +++ b/scm/driver/gitee/testdata/org.json @@ -0,0 +1,12 @@ +{ + "id": 8538153, + "login": "kit101-personal", + "name": "kit101-personal", + "url": "https://gitee.com/api/v5/orgs/kit101-personal", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/namespace/2846/8538153_kit101-personal_1632964073.png?is_link=true", + "repos_url": "https://gitee.com/api/v5/orgs/kit101-personal/repos", + "events_url": "https://gitee.com/api/v5/orgs/kit101-personal/events", + "members_url": "https://gitee.com/api/v5/orgs/kit101-personal/members{/member}", + "description": "", + "follow_count": 1 +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/org.json.golden b/scm/driver/gitee/testdata/org.json.golden new file mode 100644 index 000000000..0259356f0 --- /dev/null +++ b/scm/driver/gitee/testdata/org.json.golden @@ -0,0 +1,4 @@ +{ + "Name": "kit101-personal", + "Avatar": "https://portrait.gitee.com/uploads/avatars/namespace/2846/8538153_kit101-personal_1632964073.png?is_link=true" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/orgs.json b/scm/driver/gitee/testdata/orgs.json new file mode 100644 index 000000000..bd511847a --- /dev/null +++ b/scm/driver/gitee/testdata/orgs.json @@ -0,0 +1,15 @@ +[ + { + "id": 8538153, + "login": "kit101-personal", + "name": "kit101-personal", + "url": "https://gitee.com/api/v5/orgs/kit101-personal", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/namespace/2846/8538153_kit101-personal_1632964073.png?is_link=true", + "repos_url": "https://gitee.com/api/v5/orgs/kit101-personal/repos", + "events_url": "https://gitee.com/api/v5/orgs/kit101-personal/events", + "members_url": "https://gitee.com/api/v5/orgs/kit101-personal/members{/member}", + "description": "", + "follow_count": 1 + } +] + \ No newline at end of file diff --git a/scm/driver/gitee/testdata/orgs.json.golden b/scm/driver/gitee/testdata/orgs.json.golden new file mode 100644 index 000000000..c0816e83d --- /dev/null +++ b/scm/driver/gitee/testdata/orgs.json.golden @@ -0,0 +1,6 @@ +[ + { + "Name": "kit101-personal", + "Avatar": "https://portrait.gitee.com/uploads/avatars/namespace/2846/8538153_kit101-personal_1632964073.png?is_link=true" + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/pr.json b/scm/driver/gitee/testdata/pr.json new file mode 100644 index 000000000..1cadc54a3 --- /dev/null +++ b/scm/driver/gitee/testdata/pr.json @@ -0,0 +1,239 @@ +{ + "id": 4730187, + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/6", + "html_url": "https://gitee.com/kit101/drone-yml-test/pulls/6", + "diff_url": "https://gitee.com/kit101/drone-yml-test/pulls/6.diff", + "patch_url": "https://gitee.com/kit101/drone-yml-test/pulls/6.patch", + "issue_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/6/issues", + "commits_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/6/commits", + "review_comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/comments/{/number}", + "review_comment_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/comments", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/6/comments", + "number": 6, + "state": "open", + "title": "new-feature", + "body": "Please pull these awesome changes", + "assignees_number": 1, + "testers_number": 1, + "assignees": [], + "testers": [], + "milestone": null, + "labels": [], + "locked": false, + "created_at": "2021-09-30T16:38:19+08:00", + "updated_at": "2021-09-30T16:38:19+08:00", + "closed_at": null, + "merged_at": null, + "mergeable": true, + "can_merge_check": false, + "head": { + "label": "crud", + "ref": "crud", + "sha": "411db0d9e9072851383751c260dc1601840906e4", + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "repo": { + "id": 14836026, + "full_name": "kit101/drone-yml-test", + "human_name": "kit101/drone-yml-test", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test", + "namespace": { + "id": 1576684, + "type": "personal", + "name": "kit101", + "path": "kit101", + "html_url": "https://gitee.com/kit101" + }, + "path": "drone-yml-test", + "name": "drone-yml-test", + "owner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "assigner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "description": "", + "private": false, + "public": true, + "internal": false, + "fork": false, + "html_url": "https://gitee.com/kit101/drone-yml-test.git", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git" + } + }, + "base": { + "label": "master", + "ref": "master", + "sha": "2eac1cac02c325058cf959725c45b0612d3e8177", + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "repo": { + "id": 14836026, + "full_name": "kit101/drone-yml-test", + "human_name": "kit101/drone-yml-test", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test", + "namespace": { + "id": 1576684, + "type": "personal", + "name": "kit101", + "path": "kit101", + "html_url": "https://gitee.com/kit101" + }, + "path": "drone-yml-test", + "name": "drone-yml-test", + "owner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "assigner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "description": "", + "private": false, + "public": true, + "internal": false, + "fork": false, + "html_url": "https://gitee.com/kit101/drone-yml-test.git", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git" + } + }, + "_links": { + "self": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/6" + }, + "html": { + "href": "https://gitee.com/kit101/drone-yml-test/pulls/6" + }, + "issue": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/6/issues" + }, + "comments": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/6/comments" + }, + "review_comments": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/6/comments" + }, + "review_comment": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/comments/6" + }, + "commits": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/6/commits" + } + }, + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/pr.json.golden b/scm/driver/gitee/testdata/pr.json.golden new file mode 100644 index 000000000..f5fc30fe1 --- /dev/null +++ b/scm/driver/gitee/testdata/pr.json.golden @@ -0,0 +1,30 @@ +{ + "Number": 6, + "Title": "new-feature", + "Body": "Please pull these awesome changes", + "Sha": "411db0d9e9072851383751c260dc1601840906e4", + "Ref": "refs/pull/6/head", + "Source": "crud", + "Target": "master", + "Fork": "kit101/drone-yml-test", + "Link": "https://gitee.com/kit101/drone-yml-test/pulls/6", + "Diff": "https://gitee.com/kit101/drone-yml-test/pulls/6.diff", + "Closed": false, + "Merged": false, + "Base": { + "Sha": "2eac1cac02c325058cf959725c45b0612d3e8177", + "Path": "refs/heads/master", + "Name": "master" + }, + "Head": { + "Sha": "411db0d9e9072851383751c260dc1601840906e4", + "Path": "refs/heads/crud", + "Name": "crud" + }, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-09-30T16:38:19+08:00", + "Updated": "2021-09-30T16:38:19+08:00" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/pr_comment.json b/scm/driver/gitee/testdata/pr_comment.json new file mode 100644 index 000000000..ff5892789 --- /dev/null +++ b/scm/driver/gitee/testdata/pr_comment.json @@ -0,0 +1,44 @@ +{ + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/comments/6922557", + "id": 6922557, + "path": null, + "position": null, + "original_position": null, + "commit_id": null, + "original_commit_id": null, + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "created_at": "2021-10-07T09:26:45+08:00", + "updated_at": "2021-10-07T09:26:45+08:00", + "body": "test comment 1", + "html_url": "https://gitee.com/kit101/drone-yml-test/pulls/7#note_6922557", + "pull_request_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/7", + "_links": { + "self": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/comments/6922557" + }, + "html": { + "href": "https://gitee.com/kit101/drone-yml-test/pulls/7#note_6922557" + }, + "pull_request": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/7" + } + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/pr_comment.json.golden b/scm/driver/gitee/testdata/pr_comment.json.golden new file mode 100644 index 000000000..636bc0e05 --- /dev/null +++ b/scm/driver/gitee/testdata/pr_comment.json.golden @@ -0,0 +1,11 @@ +{ + "ID": 6922557, + "Body": "test comment 1", + "Author": { + "Login": "kit101", + "Name": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-10-07T09:26:45+08:00", + "Updated": "2021-10-07T09:26:45+08:00" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/pr_comments.json b/scm/driver/gitee/testdata/pr_comments.json new file mode 100644 index 000000000..02652c4f7 --- /dev/null +++ b/scm/driver/gitee/testdata/pr_comments.json @@ -0,0 +1,46 @@ +[ + { + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/comments/6922557", + "id": 6922557, + "path": null, + "position": null, + "original_position": null, + "commit_id": null, + "original_commit_id": null, + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "created_at": "2021-10-07T09:26:45+08:00", + "updated_at": "2021-10-07T09:26:45+08:00", + "body": "test comment 1", + "html_url": "https://gitee.com/kit101/drone-yml-test/pulls/7#note_6922557", + "pull_request_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/7", + "_links": { + "self": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/comments/6922557" + }, + "html": { + "href": "https://gitee.com/kit101/drone-yml-test/pulls/7#note_6922557" + }, + "pull_request": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/7" + } + } + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/pr_comments.json.golden b/scm/driver/gitee/testdata/pr_comments.json.golden new file mode 100644 index 000000000..93743f276 --- /dev/null +++ b/scm/driver/gitee/testdata/pr_comments.json.golden @@ -0,0 +1,13 @@ +[ + { + "ID": 6922557, + "Body": "test comment 1", + "Author": { + "Login": "kit101", + "Name": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-10-07T09:26:45+08:00", + "Updated": "2021-10-07T09:26:45+08:00" + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/pr_commits.json b/scm/driver/gitee/testdata/pr_commits.json new file mode 100644 index 000000000..9c82717fe --- /dev/null +++ b/scm/driver/gitee/testdata/pr_commits.json @@ -0,0 +1,65 @@ +[ + { + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/00b76e8abd51ae6a96318b3450944b32995f9158", + "sha": "00b76e8abd51ae6a96318b3450944b32995f9158", + "html_url": "https://gitee.com/kit101/drone-yml-test/commits/00b76e8abd51ae6a96318b3450944b32995f9158", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/00b76e8abd51ae6a96318b3450944b32995f9158/comments", + "commit": { + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/00b76e8abd51ae6a96318b3450944b32995f9158", + "author": { + "name": "kit101", + "email": "qkssk1711@163.com", + "date": "2021-09-30T18:09:57+08:00" + }, + "committer": { + "name": "kit101", + "email": "qkssk1711@163.com", + "date": "2021-09-30T18:09:57+08:00" + }, + "message": "add3\n", + "comment_count": 7 + }, + "author": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "committer": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "parents": { + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits/00b76e8abd51ae6a96318b3450944b32995f9158", + "sha": "2eac1cac02c325058cf959725c45b0612d3e8177" + } + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/pr_commits.json.golden b/scm/driver/gitee/testdata/pr_commits.json.golden new file mode 100644 index 000000000..b28ce6888 --- /dev/null +++ b/scm/driver/gitee/testdata/pr_commits.json.golden @@ -0,0 +1,21 @@ +[ + { + "Message": "add3\n", + "Sha": "00b76e8abd51ae6a96318b3450944b32995f9158", + "Link": "https://gitee.com/kit101/drone-yml-test/commits/00b76e8abd51ae6a96318b3450944b32995f9158", + "Author": { + "Name": "kit101", + "Email": "qkssk1711@163.com", + "Date": "2021-09-30T18:09:57+08:00", + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Committer": { + "Name": "kit101", + "Email": "qkssk1711@163.com", + "Date": "2021-09-30T18:09:57+08:00", + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + } + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/pr_files.json b/scm/driver/gitee/testdata/pr_files.json new file mode 100644 index 000000000..975b27f21 --- /dev/null +++ b/scm/driver/gitee/testdata/pr_files.json @@ -0,0 +1,82 @@ +[ + { + "sha": "2eac1cac02c325058cf959725c45b0612d3e8177", + "filename": "change/add.txt", + "status": "deleted", + "additions": "0", + "deletions": "1", + "blob_url": "https://gitee.com/kit101/drone-yml-test/blob/2eac1cac02c325058cf959725c45b0612d3e8177/change/add.txt", + "raw_url": "https://gitee.com/kit101/drone-yml-test/raw/2eac1cac02c325058cf959725c45b0612d3e8177/change/add.txt", + "patch": { + "diff": "@@ -1 +0,0 @@\n-add\n\\ No newline at end of file\n", + "new_path": "change/add.txt", + "old_path": "change/add.txt", + "a_mode": "100644", + "b_mode": "0", + "new_file": false, + "renamed_file": false, + "deleted_file": true, + "too_large": false + } + }, + { + "sha": "411db0d9e9072851383751c260dc1601840906e4", + "filename": "change/add2.txt", + "status": "added", + "additions": "4", + "deletions": "0", + "blob_url": "https://gitee.com/kit101/drone-yml-test/blob/411db0d9e9072851383751c260dc1601840906e4/change/add2.txt", + "raw_url": "https://gitee.com/kit101/drone-yml-test/raw/411db0d9e9072851383751c260dc1601840906e4/change/add2.txt", + "patch": { + "diff": "@@ -0,0 +1,4 @@\n+add 2\n+add 2\n+add 2\n+add 2\n\\ No newline at end of file\n", + "new_path": "change/add2.txt", + "old_path": "change/add2.txt", + "a_mode": "0", + "b_mode": "100644", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + } + }, + { + "sha": "411db0d9e9072851383751c260dc1601840906e4", + "filename": "change/modified.txt", + "status": null, + "additions": "6", + "deletions": "1", + "blob_url": "https://gitee.com/kit101/drone-yml-test/blob/411db0d9e9072851383751c260dc1601840906e4/change/modified.txt", + "raw_url": "https://gitee.com/kit101/drone-yml-test/raw/411db0d9e9072851383751c260dc1601840906e4/change/modified.txt", + "patch": { + "diff": "@@ -1,2 +1,7 @@\n will be modified\n-modified\n\\ No newline at end of file\n+modified\n+modified 2\n+modified 2\n+modified 2\n+modified 2\n+modified 2\n\\ No newline at end of file\n", + "new_path": "change/modified.txt", + "old_path": "change/modified.txt", + "a_mode": "100644", + "b_mode": "100644", + "new_file": false, + "renamed_file": false, + "deleted_file": false, + "too_large": false + } + }, + { + "sha": "411db0d9e9072851383751c260dc1601840906e4", + "filename": "change/rename.2.txt", + "status": "renamed", + "additions": "0", + "deletions": "0", + "blob_url": "https://gitee.com/kit101/drone-yml-test/blob/411db0d9e9072851383751c260dc1601840906e4/change/rename.2.txt", + "raw_url": "https://gitee.com/kit101/drone-yml-test/raw/411db0d9e9072851383751c260dc1601840906e4/change/rename.2.txt", + "patch": { + "diff": "", + "new_path": "change/rename.2.txt", + "old_path": "change/rename.1.txt", + "a_mode": "100644", + "b_mode": "100644", + "new_file": false, + "renamed_file": true, + "deleted_file": false, + "too_large": false + } + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/pr_files.json.golden b/scm/driver/gitee/testdata/pr_files.json.golden new file mode 100644 index 000000000..be4c1d330 --- /dev/null +++ b/scm/driver/gitee/testdata/pr_files.json.golden @@ -0,0 +1,30 @@ +[ + { + "BlobID": "2eac1cac02c325058cf959725c45b0612d3e8177", + "Path": "change/add.txt", + "Added": false, + "Renamed": false, + "Deleted": true + }, + { + "BlobID": "411db0d9e9072851383751c260dc1601840906e4", + "Path": "change/add2.txt", + "Added": true, + "Renamed": false, + "Deleted": false + }, + { + "BlobID": "411db0d9e9072851383751c260dc1601840906e4", + "Path": "change/modified.txt", + "Added": false, + "Renamed": false, + "Deleted": false + }, + { + "BlobID": "411db0d9e9072851383751c260dc1601840906e4", + "Path": "change/rename.2.txt", + "Added": false, + "Renamed": true, + "Deleted": false + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/pulls.json b/scm/driver/gitee/testdata/pulls.json new file mode 100644 index 000000000..8f5b93450 --- /dev/null +++ b/scm/driver/gitee/testdata/pulls.json @@ -0,0 +1,839 @@ +[ + { + "id": 4730187, + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/6", + "html_url": "https://gitee.com/kit101/drone-yml-test/pulls/6", + "diff_url": "https://gitee.com/kit101/drone-yml-test/pulls/6.diff", + "patch_url": "https://gitee.com/kit101/drone-yml-test/pulls/6.patch", + "issue_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/6/issues", + "commits_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/6/commits", + "review_comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/comments/{/number}", + "review_comment_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/comments", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/6/comments", + "number": 6, + "state": "open", + "title": "new-feature", + "body": "Please pull these awesome changes", + "assignees_number": 1, + "testers_number": 1, + "assignees": [ + { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + ], + "testers": [ + { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + ], + "milestone": null, + "labels": [], + "locked": false, + "created_at": "2021-09-30T16:38:19+08:00", + "updated_at": "2021-09-30T16:38:19+08:00", + "closed_at": null, + "merged_at": null, + "mergeable": true, + "can_merge_check": false, + "head": { + "label": "crud", + "ref": "crud", + "sha": "411db0d9e9072851383751c260dc1601840906e4", + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "repo": { + "id": 14836026, + "full_name": "kit101/drone-yml-test", + "human_name": "kit101/drone-yml-test", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test", + "namespace": { + "id": 1576684, + "type": "personal", + "name": "kit101", + "path": "kit101", + "html_url": "https://gitee.com/kit101" + }, + "path": "drone-yml-test", + "name": "drone-yml-test", + "owner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "assigner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "description": "", + "private": false, + "public": true, + "internal": false, + "fork": false, + "html_url": "https://gitee.com/kit101/drone-yml-test.git", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git" + } + }, + "base": { + "label": "master", + "ref": "master", + "sha": "2eac1cac02c325058cf959725c45b0612d3e8177", + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "repo": { + "id": 14836026, + "full_name": "kit101/drone-yml-test", + "human_name": "kit101/drone-yml-test", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test", + "namespace": { + "id": 1576684, + "type": "personal", + "name": "kit101", + "path": "kit101", + "html_url": "https://gitee.com/kit101" + }, + "path": "drone-yml-test", + "name": "drone-yml-test", + "owner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "assigner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "description": "", + "private": false, + "public": true, + "internal": false, + "fork": false, + "html_url": "https://gitee.com/kit101/drone-yml-test.git", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git" + } + }, + "_links": { + "self": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/6" + }, + "html": { + "href": "https://gitee.com/kit101/drone-yml-test/pulls/6" + }, + "issue": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/6/issues" + }, + "comments": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/6/comments" + }, + "review_comments": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/6/comments" + }, + "review_comment": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/comments/6" + }, + "commits": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/6/commits" + } + }, + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + }, + { + "id": 4730175, + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/5", + "html_url": "https://gitee.com/kit101/drone-yml-test/pulls/5", + "diff_url": "https://gitee.com/kit101/drone-yml-test/pulls/5.diff", + "patch_url": "https://gitee.com/kit101/drone-yml-test/pulls/5.patch", + "issue_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/5/issues", + "commits_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/5/commits", + "review_comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/comments/{/number}", + "review_comment_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/comments", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/5/comments", + "number": 5, + "state": "closed", + "title": "new-feature", + "body": "Please pull these awesome changes", + "assignees_number": 1, + "testers_number": 1, + "assignees": [ + { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + ], + "testers": [ + { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + ], + "milestone": null, + "labels": [], + "locked": false, + "created_at": "2021-09-30T16:37:34+08:00", + "updated_at": "2021-09-30T16:38:14+08:00", + "closed_at": "2021-09-30T16:38:14+08:00", + "merged_at": null, + "mergeable": true, + "can_merge_check": false, + "head": { + "label": "crud", + "ref": "crud", + "sha": "411db0d9e9072851383751c260dc1601840906e4", + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "repo": { + "id": 14836026, + "full_name": "kit101/drone-yml-test", + "human_name": "kit101/drone-yml-test", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test", + "namespace": { + "id": 1576684, + "type": "personal", + "name": "kit101", + "path": "kit101", + "html_url": "https://gitee.com/kit101" + }, + "path": "drone-yml-test", + "name": "drone-yml-test", + "owner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "assigner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "description": "", + "private": false, + "public": true, + "internal": false, + "fork": false, + "html_url": "https://gitee.com/kit101/drone-yml-test.git", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git" + } + }, + "base": { + "label": "master", + "ref": "master", + "sha": "2eac1cac02c325058cf959725c45b0612d3e8177", + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "repo": { + "id": 14836026, + "full_name": "kit101/drone-yml-test", + "human_name": "kit101/drone-yml-test", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test", + "namespace": { + "id": 1576684, + "type": "personal", + "name": "kit101", + "path": "kit101", + "html_url": "https://gitee.com/kit101" + }, + "path": "drone-yml-test", + "name": "drone-yml-test", + "owner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "assigner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "description": "", + "private": false, + "public": true, + "internal": false, + "fork": false, + "html_url": "https://gitee.com/kit101/drone-yml-test.git", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git" + } + }, + "_links": { + "self": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/5" + }, + "html": { + "href": "https://gitee.com/kit101/drone-yml-test/pulls/5" + }, + "issue": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/5/issues" + }, + "comments": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/5/comments" + }, + "review_comments": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/5/comments" + }, + "review_comment": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/comments/5" + }, + "commits": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/5/commits" + } + }, + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + }, + { + "id": 4730041, + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/4", + "html_url": "https://gitee.com/kit101/drone-yml-test/pulls/4", + "diff_url": "https://gitee.com/kit101/drone-yml-test/pulls/4.diff", + "patch_url": "https://gitee.com/kit101/drone-yml-test/pulls/4.patch", + "issue_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/4/issues", + "commits_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/4/commits", + "review_comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/comments/{/number}", + "review_comment_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/comments", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/4/comments", + "number": 4, + "state": "open", + "title": "create crud pr by api", + "body": "create crud pr by api", + "assignees_number": 1, + "testers_number": 1, + "assignees": [ + { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + ], + "testers": [ + { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + ], + "milestone": null, + "labels": [], + "locked": false, + "created_at": "2021-09-30T16:28:09+08:00", + "updated_at": "2021-09-30T16:28:10+08:00", + "closed_at": null, + "merged_at": null, + "mergeable": true, + "can_merge_check": false, + "head": { + "label": "feat-1", + "ref": "feat-1", + "sha": "2700445cd84c08546f4d003f8aa54d2099a006b7", + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "repo": { + "id": 14836026, + "full_name": "kit101/drone-yml-test", + "human_name": "kit101/drone-yml-test", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test", + "namespace": { + "id": 1576684, + "type": "personal", + "name": "kit101", + "path": "kit101", + "html_url": "https://gitee.com/kit101" + }, + "path": "drone-yml-test", + "name": "drone-yml-test", + "owner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "assigner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "description": "", + "private": false, + "public": true, + "internal": false, + "fork": false, + "html_url": "https://gitee.com/kit101/drone-yml-test.git", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git" + } + }, + "base": { + "label": "master", + "ref": "master", + "sha": "2eac1cac02c325058cf959725c45b0612d3e8177", + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "repo": { + "id": 14836026, + "full_name": "kit101/drone-yml-test", + "human_name": "kit101/drone-yml-test", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test", + "namespace": { + "id": 1576684, + "type": "personal", + "name": "kit101", + "path": "kit101", + "html_url": "https://gitee.com/kit101" + }, + "path": "drone-yml-test", + "name": "drone-yml-test", + "owner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "assigner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "description": "", + "private": false, + "public": true, + "internal": false, + "fork": false, + "html_url": "https://gitee.com/kit101/drone-yml-test.git", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git" + } + }, + "_links": { + "self": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/4" + }, + "html": { + "href": "https://gitee.com/kit101/drone-yml-test/pulls/4" + }, + "issue": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/4/issues" + }, + "comments": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/4/comments" + }, + "review_comments": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/4/comments" + }, + "review_comment": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/comments/4" + }, + "commits": { + "href": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls/4/commits" + } + }, + "user": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/pulls.json.golden b/scm/driver/gitee/testdata/pulls.json.golden new file mode 100644 index 000000000..e0d127ef0 --- /dev/null +++ b/scm/driver/gitee/testdata/pulls.json.golden @@ -0,0 +1,92 @@ +[ + { + "Number": 6, + "Title": "new-feature", + "Body": "Please pull these awesome changes", + "Sha": "411db0d9e9072851383751c260dc1601840906e4", + "Ref": "refs/pull/6/head", + "Source": "crud", + "Target": "master", + "Fork": "kit101/drone-yml-test", + "Link": "https://gitee.com/kit101/drone-yml-test/pulls/6", + "Diff": "https://gitee.com/kit101/drone-yml-test/pulls/6.diff", + "Closed": false, + "Merged": false, + "Created": "2021-09-30T16:38:19+08:00", + "Updated": "2021-09-30T16:38:19+08:00", + "Head": { + "Sha": "411db0d9e9072851383751c260dc1601840906e4", + "Path": "refs/heads/crud", + "Name": "crud" + }, + "Base": { + "Sha": "2eac1cac02c325058cf959725c45b0612d3e8177", + "Path": "refs/heads/master", + "Name": "master" + }, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + } + }, + { + "Number": 5, + "Title": "new-feature", + "Body": "Please pull these awesome changes", + "Sha": "411db0d9e9072851383751c260dc1601840906e4", + "Ref": "refs/pull/5/head", + "Source": "crud", + "Target": "master", + "Fork": "kit101/drone-yml-test", + "Link": "https://gitee.com/kit101/drone-yml-test/pulls/5", + "Diff": "https://gitee.com/kit101/drone-yml-test/pulls/5.diff", + "Closed": true, + "Merged": false, + "Created": "2021-09-30T16:37:34+08:00", + "Updated": "2021-09-30T16:38:14+08:00", + "Head": { + "Sha": "411db0d9e9072851383751c260dc1601840906e4", + "Path": "refs/heads/crud", + "Name": "crud" + }, + "Base": { + "Sha": "2eac1cac02c325058cf959725c45b0612d3e8177", + "Path": "refs/heads/master", + "Name": "master" + }, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + } + }, + { + "Number": 4, + "Title": "create crud pr by api", + "Body": "create crud pr by api", + "Sha": "2700445cd84c08546f4d003f8aa54d2099a006b7", + "Ref": "refs/pull/4/head", + "Source": "feat-1", + "Target": "master", + "Fork": "kit101/drone-yml-test", + "Link": "https://gitee.com/kit101/drone-yml-test/pulls/4", + "Diff": "https://gitee.com/kit101/drone-yml-test/pulls/4.diff", + "Closed": false, + "Merged": false, + "Created": "2021-09-30T16:28:09+08:00", + "Updated": "2021-09-30T16:28:10+08:00", + "Head": { + "Sha": "2700445cd84c08546f4d003f8aa54d2099a006b7", + "Path": "refs/heads/feat-1", + "Name": "feat-1" + }, + "Base": { + "Sha": "2eac1cac02c325058cf959725c45b0612d3e8177", + "Path": "refs/heads/master", + "Name": "master" + }, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + } + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/repo.json b/scm/driver/gitee/testdata/repo.json new file mode 100644 index 000000000..b567618b5 --- /dev/null +++ b/scm/driver/gitee/testdata/repo.json @@ -0,0 +1,160 @@ +{ + "id": 14836026, + "full_name": "kit101/drone-yml-test", + "human_name": "kit101/drone-yml-test", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test", + "namespace": { + "id": 1576684, + "type": "personal", + "name": "kit101", + "path": "kit101", + "html_url": "https://gitee.com/kit101" + }, + "path": "drone-yml-test", + "name": "drone-yml-test", + "owner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "assigner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "description": "", + "private": false, + "public": true, + "internal": false, + "fork": false, + "html_url": "https://gitee.com/kit101/drone-yml-test.git", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "forks_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/forks", + "keys_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/keys{/key_id}", + "collaborators_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/collaborators{/collaborator}", + "hooks_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/hooks", + "branches_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/branches{/branch}", + "tags_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/tags", + "blobs_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/blobs{/sha}", + "stargazers_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/stargazers", + "contributors_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contributors", + "commits_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits{/sha}", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/comments{/number}", + "issue_comment_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues/comments{/number}", + "issues_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues{/number}", + "pulls_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls{/number}", + "milestones_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/milestones{/number}", + "notifications_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/notifications{?since,all,participating}", + "labels_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/labels{/name}", + "releases_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/releases{/id}", + "recommend": false, + "gvp": false, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "language": null, + "forks_count": 0, + "stargazers_count": 0, + "watchers_count": 1, + "default_branch": "master", + "open_issues_count": 2, + "has_issues": true, + "has_wiki": true, + "issue_comment": false, + "can_comment": true, + "pull_requests_enabled": true, + "has_page": false, + "license": null, + "outsourced": false, + "project_creator": "kit101", + "members": [ + "kit101" + ], + "pushed_at": "2021-09-30T18:10:23+08:00", + "created_at": "2021-03-24T11:24:34+08:00", + "updated_at": "2021-09-30T18:10:27+08:00", + "parent": null, + "paas": null, + "stared": false, + "watched": true, + "permission": { + "pull": true, + "push": true, + "admin": true + }, + "relation": "master", + "assignees_number": 1, + "testers_number": 1, + "assignee": [ + { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + ], + "testers": [ + { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + ], + "status": "开始", + "empty_repo": false, + "programs": [], + "enterprise": null +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/repo.json.golden b/scm/driver/gitee/testdata/repo.json.golden new file mode 100644 index 000000000..fd7593d97 --- /dev/null +++ b/scm/driver/gitee/testdata/repo.json.golden @@ -0,0 +1,17 @@ +{ + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Perm": { + "Pull": true, + "Push": true, + "Admin": true + }, + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test.git", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-09-30T18:10:27+08:00" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/repos.json b/scm/driver/gitee/testdata/repos.json new file mode 100644 index 000000000..57b247b62 --- /dev/null +++ b/scm/driver/gitee/testdata/repos.json @@ -0,0 +1,162 @@ +[ + { + "id": 14836026, + "full_name": "kit101/drone-yml-test", + "human_name": "kit101/drone-yml-test", + "url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test", + "namespace": { + "id": 1576684, + "type": "personal", + "name": "kit101", + "path": "kit101", + "html_url": "https://gitee.com/kit101" + }, + "path": "drone-yml-test", + "name": "drone-yml-test", + "owner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "assigner": { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + }, + "description": "", + "private": false, + "public": true, + "internal": false, + "fork": false, + "html_url": "https://gitee.com/kit101/drone-yml-test.git", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "forks_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/forks", + "keys_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/keys{/key_id}", + "collaborators_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/collaborators{/collaborator}", + "hooks_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/hooks", + "branches_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/branches{/branch}", + "tags_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/tags", + "blobs_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/blobs{/sha}", + "stargazers_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/stargazers", + "contributors_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/contributors", + "commits_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/commits{/sha}", + "comments_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/comments{/number}", + "issue_comment_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues/comments{/number}", + "issues_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/issues{/number}", + "pulls_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/pulls{/number}", + "milestones_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/milestones{/number}", + "notifications_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/notifications{?since,all,participating}", + "labels_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/labels{/name}", + "releases_url": "https://gitee.com/api/v5/repos/kit101/drone-yml-test/releases{/id}", + "recommend": false, + "gvp": false, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "language": null, + "forks_count": 0, + "stargazers_count": 0, + "watchers_count": 1, + "default_branch": "master", + "open_issues_count": 2, + "has_issues": true, + "has_wiki": true, + "issue_comment": false, + "can_comment": true, + "pull_requests_enabled": true, + "has_page": false, + "license": null, + "outsourced": false, + "project_creator": "kit101", + "members": [ + "kit101" + ], + "pushed_at": "2021-09-30T18:10:23+08:00", + "created_at": "2021-03-24T11:24:34+08:00", + "updated_at": "2021-09-30T18:10:27+08:00", + "parent": null, + "paas": null, + "stared": false, + "watched": true, + "permission": { + "pull": true, + "push": true, + "admin": true + }, + "relation": "master", + "assignees_number": 1, + "testers_number": 1, + "assignee": [ + { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + ], + "testers": [ + { + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "remark": "", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User" + } + ], + "status": "开始", + "empty_repo": false, + "programs": [], + "enterprise": null + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/repos.json.golden b/scm/driver/gitee/testdata/repos.json.golden new file mode 100644 index 000000000..3437a1eb1 --- /dev/null +++ b/scm/driver/gitee/testdata/repos.json.golden @@ -0,0 +1,19 @@ +[ + { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Perm": { + "Pull": true, + "Push": true, + "Admin": true + }, + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test.git", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-09-30T18:10:27+08:00" + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/tag.json b/scm/driver/gitee/testdata/tag.json new file mode 100644 index 000000000..34d894a5b --- /dev/null +++ b/scm/driver/gitee/testdata/tag.json @@ -0,0 +1,8 @@ +{ + "name": "1.0", + "message": "1.0", + "commit": { + "sha": "5e7876efb3468ff679410b82a72f7c002382d41e", + "date": "2021-03-24T11:29:35+08:00" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/tag.json.golden b/scm/driver/gitee/testdata/tag.json.golden new file mode 100644 index 000000000..1e286b6e4 --- /dev/null +++ b/scm/driver/gitee/testdata/tag.json.golden @@ -0,0 +1,5 @@ +{ + "name": "1.0", + "Path": "refs/tags/1.0", + "Sha": "5e7876efb3468ff679410b82a72f7c002382d41e" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/tags.json b/scm/driver/gitee/testdata/tags.json new file mode 100644 index 000000000..dd2ef627c --- /dev/null +++ b/scm/driver/gitee/testdata/tags.json @@ -0,0 +1,34 @@ +[ + { + "name": "release-test", + "message": "", + "commit": { + "sha": "25b13a79d771314d0075302178eb18aef79e80db", + "date": "2021-08-17T16:01:03+00:00" + } + }, + { + "name": "1.1", + "message": "1.1", + "commit": { + "sha": "5e7876efb3468ff679410b82a72f7c002382d41e", + "date": "2021-03-24T11:29:35+08:00" + } + }, + { + "name": "1.0", + "message": "1.0", + "commit": { + "sha": "5e7876efb3468ff679410b82a72f7c002382d41e", + "date": "2021-03-24T11:29:35+08:00" + } + }, + { + "name": "1.2", + "message": "", + "commit": { + "sha": "5e7876efb3468ff679410b82a72f7c002382d41e", + "date": "2021-03-24T11:29:35+08:00" + } + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/tags.json.golden b/scm/driver/gitee/testdata/tags.json.golden new file mode 100644 index 000000000..1bcaa50c6 --- /dev/null +++ b/scm/driver/gitee/testdata/tags.json.golden @@ -0,0 +1,22 @@ +[ + { + "Name": "release-test", + "Path": "refs/tags/release-test", + "Sha": "25b13a79d771314d0075302178eb18aef79e80db" + }, + { + "name": "1.1", + "Path": "refs/tags/1.1", + "Sha": "5e7876efb3468ff679410b82a72f7c002382d41e" + }, + { + "name": "1.0", + "Path": "refs/tags/1.0", + "Sha": "5e7876efb3468ff679410b82a72f7c002382d41e" + }, + { + "name": "1.2", + "Path": "refs/tags/1.2", + "Sha": "5e7876efb3468ff679410b82a72f7c002382d41e" + } +] \ No newline at end of file diff --git a/scm/driver/gitee/testdata/user.json b/scm/driver/gitee/testdata/user.json new file mode 100644 index 000000000..b46072350 --- /dev/null +++ b/scm/driver/gitee/testdata/user.json @@ -0,0 +1,30 @@ +{ + "id": 1535738, + "login": "kit101", + "name": "kit101", + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "url": "https://gitee.com/api/v5/users/kit101", + "html_url": "https://gitee.com/kit101", + "followers_url": "https://gitee.com/api/v5/users/kit101/followers", + "following_url": "https://gitee.com/api/v5/users/kit101/following_url{/other_user}", + "gists_url": "https://gitee.com/api/v5/users/kit101/gists{/gist_id}", + "starred_url": "https://gitee.com/api/v5/users/kit101/starred{/owner}{/repo}", + "subscriptions_url": "https://gitee.com/api/v5/users/kit101/subscriptions", + "organizations_url": "https://gitee.com/api/v5/users/kit101/orgs", + "repos_url": "https://gitee.com/api/v5/users/kit101/repos", + "events_url": "https://gitee.com/api/v5/users/kit101/events{/privacy}", + "received_events_url": "https://gitee.com/api/v5/users/kit101/received_events", + "type": "User", + "blog": null, + "weibo": null, + "bio": "", + "public_repos": 6, + "public_gists": 0, + "followers": 2, + "following": 3, + "stared": 12, + "watched": 17, + "created_at": "2017-09-15T11:34:30+08:00", + "updated_at": "2021-08-06T16:34:48+08:00", + "email": "qkssk1711@163.com" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/user.json.golden b/scm/driver/gitee/testdata/user.json.golden new file mode 100644 index 000000000..d0ddb0d43 --- /dev/null +++ b/scm/driver/gitee/testdata/user.json.golden @@ -0,0 +1,8 @@ +{ + "Login": "kit101", + "Name": "kit101", + "Email": "qkssk1711@163.com", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Created": "2017-09-15T11:34:30+08:00", + "Updated": "2021-08-06T16:34:48+08:00" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/issue_hook_assign.json b/scm/driver/gitee/testdata/webhooks/issue_hook_assign.json new file mode 100644 index 000000000..913920c2d --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/issue_hook_assign.json @@ -0,0 +1,223 @@ +{ + "action": "assign", + "assignee": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "description": "test issue hook\nupdate 1", + "enterprise": null, + "hook_id": 788005, + "hook_name": "issue_hooks", + "hook_url": "https://gitee.com/kit101/drone-yml-test/hooks/788005/edit", + "iid": "I4CYEO", + "issue": { + "assignee": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "body": "test issue hook\nupdate 1", + "collaborators": [ + ], + "comments": 0, + "created_at": "2021-10-08T16:08:32+08:00", + "html_url": "https://gitee.com/kit101/drone-yml-test/issues/I4CYEO", + "id": 7322928, + "labels": [ + { + "color": "767676", + "id": 102145593, + "name": "duplicate" + } + ], + "milestone": null, + "number": "I4CYEO", + "state": "progressing", + "state_name": "进行中", + "title": "test issue hook", + "type_name": "任务", + "updated_at": "2021-10-08T16:12:33+08:00", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "milestone": null, + "password": "", + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T16:01:12+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T16:12:29+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "push_data": null, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T16:01:12+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T16:12:29+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sender": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "sign": "kBmUwLrajnSpjC4uH+Qkb7LpuEulsXRYt8Rf2H4eXg4=", + "state": "progressing", + "target_user": null, + "timestamp": "1633680755274", + "title": "test issue hook", + "updated_by": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "url": "https://gitee.com/kit101/drone-yml-test/issues/I4CYEO", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/issue_hook_assign.json.golden b/scm/driver/gitee/testdata/webhooks/issue_hook_assign.json.golden new file mode 100644 index 000000000..a16772286 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/issue_hook_assign.json.golden @@ -0,0 +1,37 @@ +{ + "Action": "updated", + "Repo": { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-10-08T16:12:29+08:00" + }, + "Issue": { + "Number": 735267896979, + "Title": "test issue hook", + "Body": "test issue hook\nupdate 1", + "Link": "https://gitee.com/kit101/drone-yml-test/issues/I4CYEO", + "Labels": [ + "duplicate" + ], + "Closed": false, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-10-08T16:08:32+08:00", + "Updated": "2021-10-08T16:12:33+08:00" + }, + "Sender": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/issue_hook_delete.json b/scm/driver/gitee/testdata/webhooks/issue_hook_delete.json new file mode 100644 index 000000000..3b09b5aeb --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/issue_hook_delete.json @@ -0,0 +1,235 @@ +{ + "action": "delete", + "assignee": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "description": "test issue hook\nupdate 1", + "enterprise": null, + "hook_id": 788005, + "hook_name": "issue_hooks", + "hook_url": "https://gitee.com/kit101/drone-yml-test/hooks/788005/edit", + "iid": "I4CYEO", + "issue": { + "assignee": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "body": "test issue hook\nupdate 1", + "collaborators": [ + ], + "comments": 0, + "created_at": "2021-10-08T16:08:32+08:00", + "html_url": "https://gitee.com/kit101/drone-yml-test/issues/I4CYEO", + "id": 7322928, + "labels": [ + { + "color": "767676", + "id": 102145593, + "name": "duplicate" + } + ], + "milestone": { + "closed_issues": 0, + "created_at": "2021-09-30T11:23:19+08:00", + "description": "测试里程碑", + "due_on": "2021-10-29", + "html_url": "https://gitee.com/kit101/drone-yml-test/milestones/147062", + "id": 147062, + "number": 147062, + "open_issues": 0, + "state": "open", + "title": "beta1.0", + "updated_at": "2021-09-30T11:23:19+08:00" + }, + "number": "I4CYEO", + "state": "progressing", + "state_name": "进行中", + "title": "test issue hook", + "type_name": "任务", + "updated_at": "2021-10-08T16:27:14+08:00", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "milestone": "beta1.0", + "password": "", + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T16:16:28+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T16:27:14+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "push_data": null, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T16:16:28+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T16:27:14+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sender": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "sign": "9J18Ih1nI+TKqddSYd1ORCjVjBUQhVGqIZdX3Jqk32Q=", + "state": "progressing", + "target_user": null, + "timestamp": "1633681683513", + "title": "test issue hook", + "updated_by": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "url": "https://gitee.com/kit101/drone-yml-test/issues/I4CYEO", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/issue_hook_delete.json.golden b/scm/driver/gitee/testdata/webhooks/issue_hook_delete.json.golden new file mode 100644 index 000000000..211795e90 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/issue_hook_delete.json.golden @@ -0,0 +1,37 @@ +{ + "Action": "closed", + "Repo": { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-10-08T16:27:14+08:00" + }, + "Issue": { + "Number": 735267896979, + "Title": "test issue hook", + "Body": "test issue hook\nupdate 1", + "Link": "https://gitee.com/kit101/drone-yml-test/issues/I4CYEO", + "Labels": [ + "duplicate" + ], + "Closed": false, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-10-08T16:08:32+08:00", + "Updated": "2021-10-08T16:27:14+08:00" + }, + "Sender": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/issue_hook_open.json b/scm/driver/gitee/testdata/webhooks/issue_hook_open.json new file mode 100644 index 000000000..f436f4738 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/issue_hook_open.json @@ -0,0 +1,192 @@ +{ + "action": "open", + "assignee": null, + "description": "test issue hook", + "enterprise": null, + "hook_id": 788005, + "hook_name": "issue_hooks", + "hook_url": "https://gitee.com/kit101/drone-yml-test/hooks/788005/edit", + "iid": "I4CYEO", + "issue": { + "assignee": null, + "body": "test issue hook", + "collaborators": [ + ], + "comments": 0, + "created_at": "2021-10-08T16:08:32+08:00", + "html_url": "https://gitee.com/kit101/drone-yml-test/issues/I4CYEO", + "id": 7322928, + "labels": [ + ], + "milestone": null, + "number": "I4CYEO", + "state": "open", + "state_name": "待办的", + "title": "test issue hook", + "type_name": "任务", + "updated_at": "2021-10-08T16:08:32+08:00", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "milestone": null, + "password": "", + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 3, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T16:01:12+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T16:08:32+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "push_data": null, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 3, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T16:01:12+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T16:08:32+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sender": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "sign": "8v2uENuUH9QeZVl3olFEA3aPE/5fECC6RkmmsJV62DQ=", + "state": "open", + "target_user": null, + "timestamp": "1633680515785", + "title": "test issue hook", + "updated_by": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "url": "https://gitee.com/kit101/drone-yml-test/issues/I4CYEO", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/issue_hook_open.json.golden b/scm/driver/gitee/testdata/webhooks/issue_hook_open.json.golden new file mode 100644 index 000000000..a87054c90 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/issue_hook_open.json.golden @@ -0,0 +1,34 @@ +{ + "Action": "opened", + "Repo": { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-10-08T16:08:32+08:00" + }, + "Issue": { + "Number": 735267896979, + "Title": "test issue hook", + "Body": "test issue hook", + "Link": "https://gitee.com/kit101/drone-yml-test/issues/I4CYEO", + "Closed": false, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-10-08T16:08:32+08:00", + "Updated": "2021-10-08T16:08:32+08:00" + }, + "Sender": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/issue_hook_state_change.json b/scm/driver/gitee/testdata/webhooks/issue_hook_state_change.json new file mode 100644 index 000000000..0b6c9c8a4 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/issue_hook_state_change.json @@ -0,0 +1,235 @@ +{ + "action": "state_change", + "assignee": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "description": "test issue hook\nupdate 1", + "enterprise": null, + "hook_id": 788005, + "hook_name": "issue_hooks", + "hook_url": "https://gitee.com/kit101/drone-yml-test/hooks/788005/edit", + "iid": "I4CYEO", + "issue": { + "assignee": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "body": "test issue hook\nupdate 1", + "collaborators": [ + ], + "comments": 0, + "created_at": "2021-10-08T16:08:32+08:00", + "html_url": "https://gitee.com/kit101/drone-yml-test/issues/I4CYEO", + "id": 7322928, + "labels": [ + { + "color": "767676", + "id": 102145593, + "name": "duplicate" + } + ], + "milestone": { + "closed_issues": 0, + "created_at": "2021-09-30T11:23:19+08:00", + "description": "测试里程碑", + "due_on": "2021-10-29", + "html_url": "https://gitee.com/kit101/drone-yml-test/milestones/147062", + "id": 147062, + "number": 147062, + "open_issues": 0, + "state": "open", + "title": "beta1.0", + "updated_at": "2021-09-30T11:23:19+08:00" + }, + "number": "I4CYEO", + "state": "progressing", + "state_name": "进行中", + "title": "test issue hook", + "type_name": "任务", + "updated_at": "2021-10-08T16:27:14+08:00", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "milestone": "beta1.0", + "password": "", + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T16:16:28+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T16:27:14+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "push_data": null, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T16:16:28+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T16:27:14+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sender": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "sign": "HdIghS5Ua3zzLgqI4LxxQz313V08QxrR3+0YITiGf1s=", + "state": "progressing", + "target_user": null, + "timestamp": "1633681635600", + "title": "test issue hook", + "updated_by": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "url": "https://gitee.com/kit101/drone-yml-test/issues/I4CYEO", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/issue_hook_state_change.json.golden b/scm/driver/gitee/testdata/webhooks/issue_hook_state_change.json.golden new file mode 100644 index 000000000..211c790b4 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/issue_hook_state_change.json.golden @@ -0,0 +1,37 @@ +{ + "Action": "opened", + "Repo": { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-10-08T16:27:14+08:00" + }, + "Issue": { + "Number": 735267896979, + "Title": "test issue hook", + "Body": "test issue hook\nupdate 1", + "Link": "https://gitee.com/kit101/drone-yml-test/issues/I4CYEO", + "Labels": [ + "duplicate" + ], + "Closed": false, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-10-08T16:08:32+08:00", + "Updated": "2021-10-08T16:27:14+08:00" + }, + "Sender": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/note_hook_issue_comment.json b/scm/driver/gitee/testdata/webhooks/note_hook_issue_comment.json new file mode 100644 index 000000000..3b0f78cea --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/note_hook_issue_comment.json @@ -0,0 +1,217 @@ +{ + "action": "comment", + "author": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "comment": { + "body": "test issue comment hook\r\n\r\n", + "created_at": "2021-10-08T15:45:08+08:00", + "html_url": "https://gitee.com/kit101/drone-yml-test/issues/I4CF12#note_6933558", + "id": 6933558, + "updated_at": "2021-10-08T15:45:08+08:00", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "enterprise": null, + "hook_id": 788005, + "hook_name": "note_hooks", + "hook_url": "https://gitee.com/kit101/drone-yml-test/hooks/788005/edit", + "issue": { + "assignee": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "body": "create by api body", + "collaborators": [ + ], + "comments": 2, + "created_at": "2021-09-29T13:33:00+08:00", + "html_url": "https://gitee.com/kit101/drone-yml-test/issues/I4CF12", + "id": 7297814, + "labels": [ + { + "color": "DB2828", + "id": 102145590, + "name": "bug" + } + ], + "milestone": null, + "number": "I4CF12", + "state": "open", + "state_name": "待办的", + "title": "create by api", + "type_name": "任务", + "updated_at": "2021-10-08T15:45:08+08:00", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "note": "test issue comment hook\r\n\r\n", + "noteable_id": 7297814, + "noteable_type": "Issue", + "password": "", + "per_iid": "#I4CF12", + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T13:26:59+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T13:26:59+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "pull_request": null, + "push_data": null, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T13:26:59+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T13:26:59+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sender": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "short_commit_id": null, + "sign": "Zzv7VMOnJ5SKrQhcEsL4XaC1zR1Kl1qMuxS0HbHwpBI=", + "timestamp": "1633679110217", + "title": "create by api", + "url": "https://gitee.com/kit101/drone-yml-test/issues/I4CF12#note_6933558" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/note_hook_issue_comment.json.golden b/scm/driver/gitee/testdata/webhooks/note_hook_issue_comment.json.golden new file mode 100644 index 000000000..53845e677 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/note_hook_issue_comment.json.golden @@ -0,0 +1,49 @@ +{ + "Action": "created", + "Repo": { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-10-08T13:26:59+08:00" + }, + "Issue": { + "Number": 735267704950, + "Title": "create by api", + "Body": "create by api body", + "Link": "https://gitee.com/kit101/drone-yml-test/issues/I4CF12", + "Labels": [ + "bug" + ], + "Closed": false, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-09-29T13:33:00+08:00", + "Updated": "2021-10-08T15:45:08+08:00" + }, + "Comment": { + "ID": 6933558, + "Body": "test issue comment hook\r\n\r\n", + "Author": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + }, + "Created": "2021-10-08T15:45:08+08:00", + "Updated": "2021-10-08T15:45:08+08:00" + }, + "Sender": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + } +} diff --git a/scm/driver/gitee/testdata/webhooks/note_hook_pr_comment.json b/scm/driver/gitee/testdata/webhooks/note_hook_pr_comment.json new file mode 100644 index 000000000..7d871105b --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/note_hook_pr_comment.json @@ -0,0 +1,394 @@ +{ + "action": "comment", + "author": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "comment": { + "body": "comment", + "created_at": "2021-10-08T19:13:20+08:00", + "html_url": "https://gitee.com/kit101/drone-yml-test/pulls/7#note_6937563", + "id": 6937563, + "updated_at": "2021-10-08T19:13:20+08:00", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "enterprise": null, + "hook_id": 788005, + "hook_name": "note_hooks", + "hook_url": "https://gitee.com/kit101/drone-yml-test/hooks/788005/edit", + "issue": null, + "note": "comment", + "noteable_id": 4731382, + "noteable_type": "PullRequest", + "password": "", + "per_iid": "!7", + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:54:02+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:54:02+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "pull_request": { + "additions": 11, + "assignee": null, + "assignees": [ + { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + ], + "base": { + "label": "kit101:master", + "ref": "master", + "repo": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:54:02+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:54:02+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sha": "2eac1cac02c325058cf959725c45b0612d3e8177", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "body": "", + "changed_files": 2, + "closed_at": null, + "comments": 11, + "commits": 2, + "created_at": "2021-09-30T18:10:27+08:00", + "deletions": 0, + "diff_url": "https://gitee.com/kit101/drone-yml-test/pulls/7.diff", + "head": { + "label": "kit101:feat-2", + "ref": "feat-2", + "repo": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:54:02+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:54:02+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sha": "6168d9dae737b47f00c59fafca10c913a6850c3a", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "html_url": "https://gitee.com/kit101/drone-yml-test/pulls/7", + "id": 4731382, + "languages": [ + "Python" + ], + "merge_commit_sha": "d10df103c351de96ceb9e62e6e4097f0e3420b72", + "merge_reference_name": "refs/pull/7/MERGE", + "merge_status": "can_be_resolve", + "mergeable": false, + "merged": false, + "merged_at": null, + "milestone": null, + "need_review": true, + "need_test": true, + "number": 7, + "patch_url": "https://gitee.com/kit101/drone-yml-test/pulls/7.patch", + "state": "open", + "tester": null, + "testers": [ + { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + ], + "title": "feat add 3", + "updated_at": "2021-10-08T19:13:20+08:00", + "updated_by": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "push_data": null, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:54:02+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:54:02+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sender": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "short_commit_id": null, + "sign": "wi4uRDdmlbPvs3DMQsm88rV0rzx11rLvuo0AOJOH28s=", + "timestamp": "1633691608022", + "title": "feat add 3", + "url": "https://gitee.com/kit101/drone-yml-test/pulls/7#note_6937563" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/note_hook_pr_comment.json.golden b/scm/driver/gitee/testdata/webhooks/note_hook_pr_comment.json.golden new file mode 100644 index 000000000..c91349ba4 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/note_hook_pr_comment.json.golden @@ -0,0 +1,63 @@ +{ + "Action": "created", + "Repo": { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-10-08T17:54:02+08:00" + }, + "PullRequest": { + "Number": 7, + "Title": "feat add 3", + "Body": "", + "Sha": "6168d9dae737b47f00c59fafca10c913a6850c3a", + "Ref": "refs/pull/7/head", + "Source": "feat-2", + "Target": "master", + "Fork": "kit101/drone-yml-test", + "Link": "https://gitee.com/kit101/drone-yml-test/pulls/7", + "Diff": "https://gitee.com/kit101/drone-yml-test/pulls/7.diff", + "Closed": false, + "Merged": false, + "Head": { + "Name": "feat-2", + "Path": "refs/heads/feat-2", + "Sha": "6168d9dae737b47f00c59fafca10c913a6850c3a" + }, + "Base": { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "2eac1cac02c325058cf959725c45b0612d3e8177" + }, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-09-30T18:10:27+08:00", + "Updated": "2021-10-08T19:13:20+08:00" + }, + "Comment": { + "ID": 6937563, + "Body": "comment", + "Author": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + }, + "Created": "2021-10-08T19:13:20+08:00", + "Updated": "2021-10-08T19:13:20+08:00" + }, + "Sender": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/pr_close.json b/scm/driver/gitee/testdata/webhooks/pr_close.json new file mode 100644 index 000000000..d5ad5c9a0 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/pr_close.json @@ -0,0 +1,601 @@ +{ + "action": "close", + "action_desc": "open", + "author": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "body": "feat-3 1", + "enterprise": null, + "hook_id": 788005, + "hook_name": "merge_request_hooks", + "hook_url": "https://gitee.com/kit101/drone-yml-test/hooks/788005/edit", + "iid": 8, + "languages": [ + "Python" + ], + "merge_commit_sha": "cd09abc1995aede07da6524a0ace587698d74bbc", + "merge_status": "can_be_merged", + "number": 8, + "password": "", + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:28:43+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "pull_request": { + "additions": 1, + "assignee": null, + "assignees": [ + { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + ], + "base": { + "label": "kit101:master", + "ref": "master", + "repo": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:28:43+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sha": "2eac1cac02c325058cf959725c45b0612d3e8177", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "body": "feat-3 1", + "changed_files": 1, + "closed_at": "2021-10-08T17:28:43+08:00", + "comments": 0, + "commits": 1, + "created_at": "2021-10-08T17:16:06+08:00", + "deletions": 0, + "diff_url": "https://gitee.com/kit101/drone-yml-test/pulls/8.diff", + "head": { + "label": "kit101:feat-3", + "ref": "feat-3", + "repo": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:28:43+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sha": "dc8fa2ebe050d63f639c5b834311e96bc2303523", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "html_url": "https://gitee.com/kit101/drone-yml-test/pulls/8", + "id": 4744094, + "labels": [ + { + "color": "D7C38B", + "id": 127956024, + "name": "test" + } + ], + "languages": [ + "Python" + ], + "merge_commit_sha": "cd09abc1995aede07da6524a0ace587698d74bbc", + "merge_reference_name": "refs/pull/8/MERGE", + "merge_status": "can_be_merged", + "mergeable": true, + "merged": false, + "merged_at": null, + "milestone": null, + "need_review": false, + "need_test": false, + "number": 8, + "patch_url": "https://gitee.com/kit101/drone-yml-test/pulls/8.patch", + "state": "closed", + "tester": null, + "testers": [ + { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + ], + "title": "feat-3 1", + "updated_at": "2021-10-08T17:28:43+08:00", + "updated_by": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "push_data": null, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:28:43+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sender": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "sign": "yuLVNqOZKWnXuYcQ8KbOm1UYgvd9KeiCHX5QsEyrrz8=", + "source_branch": "feat-3", + "source_repo": { + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:28:43+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:28:43+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + } + }, + "state": "closed", + "target_branch": "master", + "target_repo": { + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:28:43+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:28:43+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + } + }, + "target_user": null, + "timestamp": "1633685324936", + "title": "feat-3 1", + "updated_by": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "url": "https://gitee.com/kit101/drone-yml-test/pulls/8" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/pr_close.json.golden b/scm/driver/gitee/testdata/webhooks/pr_close.json.golden new file mode 100644 index 000000000..2c71509f2 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/pr_close.json.golden @@ -0,0 +1,57 @@ +{ + "Action": "closed", + "Repo": { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-10-08T17:28:43+08:00" + }, + "PullRequest": { + "Number": 8, + "Title": "feat-3 1", + "Body": "feat-3 1", + "Sha": "dc8fa2ebe050d63f639c5b834311e96bc2303523", + "Ref": "refs/pull/8/head", + "Source": "feat-3", + "Target": "master", + "Fork": "kit101/drone-yml-test", + "Link": "https://gitee.com/kit101/drone-yml-test/pulls/8", + "Diff": "https://gitee.com/kit101/drone-yml-test/pulls/8.diff", + "Closed": true, + "Merged": false, + "Head": { + "Name": "feat-3", + "Path": "refs/heads/feat-3", + "Sha": "dc8fa2ebe050d63f639c5b834311e96bc2303523" + }, + "Base": { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "2eac1cac02c325058cf959725c45b0612d3e8177" + }, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-10-08T17:16:06+08:00", + "Updated": "2021-10-08T17:28:43+08:00", + "Labels": [ + { + "Name": "test", + "Color": "D7C38B" + } + ] + }, + "Sender": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/pr_labeled.json b/scm/driver/gitee/testdata/webhooks/pr_labeled.json new file mode 100644 index 000000000..bc682cc3f --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/pr_labeled.json @@ -0,0 +1,601 @@ +{ + "action": "update", + "action_desc": "update_label", + "author": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "body": "feat-3 1", + "enterprise": null, + "hook_id": 788005, + "hook_name": "merge_request_hooks", + "hook_url": "https://gitee.com/kit101/drone-yml-test/hooks/788005/edit", + "iid": 8, + "languages": [ + "Python" + ], + "merge_commit_sha": "cd09abc1995aede07da6524a0ace587698d74bbc", + "merge_status": "can_be_merged", + "number": 8, + "password": "", + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:16:06+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "pull_request": { + "additions": 1, + "assignee": null, + "assignees": [ + { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + ], + "base": { + "label": "kit101:master", + "ref": "master", + "repo": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:16:06+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sha": "2eac1cac02c325058cf959725c45b0612d3e8177", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "body": "feat-3 1", + "changed_files": 1, + "closed_at": null, + "comments": 0, + "commits": 1, + "created_at": "2021-10-08T17:16:06+08:00", + "deletions": 0, + "diff_url": "https://gitee.com/kit101/drone-yml-test/pulls/8.diff", + "head": { + "label": "kit101:feat-3", + "ref": "feat-3", + "repo": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:16:06+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sha": "dc8fa2ebe050d63f639c5b834311e96bc2303523", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "html_url": "https://gitee.com/kit101/drone-yml-test/pulls/8", + "id": 4744094, + "labels": [ + { + "color": "00B5AD", + "id": 102145595, + "name": "question" + } + ], + "languages": [ + "Python" + ], + "merge_commit_sha": "cd09abc1995aede07da6524a0ace587698d74bbc", + "merge_reference_name": "refs/pull/8/MERGE", + "merge_status": "can_be_merged", + "mergeable": true, + "merged": false, + "merged_at": null, + "milestone": null, + "need_review": true, + "need_test": true, + "number": 8, + "patch_url": "https://gitee.com/kit101/drone-yml-test/pulls/8.patch", + "state": "open", + "tester": null, + "testers": [ + { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + ], + "title": "feat-3 1", + "updated_at": "2021-10-08T17:19:39+08:00", + "updated_by": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "push_data": null, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:16:06+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sender": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "sign": "Fid06lsV72m4QMmmwMAPqTwYLLwFYNgjz32pUeAIaTE=", + "source_branch": "feat-3", + "source_repo": { + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:16:06+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:16:06+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + } + }, + "state": "open", + "target_branch": "master", + "target_repo": { + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:16:06+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:16:06+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + } + }, + "target_user": null, + "timestamp": "1633684782533", + "title": "feat-3 1", + "updated_by": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "url": "https://gitee.com/kit101/drone-yml-test/pulls/8" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/pr_labeled.json.golden b/scm/driver/gitee/testdata/webhooks/pr_labeled.json.golden new file mode 100644 index 000000000..1aaa28281 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/pr_labeled.json.golden @@ -0,0 +1,57 @@ +{ + "Action": "labeled", + "Repo": { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-10-08T17:16:06+08:00" + }, + "PullRequest": { + "Number": 8, + "Title": "feat-3 1", + "Body": "feat-3 1", + "Sha": "dc8fa2ebe050d63f639c5b834311e96bc2303523", + "Ref": "refs/pull/8/head", + "Source": "feat-3", + "Target": "master", + "Fork": "kit101/drone-yml-test", + "Link": "https://gitee.com/kit101/drone-yml-test/pulls/8", + "Diff": "https://gitee.com/kit101/drone-yml-test/pulls/8.diff", + "Closed": false, + "Merged": false, + "Head": { + "Name": "feat-3", + "Path": "refs/heads/feat-3", + "Sha": "dc8fa2ebe050d63f639c5b834311e96bc2303523" + }, + "Base": { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "2eac1cac02c325058cf959725c45b0612d3e8177" + }, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-10-08T17:16:06+08:00", + "Updated": "2021-10-08T17:19:39+08:00", + "Labels": [ + { + "Name": "question", + "Color": "00B5AD" + } + ] + }, + "Sender": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/pr_merge.json b/scm/driver/gitee/testdata/webhooks/pr_merge.json new file mode 100644 index 000000000..9b94fc405 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/pr_merge.json @@ -0,0 +1,596 @@ +{ + "action": "merge", + "action_desc": "open", + "author": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "body": "feat-3", + "enterprise": null, + "hook_id": 788005, + "hook_name": "merge_request_hooks", + "hook_url": "https://gitee.com/kit101/drone-yml-test/hooks/788005/edit", + "iid": 9, + "languages": [ + "Python" + ], + "merge_commit_sha": "6c363013dfccedad4c68c88e8649f4ffacc644ea", + "merge_status": "can_be_merged", + "number": 9, + "password": "", + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:32:30+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:32:30+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "pull_request": { + "additions": 1, + "assignee": null, + "assignees": [ + { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + ], + "base": { + "label": "kit101:master", + "ref": "master", + "repo": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:32:30+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:32:30+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sha": "2eac1cac02c325058cf959725c45b0612d3e8177", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "body": "feat-3", + "changed_files": 1, + "closed_at": "2021-10-08T17:32:30+08:00", + "comments": 0, + "commits": 1, + "created_at": "2021-10-08T17:29:49+08:00", + "deletions": 0, + "diff_url": "https://gitee.com/kit101/drone-yml-test/pulls/9.diff", + "head": { + "label": "kit101:feat-3", + "ref": "feat-3", + "repo": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:32:30+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:32:30+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sha": "dc8fa2ebe050d63f639c5b834311e96bc2303523", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "html_url": "https://gitee.com/kit101/drone-yml-test/pulls/9", + "id": 4744278, + "labels": [ + ], + "languages": [ + "Python" + ], + "merge_commit_sha": "6c363013dfccedad4c68c88e8649f4ffacc644ea", + "merge_reference_name": "refs/pull/9/MERGE", + "merge_status": "can_be_merged", + "mergeable": true, + "merged": true, + "merged_at": "2021-10-08T17:32:30+08:00", + "milestone": null, + "need_review": false, + "need_test": false, + "number": 9, + "patch_url": "https://gitee.com/kit101/drone-yml-test/pulls/9.patch", + "state": "merged", + "tester": null, + "testers": [ + { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + ], + "title": "feat-3", + "updated_at": "2021-10-08T17:32:29+08:00", + "updated_by": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "push_data": null, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:32:30+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:32:30+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sender": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "sign": "SPeRZ3+TLzetOj+eEdAuMt8zVVbs6o+k5xrCPf5WGDI=", + "source_branch": "feat-3", + "source_repo": { + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:32:30+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:32:30+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:32:30+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:32:30+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + } + }, + "state": "merged", + "target_branch": "master", + "target_repo": { + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:32:30+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:32:30+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:32:30+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:32:30+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + } + }, + "target_user": null, + "timestamp": "1633685551222", + "title": "feat-3", + "updated_by": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "url": "https://gitee.com/kit101/drone-yml-test/pulls/9" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/pr_merge.json.golden b/scm/driver/gitee/testdata/webhooks/pr_merge.json.golden new file mode 100644 index 000000000..54e89f254 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/pr_merge.json.golden @@ -0,0 +1,51 @@ +{ + "Action": "merged", + "Repo": { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-10-08T17:32:30+08:00" + }, + "PullRequest": { + "Number": 9, + "Title": "feat-3", + "Body": "feat-3", + "Sha": "dc8fa2ebe050d63f639c5b834311e96bc2303523", + "Ref": "refs/pull/9/head", + "Source": "feat-3", + "Target": "master", + "Fork": "kit101/drone-yml-test", + "Link": "https://gitee.com/kit101/drone-yml-test/pulls/9", + "Diff": "https://gitee.com/kit101/drone-yml-test/pulls/9.diff", + "Closed": true, + "Merged": true, + "Head": { + "Name": "feat-3", + "Path": "refs/heads/feat-3", + "Sha": "dc8fa2ebe050d63f639c5b834311e96bc2303523" + }, + "Base": { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "2eac1cac02c325058cf959725c45b0612d3e8177" + }, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-10-08T17:29:49+08:00", + "Updated": "2021-10-08T17:32:29+08:00" + }, + "Sender": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/pr_open.json b/scm/driver/gitee/testdata/webhooks/pr_open.json new file mode 100644 index 000000000..62b9bd0cb --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/pr_open.json @@ -0,0 +1,596 @@ +{ + "action": "open", + "action_desc": "open", + "author": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "body": "feat-3", + "enterprise": null, + "hook_id": 788005, + "hook_name": "merge_request_hooks", + "hook_url": "https://gitee.com/kit101/drone-yml-test/hooks/788005/edit", + "iid": 9, + "languages": [ + "Python" + ], + "merge_commit_sha": "3fbdff5796f6d57ed9f5a5dd48e5d0cad7f9c0a1", + "merge_status": "can_be_merged", + "number": 9, + "password": "", + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:29:49+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "pull_request": { + "additions": 1, + "assignee": null, + "assignees": [ + { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + ], + "base": { + "label": "kit101:master", + "ref": "master", + "repo": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:29:49+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sha": "2eac1cac02c325058cf959725c45b0612d3e8177", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "body": "feat-3", + "changed_files": 1, + "closed_at": null, + "comments": 0, + "commits": 1, + "created_at": "2021-10-08T17:29:49+08:00", + "deletions": 0, + "diff_url": "https://gitee.com/kit101/drone-yml-test/pulls/9.diff", + "head": { + "label": "kit101:feat-3", + "ref": "feat-3", + "repo": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:29:49+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sha": "dc8fa2ebe050d63f639c5b834311e96bc2303523", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "html_url": "https://gitee.com/kit101/drone-yml-test/pulls/9", + "id": 4744278, + "labels": [ + ], + "languages": [ + "Python" + ], + "merge_commit_sha": "3fbdff5796f6d57ed9f5a5dd48e5d0cad7f9c0a1", + "merge_reference_name": "refs/pull/9/MERGE", + "merge_status": "can_be_merged", + "mergeable": true, + "merged": false, + "merged_at": null, + "milestone": null, + "need_review": true, + "need_test": true, + "number": 9, + "patch_url": "https://gitee.com/kit101/drone-yml-test/pulls/9.patch", + "state": "open", + "tester": null, + "testers": [ + { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + ], + "title": "feat-3", + "updated_at": "2021-10-08T17:29:50+08:00", + "updated_by": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "push_data": null, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:29:49+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sender": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "sign": "o5L+cMcrXR+F8rVIRW+v2J/jTd9N8ZmyM3cXBte12Nc=", + "source_branch": "feat-3", + "source_repo": { + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:29:49+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:29:49+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + } + }, + "state": "open", + "target_branch": "master", + "target_repo": { + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:29:49+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:29:49+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + } + }, + "target_user": null, + "timestamp": "1633685391315", + "title": "feat-3", + "updated_by": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "url": "https://gitee.com/kit101/drone-yml-test/pulls/9" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/pr_open.json.golden b/scm/driver/gitee/testdata/webhooks/pr_open.json.golden new file mode 100644 index 000000000..6372fcc91 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/pr_open.json.golden @@ -0,0 +1,51 @@ +{ + "Action": "opened", + "Repo": { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-10-08T17:29:49+08:00" + }, + "PullRequest": { + "Number": 9, + "Title": "feat-3", + "Body": "feat-3", + "Sha": "dc8fa2ebe050d63f639c5b834311e96bc2303523", + "Ref": "refs/pull/9/head", + "Source": "feat-3", + "Target": "master", + "Fork": "kit101/drone-yml-test", + "Link": "https://gitee.com/kit101/drone-yml-test/pulls/9", + "Diff": "https://gitee.com/kit101/drone-yml-test/pulls/9.diff", + "Closed": false, + "Merged": false, + "Head": { + "Name": "feat-3", + "Path": "refs/heads/feat-3", + "Sha": "dc8fa2ebe050d63f639c5b834311e96bc2303523" + }, + "Base": { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "2eac1cac02c325058cf959725c45b0612d3e8177" + }, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-10-08T17:29:49+08:00", + "Updated": "2021-10-08T17:29:50+08:00" + }, + "Sender": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/pr_unlabeled.json b/scm/driver/gitee/testdata/webhooks/pr_unlabeled.json new file mode 100644 index 000000000..2e317e8bb --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/pr_unlabeled.json @@ -0,0 +1,596 @@ +{ + "action": "update", + "action_desc": "update_label", + "author": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "body": "feat-3 1", + "enterprise": null, + "hook_id": 788005, + "hook_name": "merge_request_hooks", + "hook_url": "https://gitee.com/kit101/drone-yml-test/hooks/788005/edit", + "iid": 8, + "languages": [ + "Python" + ], + "merge_commit_sha": "cd09abc1995aede07da6524a0ace587698d74bbc", + "merge_status": "can_be_merged", + "number": 8, + "password": "", + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:16:06+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "pull_request": { + "additions": 1, + "assignee": null, + "assignees": [ + { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + ], + "base": { + "label": "kit101:master", + "ref": "master", + "repo": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:16:06+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sha": "2eac1cac02c325058cf959725c45b0612d3e8177", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "body": "feat-3 1", + "changed_files": 1, + "closed_at": null, + "comments": 0, + "commits": 1, + "created_at": "2021-10-08T17:16:06+08:00", + "deletions": 0, + "diff_url": "https://gitee.com/kit101/drone-yml-test/pulls/8.diff", + "head": { + "label": "kit101:feat-3", + "ref": "feat-3", + "repo": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:16:06+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sha": "dc8fa2ebe050d63f639c5b834311e96bc2303523", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "html_url": "https://gitee.com/kit101/drone-yml-test/pulls/8", + "id": 4744094, + "labels": [ + ], + "languages": [ + "Python" + ], + "merge_commit_sha": "cd09abc1995aede07da6524a0ace587698d74bbc", + "merge_reference_name": "refs/pull/8/MERGE", + "merge_status": "can_be_merged", + "mergeable": true, + "merged": false, + "merged_at": null, + "milestone": null, + "need_review": true, + "need_test": true, + "number": 8, + "patch_url": "https://gitee.com/kit101/drone-yml-test/pulls/8.patch", + "state": "open", + "tester": null, + "testers": [ + { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + ], + "title": "feat-3 1", + "updated_at": "2021-10-08T17:23:09+08:00", + "updated_by": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "push_data": null, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:16:06+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sender": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "sign": "X52dWAExMGFaN1+5a/RAuVtPmP5R0GL3AE4Br/MngRg=", + "source_branch": "feat-3", + "source_repo": { + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:16:06+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:16:06+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + } + }, + "state": "open", + "target_branch": "master", + "target_repo": { + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:16:06+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:15:39+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:16:06+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + } + }, + "target_user": null, + "timestamp": "1633684991291", + "title": "feat-3 1", + "updated_by": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "url": "https://gitee.com/kit101/drone-yml-test/pulls/8" +} diff --git a/scm/driver/gitee/testdata/webhooks/pr_unlabeled.json.golden b/scm/driver/gitee/testdata/webhooks/pr_unlabeled.json.golden new file mode 100644 index 000000000..4b66f143c --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/pr_unlabeled.json.golden @@ -0,0 +1,51 @@ +{ + "Action": "unlabeled", + "Repo": { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-10-08T17:16:06+08:00" + }, + "PullRequest": { + "Number": 8, + "Title": "feat-3 1", + "Body": "feat-3 1", + "Sha": "dc8fa2ebe050d63f639c5b834311e96bc2303523", + "Ref": "refs/pull/8/head", + "Source": "feat-3", + "Target": "master", + "Fork": "kit101/drone-yml-test", + "Link": "https://gitee.com/kit101/drone-yml-test/pulls/8", + "Diff": "https://gitee.com/kit101/drone-yml-test/pulls/8.diff", + "Closed": false, + "Merged": false, + "Head": { + "Name": "feat-3", + "Path": "refs/heads/feat-3", + "Sha": "dc8fa2ebe050d63f639c5b834311e96bc2303523" + }, + "Base": { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "2eac1cac02c325058cf959725c45b0612d3e8177" + }, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-10-08T17:16:06+08:00", + "Updated": "2021-10-08T17:23:09+08:00" + }, + "Sender": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/pr_update.json b/scm/driver/gitee/testdata/webhooks/pr_update.json new file mode 100644 index 000000000..8ca8146eb --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/pr_update.json @@ -0,0 +1,596 @@ +{ + "action": "update", + "action_desc": "source_branch_changed", + "author": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "body": "", + "enterprise": null, + "hook_id": 788005, + "hook_name": "merge_request_hooks", + "hook_url": "https://gitee.com/kit101/drone-yml-test/hooks/788005/edit", + "iid": 7, + "languages": [ + "Python" + ], + "merge_commit_sha": "d10df103c351de96ceb9e62e6e4097f0e3420b72", + "merge_status": "can_be_resolve", + "number": 7, + "password": "", + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:38:53+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:38:53+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "pull_request": { + "additions": 11, + "assignee": null, + "assignees": [ + { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + ], + "base": { + "label": "kit101:master", + "ref": "master", + "repo": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:38:53+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:38:53+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sha": "2eac1cac02c325058cf959725c45b0612d3e8177", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "body": "", + "changed_files": 2, + "closed_at": null, + "comments": 8, + "commits": 2, + "created_at": "2021-09-30T18:10:27+08:00", + "deletions": 0, + "diff_url": "https://gitee.com/kit101/drone-yml-test/pulls/7.diff", + "head": { + "label": "kit101:feat-2", + "ref": "feat-2", + "repo": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:38:53+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:38:53+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sha": "6168d9dae737b47f00c59fafca10c913a6850c3a", + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "html_url": "https://gitee.com/kit101/drone-yml-test/pulls/7", + "id": 4731382, + "labels": [ + ], + "languages": [ + "Python" + ], + "merge_commit_sha": "d10df103c351de96ceb9e62e6e4097f0e3420b72", + "merge_reference_name": "refs/pull/7/MERGE", + "merge_status": "can_be_resolve", + "mergeable": false, + "merged": false, + "merged_at": null, + "milestone": null, + "need_review": true, + "need_test": true, + "number": 7, + "patch_url": "https://gitee.com/kit101/drone-yml-test/pulls/7.patch", + "state": "open", + "tester": null, + "testers": [ + { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + ], + "title": "feat add 3", + "updated_at": "2021-10-08T17:36:07+08:00", + "updated_by": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "user": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + } + }, + "push_data": null, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:38:53+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:38:53+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sender": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "sign": "/gLVmA+/dd5q+siOduWu3z6UGhBJ8I5Fe/Gl8zxLU7A=", + "source_branch": "feat-2", + "source_repo": { + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:38:53+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:38:53+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:38:53+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:38:53+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + } + }, + "state": "open", + "target_branch": "master", + "target_repo": { + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:38:53+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:38:53+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:38:53+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:38:53+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + } + }, + "target_user": null, + "timestamp": "1633685873030", + "title": "feat add 3", + "updated_by": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "url": "https://gitee.com/kit101/drone-yml-test/pulls/7" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/pr_update.json.golden b/scm/driver/gitee/testdata/webhooks/pr_update.json.golden new file mode 100644 index 000000000..5e11ac3d7 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/pr_update.json.golden @@ -0,0 +1,51 @@ +{ + "Action": "synchronized", + "Repo": { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-10-08T17:38:53+08:00" + }, + "PullRequest": { + "Number": 7, + "Title": "feat add 3", + "Body": "", + "Sha": "6168d9dae737b47f00c59fafca10c913a6850c3a", + "Ref": "refs/pull/7/head", + "Source": "feat-2", + "Target": "master", + "Fork": "kit101/drone-yml-test", + "Link": "https://gitee.com/kit101/drone-yml-test/pulls/7", + "Diff": "https://gitee.com/kit101/drone-yml-test/pulls/7.diff", + "Closed": false, + "Merged": false, + "Head": { + "Name": "feat-2", + "Path": "refs/heads/feat-2", + "Sha": "6168d9dae737b47f00c59fafca10c913a6850c3a" + }, + "Base": { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "2eac1cac02c325058cf959725c45b0612d3e8177" + }, + "Author": { + "Login": "kit101", + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png" + }, + "Created": "2021-09-30T18:10:27+08:00", + "Updated": "2021-10-08T17:36:07+08:00" + }, + "Sender": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/push.json b/scm/driver/gitee/testdata/webhooks/push.json new file mode 100644 index 000000000..24cde84b3 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/push.json @@ -0,0 +1,230 @@ +{ + "after": "9921e45e570db8e57e544650baf837932fb2100f", + "before": "6168d9dae737b47f00c59fafca10c913a6850c3a", + "commits": [ + { + "added": [ + ], + "author": { + "email": "qkssk1711@163.com", + "id": 1535738, + "name": "kit101", + "remark": null, + "time": "2021-10-08T17:53:12+08:00", + "url": "https://gitee.com/kit101", + "user": null, + "user_name": "kit101", + "username": "kit101" + }, + "committer": { + "email": "qkssk1711@163.com", + "id": 1535738, + "name": "kit101", + "remark": null, + "time": null, + "url": "https://gitee.com/kit101", + "user": null, + "user_name": "kit101", + "username": "kit101" + }, + "distinct": true, + "id": "9921e45e570db8e57e544650baf837932fb2100f", + "message": "feat-2-1\n", + "modified": [ + "modify.txt" + ], + "parent_ids": [ + "6168d9dae737b47f00c59fafca10c913a6850c3a" + ], + "removed": [ + ], + "timestamp": "2021-10-08T17:53:12+08:00", + "tree_id": "fdbf4a1239cdef7f81b6a0e76451735a8a27d2c8", + "url": "https://gitee.com/kit101/drone-yml-test/commit/9921e45e570db8e57e544650baf837932fb2100f" + } + ], + "commits_more_than_ten": false, + "compare": "https://gitee.com/kit101/drone-yml-test/compare/6168d9dae737b47f00c59fafca10c913a6850c3a...9921e45e570db8e57e544650baf837932fb2100f", + "created": false, + "deleted": false, + "enterprise": null, + "head_commit": { + "added": [ + ], + "author": { + "email": "qkssk1711@163.com", + "id": 1535738, + "name": "kit101", + "remark": null, + "time": "2021-10-08T17:53:12+08:00", + "url": "https://gitee.com/kit101", + "user": null, + "user_name": "kit101", + "username": "kit101" + }, + "committer": { + "email": "qkssk1711@163.com", + "id": 1535738, + "name": "kit101", + "remark": null, + "time": null, + "url": "https://gitee.com/kit101", + "user": null, + "user_name": "kit101", + "username": "kit101" + }, + "distinct": true, + "id": "9921e45e570db8e57e544650baf837932fb2100f", + "message": "feat-2-1\n", + "modified": [ + "modify.txt" + ], + "parent_ids": [ + "6168d9dae737b47f00c59fafca10c913a6850c3a" + ], + "removed": [ + ], + "timestamp": "2021-10-08T17:53:12+08:00", + "tree_id": "fdbf4a1239cdef7f81b6a0e76451735a8a27d2c8", + "url": "https://gitee.com/kit101/drone-yml-test/commit/9921e45e570db8e57e544650baf837932fb2100f" + }, + "hook_id": 788005, + "hook_name": "push_hooks", + "hook_url": "https://gitee.com/kit101/drone-yml-test/hooks/788005/edit", + "password": "", + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:53:18+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:53:18+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "push_data": null, + "pusher": { + "email": "qkssk1711@163.com", + "id": 1535738, + "name": "kit101", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "ref": "refs/heads/feat-2-1", + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:53:18+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:53:18+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sender": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "sign": "OyjGt7PDU9xXl5khawx5APOUmODD+SaulKYnS/Nifew=", + "timestamp": "1633686799688", + "total_commits_count": 1, + "user": { + "email": "qkssk1711@163.com", + "id": 1535738, + "name": "kit101", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "user_id": 1535738, + "user_name": "kit101" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/push.json.golden b/scm/driver/gitee/testdata/webhooks/push.json.golden new file mode 100644 index 000000000..ce613f8d6 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/push.json.golden @@ -0,0 +1,60 @@ +{ + "Ref": "refs/heads/feat-2-1", + "Before": "6168d9dae737b47f00c59fafca10c913a6850c3a", + "After": "9921e45e570db8e57e544650baf837932fb2100f", + "Repo": { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Perm": null, + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-10-08T17:53:18+08:00" + }, + "Commit": { + "Sha": "9921e45e570db8e57e544650baf837932fb2100f", + "Message": "feat-2-1\n", + "Author": { + "Login": "kit101", + "Name": "kit101", + "Email": "qkssk1711@163.com", + "Date": "2021-10-08T17:53:12+08:00" + }, + "Committer": { + "Login": "kit101", + "Name": "kit101", + "Email": "qkssk1711@163.com", + "Date": "2021-10-08T17:53:12+08:00" + }, + "Link": "https://gitee.com/kit101/drone-yml-test/compare/6168d9dae737b47f00c59fafca10c913a6850c3a...9921e45e570db8e57e544650baf837932fb2100f" + }, + "Commits": [ + { + "Sha": "9921e45e570db8e57e544650baf837932fb2100f", + "Message": "feat-2-1\n", + "Link": "https://gitee.com/kit101/drone-yml-test/commit/9921e45e570db8e57e544650baf837932fb2100f", + "Author": { + "Login": "kit101", + "Email": "qkssk1711@163.com", + "Name": "kit101", + "Date": "2021-10-08T17:53:12+08:00" + }, + "Committer": { + "Login": "kit101", + "Email": "qkssk1711@163.com", + "Name": "kit101", + "Date": "2021-10-08T17:53:12+08:00" + } + } + ], + "Sender": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/push_branch_create.json b/scm/driver/gitee/testdata/webhooks/push_branch_create.json new file mode 100644 index 000000000..f6d56f311 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/push_branch_create.json @@ -0,0 +1,189 @@ +{ + "after": "6168d9dae737b47f00c59fafca10c913a6850c3a", + "before": "0000000000000000000000000000000000000000", + "commits": null, + "commits_more_than_ten": true, + "compare": "https://gitee.com/kit101/drone-yml-test/compare/0000000000000000000000000000000000000000...6168d9dae737b47f00c59fafca10c913a6850c3a", + "created": true, + "deleted": false, + "enterprise": null, + "head_commit": { + "added": [ + ], + "author": { + "email": "qkssk1711@163.com", + "id": 1535738, + "name": "kit101", + "remark": null, + "time": "2021-10-08T17:37:47+08:00", + "url": "https://gitee.com/kit101", + "user": null, + "user_name": "kit101", + "username": "kit101" + }, + "committer": { + "email": "qkssk1711@163.com", + "id": 1535738, + "name": "kit101", + "remark": null, + "time": null, + "url": "https://gitee.com/kit101", + "user": null, + "user_name": "kit101", + "username": "kit101" + }, + "distinct": true, + "id": "6168d9dae737b47f00c59fafca10c913a6850c3a", + "message": "feat-2\n", + "modified": [ + "modify.txt" + ], + "parent_ids": [ + "00b76e8abd51ae6a96318b3450944b32995f9158" + ], + "removed": [ + ], + "timestamp": "2021-10-08T17:37:47+08:00", + "tree_id": "59792feaa92f1bc2460eb1fbc0122dd5029ac583", + "url": "https://gitee.com/kit101/drone-yml-test/commit/6168d9dae737b47f00c59fafca10c913a6850c3a" + }, + "hook_id": 788005, + "hook_name": "push_hooks", + "hook_url": "https://gitee.com/kit101/drone-yml-test/hooks/788005/edit", + "password": "", + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:39:43+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:39:44+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "push_data": null, + "pusher": { + "email": "qkssk1711@163.com", + "id": 1535738, + "name": "kit101", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "ref": "refs/heads/feat-2-1", + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:39:43+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:39:44+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sender": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "sign": "5QkJzTgTd5PJ555MAindBUxryzHWESPOMeOz+dIzTFc=", + "timestamp": "1633686089510", + "total_commits_count": 13, + "user": { + "email": "qkssk1711@163.com", + "id": 1535738, + "name": "kit101", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "user_id": 1535738, + "user_name": "kit101" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/push_branch_create.json.golden b/scm/driver/gitee/testdata/webhooks/push_branch_create.json.golden new file mode 100644 index 000000000..3a185c633 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/push_branch_create.json.golden @@ -0,0 +1,41 @@ +{ + "Ref": "refs/heads/feat-2-1", + "Before": "0000000000000000000000000000000000000000", + "After": "6168d9dae737b47f00c59fafca10c913a6850c3a", + "Repo": { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Perm": null, + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-10-08T17:39:44+08:00" + }, + "Commit": { + "Sha": "6168d9dae737b47f00c59fafca10c913a6850c3a", + "Message": "feat-2\n", + "Author": { + "Login": "kit101", + "Name": "kit101", + "Email": "qkssk1711@163.com", + "Date": "2021-10-08T17:37:47+08:00" + }, + "Committer": { + "Login": "kit101", + "Name": "kit101", + "Email": "qkssk1711@163.com", + "Date": "2021-10-08T17:37:47+08:00" + }, + "Link": "https://gitee.com/kit101/drone-yml-test/compare/0000000000000000000000000000000000000000...6168d9dae737b47f00c59fafca10c913a6850c3a" + }, + "Sender": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/push_branch_delete.json b/scm/driver/gitee/testdata/webhooks/push_branch_delete.json new file mode 100644 index 000000000..ed3d5c1f9 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/push_branch_delete.json @@ -0,0 +1,151 @@ +{ + "after": "0000000000000000000000000000000000000000", + "before": "dc8fa2ebe050d63f639c5b834311e96bc2303523", + "commits": [ + ], + "commits_more_than_ten": null, + "compare": "https://gitee.com/kit101/drone-yml-test/compare/dc8fa2ebe050d63f639c5b834311e96bc2303523...0000000000000000000000000000000000000000", + "created": false, + "deleted": true, + "enterprise": null, + "head_commit": null, + "hook_id": 788005, + "hook_name": "push_hooks", + "hook_url": "https://gitee.com/kit101/drone-yml-test/hooks/788005/edit", + "password": "", + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:32:30+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:32:30+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "push_data": null, + "pusher": { + "email": "qkssk1711@163.com", + "id": 1535738, + "name": "kit101", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "ref": "refs/heads/feat-3", + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T17:32:30+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T17:32:30+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sender": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "sign": "l9f7bD44j3IX+WILn5LlyNy8E37v4xP1xB6eaiMGa5A=", + "timestamp": "1633685551787", + "total_commits_count": null, + "user": { + "email": "qkssk1711@163.com", + "id": 1535738, + "name": "kit101", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "user_id": 1535738, + "user_name": "kit101" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/push_branch_delete.json.golden b/scm/driver/gitee/testdata/webhooks/push_branch_delete.json.golden new file mode 100644 index 000000000..1ddc616d3 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/push_branch_delete.json.golden @@ -0,0 +1,28 @@ +{ + "Ref": "refs/heads/feat-3", + "Before": "dc8fa2ebe050d63f639c5b834311e96bc2303523", + "After": "0000000000000000000000000000000000000000", + "Repo": { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Perm": null, + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-10-08T17:32:30+08:00" + }, + "Commit": { + "Sha": "0000000000000000000000000000000000000000", + "Link": "https://gitee.com/kit101/drone-yml-test/compare/dc8fa2ebe050d63f639c5b834311e96bc2303523...0000000000000000000000000000000000000000" + }, + "Sender": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/tag_create.json b/scm/driver/gitee/testdata/webhooks/tag_create.json new file mode 100644 index 000000000..6a3e31511 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/tag_create.json @@ -0,0 +1,189 @@ +{ + "after": "aa9d11518a64dcd0d591a2a4eb35dfb4d91d49d5", + "before": "0000000000000000000000000000000000000000", + "commits": null, + "commits_more_than_ten": null, + "compare": "https://gitee.com/kit101/drone-yml-test/compare/0000000000000000000000000000000000000000...aa9d11518a64dcd0d591a2a4eb35dfb4d91d49d5", + "created": true, + "deleted": false, + "enterprise": null, + "head_commit": { + "added": [ + ], + "author": { + "email": "qkssk1711@163.com", + "id": 1535738, + "name": "kit101", + "remark": null, + "time": "2021-10-08T05:26:59+00:00", + "url": "https://gitee.com/kit101", + "user": null, + "user_name": "kit101", + "username": "kit101" + }, + "committer": { + "email": "noreply@gitee.com", + "id": null, + "name": "Gitee", + "remark": null, + "time": null, + "url": null, + "user": null, + "user_name": null, + "username": null + }, + "distinct": true, + "id": "aa9d11518a64dcd0d591a2a4eb35dfb4d91d49d5", + "message": "update .drone.yml.\n", + "modified": [ + ".drone.yml" + ], + "parent_ids": [ + "c2b3132aaed2dac67923a0bf7c30d8391f99d4a9" + ], + "removed": [ + ], + "timestamp": "2021-10-08T05:26:59+00:00", + "tree_id": "ce6ea40403ba16fa848a190acc5356bdb4ef2025", + "url": "https://gitee.com/kit101/drone-yml-test/commit/aa9d11518a64dcd0d591a2a4eb35dfb4d91d49d5" + }, + "hook_id": 788005, + "hook_name": "tag_push_hooks", + "hook_url": "https://gitee.com/kit101/drone-yml-test/hooks/788005/edit", + "password": "", + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T16:01:12+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T16:01:12+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "push_data": null, + "pusher": { + "email": "qkssk1711@163.com", + "id": 1535738, + "name": "kit101", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "ref": "refs/tags/1.3", + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T16:01:12+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T16:01:12+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sender": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "sign": "EDYOaI5dlyJgaiRE3jAe/fwaqZPNt1kLsRW1HY0p4tA=", + "timestamp": "1633680073933", + "total_commits_count": null, + "user": { + "email": "qkssk1711@163.com", + "id": 1535738, + "name": "kit101", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "user_id": 1535738, + "user_name": "kit101" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/tag_create.json.golden b/scm/driver/gitee/testdata/webhooks/tag_create.json.golden new file mode 100644 index 000000000..acb55e6b8 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/tag_create.json.golden @@ -0,0 +1,25 @@ +{ + "Action": "created", + "Ref": { + "Name": "1.3", + "Sha": "aa9d11518a64dcd0d591a2a4eb35dfb4d91d49d5" + }, + "Repo": { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-10-08T16:01:12+08:00" + }, + "Sender": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/tag_delete.json b/scm/driver/gitee/testdata/webhooks/tag_delete.json new file mode 100644 index 000000000..d3eb43ca8 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/tag_delete.json @@ -0,0 +1,151 @@ +{ + "after": "0000000000000000000000000000000000000000", + "before": "aa9d11518a64dcd0d591a2a4eb35dfb4d91d49d5", + "commits": [ + ], + "commits_more_than_ten": null, + "compare": "https://gitee.com/kit101/drone-yml-test/compare/aa9d11518a64dcd0d591a2a4eb35dfb4d91d49d5...0000000000000000000000000000000000000000", + "created": false, + "deleted": true, + "enterprise": null, + "head_commit": null, + "hook_id": 788005, + "hook_name": "tag_push_hooks", + "hook_url": "https://gitee.com/kit101/drone-yml-test/hooks/788005/edit", + "password": "", + "project": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T16:16:28+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T16:16:28+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "push_data": null, + "pusher": { + "email": "qkssk1711@163.com", + "id": 1535738, + "name": "kit101", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "ref": "refs/tags/1.3", + "repository": { + "clone_url": "https://gitee.com/kit101/drone-yml-test.git", + "created_at": "2021-03-24T11:24:34+08:00", + "default_branch": "master", + "description": "", + "fork": false, + "forks_count": 0, + "full_name": "kit101/drone-yml-test", + "git_http_url": "https://gitee.com/kit101/drone-yml-test.git", + "git_ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "git_svn_url": "svn://gitee.com/kit101/drone-yml-test", + "git_url": "git://gitee.com/kit101/drone-yml-test.git", + "has_issues": true, + "has_pages": false, + "has_wiki": true, + "homepage": "https://gitee.com/kit101/drone-yml-test", + "html_url": "https://gitee.com/kit101/drone-yml-test", + "id": 14836026, + "language": null, + "license": null, + "name": "drone-yml-test", + "name_with_namespace": "kit101/drone-yml-test", + "namespace": "kit101", + "open_issues_count": 2, + "owner": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "path": "drone-yml-test", + "path_with_namespace": "kit101/drone-yml-test", + "private": false, + "pushed_at": "2021-10-08T16:16:28+08:00", + "ssh_url": "git@gitee.com:kit101/drone-yml-test.git", + "stargazers_count": 0, + "svn_url": "svn://gitee.com/kit101/drone-yml-test", + "updated_at": "2021-10-08T16:16:28+08:00", + "url": "https://gitee.com/kit101/drone-yml-test", + "watchers_count": 1 + }, + "sender": { + "avatar_url": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "email": "qkssk1711@163.com", + "html_url": "https://gitee.com/kit101", + "id": 1535738, + "login": "kit101", + "name": "kit101", + "remark": null, + "site_admin": false, + "type": "User", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "sign": "p2XLcddyIKP/Yf7VatUqTj+N1tuHchQ1c7//Lk4KSE8=", + "timestamp": "1633680992245", + "total_commits_count": null, + "user": { + "email": "qkssk1711@163.com", + "id": 1535738, + "name": "kit101", + "url": "https://gitee.com/kit101", + "user_name": "kit101", + "username": "kit101" + }, + "user_id": 1535738, + "user_name": "kit101" +} \ No newline at end of file diff --git a/scm/driver/gitee/testdata/webhooks/tag_delete.json.golden b/scm/driver/gitee/testdata/webhooks/tag_delete.json.golden new file mode 100644 index 000000000..7152c2287 --- /dev/null +++ b/scm/driver/gitee/testdata/webhooks/tag_delete.json.golden @@ -0,0 +1,25 @@ +{ + "Action": "deleted", + "Ref": { + "Name": "1.3", + "Sha": "" + }, + "Repo": { + "ID": "14836026", + "Namespace": "kit101", + "Name": "drone-yml-test", + "Branch": "master", + "Private": false, + "Clone": "https://gitee.com/kit101/drone-yml-test.git", + "CloneSSH": "git@gitee.com:kit101/drone-yml-test.git", + "Link": "https://gitee.com/kit101/drone-yml-test", + "Created": "2021-03-24T11:24:34+08:00", + "Updated": "2021-10-08T16:16:28+08:00" + }, + "Sender": { + "Avatar": "https://portrait.gitee.com/uploads/avatars/user/511/1535738_qkssk1711_1578953939.png", + "Email": "qkssk1711@163.com", + "Login": "kit101", + "Name": "kit101" + } +} \ No newline at end of file diff --git a/scm/driver/gitee/user.go b/scm/driver/gitee/user.go new file mode 100644 index 000000000..3221e15b1 --- /dev/null +++ b/scm/driver/gitee/user.go @@ -0,0 +1,85 @@ +// 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 gitee + +import ( + "context" + "fmt" + "time" + + "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(user) + res, err := s.client.do(ctx, "GET", "user", nil, out) + return convertUser(out), res, err +} + +func (s *userService) FindEmail(ctx context.Context) (string, *scm.Response, error) { + user, res, err := s.Find(ctx) + if err != nil { + return "", nil, err + } + return user.Email, res, err +} + +func (s *userService) FindLogin(ctx context.Context, login string) (*scm.User, *scm.Response, error) { + path := fmt.Sprintf("users/%s", login) + out := new(user) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertUser(out), res, err +} + +func (s *userService) ListEmail(context.Context, scm.ListOptions) ([]*scm.Email, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +type user struct { + ID int `json:"id"` + Login string `json:"login"` + Name string `json:"name"` + AvatarURL string `json:"avatar_url"` + URL string `json:"url"` + HtmlURL string `json:"html_url"` + FollowersURL string `json:"followers_url"` + FollowingURL string `json:"following_url"` + GistsURL string `json:"gists_url"` + StarredURL string `json:"starred_url"` + SubscriptionsURL string `json:"subscriptions_url"` + OrganizationsURL string `json:"organizations_url"` + ReposURL string `json:"repos_url"` + EventsURL string `json:"events_url"` + ReceivedEventsURL string `json:"received_events_url"` + Type string `json:"type"` + Blog string `json:"blog"` + Weibo string `json:"weibo"` + Bio string `json:"bio"` + PublicRepos int `json:"public_repos"` + PublicGists int `json:"public_gists"` + Followers int `json:"followers"` + Following int `json:"following"` + Stared int `json:"stared"` + Watched int `json:"watched"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Email string `json:"email"` + Remark string `json:"remark"` +} + +func convertUser(from *user) *scm.User { + return &scm.User{ + Avatar: from.AvatarURL, + Email: from.Email, + Login: from.Login, + Name: from.Name, + Created: from.CreatedAt, + Updated: from.UpdatedAt, + } +} diff --git a/scm/driver/gitee/user_test.go b/scm/driver/gitee/user_test.go new file mode 100644 index 000000000..dc299ddb3 --- /dev/null +++ b/scm/driver/gitee/user_test.go @@ -0,0 +1,106 @@ +// 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 gitee + +import ( + "context" + "encoding/json" + "io/ioutil" + "os" + "testing" + + "github.com/drone/go-scm/scm" + + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestUserFind(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/user"). + Reply(200). + Type("application/json"). + SetHeader("X-Request-Id", "7cb049dbf1fafae67b4f0aa81ca7e870"). + SetHeader("X-Runtime", "0.040217"). + SetHeader("ETag", "W/\"c50ecf93b72a24474a76423d6d5c338c\""). + File("testdata/user.json") + + client := NewDefault() + got, res, err := client.Users.Find(context.Background()) + if err != nil { + t.Error(err) + return + } + + want := new(scm.User) + raw, _ := ioutil.ReadFile("testdata/user.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)) +} + +func TestUserFindEmail(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/user"). + Reply(200). + Type("application/json"). + SetHeader("X-Request-Id", "7cb049dbf1fafae67b4f0aa81ca7e870"). + SetHeader("X-Runtime", "0.040217"). + SetHeader("ETag", "W/\"c50ecf93b72a24474a76423d6d5c338c\""). + File("testdata/user.json") + + client := NewDefault() + result, res, err := client.Users.FindEmail(context.Background()) + if err != nil { + t.Error(err) + return + } + if got, want := result, "qkssk1711@163.com"; got != want { + t.Errorf("Want user Email %q, got %q", want, got) + } + t.Run("Request", testRequest(res)) + // t.Run("Rate", testRate(res)) +} + +func TestUserFindLogin(t *testing.T) { + defer gock.Off() + + gock.New("https://gitee.com/api/v5"). + Get("/users/kit101"). + Reply(200). + Type("application/json"). + SetHeader("X-Request-Id", "7cb049dbf1fafae67b4f0aa81ca7e870"). + SetHeader("X-Runtime", "0.040217"). + File("testdata/user.json") + + client := NewDefault() + got, res, err := client.Users.FindLogin(context.Background(), "kit101") + if err != nil { + t.Error(err) + } + + want := new(scm.User) + raw, _ := ioutil.ReadFile("testdata/user.json.golden") + json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + json.NewEncoder(os.Stdout).Encode(got) + } + + t.Run("Request", testRequest(res)) + // t.Run("Rate", testRate(res)) +} diff --git a/scm/driver/gitee/util.go b/scm/driver/gitee/util.go new file mode 100644 index 000000000..a5e1f973e --- /dev/null +++ b/scm/driver/gitee/util.go @@ -0,0 +1,75 @@ +// 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 gitee + +import ( + "net/url" + "strconv" + + "github.com/drone/go-scm/scm" +) + +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("per_page", strconv.Itoa(opts.Size)) + } + return params.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("per_page", strconv.Itoa(opts.Size)) + } + if opts.Ref != "" { + params.Set("sha", opts.Ref) + } + 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("per_page", strconv.Itoa(opts.Size)) + } + // state: open, progressing, closed, rejected, all; default: open + if opts.Open && opts.Closed { + params.Set("state", "all") + } else if opts.Closed { + params.Set("state", "closed") + } else if opts.Open { + params.Set("state", "open") + } + 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("per_page", strconv.Itoa(opts.Size)) + } + // state: open, closed, merged, all; default: open + if opts.Open && opts.Closed { + params.Set("state", "all") + } else if opts.Closed { + params.Set("state", "closed") + } else if opts.Open { + params.Set("state", "open") + } + return params.Encode() +} diff --git a/scm/driver/gitee/util_test.go b/scm/driver/gitee/util_test.go new file mode 100644 index 000000000..2846a9bf2 --- /dev/null +++ b/scm/driver/gitee/util_test.go @@ -0,0 +1,94 @@ +// 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 gitee + +import ( + "testing" + + "github.com/drone/go-scm/scm" +) + +func Test_encodeListOptions(t *testing.T) { + opts := scm.ListOptions{ + Page: 10, + Size: 30, + } + want := "page=10&per_page=30" + got := encodeListOptions(opts) + if got != want { + t.Errorf("Want encoded list options %q, got %q", want, got) + } +} + +func Test_encodeCommitListOptions(t *testing.T) { + opts := scm.CommitListOptions{ + Page: 10, + Size: 30, + Ref: "master", + } + want := "page=10&per_page=30&sha=master" + got := encodeCommitListOptions(opts) + if got != want { + t.Errorf("Want encoded commit 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 := "page=10&per_page=30&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 := "page=10&per_page=30&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 := "page=10&per_page=30&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 := "page=10&per_page=30&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/gitee/webhook.go b/scm/driver/gitee/webhook.go new file mode 100644 index 000000000..6866baa54 --- /dev/null +++ b/scm/driver/gitee/webhook.go @@ -0,0 +1,468 @@ +// 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 gitee + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "time" + + "github.com/drone/go-scm/scm" +) + +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-Gitee-Event") { + case "Push Hook": + hook, err = s.parsePushHook(data) + case "Merge Request Hook": + hook, err = s.parseMergeRequestHook(data) + case "Issue Hook": + hook, err = s.parseIssueHook(data) + case "Note Hook": + hook, err = s.parseNoteHook(data) + case "Tag Push Hook": + hook, err = s.parseTagPushHook(data) + default: + return nil, scm.ErrUnknownEvent + } + if err != nil { + return nil, err + } + + key, err := fn(hook) + if err != nil { + return hook, err + } else if key == "" { + return hook, nil + } + + agent := req.Header.Get("User-Agent") + if agent != "git-oschina-hook" { + return hook, &Error{ + Message: "hook's user-agent is not git-oschina-hook", + } + } + timestamp := req.Header.Get("X-Gitee-Timestamp") + signature := req.Header.Get("X-Gitee-Token") + + if !validateSignature(signature, key, timestamp) { + return hook, scm.ErrSignatureInvalid + } + return hook, nil +} + +func (s *webhookService) parsePushHook(data []byte) (scm.Webhook, error) { + dst := new(pushOrTagPushHook) + err := json.Unmarshal(data, dst) + return convertPushHook(dst), err +} + +func (s *webhookService) parseMergeRequestHook(data []byte) (scm.Webhook, error) { + dst := new(mergeRequestHook) + err := json.Unmarshal(data, dst) + return convertPullRequestHook(dst), err +} + +func (s *webhookService) parseIssueHook(data []byte) (scm.Webhook, error) { + dst := new(issueHook) + err := json.Unmarshal(data, dst) + return convertIssueHook(dst), err +} + +func (s *webhookService) parseTagPushHook(data []byte) (scm.Webhook, error) { + dst := new(pushOrTagPushHook) + err := json.Unmarshal(data, dst) + return convertTagPushHook(dst), err +} + +func (s *webhookService) parseNoteHook(data []byte) (scm.Webhook, error) { + dst := new(noteHook) + err := json.Unmarshal(data, dst) + return convertNoteHook(dst), err +} + +// validateSignature +// see https://gitee.com/help/articles/4290#article-header3 +func validateSignature(signature, key, timestamp string) bool { + stringToSign := timestamp + "\n" + key + h := hmac.New(sha256.New, []byte(key)) + h.Write([]byte(stringToSign)) + computedSignature := base64.StdEncoding.EncodeToString(h.Sum(nil)) + return computedSignature == signature +} + +type ( + pushOrTagPushHook struct { + Action string `json:"action"` + HookName string `json:"hook_name"` + Password string `json:"password"` + HookID int `json:"hook_id"` + HookURL string `json:"hook_url"` + Timestamp string `json:"timestamp"` + Sign string `json:"sign"` + Ref string `json:"ref"` + Before string `json:"before"` + After string `json:"after"` + Created bool `json:"created"` + Deleted bool `json:"deleted"` + Compare string `json:"compare"` + Commits []hookCommit `json:"commits"` + HeadCommit hookCommit `json:"head_commit"` + TotalCommitsCount int `json:"total_commits_count"` + CommitsMoreThanTen bool `json:"commits_more_than_ten"` + Repository hookRepository `json:"repository"` + Sender user `json:"sender"` + Enterprise enterprise `json:"enterprise"` + } + mergeRequestHook struct { + Action string `json:"action"` + + Number int `json:"number"` + Title string `json:"title"` + Project hookRepository `json:"project"` + PullRequest pr `json:"pull_request"` + + Iid int `json:"iid"` + ActionDesc string `json:"action_desc"` + Author user `json:"author"` + Body string `json:"body"` + Enterprise enterprise `json:"enterprise"` + Languages []string `json:"languages"` + MergeCommitSha string `json:"merge_commit_sha"` + MergeStatus string `json:"merge_status"` + Password string `json:"password"` + Repository hookRepository `json:"repository"` + Sender user `json:"sender"` + SourceBranch string `json:"source_branch"` + + SourceRepo struct { + Project hookRepository `json:"project"` + Repository hookRepository `json:"repository"` + } `json:"source_repo"` + TargetRepo struct { + Project hookRepository `json:"project"` + Repository hookRepository `json:"repository"` + } `json:"target_repo"` + State string `json:"state"` + TargetBranch string `json:"target_branch"` + TargetUser user `json:"target_user"` + Timestamp string `json:"timestamp"` + UpdatedBy user `json:"updated_by"` + URL string `json:"url"` + } + noteHook struct { + Action string `json:"action"` + HookName string `json:"hook_name"` + Password string `json:"password"` + HookID int `json:"hook_id"` + HookURL string `json:"hook_url"` + Timestamp string `json:"timestamp"` + Sign string `json:"sign"` + Comment hookComment `json:"comment"` + NoteableType string `json:"noteable_type"` + Issue issue `json:"issue"` + PullRequest pr `json:"pull_request"` + Repository hookRepository `json:"repository"` + Sender user `json:"sender"` + Enterprise enterprise `json:"enterprise"` + } + issueHook struct { + Action string `json:"action"` + HookName string `json:"hook_name"` + Password string `json:"password"` + HookID int `json:"hook_id"` + HookURL string `json:"hook_url"` + Timestamp string `json:"timestamp"` + Sign string `json:"sign"` + Issue issue `json:"issue"` + Repository hookRepository `json:"repository"` + Sender user `json:"sender"` + Enterprise enterprise `json:"enterprise"` + } + + hookAuthorOrCommitter struct { + Time time.Time `json:"time"` + Name string `json:"name"` + Email string `json:"email"` + Username string `json:"username"` + UserName string `json:"user_name"` + URL string `json:"url"` + } + hookCommit struct { + ID string `json:"id"` + TreeID string `json:"tree_id"` + Distinct bool `json:"distinct"` + Message string `json:"message"` + Timestamp time.Time `json:"timestamp"` + URL string `json:"url"` + Author hookAuthorOrCommitter `json:"author"` + Committer hookAuthorOrCommitter `json:"committer"` + Added interface{} `json:"added"` + Removed interface{} `json:"removed"` + Modified []string `json:"modified"` + } + hookComment struct { + HtmlURL string `json:"html_url"` + ID int `json:"id"` + Body string `json:"body"` + User user `json:"user"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + } + hookRepository struct { + CloneURL string `json:"clone_url"` + CreatedAt time.Time `json:"created_at"` + DefaultBranch string `json:"default_branch"` + Description string `json:"description"` + Fork bool `json:"fork"` + ForksCount int `json:"forks_count"` + FullName string `json:"full_name"` + GitHttpURL string `json:"git_http_url"` + GitSshURL string `json:"git_ssh_url"` + GitSvnURL string `json:"git_svn_url"` + GitURL string `json:"git_url"` + HasIssues bool `json:"has_issues"` + HasPages bool `json:"has_pages"` + HasWiki bool `json:"has_wiki"` + Homepage string `json:"homepage"` + HtmlURL string `json:"html_url"` + ID int `json:"id"` + Language interface{} `json:"language"` + License interface{} `json:"license"` + Name string `json:"name"` + NameWithNamespace string `json:"name_with_namespace"` + Namespace string `json:"namespace"` + OpenIssuesCount int `json:"open_issues_count"` + Owner user `json:"owner"` + Path string `json:"path"` + PathWithNamespace string `json:"path_with_namespace"` + Private bool `json:"private"` + PushedAt time.Time `json:"pushed_at"` + SSHURL string `json:"ssh_url"` + StargazersCount int `json:"stargazers_count"` + SvnURL string `json:"svn_url"` + UpdatedAt time.Time `json:"updated_at"` + URL string `json:"url"` + WatchersCount int `json:"watchers_count"` + } + enterprise struct { + Name string `json:"name"` + URL string `json:"url"` + } +) + +func convertPushHook(src *pushOrTagPushHook) *scm.PushHook { + var commits []scm.Commit + if &src.Commits != nil { + for _, c := range src.Commits { + commits = append(commits, + scm.Commit{ + Sha: c.ID, + Message: c.Message, + Link: c.URL, + Author: scm.Signature{ + Login: c.Author.Username, + Email: c.Author.Email, + Name: c.Author.Name, + Date: c.Timestamp, + }, + Committer: scm.Signature{ + Login: c.Committer.Username, + Email: c.Committer.Email, + Name: c.Committer.Name, + Date: c.Timestamp, + }, + }) + } + } + + dst := &scm.PushHook{ + Ref: src.Ref, + Repo: *convertHookRepository(&src.Repository), + Before: src.Before, + After: src.After, + Commit: scm.Commit{ + Sha: src.After, + Link: src.Compare, + }, + Sender: *convertUser(&src.Sender), + Commits: commits, + } + if &src.HeadCommit != nil { + dst.Commit.Message = src.HeadCommit.Message + dst.Commit.Author = scm.Signature{ + Login: src.HeadCommit.Author.Username, + Email: src.HeadCommit.Author.Email, + Name: src.HeadCommit.Author.Name, + Date: src.HeadCommit.Timestamp, + } + dst.Commit.Committer = scm.Signature{ + Login: src.HeadCommit.Committer.Username, + Email: src.HeadCommit.Committer.Email, + Name: src.HeadCommit.Committer.Name, + Date: src.HeadCommit.Timestamp, + } + } + return dst +} + +func convertPullRequestHook(src *mergeRequestHook) *scm.PullRequestHook { + dst := &scm.PullRequestHook{ + Repo: *convertHookRepository(&src.Repository), + PullRequest: *convertPullRequest(&src.PullRequest), + Sender: *convertUser(&src.Sender), + } + switch src.Action { + case "update": + if src.ActionDesc == "update_label" { + if len(src.PullRequest.Labels) == 0 { + dst.Action = scm.ActionUnlabel + } else { + dst.Action = scm.ActionLabel + } + } else if src.ActionDesc == "source_branch_changed" { + // Gitee does not provide a synchronize action. + // But when action_desc is 'source_branch_changed', + // what happens is the same as GitHub's synchronize + dst.Action = scm.ActionSync + } + case "open": + dst.Action = scm.ActionOpen + case "close": + dst.Action = scm.ActionClose + case "merge": + dst.Action = scm.ActionMerge + case "test", "tested", "assign", "approved": + dst.Action = scm.ActionUnknown + default: + dst.Action = scm.ActionUnknown + } + return dst +} + +func convertIssueHook(src *issueHook) *scm.IssueHook { + dst := &scm.IssueHook{ + Repo: *convertHookRepository(&src.Repository), + Issue: *convertIssue(&src.Issue), + Sender: *convertUser(&src.Sender), + } + switch src.Action { + case "open": + dst.Action = scm.ActionOpen + case "delete": + dst.Action = scm.ActionClose + case "state_change": + switch src.Issue.State { + case "open", "progressing": + dst.Action = scm.ActionOpen + case "close", "rejected": + dst.Action = scm.ActionClose + } + case "assign": + dst.Action = scm.ActionUpdate + default: + dst.Action = scm.ActionUnknown + } + return dst +} + +func convertTagPushHook(src *pushOrTagPushHook) scm.Webhook { + dst := &scm.TagHook{ + Ref: scm.Reference{ + Name: scm.TrimRef(src.Ref), + Sha: src.HeadCommit.ID, + }, + Repo: *convertHookRepository(&src.Repository), + Sender: *convertUser(&src.Sender), + } + if src.Created { + dst.Action = scm.ActionCreate + } else if src.Deleted { + dst.Action = scm.ActionDelete + dst.Ref.Sha = "" + } else { + dst.Action = scm.ActionUnknown + } + return dst +} + +func convertNoteHook(src *noteHook) scm.Webhook { + convertHookComment := func(comment *hookComment) *scm.Comment { + return &scm.Comment{ + ID: comment.ID, + Body: comment.Body, + Author: *convertUser(&comment.User), + Created: comment.CreatedAt, + Updated: comment.UpdatedAt, + } + } + convertCommentAction := func(src string) (action scm.Action) { + switch src { + case "comment": + return scm.ActionCreate + case "edited": + return scm.ActionEdit + case "deleted": + return scm.ActionDelete + default: + return scm.ActionUnknown + } + } + + if src.NoteableType == "Issue" { + return &scm.IssueCommentHook{ + Action: convertCommentAction(src.Action), + Repo: *convertHookRepository(&src.Repository), + Issue: *convertIssue(&src.Issue), + Comment: *convertHookComment(&src.Comment), + Sender: *convertUser(&src.Sender), + } + } + + if src.NoteableType == "PullRequest" { + // not support review comment + return &scm.PullRequestCommentHook{ + Action: convertCommentAction(src.Action), + Repo: *convertHookRepository(&src.Repository), + PullRequest: *convertPullRequest(&src.PullRequest), + Comment: *convertHookComment(&src.Comment), + Sender: *convertUser(&src.Sender), + } + } + return nil +} + +func convertHookRepository(from *hookRepository) *scm.Repository { + return &scm.Repository{ + ID: fmt.Sprint(from.ID), + Namespace: from.Namespace, + Name: from.Name, + Branch: from.DefaultBranch, + Private: from.Private, + Clone: from.CloneURL, + CloneSSH: from.GitSshURL, + Link: from.HtmlURL, + Created: from.CreatedAt, + Updated: from.UpdatedAt, + } +} diff --git a/scm/driver/gitee/webhook_test.go b/scm/driver/gitee/webhook_test.go new file mode 100644 index 000000000..9cb013db3 --- /dev/null +++ b/scm/driver/gitee/webhook_test.go @@ -0,0 +1,265 @@ +// 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 gitee + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "net/http" + "strings" + "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{} + }{ + // + // Push Hook events + // + + // Push Hook + { + event: "Push Hook", + before: "testdata/webhooks/push.json", + after: "testdata/webhooks/push.json.golden", + obj: new(scm.PushHook), + }, + // Push Hook create + { + event: "Push Hook", + before: "testdata/webhooks/push_branch_create.json", + after: "testdata/webhooks/push_branch_create.json.golden", + obj: new(scm.PushHook), + }, + // Push Hook delete + { + event: "Push Hook", + before: "testdata/webhooks/push_branch_delete.json", + after: "testdata/webhooks/push_branch_delete.json.golden", + obj: new(scm.PushHook), + }, + + // + // Push Tag Hook events + // + + // Push Tag Hook create + { + event: "Tag Push Hook", + before: "testdata/webhooks/tag_create.json", + after: "testdata/webhooks/tag_create.json.golden", + obj: new(scm.TagHook), + }, + // Push Tag Hook delete + { + event: "Tag Push Hook", + before: "testdata/webhooks/tag_delete.json", + after: "testdata/webhooks/tag_delete.json.golden", + obj: new(scm.TagHook), + }, + + // + // Merge Request Hook events + // + + // Merge Request Hook merge + { + event: "Merge Request Hook", + before: "testdata/webhooks/pr_merge.json", + after: "testdata/webhooks/pr_merge.json.golden", + obj: new(scm.PullRequestHook), + }, + // Merge Request Hook open + { + event: "Merge Request Hook", + before: "testdata/webhooks/pr_open.json", + after: "testdata/webhooks/pr_open.json.golden", + obj: new(scm.PullRequestHook), + }, + // Merge Request Hook close + { + event: "Merge Request Hook", + before: "testdata/webhooks/pr_close.json", + after: "testdata/webhooks/pr_close.json.golden", + obj: new(scm.PullRequestHook), + }, + // pull request update + { + event: "Merge Request Hook", + before: "testdata/webhooks/pr_update.json", + after: "testdata/webhooks/pr_update.json.golden", + obj: new(scm.PullRequestHook), + }, + // Merge Request Hook labeled + { + event: "Merge Request Hook", + before: "testdata/webhooks/pr_labeled.json", + after: "testdata/webhooks/pr_labeled.json.golden", + obj: new(scm.PullRequestHook), + }, + // Merge Request Hook unlabeled + { + event: "Merge Request Hook", + before: "testdata/webhooks/pr_unlabeled.json", + after: "testdata/webhooks/pr_unlabeled.json.golden", + obj: new(scm.PullRequestHook), + }, + + // + // Issue Hook events + // + + // Issue Hook open + { + event: "Issue Hook", + before: "testdata/webhooks/issue_hook_open.json", + after: "testdata/webhooks/issue_hook_open.json.golden", + obj: new(scm.IssueHook), + }, + // Issue Hook delete + { + event: "Issue Hook", + before: "testdata/webhooks/issue_hook_delete.json", + after: "testdata/webhooks/issue_hook_delete.json.golden", + obj: new(scm.IssueHook), + }, + // Issue Hook state_change + { + event: "Issue Hook", + before: "testdata/webhooks/issue_hook_state_change.json", + after: "testdata/webhooks/issue_hook_state_change.json.golden", + obj: new(scm.IssueHook), + }, + // Issue Hook assign + { + event: "Issue Hook", + before: "testdata/webhooks/issue_hook_assign.json", + after: "testdata/webhooks/issue_hook_assign.json.golden", + obj: new(scm.IssueHook), + }, + + // + // Note Hook events + // + + // Note Hook issue comment + { + event: "Note Hook", + before: "testdata/webhooks/note_hook_issue_comment.json", + after: "testdata/webhooks/note_hook_issue_comment.json.golden", + obj: new(scm.IssueCommentHook), + }, + // Note Hook pull request comment + { + event: "Note Hook", + before: "testdata/webhooks/note_hook_pr_comment.json", + after: "testdata/webhooks/note_hook_pr_comment.json.golden", + obj: new(scm.PullRequestCommentHook), + }, + } + + 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-Gitee-Event", test.event) + r.Header.Set("X-Gitee-Token", "Xvh4YPVe6l31XpDRL9J2yeaEXabsckIoUUschpXiVck=") + r.Header.Set("X-Gitee-Timestamp", "1633679083918") + r.Header.Set("User-Agent", "git-oschina-hook") + + 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) + } + + switch event := o.(type) { + case *scm.PushHook: + if !strings.HasPrefix(event.Ref, "refs/") { + t.Errorf("Push hook reference must start with refs/") + } + case *scm.TagHook: + if strings.HasPrefix(event.Ref.Name, "refs/") { + t.Errorf("Branch hook reference must not start with refs/") + } + } + } +} + +func TestWebhook_ErrUnknownEvent(t *testing.T) { + f, _ := ioutil.ReadFile("testdata/webhooks/push.json") + r, _ := http.NewRequest("GET", "/", bytes.NewBuffer(f)) + + s := new(webhookService) + _, err := s.Parse(r, secretFunc) + if err != scm.ErrUnknownEvent { + t.Errorf("Expect unknown event error, got %v", err) + } +} + +func TestWebhookInvalid(t *testing.T) { + f, _ := ioutil.ReadFile("testdata/webhooks/push.json") + r, _ := http.NewRequest("GET", "/", bytes.NewBuffer(f)) + r.Header.Set("X-Gitee-Event", "Push Hook") + r.Header.Set("X-Gitee-Token", "Xvh4YPVe6l31XpDRL9J2yeaEXabsckIoUUschpXiVck=") + r.Header.Set("X-Gitee-Timestamp", "1633679083917") + r.Header.Set("User-Agent", "git-oschina-hook") + + s := new(webhookService) + _, err := s.Parse(r, secretFunc) + if err != scm.ErrSignatureInvalid { + t.Errorf("Expect invalid signature error, got %v", err) + } +} + +func TestWebhookValid(t *testing.T) { + f, _ := ioutil.ReadFile("testdata/webhooks/push.json") + r, _ := http.NewRequest("GET", "/", bytes.NewBuffer(f)) + r.Header.Set("X-Gitee-Event", "Push Hook") + r.Header.Set("X-Gitee-Token", "Xvh4YPVe6l31XpDRL9J2yeaEXabsckIoUUschpXiVck=") + r.Header.Set("X-Gitee-Timestamp", "1633679083918") + r.Header.Set("User-Agent", "git-oschina-hook") + + s := new(webhookService) + _, err := s.Parse(r, secretFunc) + if err != nil { + t.Errorf("Expect valid signature, got %v", err) + } +} + +func secretFunc(scm.Webhook) (string, error) { + return "bBg5lrt03VixkX85CNqYIcecC0SIGASE", nil +} diff --git a/scm/driver/github/content.go b/scm/driver/github/content.go index 16ae4b506..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,14 +18,16 @@ 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) return &scm.Content{ - Hash: out.Sha, Path: out.Path, Data: raw, + // NB the sha returned for github rest api is the blob sha, not the commit sha + BlobID: out.Sha, }, res, err } @@ -34,7 +37,6 @@ func (s *contentService) Create(ctx context.Context, repo, path string, params * Message: params.Message, Branch: params.Branch, Content: params.Data, - Sha: params.Sha, Committer: commitAuthor{ Name: params.Signature.Name, Email: params.Signature.Email, @@ -55,7 +57,8 @@ func (s *contentService) Update(ctx context.Context, repo, path string, params * Message: params.Message, Branch: params.Branch, Content: params.Data, - Sha: params.Sha, + // NB the sha passed to github rest api is the blob sha, not the commit sha + Sha: params.BlobID, Committer: commitAuthor{ Name: params.Signature.Name, Email: params.Signature.Email, @@ -69,8 +72,24 @@ func (s *contentService) Update(ctx context.Context, repo, path string, params * return res, err } -func (s *contentService) Delete(ctx context.Context, repo, path, ref string) (*scm.Response, error) { - return nil, scm.ErrNotSupported +func (s *contentService) Delete(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { + endpoint := fmt.Sprintf("repos/%s/contents/%s", repo, path) + in := &contentCreateUpdate{ + Message: params.Message, + Branch: params.Branch, + // NB the sha passed to github rest api is the blob sha, not the commit sha + Sha: params.BlobID, + Committer: commitAuthor{ + Name: params.Signature.Name, + Email: params.Signature.Email, + }, + Author: commitAuthor{ + Name: params.Signature.Name, + Email: params.Signature.Email, + }, + } + res, err := s.client.do(ctx, "DELETE", endpoint, in, nil) + return res, err } func (s *contentService) List(ctx context.Context, repo, path, ref string, _ scm.ListOptions) ([]*scm.ContentInfo, *scm.Response, error) { @@ -111,7 +130,9 @@ func convertContentInfoList(from []*content) []*scm.ContentInfo { } func convertContentInfo(from *content) *scm.ContentInfo { - to := &scm.ContentInfo{Path: from.Path} + to := &scm.ContentInfo{ + Path: from.Path, + BlobID: from.Sha} switch from.Type { case "file": to.Kind = scm.ContentKindFile diff --git a/scm/driver/github/content_test.go b/scm/driver/github/content_test.go index 5187c713f..c1e8d4110 100644 --- a/scm/driver/github/content_test.go +++ b/scm/driver/github/content_test.go @@ -40,7 +40,36 @@ func TestContentFind(t *testing.T) { want := new(scm.Content) raw, _ := ioutil.ReadFile("testdata/content.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + 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") @@ -101,7 +130,7 @@ func TestContentUpdate(t *testing.T) { params := &scm.ContentParams{ Message: "a new commit message", Data: []byte("bXkgdXBkYXRlZCBmaWxlIGNvbnRlbnRz"), - Sha: "95b966ae1c166bd92f8ae7d1c313e738c731dfc3", + BlobID: "95b966ae1c166bd92f8ae7d1c313e738c731dfc3", Signature: scm.Signature{ Name: "Monalisa Octocat", Email: "octocat@github.com", @@ -109,7 +138,7 @@ func TestContentUpdate(t *testing.T) { } client := NewDefault() - res, err := client.Contents.Create( + res, err := client.Contents.Update( context.Background(), "octocat/hello-world", "test/hello", @@ -126,11 +155,72 @@ func TestContentUpdate(t *testing.T) { } } +func TestContentUpdateBadBlobID(t *testing.T) { + defer gock.Off() + + gock.New("https://api.github.com"). + Put("/repos/octocat/hello-world/contents/test/hello"). + Reply(401). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/content_update.json.fail") + + params := &scm.ContentParams{ + Message: "a new commit message", + Data: []byte("bXkgdXBkYXRlZCBmaWxlIGNvbnRlbnRz"), + BlobID: "95b966ae1c166bd92f8ae7d1c313e738c731dfc3", + Signature: scm.Signature{ + Name: "Monalisa Octocat", + Email: "octocat@github.com", + }, + } + + client := NewDefault() + _, err := client.Contents.Update( + context.Background(), + "octocat/hello-world", + "test/hello", + params, + ) + if err.Error() != "newfile does not match" { + t.Errorf("Expecting 'newfile does not match'") + } +} + func TestContentDelete(t *testing.T) { - content := new(contentService) - _, err := content.Delete(context.Background(), "octocat/hello-world", "README", "master") - if err != scm.ErrNotSupported { - t.Errorf("Expect Not Supported error") + defer gock.Off() + + gock.New("https://api.github.com"). + Delete("/repos/octocat/hello-world/contents/test/hello"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/content_delete.json") + + params := &scm.ContentParams{ + Message: "a new commit message", + BlobID: "95b966ae1c166bd92f8ae7d1c313e738c731dfc3", + Signature: scm.Signature{ + Name: "Monalisa Octocat", + Email: "octocat@github.com", + }, + } + + client := NewDefault() + res, err := client.Contents.Delete( + context.Background(), + "octocat/hello-world", + "test/hello", + params, + ) + + if err != nil { + t.Error(err) + return + } + + if res.Status != 200 { + t.Errorf("Unexpected Results") } } @@ -160,7 +250,7 @@ func TestContentList(t *testing.T) { want := []*scm.ContentInfo{} raw, _ := ioutil.ReadFile("testdata/content_list.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") diff --git a/scm/driver/github/git.go b/scm/driver/github/git.go index 79cd8b450..11edba432 100644 --- a/scm/driver/github/git.go +++ b/scm/driver/github/git.go @@ -16,6 +16,15 @@ type gitService struct { client *wrapper } +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"), + Sha: params.Sha, + } + return s.client.do(ctx, "POST", path, in, nil) +} + func (s *gitService) FindBranch(ctx context.Context, repo, name string) (*scm.Reference, *scm.Response, error) { path := fmt.Sprintf("repos/%s/branches/%s", repo, name) out := new(branch) @@ -44,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{} @@ -52,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) { @@ -72,6 +87,11 @@ func (s *gitService) CompareChanges(ctx context.Context, repo, source, target st return convertChangeList(out.Files), res, err } +type createBranch struct { + Ref string `json:"ref"` + Sha string `json:"sha"` +} + type branch struct { Name string `json:"name"` Commit commit `json:"commit"` @@ -171,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 6e8a3707b..8d1ff4c5c 100644 --- a/scm/driver/github/git_test.go +++ b/scm/driver/github/git_test.go @@ -35,7 +35,7 @@ func TestGitFindCommit(t *testing.T) { want := new(scm.Commit) raw, _ := ioutil.ReadFile("testdata/commit.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -65,7 +65,7 @@ func TestGitFindBranch(t *testing.T) { want := new(scm.Reference) raw, _ := ioutil.ReadFile("testdata/branch.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -95,7 +95,7 @@ func TestGitFindTag(t *testing.T) { want := new(scm.Reference) raw, _ := ioutil.ReadFile("testdata/tag.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -106,6 +106,38 @@ func TestGitFindTag(t *testing.T) { t.Run("Rate", testRate(res)) } +func TestGitCreateBranch(t *testing.T) { + defer gock.Off() + + gock.New("https://api.github.com"). + Post("/repos/octocat/hello-world/git/refs"). + Reply(201). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/branch_create.json") + + params := &scm.ReferenceInput{ + Name: "Hello", + Sha: "312797ba52425353dec56871a255e2a36fc96344", + } + + client := NewDefault() + res, err := client.Git.CreateBranch( + context.Background(), + "octocat/hello-world", + params, + ) + + if err != nil { + t.Error(err) + return + } + + if res.Status != 201 { + t.Errorf("Unexpected Results") + } +} + func TestGitListCommits(t *testing.T) { defer gock.Off() @@ -113,7 +145,7 @@ func TestGitListCommits(t *testing.T) { Get("/repos/octocat/hello-world/commits"). MatchParam("page", "1"). MatchParam("per_page", "30"). - MatchParam("ref", "master"). + MatchParam("sha", "master"). Reply(200). Type("application/json"). SetHeaders(mockHeaders). @@ -129,7 +161,7 @@ func TestGitListCommits(t *testing.T) { want := []*scm.Commit{} raw, _ := ioutil.ReadFile("testdata/commits.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -163,7 +195,7 @@ func TestGitListBranches(t *testing.T) { want := []*scm.Reference{} raw, _ := ioutil.ReadFile("testdata/branches.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -179,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). @@ -197,7 +229,7 @@ func TestGitListTags(t *testing.T) { want := []*scm.Reference{} raw, _ := ioutil.ReadFile("testdata/tags.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -228,7 +260,7 @@ func TestGitListChanges(t *testing.T) { want := []*scm.Change{} raw, _ := ioutil.ReadFile("testdata/changes.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -258,7 +290,7 @@ func TestGitCompareChanges(t *testing.T) { want := []*scm.Change{} raw, _ := ioutil.ReadFile("testdata/compare.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") diff --git a/scm/driver/github/github.go b/scm/driver/github/github.go index 82f315112..8464b3e2f 100644 --- a/scm/driver/github/github.go +++ b/scm/driver/github/github.go @@ -38,9 +38,11 @@ func New(uri string) (*scm.Client, error) { client.Contents = &contentService{client} client.Git = &gitService{client} client.Issues = &issueService{client} + client.Milestones = &milestoneService{client} client.Organizations = &organizationService{client} client.PullRequests = &pullService{&issueService{client}} client.Repositories = &RepositoryService{client} + client.Releases = &releaseService{client} client.Reviews = &reviewService{client} client.Users = &userService{client} client.Webhooks = &webhookService{client} diff --git a/scm/driver/github/integration/git_test.go b/scm/driver/github/integration/git_test.go index c6192cc91..2915ad2f8 100644 --- a/scm/driver/github/integration/git_test.go +++ b/scm/driver/github/integration/git_test.go @@ -114,7 +114,8 @@ func testCommits(client *scm.Client) func(t *testing.T) { return func(t *testing.T) { t.Parallel() t.Run("Find", testCommitFind(client)) - t.Run("List", testCommitList(client)) + t.Run("List-Default-Branch", testCommitListDefaultBranch(client)) + t.Run("List-Non-Default-Branch", testCommitListNonDefaultBranch(client)) } } @@ -130,7 +131,7 @@ func testCommitFind(client *scm.Client) func(t *testing.T) { } } -func testCommitList(client *scm.Client) func(t *testing.T) { +func testCommitListDefaultBranch(client *scm.Client) func(t *testing.T) { return func(t *testing.T) { t.Parallel() opts := scm.CommitListOptions{ @@ -152,6 +153,33 @@ func testCommitList(client *scm.Client) func(t *testing.T) { } } +func testCommitListNonDefaultBranch(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + opts := scm.CommitListOptions{ + Ref: "octocat-patch-1", + } + result, _, err := client.Git.ListCommits(context.Background(), "octocat/Hello-World", opts) + if err != nil { + t.Error(err) + return + } + if len(result) == 0 { + t.Errorf("Want a non-empty commit list") + } + + if got, want := result[0].Sha, "b1b3f9723831141a31a1a7252a213e216ea76e56"; got != want { + t.Errorf("Want commit Sha %q, got %q", want, got) + } + + for _, commit := range result { + if commit.Sha == "7fd1a60b01f91b314f59955a4e4d4e80d8edf11d" { + t.Run("Commit", testCommit(commit)) + } + } + } +} + // // struct sub-tests // diff --git a/scm/driver/github/integration/issue_test.go b/scm/driver/github/integration/issue_test.go index 3b28d3aee..5ed080102 100644 --- a/scm/driver/github/integration/issue_test.go +++ b/scm/driver/github/integration/issue_test.go @@ -112,7 +112,7 @@ func testIssue(issue *scm.Issue) func(t *testing.T) { if got, want := issue.Author.Login, "octocat"; got != want { t.Errorf("Want issue Author Login %q, got %q", want, got) } - if got, want := issue.Author.Avatar, "https://avatars3.githubusercontent.com/u/583231?v=4"; got != want { + if got, want := issue.Author.Avatar, "https://avatars.githubusercontent.com/u/583231?v=4"; got != want { t.Errorf("Want issue Author Avatar %q, got %q", want, got) } if got, want := issue.Closed, false; got != want { diff --git a/scm/driver/github/integration/org_test.go b/scm/driver/github/integration/org_test.go index 8f72d968d..d58114449 100644 --- a/scm/driver/github/integration/org_test.go +++ b/scm/driver/github/integration/org_test.go @@ -44,7 +44,7 @@ func testOrg(organization *scm.Organization) func(t *testing.T) { if got, want := organization.Name, "github"; got != want { t.Errorf("Want organization Name %q, got %q", want, got) } - if got, want := organization.Avatar, "https://avatars1.githubusercontent.com/u/9919?v=4"; got != want { + if got, want := organization.Avatar, "https://avatars.githubusercontent.com/u/9919?v=4"; got != want { t.Errorf("Want organization Avatar %q, got %q", want, got) } } diff --git a/scm/driver/github/integration/pr_test.go b/scm/driver/github/integration/pr_test.go index c4ec31cbf..293aa4c33 100644 --- a/scm/driver/github/integration/pr_test.go +++ b/scm/driver/github/integration/pr_test.go @@ -22,6 +22,7 @@ func testPullRequests(client *scm.Client) func(t *testing.T) { t.Run("Find", testPullRequestFind(client)) t.Run("Changes", testPullRequestChanges(client)) t.Run("Comments", testPullRequestComments(client)) + t.Run("Commits", testPullRequestCommits(client)) } } @@ -120,6 +121,26 @@ func testPullRequestChanges(client *scm.Client) func(t *testing.T) { } } +// +// pull request commits sub-tests +// + +func testPullRequestCommits(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + opts := scm.ListOptions{} + result, _, err := client.PullRequests.ListCommits(context.Background(), "octocat/Hello-World", 140, opts) + if err != nil { + t.Error(err) + } + if len(result) == 0 { + t.Errorf("Got empty pull request change list") + return + } + t.Run("Commit", testPullRequestCommit(result[0])) + } +} + // // struct sub-tests // @@ -147,13 +168,13 @@ func testPullRequest(pr *scm.PullRequest) func(t *testing.T) { if got, want := pr.Sha, "b3cbd5bbd7e81436d2eee04537ea2b4c0cad4cdf"; got != want { t.Errorf("Want pr Sha %q, got %q", want, got) } - if got, want := pr.Link, "https://github.com/octocat/Hello-World/pull/140.diff"; got != want { + if got, want := pr.Link, "https://github.com/octocat/Hello-World/pull/140"; got != want { t.Errorf("Want pr Link %q, got %q", want, got) } if got, want := pr.Author.Login, "octocat"; got != want { t.Errorf("Want pr Author Login %q, got %q", want, got) } - if got, want := pr.Author.Avatar, "https://avatars3.githubusercontent.com/u/583231?v=4"; got != want { + if got, want := pr.Author.Avatar, "https://avatars.githubusercontent.com/u/583231?v=4"; got != want { t.Errorf("Want pr Author Avatar %q, got %q", want, got) } if got, want := pr.Closed, true; got != want { @@ -210,3 +231,32 @@ func testChange(change *scm.Change) func(t *testing.T) { } } } + +func testPullRequestCommit(commit *scm.Commit) func(t *testing.T) { + return func(t *testing.T) { + if got, want := commit.Message, "Create CONTRIBUTING.md"; got != want { + t.Errorf("Want commit Message %q, got %q", want, got) + } + if got, want := commit.Sha, "b3cbd5bbd7e81436d2eee04537ea2b4c0cad4cdf"; got != want { + t.Errorf("Want commit Sha %q, got %q", want, got) + } + if got, want := commit.Author.Name, "The Octocat"; got != want { + t.Errorf("Want commit author Name %q, got %q", want, got) + } + if got, want := commit.Author.Email, "octocat@nowhere.com"; got != want { + t.Errorf("Want commit author Email %q, got %q", want, got) + } + if got, want := commit.Author.Date.Unix(), int64(1402438946); got != want { + t.Errorf("Want commit author Date %d, got %d", want, got) + } + if got, want := commit.Committer.Name, "The Octocat"; got != want { + t.Errorf("Want commit author Name %q, got %q", want, got) + } + if got, want := commit.Committer.Email, "octocat@nowhere.com"; got != want { + t.Errorf("Want commit author Email %q, got %q", want, got) + } + if got, want := commit.Committer.Date.Unix(), int64(1402438946); got != want { + t.Errorf("Want commit author Date %d, got %d", want, got) + } + } +} diff --git a/scm/driver/github/integration/user_test.go b/scm/driver/github/integration/user_test.go index 0a5b77770..a290b22c6 100644 --- a/scm/driver/github/integration/user_test.go +++ b/scm/driver/github/integration/user_test.go @@ -47,7 +47,7 @@ func testUser(user *scm.User) func(t *testing.T) { if got, want := user.Name, "The Octocat"; got != want { t.Errorf("Want user Name %q, got %q", want, got) } - if got, want := user.Avatar, "https://avatars3.githubusercontent.com/u/583231?v=4"; got != want { + if got, want := user.Avatar, "https://avatars.githubusercontent.com/u/583231?v=4"; got != want { t.Errorf("Want user Avatar %q, got %q", want, got) } } diff --git a/scm/driver/github/issue_test.go b/scm/driver/github/issue_test.go index d6ff16f2e..af44e9bbd 100644 --- a/scm/driver/github/issue_test.go +++ b/scm/driver/github/issue_test.go @@ -35,7 +35,7 @@ func TestIssueFind(t *testing.T) { want := new(scm.Issue) raw, _ := ioutil.ReadFile("testdata/issue.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -65,7 +65,7 @@ func TestIssueCommentFind(t *testing.T) { want := new(scm.Comment) raw, _ := ioutil.ReadFile("testdata/issue_comment.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -99,7 +99,7 @@ func TestIssueList(t *testing.T) { want := []*scm.Issue{} raw, _ := ioutil.ReadFile("testdata/issues.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -133,7 +133,7 @@ func TestIssueListComments(t *testing.T) { want := []*scm.Comment{} raw, _ := ioutil.ReadFile("testdata/issue_comments.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -169,7 +169,7 @@ func TestIssueCreate(t *testing.T) { want := new(scm.Issue) raw, _ := ioutil.ReadFile("testdata/issue.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -203,7 +203,7 @@ func TestIssueCreateComment(t *testing.T) { want := new(scm.Comment) raw, _ := ioutil.ReadFile("testdata/issue_comment.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") diff --git a/scm/driver/github/milestone.go b/scm/driver/github/milestone.go new file mode 100644 index 000000000..2ff382138 --- /dev/null +++ b/scm/driver/github/milestone.go @@ -0,0 +1,111 @@ +package github + +import ( + "context" + "fmt" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/internal/null" +) + +type milestoneService struct { + client *wrapper +} + +type milestone struct { + ID int `json:"id"` + Number int `json:"number"` + Title string `json:"title"` + Description string `json:"description"` + State string `json:"state"` + DueOn null.Time `json:"due_on"` + URL string `json:"url"` + HTMLURL string `json:"html_url"` + LabelsURL string `json:"labels_url"` + Creator user `json:"creator"` + OpenIssues int `json:"open_issues"` + ClosedIssues int `json:"closed_issues"` + NodeID string `json:"node_id"` + CreatedAt null.Time `json:"created_at"` + UpdatedAt null.Time `json:"updated_at"` + ClosedAt null.Time `json:"closed_at"` +} + +type milestoneInput struct { + Title string `json:"title"` + State string `json:"state"` + Description string `json:"description"` + DueOn null.Time `json:"due_on"` +} + +func (s *milestoneService) Find(ctx context.Context, repo string, id int) (*scm.Milestone, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/milestones/%d", repo, id) + out := new(milestone) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertMilestone(out), res, err +} + +func (s *milestoneService) List(ctx context.Context, repo string, opts scm.MilestoneListOptions) ([]*scm.Milestone, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/milestones?%s", repo, encodeMilestoneListOptions(opts)) + out := []*milestone{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertMilestoneList(out), res, err +} + +func (s *milestoneService) Create(ctx context.Context, repo string, input *scm.MilestoneInput) (*scm.Milestone, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/milestones", repo) + in := &milestoneInput{ + Title: input.Title, + State: input.State, + Description: input.Description, + DueOn: null.TimeFrom(input.DueDate), + } + out := new(milestone) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertMilestone(out), res, err +} + +func (s *milestoneService) Delete(ctx context.Context, repo string, id int) (*scm.Response, error) { + path := fmt.Sprintf("repos/%s/milestones/%d", repo, id) + return s.client.do(ctx, "DELETE", path, nil, nil) +} + +func (s *milestoneService) Update(ctx context.Context, repo string, id int, input *scm.MilestoneInput) (*scm.Milestone, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/milestones/%d", repo, id) + in := &milestoneInput{} + if input.Title != "" { + in.Title = input.Title + } + if input.State != "" { + in.State = input.State + } + if input.Description != "" { + in.Description = input.Description + } + if !input.DueDate.IsZero() { + in.DueOn = null.TimeFrom(input.DueDate) + } + out := new(milestone) + res, err := s.client.do(ctx, "PATCH", path, in, out) + return convertMilestone(out), res, err +} + +func convertMilestoneList(from []*milestone) []*scm.Milestone { + var to []*scm.Milestone + for _, m := range from { + to = append(to, convertMilestone(m)) + } + return to +} + +func convertMilestone(src *milestone) *scm.Milestone { + return &scm.Milestone{ + Number: src.Number, + ID: src.ID, + Title: src.Title, + Description: src.Description, + Link: src.HTMLURL, + State: src.State, + DueDate: src.DueOn.ValueOrZero(), + } +} diff --git a/scm/driver/github/milestone_test.go b/scm/driver/github/milestone_test.go new file mode 100644 index 000000000..0d9c72d7a --- /dev/null +++ b/scm/driver/github/milestone_test.go @@ -0,0 +1,186 @@ +package github + +import ( + "context" + "encoding/json" + "io/ioutil" + "testing" + "time" + + "github.com/drone/go-scm/scm" + + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestMilestoneFind(t *testing.T) { + defer gock.Off() + + gock.New("https://api.github.com"). + Get("/repos/octocat/hello-world/milestones/1"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/milestone.json") + + client := NewDefault() + got, res, err := client.Milestones.Find(context.Background(), "octocat/hello-world", 1) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Milestone) + raw, _ := ioutil.ReadFile("testdata/milestone.json.golden") + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} + +func TestMilestoneList(t *testing.T) { + defer gock.Off() + + gock.New("https://api.github.com"). + Get("/repos/octocat/hello-world/milestones"). + MatchParam("page", "1"). + MatchParam("per_page", "30"). + MatchParam("state", "all"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/milestones.json") + client := NewDefault() + got, res, err := client.Milestones.List(context.Background(), "octocat/hello-world", scm.MilestoneListOptions{Page: 1, Size: 30, Open: true, Closed: true}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Milestone{} + raw, _ := ioutil.ReadFile("testdata/milestones.json.golden") + err = json.Unmarshal(raw, &want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} + +func TestMilestoneCreate(t *testing.T) { + defer gock.Off() + + gock.New("https://api.github.com"). + Post("/repos/octocat/hello-world/milestones"). + File("testdata/milestone_create.json"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/milestone.json") + + client := NewDefault() + dueDate, _ := time.Parse(scm.SearchTimeFormat, "2012-10-09T23:39:01Z") + input := &scm.MilestoneInput{ + Title: "v1.0", + Description: "Tracking milestone for version 1.0", + State: "open", + DueDate: dueDate, + } + + got, res, err := client.Milestones.Create(context.Background(), "octocat/hello-world", input) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Milestone) + raw, _ := ioutil.ReadFile("testdata/milestone.json.golden") + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} + +func TestMilestoneUpdate(t *testing.T) { + defer gock.Off() + + gock.New("https://api.github.com"). + Patch("/repos/octocat/hello-world/milestones/1"). + File("testdata/milestone_create.json"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/milestone.json") + + client := NewDefault() + dueDate, _ := time.Parse(scm.SearchTimeFormat, "2012-10-09T23:39:01Z") + input := &scm.MilestoneInput{ + Title: "v1.0", + Description: "Tracking milestone for version 1.0", + State: "open", + DueDate: dueDate, + } + + got, res, err := client.Milestones.Update(context.Background(), "octocat/hello-world", 1, input) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Milestone) + raw, _ := ioutil.ReadFile("testdata/milestone.json.golden") + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} + +func TestMilestoneDelete(t *testing.T) { + defer gock.Off() + + gock.New("https://api.github.com"). + Delete("/repos/octocat/hello-world/milestones/1"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders) + + client := NewDefault() + res, err := client.Milestones.Delete(context.Background(), "octocat/hello-world", 1) + if err != nil { + t.Error(err) + return + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} diff --git a/scm/driver/github/org_test.go b/scm/driver/github/org_test.go index b36c00d8e..eaa9b22f4 100644 --- a/scm/driver/github/org_test.go +++ b/scm/driver/github/org_test.go @@ -35,7 +35,7 @@ func TestOrganizationFind(t *testing.T) { want := new(scm.Organization) raw, _ := ioutil.ReadFile("testdata/org.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -65,7 +65,7 @@ func TestOrganizationFindMembership(t *testing.T) { want := new(scm.Membership) raw, _ := ioutil.ReadFile("testdata/membership.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -98,7 +98,7 @@ func TestOrganizationList(t *testing.T) { want := []*scm.Organization{} raw, _ := ioutil.ReadFile("testdata/orgs.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") diff --git a/scm/driver/github/pr.go b/scm/driver/github/pr.go index c3aebf5d2..52e980937 100644 --- a/scm/driver/github/pr.go +++ b/scm/driver/github/pr.go @@ -38,6 +38,13 @@ func (s *pullService) ListChanges(ctx context.Context, repo string, number int, return convertChangeList(out), res, err } +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)) + out := []*commit{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertCommitList(out), res, err +} + func (s *pullService) Merge(ctx context.Context, repo string, number int) (*scm.Response, error) { path := fmt.Sprintf("repos/%s/pulls/%d/merge", repo, number) res, err := s.client.do(ctx, "PUT", path, nil, nil) @@ -69,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 { @@ -111,12 +119,13 @@ type prInput struct { } type file struct { - Sha string `json:"sha"` - Filename string `json:"filename"` - Status string `json:"status"` - Additions int `json:"additions"` - Deletions int `json:"deletions"` - Changes int `json:"changes"` + BlobID string `json:"sha"` + Filename string `json:"filename"` + Status string `json:"status"` + Additions int `json:"additions"` + Deletions int `json:"deletions"` + Changes int `json:"changes"` + PreviousFilename string `json:"previous_filename"` } func convertPullRequestList(from []*pr) []*scm.PullRequest { @@ -146,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{ @@ -178,9 +188,11 @@ func convertChangeList(from []*file) []*scm.Change { func convertChange(from *file) *scm.Change { return &scm.Change{ - Path: from.Filename, - Added: from.Status == "added", - Deleted: from.Status == "deleted", - Renamed: from.Status == "moved", + Path: from.Filename, + Added: from.Status == "added", + Deleted: from.Status == "removed", + Renamed: from.Status == "renamed", + BlobID: from.BlobID, + PrevFilePath: from.PreviousFilename, } } diff --git a/scm/driver/github/pr_test.go b/scm/driver/github/pr_test.go index e239fc3b1..d49d5cef3 100644 --- a/scm/driver/github/pr_test.go +++ b/scm/driver/github/pr_test.go @@ -35,7 +35,7 @@ func TestPullFind(t *testing.T) { want := new(scm.PullRequest) raw, _ := ioutil.ReadFile("testdata/pr.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -69,7 +69,7 @@ func TestPullList(t *testing.T) { want := []*scm.PullRequest{} raw, _ := ioutil.ReadFile("testdata/pulls.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -101,7 +101,7 @@ func TestPullListChanges(t *testing.T) { want := []*scm.Change{} raw, _ := ioutil.ReadFile("testdata/pr_files.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -179,7 +179,7 @@ func TestPullCreate(t *testing.T) { want := new(scm.PullRequest) raw, _ := ioutil.ReadFile("testdata/pr.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -189,3 +189,35 @@ func TestPullCreate(t *testing.T) { t.Run("Request", testRequest(res)) t.Run("rate", testRate(res)) } + +func TestPullListCommits(t *testing.T) { + gock.New("https://api.github.com"). + Get("/repos/octocat/hello-world/pulls/1347/commits"). + MatchParam("page", "1"). + MatchParam("per_page", "30"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/commits.json") + + client := NewDefault() + got, res, err := client.PullRequests.ListCommits(context.Background(), "octocat/hello-world", 1347, scm.ListOptions{Page: 1, Size: 30}) + 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) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) + t.Run("Page", testPage(res)) +} diff --git a/scm/driver/github/release.go b/scm/driver/github/release.go new file mode 100644 index 000000000..afc848c79 --- /dev/null +++ b/scm/driver/github/release.go @@ -0,0 +1,131 @@ +package github + +import ( + "context" + "fmt" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/internal/null" +) + +type releaseService struct { + client *wrapper +} + +type release struct { + ID int `json:"id"` + Title string `json:"name"` + Description string `json:"body"` + Link string `json:"html_url,omitempty"` + Tag string `json:"tag_name,omitempty"` + Commitish string `json:"target_commitish,omitempty"` + Draft bool `json:"draft"` + Prerelease bool `json:"prerelease"` + Created null.Time `json:"created_at"` + Published null.Time `json:"published_at"` +} + +type releaseInput struct { + Title string `json:"name"` + Description string `json:"body"` + Tag string `json:"tag_name"` + Commitish string `json:"target_commitish"` + Draft bool `json:"draft"` + Prerelease bool `json:"prerelease"` +} + +func (s *releaseService) Find(ctx context.Context, repo string, id int) (*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/releases/%d", repo, id) + out := new(release) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertRelease(out), res, err +} + +func (s *releaseService) FindByTag(ctx context.Context, repo string, tag string) (*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/releases/tags/%s", repo, tag) + out := new(release) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertRelease(out), res, err +} + +func (s *releaseService) List(ctx context.Context, repo string, opts scm.ReleaseListOptions) ([]*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/releases?%s", repo, encodeReleaseListOptions(opts)) + out := []*release{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertReleaseList(out), res, err +} + +func (s *releaseService) Create(ctx context.Context, repo string, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/releases", repo) + in := &releaseInput{ + Title: input.Title, + Commitish: input.Commitish, + Description: input.Description, + Draft: input.Draft, + Prerelease: input.Prerelease, + Tag: input.Tag, + } + out := new(release) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertRelease(out), res, err +} + +func (s *releaseService) Delete(ctx context.Context, repo string, id int) (*scm.Response, error) { + path := fmt.Sprintf("repos/%s/releases/%d", repo, id) + return s.client.do(ctx, "DELETE", path, nil, nil) +} + +func (s *releaseService) DeleteByTag(ctx context.Context, repo string, tag string) (*scm.Response, error) { + rel, _, _ := s.FindByTag(ctx, repo, tag) + return s.Delete(ctx, repo, rel.ID) +} + +func (s *releaseService) Update(ctx context.Context, repo string, id int, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("repos/%s/releases/%d", repo, id) + in := &releaseInput{} + if input.Title != "" { + in.Title = input.Title + } + if input.Description != "" { + in.Description = input.Description + } + if input.Commitish != "" { + in.Commitish = input.Commitish + } + if input.Tag != "" { + in.Tag = input.Tag + } + in.Draft = input.Draft + in.Prerelease = input.Prerelease + out := new(release) + res, err := s.client.do(ctx, "PATCH", path, in, out) + return convertRelease(out), res, err +} + +func (s *releaseService) UpdateByTag(ctx context.Context, repo string, tag string, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + rel, _, _ := s.FindByTag(ctx, repo, tag) + return s.Update(ctx, repo, rel.ID, input) +} + +func convertReleaseList(from []*release) []*scm.Release { + var to []*scm.Release + for _, m := range from { + to = append(to, convertRelease(m)) + } + return to +} + +func convertRelease(from *release) *scm.Release { + return &scm.Release{ + ID: from.ID, + Title: from.Title, + Description: from.Description, + Link: from.Link, + Tag: from.Tag, + Commitish: from.Commitish, + Draft: from.Draft, + Prerelease: from.Prerelease, + Created: from.Created.ValueOrZero(), + Published: from.Published.ValueOrZero(), + } +} diff --git a/scm/driver/github/release_test.go b/scm/driver/github/release_test.go new file mode 100644 index 000000000..20ebd2ffb --- /dev/null +++ b/scm/driver/github/release_test.go @@ -0,0 +1,194 @@ +package github + +import ( + "context" + "encoding/json" + "io/ioutil" + "testing" + + "github.com/drone/go-scm/scm" + + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestReleaseFind(t *testing.T) { + defer gock.Off() + + gock.New("https://api.github.com"). + Get("/repos/octocat/hello-world/releases/1"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/release.json") + + client := NewDefault() + got, res, err := client.Releases.Find(context.Background(), "octocat/hello-world", 1) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Release) + raw, _ := ioutil.ReadFile("testdata/release.json.golden") + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + + data, _ := json.Marshal(got) + t.Log("got JSON:") + t.Log(string(data)) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} + +func TestReleaseList(t *testing.T) { + defer gock.Off() + + gock.New("https://api.github.com"). + Get("/repos/octocat/hello-world/releases"). + MatchParam("page", "1"). + MatchParam("per_page", "30"). + MatchParam("state", "all"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/releases.json") + + client := NewDefault() + got, res, err := client.Releases.List(context.Background(), "octocat/hello-world", scm.ReleaseListOptions{Page: 1, Size: 30, Open: true, Closed: true}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Release{} + raw, _ := ioutil.ReadFile("testdata/releases.json.golden") + err = json.Unmarshal(raw, &want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + + data, _ := json.Marshal(got) + t.Log("got JSON:") + t.Log(string(data)) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} + +func TestReleaseCreate(t *testing.T) { + defer gock.Off() + + gock.New("https://api.github.com"). + Post("/repos/octocat/hello-world/releases"). + File("testdata/release_create.json"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/release.json") + + client := NewDefault() + input := &scm.ReleaseInput{ + Title: "v1.0", + Description: "Tracking release for version 1.0", + Tag: "v1.0", + } + + got, res, err := client.Releases.Create(context.Background(), "octocat/hello-world", input) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Release) + raw, _ := ioutil.ReadFile("testdata/release.json.golden") + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + + data, _ := json.Marshal(got) + t.Log("got JSON:") + t.Log(string(data)) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} + +func TestReleaseUpdate(t *testing.T) { + defer gock.Off() + + gock.New("https://api.github.com"). + Patch("/repos/octocat/hello-world/releases/1"). + File("testdata/release_create.json"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/release.json") + + client := NewDefault() + input := &scm.ReleaseInput{ + Title: "v1.0", + Description: "Tracking release for version 1.0", + Tag: "v1.0", + } + + got, res, err := client.Releases.Update(context.Background(), "octocat/hello-world", 1, input) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Release) + raw, _ := ioutil.ReadFile("testdata/release.json.golden") + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} + +func TestReleaseDelete(t *testing.T) { + defer gock.Off() + + gock.New("https://api.github.com"). + Delete("/repos/octocat/hello-world/releases/1"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders) + + client := NewDefault() + res, err := client.Releases.Delete(context.Background(), "octocat/hello-world", 1) + if err != nil { + t.Error(err) + return + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} diff --git a/scm/driver/github/repo.go b/scm/driver/github/repo.go index 27cb11794..cad7f917f 100644 --- a/scm/driver/github/repo.go +++ b/scm/driver/github/repo.go @@ -6,6 +6,7 @@ package github import ( "context" + "errors" "fmt" "strconv" "time" @@ -24,6 +25,7 @@ type repository struct { FullName string `json:"full_name"` Private bool `json:"private"` Fork bool `json:"fork"` + Archived bool `json:"archived"` Visibility string `json:"visibility"` HTMLURL string `json:"html_url"` SSHURL string `json:"ssh_url"` @@ -38,6 +40,10 @@ type repository struct { } `json:"permissions"` } +type searchRepositoryList struct { + Repositories []*repository `json:"items"` +} + type hook struct { ID int `json:"id,omitempty"` Name string `json:"name"` @@ -51,6 +57,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 { @@ -62,7 +73,14 @@ func (s *RepositoryService) Find(ctx context.Context, repo string) (*scm.Reposit path := fmt.Sprintf("repos/%s", repo) out := new(repository) res, err := s.client.do(ctx, "GET", path, nil, out) - return convertRepository(out), res, err + if err != nil { + return nil, res, err + } + convertedRepo := convertRepository(out) + if convertedRepo == nil { + return nil, res, errors.New("GitHub returned an unexpected null repository") + } + return convertedRepo, res, err } // FindHook returns a repository hook. @@ -78,7 +96,14 @@ func (s *RepositoryService) FindPerms(ctx context.Context, repo string) (*scm.Pe path := fmt.Sprintf("repos/%s", repo) out := new(repository) res, err := s.client.do(ctx, "GET", path, nil, out) - return convertRepository(out).Perm, res, err + if err != nil { + return nil, res, err + } + convertedRepo := convertRepository(out) + if convertedRepo == nil { + return nil, res, errors.New("GitHub returned an unexpected null repository") + } + return convertedRepo.Perm, res, err } // List returns the user repository list. @@ -89,6 +114,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 +} + // ListHooks returns a list or repository hooks. func (s *RepositoryService) ListHooks(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Hook, *scm.Response, error) { path := fmt.Sprintf("repos/%s/hooks?%s", repo, encodeListOptions(opts)) @@ -181,19 +230,24 @@ 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{} for _, v := range from { - to = append(to, convertRepository(v)) + if repo := convertRepository(v); repo != nil { + to = append(to, repo) + } } 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 { + return nil + } return &scm.Repository{ ID: strconv.Itoa(from.ID), Name: from.Name, @@ -205,8 +259,9 @@ func convertRepository(from *repository) *scm.Repository { }, Link: from.HTMLURL, 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, @@ -259,19 +314,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 731f960fe..6af3dba6a 100644 --- a/scm/driver/github/repo_test.go +++ b/scm/driver/github/repo_test.go @@ -8,6 +8,7 @@ import ( "context" "encoding/json" "io/ioutil" + "reflect" "testing" "github.com/drone/go-scm/scm" @@ -34,7 +35,7 @@ func TestRepositoryFind(t *testing.T) { want := new(scm.Repository) raw, _ := ioutil.ReadFile("testdata/repo.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -64,7 +65,7 @@ func TestRepositoryPerms(t *testing.T) { want := new(scm.Repository) raw, _ := ioutil.ReadFile("testdata/repo.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want.Perm); diff != "" { t.Errorf("Unexpected Results") @@ -118,7 +119,83 @@ func TestRepositoryList(t *testing.T) { want := []*scm.Repository{} raw, _ := ioutil.ReadFile("testdata/repos.json.golden") - json.Unmarshal(raw, &want) + _ = 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 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") @@ -152,7 +229,7 @@ func TestStatusList(t *testing.T) { want := []*scm.Status{} raw, _ := ioutil.ReadFile("testdata/statuses.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -190,7 +267,7 @@ func TestStatusCreate(t *testing.T) { want := new(scm.Status) raw, _ := ioutil.ReadFile("testdata/status.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -229,7 +306,7 @@ func TestDeployStatusCreate(t *testing.T) { want := new(scm.DeployStatus) raw, _ := ioutil.ReadFile("testdata/deployment.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -259,7 +336,7 @@ func TestRepositoryHookFind(t *testing.T) { want := new(scm.Hook) raw, _ := ioutil.ReadFile("testdata/hook.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -292,7 +369,7 @@ func TestRepositoryHookList(t *testing.T) { want := []*scm.Hook{} raw, _ := ioutil.ReadFile("testdata/hooks.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -330,7 +407,7 @@ func TestRepositoryHookCreate(t *testing.T) { want := new(scm.Hook) raw, _ := ioutil.ReadFile("testdata/hook.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -367,7 +444,7 @@ func TestRepositoryHookUpdate(t *testing.T) { want := new(scm.Hook) raw, _ := ioutil.ReadFile("testdata/hook.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -528,3 +605,77 @@ func TestHookEvents(t *testing.T) { } } } + +func Test_convertRepository(t *testing.T) { + permissionsStruct := &repository{ + Name: "bla", + } + permissionsStruct.Permissions.Admin = true + tests := []struct { + name string + from *repository + want *scm.Repository + }{ + { + name: "Simple", + from: &repository{ + Name: "hello-world", + ID: 1, + Permissions: permissionsStruct.Permissions, + }, + want: &scm.Repository{ + Name: "hello-world", + ID: "1", + Perm: &scm.Perm{ + Admin: true, + }, + }, + }, + { + name: "null", + from: nil, + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := convertRepository(tt.from); !reflect.DeepEqual(got, tt.want) { + t.Errorf("convertRepository() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestRepositoryListWithNull(t *testing.T) { + defer gock.Off() + + gock.New("https://api.github.com"). + Get("/user/repos"). + MatchParam("page", "1"). + MatchParam("per_page", "30"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/reposWithNull.json") + + client := NewDefault() + got, res, err := client.Repositories.List(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)) +} diff --git a/scm/driver/github/review_test.go b/scm/driver/github/review_test.go index 3aaf08ba5..4d12b7947 100644 --- a/scm/driver/github/review_test.go +++ b/scm/driver/github/review_test.go @@ -34,7 +34,7 @@ func TestReviewFind(t *testing.T) { want := new(scm.Review) raw, _ := ioutil.ReadFile("testdata/pr_comment.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -67,7 +67,7 @@ func TestReviewList(t *testing.T) { want := []*scm.Review{} raw, _ := ioutil.ReadFile("testdata/pr_comments.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -105,7 +105,7 @@ func TestReviewCreate(t *testing.T) { want := new(scm.Review) raw, _ := ioutil.ReadFile("testdata/pr_comment.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") diff --git a/scm/driver/github/testdata/branch_create.json b/scm/driver/github/testdata/branch_create.json new file mode 100644 index 000000000..90f12b96a --- /dev/null +++ b/scm/driver/github/testdata/branch_create.json @@ -0,0 +1,10 @@ +{ + "ref": "refs/heads/Hello", + "node_id": "MDM6UmVmMzQ0NDI5MDA5OnJlZnMvaGVhZHMvSGVsbG8=", + "url": "https://api.github.com/repos/tphoney/scm-test/git/refs/heads/Hello", + "object": { + "sha": "312797ba52425353dec56871a255e2a36fc96344", + "type": "commit", + "url": "https://api.github.com/repos/tphoney/scm-test/git/commits/312797ba52425353dec56871a255e2a36fc96344" + } +} \ No newline at end of file diff --git a/scm/driver/github/testdata/changes.json.golden b/scm/driver/github/testdata/changes.json.golden index 9b502353c..b5034d7cf 100644 --- a/scm/driver/github/testdata/changes.json.golden +++ b/scm/driver/github/testdata/changes.json.golden @@ -3,6 +3,7 @@ "Path": "file1.txt", "Added": true, "Renamed": false, - "Deleted": false + "Deleted": false, + "BlobID": "bbcd538c8e72b8c175046e27cc8f907076331401" } ] \ No newline at end of file diff --git a/scm/driver/github/testdata/compare.json.golden b/scm/driver/github/testdata/compare.json.golden index f502bc0db..fb8197d1f 100644 --- a/scm/driver/github/testdata/compare.json.golden +++ b/scm/driver/github/testdata/compare.json.golden @@ -3,6 +3,7 @@ "Path": "README", "Added": false, "Renamed": false, - "Deleted": false + "Deleted": false, + "BlobID": "980a0d5f19a64b4b30a87d4206aade58726b60e3" } ] diff --git a/scm/driver/github/testdata/content.json.golden b/scm/driver/github/testdata/content.json.golden index 4c414c519..d58e10b30 100644 --- a/scm/driver/github/testdata/content.json.golden +++ b/scm/driver/github/testdata/content.json.golden @@ -1,5 +1,5 @@ { "Path": "README", "Data": "SGVsbG8gV29ybGQhCg==", - "Hash": "980a0d5f19a64b4b30a87d4206aade58726b60e3" + "BlobID": "980a0d5f19a64b4b30a87d4206aade58726b60e3" } \ No newline at end of file diff --git a/scm/driver/github/testdata/content_delete.json b/scm/driver/github/testdata/content_delete.json new file mode 100644 index 000000000..eeefc02b8 --- /dev/null +++ b/scm/driver/github/testdata/content_delete.json @@ -0,0 +1,37 @@ +{ + "content": null, + "commit": { + "sha": "7638417db6d59f3c431d3e1f261cc637155684cd", + "node_id": "MDY6Q29tbWl0NzYzODQxN2RiNmQ1OWYzYzQzMWQzZTFmMjYxY2M2MzcxNTU2ODRjZA==", + "url": "https://api.github.com/repos/octocat/Hello-World/git/commits/7638417db6d59f3c431d3e1f261cc637155684cd", + "html_url": "https://github.com/octocat/Hello-World/git/commit/7638417db6d59f3c431d3e1f261cc637155684cd", + "author": { + "date": "2014-11-07T22:01:45Z", + "name": "Monalisa Octocat", + "email": "octocat@github.com" + }, + "committer": { + "date": "2014-11-07T22:01:45Z", + "name": "Monalisa Octocat", + "email": "octocat@github.com" + }, + "message": "my commit message", + "tree": { + "url": "https://api.github.com/repos/octocat/Hello-World/git/trees/691272480426f78a0138979dd3ce63b77f706feb", + "sha": "691272480426f78a0138979dd3ce63b77f706feb" + }, + "parents": [ + { + "url": "https://api.github.com/repos/octocat/Hello-World/git/commits/1acc419d4d6a9ce985db7be48c6349a0475975b5", + "html_url": "https://github.com/octocat/Hello-World/git/commit/1acc419d4d6a9ce985db7be48c6349a0475975b5", + "sha": "1acc419d4d6a9ce985db7be48c6349a0475975b5" + } + ], + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null + } + } +} \ No newline at end of file diff --git a/scm/driver/github/testdata/content_list.json.golden b/scm/driver/github/testdata/content_list.json.golden index 1ecb4b434..3843e16eb 100644 --- a/scm/driver/github/testdata/content_list.json.golden +++ b/scm/driver/github/testdata/content_list.json.golden @@ -1,106 +1,132 @@ [ { "path": "scm/driver/github/content.go", - "kind": "file" + "kind": "file", + "BlobID": "6049c0a9f0859fe56344559006f739a3a81475fb" }, { "path": "scm/driver/github/content_test.go", - "kind": "file" + "kind": "file", + "BlobID": "bec0acdbdf9b5be391a749f13aa6ea223f7f6b2e" }, { "path": "scm/driver/github/git.go", - "kind": "file" + "kind": "file", + "BlobID": "fb07733ece5525869d630df704a76ab29dde227c" }, { "path": "scm/driver/github/git_test.go", - "kind": "file" + "kind": "file", + "BlobID": "4bc40050b43314f637c10b767c53c3d548fd359a" }, { "path": "scm/driver/github/github.go", - "kind": "file" + "kind": "file", + "BlobID": "82f31511232a18a949e8035aa2f346a90754a387" }, { "path": "scm/driver/github/github_test.go", - "kind": "file" + "kind": "file", + "BlobID": "8d82e48e410796f27cc92fcb5bd9ffbed154b6cb" }, { "path": "scm/driver/github/integration", - "kind": "directory" + "kind": "directory", + "BlobID": "f29b9ffe7db8788d4db88de3128015927297f3e1" }, { "path": "scm/driver/github/issue.go", - "kind": "file" + "kind": "file", + "BlobID": "b360d4a3b70f368d44734aebac3803de1f9e2bc4" }, { "path": "scm/driver/github/issue_test.go", - "kind": "file" + "kind": "file", + "BlobID": "d6ff16f2eedd1a34200071b97ee5fed0b10e8dad" }, { "path": "scm/driver/github/linker.go", - "kind": "file" + "kind": "file", + "BlobID": "92d8da78b2a0433c2df15392fd6211091280e037" }, { "path": "scm/driver/github/linker_test.go", - "kind": "file" + "kind": "file", + "BlobID": "b952f3e5a7ae77a0fa789f3ecfc5bfc46aede1ef" }, { "path": "scm/driver/github/org.go", - "kind": "file" + "kind": "file", + "BlobID": "9d4f534054ad4719c25e1551fa2d2bca949f7dc9" }, { "path": "scm/driver/github/org_test.go", - "kind": "file" + "kind": "file", + "BlobID": "b36c00d8e9042ad23f244cee678837cf752d30e9" }, { "path": "scm/driver/github/pr.go", - "kind": "file" + "kind": "file", + "BlobID": "a008cbe0473c1f4a4fd9b345c85326120ec4fc35" }, { "path": "scm/driver/github/pr_test.go", - "kind": "file" + "kind": "file", + "BlobID": "6ab42e0a467f593ab805a0ed2992c209ecbe4914" }, { "path": "scm/driver/github/repo.go", - "kind": "file" + "kind": "file", + "BlobID": "19eb345a307550d356a1d3f50fc56b48a363acf2" }, { "path": "scm/driver/github/repo_test.go", - "kind": "file" + "kind": "file", + "BlobID": "73880b97306f3e6b6ac9b410b3e10b45f0bede8c" }, { "path": "scm/driver/github/review.go", - "kind": "file" + "kind": "file", + "BlobID": "efb31fb34c89d564e4c7381a4cd5a2bf097d8c1b" }, { "path": "scm/driver/github/review_test.go", - "kind": "file" + "kind": "file", + "BlobID": "3aaf08ba51ffb1626a73ab8719e4d0d7d5b0ce5f" }, { "path": "scm/driver/github/testdata", - "kind": "directory" + "kind": "directory", + "BlobID": "2668c2a5e6a9c5cf4d66e72942e12d85527915b4" }, { "path": "scm/driver/github/user.go", - "kind": "file" + "kind": "file", + "BlobID": "4b04b38a805b833f6bd37166e4256a66722b879b" }, { "path": "scm/driver/github/user_test.go", - "kind": "file" + "kind": "file", + "BlobID": "86e5b709daeced102302fba8e46e48e9457adbd3" }, { "path": "scm/driver/github/util.go", - "kind": "file" + "kind": "file", + "BlobID": "a6b3c55a7a8924e53e94ee35e6839e5a0a78d724" }, { "path": "scm/driver/github/util_test.go", - "kind": "file" + "kind": "file", + "BlobID": "c6a2664339b965396a861fd224e3bb9733757444" }, { "path": "scm/driver/github/webhook.go", - "kind": "file" + "kind": "file", + "BlobID": "1789ca55651f7d7903fce3e985212b96592f8800" }, { "path": "scm/driver/github/webhook_test.go", - "kind": "file" + "kind": "file", + "BlobID": "136f2e0e55a4ed961af1b67d45d72fa84a68943a" } ] diff --git a/scm/driver/github/testdata/content_update.json.fail b/scm/driver/github/testdata/content_update.json.fail new file mode 100644 index 000000000..1ae315d60 --- /dev/null +++ b/scm/driver/github/testdata/content_update.json.fail @@ -0,0 +1,4 @@ +{ + "message": "newfile does not match", + "documentation_url": "https://docs.github.com/rest/reference/repos#create-or-update-file-contents" +} \ No newline at end of file diff --git a/scm/driver/github/testdata/emails.json b/scm/driver/github/testdata/emails.json new file mode 100644 index 000000000..b251b370e --- /dev/null +++ b/scm/driver/github/testdata/emails.json @@ -0,0 +1,8 @@ +[ + { + "email": "octocat@github.com", + "verified": true, + "primary": true, + "visibility": "public" + } +] \ No newline at end of file diff --git a/scm/driver/github/testdata/emails.json.golden b/scm/driver/github/testdata/emails.json.golden new file mode 100644 index 000000000..dc0613ac5 --- /dev/null +++ b/scm/driver/github/testdata/emails.json.golden @@ -0,0 +1,7 @@ +[ + { + "Value": "octocat@github.com", + "verified": true, + "primary": true + } +] \ No newline at end of file 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/milestone.json b/scm/driver/github/testdata/milestone.json new file mode 100644 index 000000000..cabb83865 --- /dev/null +++ b/scm/driver/github/testdata/milestone.json @@ -0,0 +1,37 @@ +{ + "url": "https://api.github.com/repos/octocat/Hello-World/milestones/1", + "html_url": "https://github.com/octocat/Hello-World/milestones/v1.0", + "labels_url": "https://api.github.com/repos/octocat/Hello-World/milestones/1/labels", + "id": 1002604, + "node_id": "MDk6TWlsZXN0b25lMTAwMjYwNA==", + "number": 1, + "state": "open", + "title": "v1.0", + "description": "Tracking milestone for version 1.0", + "creator": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "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 + }, + "open_issues": 4, + "closed_issues": 8, + "created_at": "2011-04-10T20:09:31Z", + "updated_at": "2014-03-03T18:58:10Z", + "closed_at": "2013-02-12T13:22:01Z", + "due_on": "2012-10-09T23:39:01Z" +} diff --git a/scm/driver/github/testdata/milestone.json.golden b/scm/driver/github/testdata/milestone.json.golden new file mode 100644 index 000000000..ccab27361 --- /dev/null +++ b/scm/driver/github/testdata/milestone.json.golden @@ -0,0 +1,9 @@ +{ + "Link": "https://github.com/octocat/Hello-World/milestones/v1.0", + "ID": 1002604, + "Number": 1, + "State": "open", + "Title": "v1.0", + "Description": "Tracking milestone for version 1.0", + "DueDate": "2012-10-09T23:39:01Z" +} diff --git a/scm/driver/github/testdata/milestone_create.json b/scm/driver/github/testdata/milestone_create.json new file mode 100644 index 000000000..c89bac2bc --- /dev/null +++ b/scm/driver/github/testdata/milestone_create.json @@ -0,0 +1,6 @@ +{ + "state": "open", + "title": "v1.0", + "description": "Tracking milestone for version 1.0", + "due_on": "2012-10-09T23:39:01Z" +} diff --git a/scm/driver/github/testdata/milestones.json b/scm/driver/github/testdata/milestones.json new file mode 100644 index 000000000..6a4e96bb0 --- /dev/null +++ b/scm/driver/github/testdata/milestones.json @@ -0,0 +1,39 @@ +[ + { + "url": "https://api.github.com/repos/octocat/Hello-World/milestones/1", + "html_url": "https://github.com/octocat/Hello-World/milestones/v1.0", + "labels_url": "https://api.github.com/repos/octocat/Hello-World/milestones/1/labels", + "id": 1002604, + "node_id": "MDk6TWlsZXN0b25lMTAwMjYwNA==", + "number": 1, + "state": "open", + "title": "v1.0", + "description": "Tracking milestone for version 1.0", + "creator": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "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 + }, + "open_issues": 4, + "closed_issues": 8, + "created_at": "2011-04-10T20:09:31Z", + "updated_at": "2014-03-03T18:58:10Z", + "closed_at": "2013-02-12T13:22:01Z", + "due_on": "2012-10-09T23:39:01Z" + } +] diff --git a/scm/driver/github/testdata/milestones.json.golden b/scm/driver/github/testdata/milestones.json.golden new file mode 100644 index 000000000..4d3a51459 --- /dev/null +++ b/scm/driver/github/testdata/milestones.json.golden @@ -0,0 +1,11 @@ +[ + { + "Link": "https://github.com/octocat/Hello-World/milestones/v1.0", + "ID": 1002604, + "Number": 1, + "State": "open", + "Title": "v1.0", + "Description": "Tracking milestone for version 1.0", + "DueDate": "2012-10-09T23:39:01Z" + } +] 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/pr_files.json b/scm/driver/github/testdata/pr_files.json index d3ca75649..18488635a 100644 --- a/scm/driver/github/testdata/pr_files.json +++ b/scm/driver/github/testdata/pr_files.json @@ -1,14 +1,50 @@ [ { - "sha": "bbcd538c8e72b8c175046e27cc8f907076331401", - "filename": "file1.txt", + "sha": "291b15982c4926705f5639abffe96b2b6c419ce7", + "filename": "asda2", + "status": "modified", + "additions": 1, + "deletions": 1, + "changes": 2, + "blob_url": "https://github.com/tphoney/scm-test/blob/ad442ec8e99589912117c7d1e689f56b32356868/asda2", + "raw_url": "https://github.com/tphoney/scm-test/raw/ad442ec8e99589912117c7d1e689f56b32356868/asda2", + "contents_url": "https://api.github.com/repos/tphoney/scm-test/contents/asda2?ref=ad442ec8e99589912117c7d1e689f56b32356868", + "patch": "@@ -1,2 +1,2 @@n-n+asdasdn asdasdasd" + }, + { + "sha": "ce013625030ba8dba906f756967f9e9ca394464a", + "filename": "remove_me", "status": "added", - "additions": 103, - "deletions": 21, - "changes": 124, - "blob_url": "https://github.com/octocat/Hello-World/blob/6dcb09b5b57875f334f61aebed695e2e4193db5e/file1.txt", - "raw_url": "https://github.com/octocat/Hello-World/raw/6dcb09b5b57875f334f61aebed695e2e4193db5e/file1.txt", - "contents_url": "https://api.github.com/repos/octocat/Hello-World/contents/file1.txt?ref=6dcb09b5b57875f334f61aebed695e2e4193db5e", - "patch": "@@ -132,7 +132,7 @@ module Test @@ -1000,7 +1000,7 @@ module Test" + "additions": 1, + "deletions": 0, + "changes": 1, + "blob_url": "https://github.com/tphoney/scm-test/blob/ad442ec8e99589912117c7d1e689f56b32356868/remove_me", + "raw_url": "https://github.com/tphoney/scm-test/raw/ad442ec8e99589912117c7d1e689f56b32356868/remove_me", + "contents_url": "https://api.github.com/repos/tphoney/scm-test/contents/remove_me?ref=ad442ec8e99589912117c7d1e689f56b32356868", + "patch": "@@ -0,0 +1 @@n+hello" + }, + { + "sha": "70c379b63ffa0795fdbfbc128e5a2818397b7ef8", + "filename": "tp", + "status": "renamed", + "additions": 0, + "deletions": 0, + "changes": 0, + "blob_url": "https://github.com/tphoney/scm-test/blob/ad442ec8e99589912117c7d1e689f56b32356868/tp", + "raw_url": "https://github.com/tphoney/scm-test/raw/ad442ec8e99589912117c7d1e689f56b32356868/tp", + "contents_url": "https://api.github.com/repos/tphoney/scm-test/contents/tp?ref=ad442ec8e99589912117c7d1e689f56b32356868", + "previous_filename": "abhinav" + }, + { + "sha": "0f9282d7e71e0f8cb748bfe00e52d7ed13dad036", + "filename": "upsert", + "status": "removed", + "additions": 0, + "deletions": 1, + "changes": 1, + "blob_url": "https://github.com/tphoney/scm-test/blob/6a86c7aca4425c8781876c31ffb6e4284fb07d56/upsert", + "raw_url": "https://github.com/tphoney/scm-test/raw/6a86c7aca4425c8781876c31ffb6e4284fb07d56/upsert", + "contents_url": "https://api.github.com/repos/tphoney/scm-test/contents/upsert?ref=6a86c7aca4425c8781876c31ffb6e4284fb07d56", + "patch": "@@ -1 +0,0 @@n-asdasn No newline at end of file" } ] \ No newline at end of file diff --git a/scm/driver/github/testdata/pr_files.json.golden b/scm/driver/github/testdata/pr_files.json.golden index 9b502353c..4be7ddc87 100644 --- a/scm/driver/github/testdata/pr_files.json.golden +++ b/scm/driver/github/testdata/pr_files.json.golden @@ -1,8 +1,34 @@ [ { - "Path": "file1.txt", + "Path": "asda2", + "Added": false, + "Renamed": false, + "Deleted": false, + "BlobID": "291b15982c4926705f5639abffe96b2b6c419ce7", + "PrevFilePath": "" + }, + { + "Path": "remove_me", "Added": true, "Renamed": false, - "Deleted": false + "Deleted": false, + "BlobID": "ce013625030ba8dba906f756967f9e9ca394464a", + "PrevFilePath": "" + }, + { + "Path": "tp", + "Added": false, + "Renamed": true, + "Deleted": false, + "BlobID": "70c379b63ffa0795fdbfbc128e5a2818397b7ef8", + "PrevFilePath": "abhinav" + }, + { + "Path": "upsert", + "Added": false, + "Renamed": false, + "Deleted": true, + "BlobID": "0f9282d7e71e0f8cb748bfe00e52d7ed13dad036", + "PrevFilePath": "" } ] \ No newline at end of file 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/release.json b/scm/driver/github/testdata/release.json new file mode 100644 index 000000000..b85892dbf --- /dev/null +++ b/scm/driver/github/testdata/release.json @@ -0,0 +1,74 @@ +{ + "url": "https://api.github.com/repos/octocat/Hello-World/releases/1", + "html_url": "https://github.com/octocat/Hello-World/releases/v1.0.0", + "assets_url": "https://api.github.com/repos/octocat/Hello-World/releases/1/assets", + "upload_url": "https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets{?name,label}", + "tarball_url": "https://api.github.com/repos/octocat/Hello-World/tarball/v1.0.0", + "zipball_url": "https://api.github.com/repos/octocat/Hello-World/zipball/v1.0.0", + "id": 1, + "node_id": "MDc6UmVsZWFzZTE=", + "tag_name": "v1.0.0", + "target_commitish": "master", + "name": "v1.0.0", + "body": "Description of the release", + "draft": false, + "prerelease": false, + "created_at": "2013-02-27T19:35:32Z", + "published_at": "2013-02-27T19:35:32Z", + "author": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "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 + }, + "assets": [ + { + "url": "https://api.github.com/repos/octocat/Hello-World/releases/assets/1", + "browser_download_url": "https://github.com/octocat/Hello-World/releases/download/v1.0.0/example.zip", + "id": 1, + "node_id": "MDEyOlJlbGVhc2VBc3NldDE=", + "name": "example.zip", + "label": "short description", + "state": "uploaded", + "content_type": "application/zip", + "size": 1024, + "download_count": 42, + "created_at": "2013-02-27T19:35:32Z", + "updated_at": "2013-02-27T19:35:32Z", + "uploader": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "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 + } + } + ] +} \ No newline at end of file diff --git a/scm/driver/github/testdata/release.json.golden b/scm/driver/github/testdata/release.json.golden new file mode 100644 index 000000000..f199eca60 --- /dev/null +++ b/scm/driver/github/testdata/release.json.golden @@ -0,0 +1,12 @@ +{ + "ID": 1, + "Title": "v1.0.0", + "Description": "Description of the release", + "Link": "https://github.com/octocat/Hello-World/releases/v1.0.0", + "Tag": "v1.0.0", + "Commitish": "master", + "Draft": false, + "Prerelease": false, + "Created": "2013-02-27T19:35:32Z", + "Published": "2013-02-27T19:35:32Z" +} \ No newline at end of file diff --git a/scm/driver/github/testdata/releases.json b/scm/driver/github/testdata/releases.json new file mode 100644 index 000000000..e544c30b4 --- /dev/null +++ b/scm/driver/github/testdata/releases.json @@ -0,0 +1,76 @@ +[ + { + "url": "https://api.github.com/repos/octocat/Hello-World/releases/1", + "html_url": "https://github.com/octocat/Hello-World/releases/v1.0.0", + "assets_url": "https://api.github.com/repos/octocat/Hello-World/releases/1/assets", + "upload_url": "https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets{?name,label}", + "tarball_url": "https://api.github.com/repos/octocat/Hello-World/tarball/v1.0.0", + "zipball_url": "https://api.github.com/repos/octocat/Hello-World/zipball/v1.0.0", + "id": 1, + "node_id": "MDc6UmVsZWFzZTE=", + "tag_name": "v1.0.0", + "target_commitish": "master", + "name": "v1.0.0", + "body": "Description of the release", + "draft": false, + "prerelease": false, + "created_at": "2013-02-27T19:35:32Z", + "published_at": "2013-02-27T19:35:32Z", + "author": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "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 + }, + "assets": [ + { + "url": "https://api.github.com/repos/octocat/Hello-World/releases/assets/1", + "browser_download_url": "https://github.com/octocat/Hello-World/releases/download/v1.0.0/example.zip", + "id": 1, + "node_id": "MDEyOlJlbGVhc2VBc3NldDE=", + "name": "example.zip", + "label": "short description", + "state": "uploaded", + "content_type": "application/zip", + "size": 1024, + "download_count": 42, + "created_at": "2013-02-27T19:35:32Z", + "updated_at": "2013-02-27T19:35:32Z", + "uploader": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "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 + } + } + ] + } +] \ No newline at end of file diff --git a/scm/driver/github/testdata/releases.json.golden b/scm/driver/github/testdata/releases.json.golden new file mode 100644 index 000000000..db9d598a5 --- /dev/null +++ b/scm/driver/github/testdata/releases.json.golden @@ -0,0 +1,14 @@ +[ + { + "ID": 1, + "Title": "v1.0.0", + "Description": "Description of the release", + "Link": "https://github.com/octocat/Hello-World/releases/v1.0.0", + "Tag": "v1.0.0", + "Commitish": "master", + "Draft": false, + "Prerelease": false, + "Created": "2013-02-27T19:35:32Z", + "Published": "2013-02-27T19:35:32Z" + } +] \ No newline at end of file diff --git a/scm/driver/github/testdata/repo.json b/scm/driver/github/testdata/repo.json index 7a759a19b..b30d1d653 100644 --- a/scm/driver/github/testdata/repo.json +++ b/scm/driver/github/testdata/repo.json @@ -86,7 +86,7 @@ "has_wiki": true, "has_pages": false, "has_downloads": true, - "archived": false, + "archived": true, "pushed_at": "2011-01-26T19:06:43Z", "created_at": "2011-01-26T19:01:12Z", "updated_at": "2011-01-26T19:14:43Z", diff --git a/scm/driver/github/testdata/repo.json.golden b/scm/driver/github/testdata/repo.json.golden index 5fa8c4db1..472a08636 100644 --- a/scm/driver/github/testdata/repo.json.golden +++ b/scm/driver/github/testdata/repo.json.golden @@ -9,6 +9,7 @@ }, "Branch": "master", "Private": true, + "Archived": true, "Visibility": 1, "Clone": "https://github.com/octocat/Hello-World.git", "CloneSSH": "git@github.com:octocat/Hello-World.git", diff --git a/scm/driver/github/testdata/reposWithNull.json b/scm/driver/github/testdata/reposWithNull.json new file mode 100644 index 000000000..bcd5c18c6 --- /dev/null +++ b/scm/driver/github/testdata/reposWithNull.json @@ -0,0 +1,113 @@ +[ + { + "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/" + } + }, + null +] 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/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 4b04b38a8..6da295679 100644 --- a/scm/driver/github/user.go +++ b/scm/driver/github/user.go @@ -31,8 +31,15 @@ func (s *userService) FindLogin(ctx context.Context, login string) (*scm.User, * } func (s *userService) FindEmail(ctx context.Context) (string, *scm.Response, error) { - user, res, err := s.Find(ctx) - return user.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) { + path := fmt.Sprintf("user/emails?%s", encodeListOptions(opts)) + out := []*email{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertEmailList(out), res, err } type user struct { @@ -45,6 +52,12 @@ type user struct { Updated time.Time `json:"updated_at"` } +type email struct { + Email string `json:"email"` + Primary bool `json:"primary"` + Verified bool `json:"verified"` +} + func convertUser(from *user) *scm.User { return &scm.User{ Avatar: from.Avatar, @@ -55,3 +68,32 @@ func convertUser(from *user) *scm.User { Updated: from.Updated, } } + +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 { + to := []*scm.Email{} + for _, v := range from { + to = append(to, convertEmail(v)) + } + return to +} + +// helper function to convert from the github email structure to +// the common email structure. +func convertEmail(from *email) *scm.Email { + return &scm.Email{ + Value: from.Email, + Primary: from.Primary, + Verified: from.Verified, + } +} diff --git a/scm/driver/github/user_test.go b/scm/driver/github/user_test.go index 86e5b709d..8888d18a5 100644 --- a/scm/driver/github/user_test.go +++ b/scm/driver/github/user_test.go @@ -39,7 +39,7 @@ func TestUserFind(t *testing.T) { want := new(scm.User) raw, _ := ioutil.ReadFile("testdata/user.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -71,12 +71,12 @@ func TestUserLoginFind(t *testing.T) { want := new(scm.User) raw, _ := ioutil.ReadFile("testdata/user.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") t.Log(diff) - json.NewEncoder(os.Stdout).Encode(got) + _ = json.NewEncoder(os.Stdout).Encode(got) } t.Run("Request", testRequest(res)) @@ -87,14 +87,14 @@ func TestUserEmailFind(t *testing.T) { defer gock.Off() gock.New("https://api.github.com"). - Get("/user"). + Get("/user/emails"). Reply(200). Type("application/json"). SetHeader("X-GitHub-Request-Id", "DD0E:6011:12F21A8:1926790:5A2064E2"). SetHeader("X-RateLimit-Limit", "60"). SetHeader("X-RateLimit-Remaining", "59"). SetHeader("X-RateLimit-Reset", "1512076018"). - File("testdata/user.json") + File("testdata/emails.json") client := NewDefault() result, res, err := client.Users.FindEmail(context.Background()) @@ -108,3 +108,37 @@ func TestUserEmailFind(t *testing.T) { t.Run("Request", testRequest(res)) t.Run("Rate", testRate(res)) } + +func TestUserEmailList(t *testing.T) { + defer gock.Off() + + gock.New("https://api.github.com"). + Get("/user/emails"). + MatchParam("page", "1"). + MatchParam("per_page", "30"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/emails.json") + + client := NewDefault() + got, res, err := client.Users.ListEmail(context.Background(), scm.ListOptions{Size: 30, Page: 1}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Email{} + raw, _ := ioutil.ReadFile("testdata/emails.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)) +} diff --git a/scm/driver/github/util.go b/scm/driver/github/util.go index a6b3c55a7..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 { @@ -31,7 +59,10 @@ func encodeCommitListOptions(opts scm.CommitListOptions) string { params.Set("per_page", strconv.Itoa(opts.Size)) } if opts.Ref != "" { - params.Set("ref", opts.Ref) + params.Set("sha", opts.Ref) + } + if opts.Path != "" { + params.Set("path", opts.Path) } return params.Encode() } @@ -67,3 +98,35 @@ func encodePullRequestListOptions(opts scm.PullRequestListOptions) string { } return params.Encode() } + +func encodeMilestoneListOptions(opts scm.MilestoneListOptions) string { + params := url.Values{} + if opts.Page != 0 { + params.Set("page", strconv.Itoa(opts.Page)) + } + if opts.Size != 0 { + params.Set("per_page", strconv.Itoa(opts.Size)) + } + if opts.Open && opts.Closed { + params.Set("state", "all") + } else if opts.Closed { + params.Set("state", "closed") + } + return params.Encode() +} + +func encodeReleaseListOptions(opts scm.ReleaseListOptions) string { + params := url.Values{} + if opts.Page != 0 { + params.Set("page", strconv.Itoa(opts.Page)) + } + if opts.Size != 0 { + params.Set("per_page", strconv.Itoa(opts.Size)) + } + if opts.Open && opts.Closed { + params.Set("state", "all") + } else if opts.Closed { + params.Set("state", "closed") + } + return params.Encode() +} diff --git a/scm/driver/github/util_test.go b/scm/driver/github/util_test.go index c6a266433..46a87888e 100644 --- a/scm/driver/github/util_test.go +++ b/scm/driver/github/util_test.go @@ -27,8 +27,9 @@ func Test_encodeCommitListOptions(t *testing.T) { Page: 10, Size: 30, Ref: "master", + Path: "readme.md", } - want := "page=10&per_page=30&ref=master" + want := "page=10&path=readme.md&per_page=30&sha=master" got := encodeCommitListOptions(opts) if got != want { t.Errorf("Want encoded commit list options %q, got %q", want, got) diff --git a/scm/driver/github/webhook.go b/scm/driver/github/webhook.go index 4aa87f5c4..2fbdae938 100644 --- a/scm/driver/github/webhook.go +++ b/scm/driver/github/webhook.go @@ -46,6 +46,8 @@ 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) default: return nil, scm.ErrUnknownEvent } @@ -63,7 +65,10 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo return hook, nil } - sig := req.Header.Get("X-Hub-Signature") + sig := req.Header.Get("X-Hub-Signature-256") + if sig == "" { + sig = req.Header.Get("X-Hub-Signature") + } if !hmac.ValidatePrefix(data, []byte(key), sig) { return hook, scm.ErrSignatureInvalid } @@ -167,7 +172,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 @@ -175,6 +182,34 @@ func (s *webhookService) parsePullRequestHook(data []byte) (scm.Webhook, error) return dst, nil } +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 +} + // // native data structures // @@ -298,6 +333,25 @@ 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"` + } ) // @@ -354,7 +408,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, @@ -381,7 +435,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, @@ -401,7 +455,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, @@ -419,7 +473,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, @@ -445,7 +499,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, @@ -479,7 +533,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, @@ -497,6 +551,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 3f62cb8c6..f7c63c3fd 100644 --- a/scm/driver/github/webhook_test.go +++ b/scm/driver/github/webhook_test.go @@ -28,7 +28,6 @@ func TestWebhooks(t *testing.T) { // // push events // - // push hooks { event: "push", @@ -126,6 +125,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 +191,51 @@ 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), + }, } for _, test := range tests { @@ -202,7 +253,7 @@ func TestWebhooks(t *testing.T) { buf := bytes.NewBuffer(before) r, _ := http.NewRequest("GET", "/", buf) r.Header.Set("X-GitHub-Event", test.event) - r.Header.Set("X-Hub-Signature", "sha1=380f462cd2e160b84765144beabdad2e930a7ec5") + r.Header.Set("X-Hub-Signature-256", "sha256=3bfbbc3bfc44498db2254f577b2e4bed201ece6163518ba91cb2c21f0f59d512") r.Header.Set("X-GitHub-Delivery", "f2467dea-70d6-11e8-8955-3c83993e0aef") s := new(webhookService) @@ -223,7 +274,7 @@ func TestWebhooks(t *testing.T) { t.Log(diff) // debug only. remove once implemented - json.NewEncoder(os.Stdout).Encode(o) + _ = json.NewEncoder(os.Stdout).Encode(o) } switch event := o.(type) { @@ -259,7 +310,7 @@ func TestWebhookInvalid(t *testing.T) { r, _ := http.NewRequest("GET", "/", bytes.NewBuffer(f)) r.Header.Set("X-GitHub-Event", "push") r.Header.Set("X-GitHub-Delivery", "ee8d97b4-1479-43f1-9cac-fbbd1b80da55") - r.Header.Set("X-Hub-Signature", "sha1=380f462cd2e160b84765144beabdad2e930a7ec5") + r.Header.Set("X-Hub-Signature-256", "sha256=3bfbbc3bfc44498db2254f577b2e4bed201ece6163518ba91cb2c21f0f59d512") s := new(webhookService) _, err := s.Parse(r, secretFunc) @@ -269,6 +320,23 @@ func TestWebhookInvalid(t *testing.T) { } func TestWebhookValid(t *testing.T) { + // the sha can be recalculated with the below command + // openssl dgst -sha256 -hmac + + f, _ := ioutil.ReadFile("testdata/webhooks/push.json") + r, _ := http.NewRequest("GET", "/", bytes.NewBuffer(f)) + r.Header.Set("X-GitHub-Event", "push") + r.Header.Set("X-GitHub-Delivery", "ee8d97b4-1479-43f1-9cac-fbbd1b80da55") + r.Header.Set("X-Hub-Signature-256", "sha256=e3bfe744d4e2e29ed990bde8acfb8255ca51ef65f99657767989fb6349f32957") + + s := new(webhookService) + _, err := s.Parse(r, secretFunc) + if err != nil { + t.Errorf("Expect valid signature, got %v", err) + } +} + +func TestWebhookSignatureFallback(t *testing.T) { // the sha can be recalculated with the below command // openssl dgst -sha1 -hmac diff --git a/scm/driver/gitlab/content.go b/scm/driver/gitlab/content.go index f4263489c..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) @@ -32,8 +33,10 @@ func (s *contentService) Find(ctx context.Context, repo, path, ref string) (*scm } } return &scm.Content{ - Path: out.FilePath, - Data: raw, + Path: out.FilePath, + Data: raw, + Sha: out.LastCommitID, + BlobID: out.BlobID, }, res, err } @@ -61,13 +64,24 @@ func (s *contentService) Update(ctx context.Context, repo, path string, params * Encoding: "base64", AuthorName: params.Signature.Name, AuthorEmail: params.Signature.Email, + LastCommitID: params.Sha, } res, err := s.client.do(ctx, "PUT", endpoint, in, nil) return res, err } -func (s *contentService) Delete(ctx context.Context, repo, path, ref string) (*scm.Response, error) { - return nil, scm.ErrNotSupported +func (s *contentService) Delete(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { + endpoint := fmt.Sprintf("api/v4/projects/%s/repository/files/%s", encode(repo), encodePath(path)) + in := &createUpdateContent{ + Branch: params.Branch, + CommitMessage: params.Message, + Encoding: "base64", + AuthorName: params.Signature.Name, + AuthorEmail: params.Signature.Email, + LastCommitID: params.Sha, + } + res, err := s.client.do(ctx, "DELETE", endpoint, in, nil) + return res, err } func (s *contentService) List(ctx context.Context, repo, path, ref string, opts scm.ListOptions) ([]*scm.ContentInfo, *scm.Response, error) { @@ -96,6 +110,7 @@ type createUpdateContent struct { Encoding string `json:"encoding"` AuthorEmail string `json:"author_email"` AuthorName string `json:"author_name"` + LastCommitID string `json:"last_commit_id"` } type object struct { diff --git a/scm/driver/gitlab/content_test.go b/scm/driver/gitlab/content_test.go index 16e7b44a1..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)) } @@ -114,11 +143,59 @@ func TestContentUpdate(t *testing.T) { } } +func TestContentUpdateBadCommitID(t *testing.T) { + defer gock.Off() + + gock.New("https://gitlab.com"). + Put("/api/v4/projects/diaspora/diaspora/repository/files/app/project.rb"). + Reply(400). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/content_update.json.fail") + + client := NewDefault() + params := &scm.ContentParams{ + Message: "update file", + Data: []byte("bXkgbmV3IGZpbGUgY29udGVudHM="), + Sha: "bad sha", + Signature: scm.Signature{ + Name: "Firstname Lastname", + Email: "kubesphere@example.com", + }, + } + + _, err := client.Contents.Update(context.Background(), "diaspora/diaspora", "app/project.rb", params) + if err.Error() != "You are attempting to update a file that has changed since you started editing it." { + t.Errorf("Expecting error 'You are attempting to update a file that has changed since you started editing it.'") + } +} + func TestContentDelete(t *testing.T) { - content := new(contentService) - _, err := content.Delete(context.Background(), "octocat/hello-world", "README", "master") - if err != scm.ErrNotSupported { - t.Errorf("Expect Not Supported error") + defer gock.Off() + + gock.New("https://gitlab.com"). + Delete("/api/v4/projects/diaspora/diaspora/repository/files/app/project.rb"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders) + + client := NewDefault() + params := &scm.ContentParams{ + Message: "update file", + Signature: scm.Signature{ + Name: "Firstname Lastname", + Email: "kubesphere@example.com", + }, + } + + res, err := client.Contents.Delete(context.Background(), "diaspora/diaspora", "app/project.rb", params) + if err != nil { + t.Error(err) + return + } + + if res.Status != 200 { + t.Errorf("Unexpected Results") } } diff --git a/scm/driver/gitlab/git.go b/scm/driver/gitlab/git.go index 7b7e78d09..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,6 +18,15 @@ type gitService struct { client *wrapper } +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, + Ref: params.Sha, + } + return s.client.do(ctx, "POST", path, in, nil) +} + func (s *gitService) FindBranch(ctx context.Context, repo, name string) (*scm.Reference, *scm.Response, error) { path := fmt.Sprintf("api/v4/projects/%s/repository/branches/%s", encode(repo), name) out := new(branch) @@ -24,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) @@ -44,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{} @@ -79,6 +102,11 @@ type branch struct { } } +type createBranch struct { + Branch string `json:"branch"` + Ref string `json:"ref"` +} + type commit struct { ID string `json:"id"` Title string `json:"title"` diff --git a/scm/driver/gitlab/git_test.go b/scm/driver/gitlab/git_test.go index dab63658b..49fefee66 100644 --- a/scm/driver/gitlab/git_test.go +++ b/scm/driver/gitlab/git_test.go @@ -80,6 +80,33 @@ func TestGitFindBranch(t *testing.T) { t.Run("Rate", testRate(res)) } +func TestGitCreateBranch(t *testing.T) { + defer gock.Off() + + gock.New("https://gitlab.com"). + Post("/api/v4/projects/diaspora/diaspora/repository/branches"). + Reply(201). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/branch_create.json") + + params := &scm.ReferenceInput{ + Name: "yooo", + Sha: "0efb1bed7c6a4871cb4ddb862ecc2111e11f31ee", + } + + client := NewDefault() + res, err := client.Git.CreateBranch(context.Background(), "diaspora/diaspora", params) + + if err != nil { + t.Error(err) + return + } + + if res.Status != 201 { + t.Errorf("Unexpected Results") + } +} func TestGitFindTag(t *testing.T) { defer gock.Off() @@ -179,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/gitlab.go b/scm/driver/gitlab/gitlab.go index 1a907e511..4d92016cd 100644 --- a/scm/driver/gitlab/gitlab.go +++ b/scm/driver/gitlab/gitlab.go @@ -34,8 +34,10 @@ func New(uri string) (*scm.Client, error) { client.Git = &gitService{client} client.Issues = &issueService{client} client.Organizations = &organizationService{client} + client.Milestones = &milestoneService{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} diff --git a/scm/driver/gitlab/integration/pr_test.go b/scm/driver/gitlab/integration/pr_test.go index c11623066..64c64d05b 100644 --- a/scm/driver/gitlab/integration/pr_test.go +++ b/scm/driver/gitlab/integration/pr_test.go @@ -22,6 +22,7 @@ func testPullRequests(client *scm.Client) func(t *testing.T) { t.Run("Find", testPullRequestFind(client)) t.Run("Changes", testPullRequestChanges(client)) t.Run("Comments", testPullRequestComments(client)) + t.Run("Commits", testPullRequestCommitList(client)) } } @@ -120,6 +121,22 @@ func testPullRequestChanges(client *scm.Client) func(t *testing.T) { } } +func testPullRequestCommitList(client *scm.Client) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + opts := scm.ListOptions{} + result, _, err := client.PullRequests.ListCommits(context.Background(), "gitlab-org/testme", 1, opts) + if err != nil { + t.Error(err) + } + if len(result) == 0 { + t.Errorf("Got empty pull request commit list") + return + } + t.Run("Commit", testPullRequestCommit(result[0])) + } +} + // // struct sub-tests // @@ -216,3 +233,32 @@ func testChange(change *scm.Change) func(t *testing.T) { } } } + +func testPullRequestCommit(commit *scm.Commit) func(t *testing.T) { + return func(t *testing.T) { + if got, want := commit.Message, "JS fix\n\nSigned-off-by: Dmitriy Zaporozhets \n"; got != want { + t.Errorf("Want commit Message %q, got %q", want, got) + } + if got, want := commit.Sha, "12d65c8dd2b2676fa3ac47d955accc085a37a9c1"; got != want { + t.Errorf("Want commit Sha %q, got %q", want, got) + } + if got, want := commit.Author.Name, "Dmitriy Zaporozhets"; got != want { + t.Errorf("Want commit author Name %q, got %q", want, got) + } + if got, want := commit.Author.Email, "dmitriy.zaporozhets@gmail.com"; got != want { + t.Errorf("Want commit author Email %q, got %q", want, got) + } + if got, want := commit.Author.Date.Unix(), int64(1393489620); got != want { + t.Errorf("Want commit author Date %d, got %d", want, got) + } + if got, want := commit.Committer.Name, "Dmitriy Zaporozhets"; got != want { + t.Errorf("Want commit author Name %q, got %q", want, got) + } + if got, want := commit.Committer.Email, "dmitriy.zaporozhets@gmail.com"; got != want { + t.Errorf("Want commit author Email %q, got %q", want, got) + } + if got, want := commit.Committer.Date.Unix(), int64(1393489620); got != want { + t.Errorf("Want commit author Date %d, got %d", want, got) + } + } +} diff --git a/scm/driver/gitlab/milestone.go b/scm/driver/gitlab/milestone.go new file mode 100644 index 000000000..111897508 --- /dev/null +++ b/scm/driver/gitlab/milestone.go @@ -0,0 +1,167 @@ +package gitlab + +import ( + "context" + "errors" + "fmt" + "github.com/drone/go-scm/scm/driver/internal/null" + "net/url" + "time" + + "github.com/drone/go-scm/scm" +) + +type milestoneService struct { + client *wrapper +} + +// isoTime represents an ISO 8601 formatted date +type isoTime time.Time + +// ISO 8601 date format +const iso8601 = "2006-01-02" + +// MarshalJSON implements the json.Marshaler interface +func (t isoTime) MarshalJSON() ([]byte, error) { + if y := time.Time(t).Year(); y < 0 || y >= 10000 { + // ISO 8901 uses 4 digits for the years + return nil, errors.New("json: ISOTime year outside of range [0,9999]") + } + + b := make([]byte, 0, len(iso8601)+2) + b = append(b, '"') + b = time.Time(t).AppendFormat(b, iso8601) + b = append(b, '"') + + return b, nil +} + +// UnmarshalJSON implements the json.Unmarshaler interface +func (t *isoTime) UnmarshalJSON(data []byte) error { + // Ignore null, like in the main JSON package + if string(data) == "null" { + return nil + } + + isotime, err := time.Parse(`"`+iso8601+`"`, string(data)) + *t = isoTime(isotime) + + return err +} + +// EncodeValues implements the query.Encoder interface +func (t *isoTime) EncodeValues(key string, v *url.Values) error { + if t == nil || (time.Time(*t)).IsZero() { + return nil + } + v.Add(key, t.String()) + return nil +} + +// String implements the Stringer interface +func (t isoTime) String() string { + return time.Time(t).Format(iso8601) +} + +type milestone struct { + ID int `json:"id"` + IID int `json:"iid"` + ProjectID int `json:"project_id"` + Title string `json:"title"` + Description string `json:"description"` + State string `json:"state"` + DueDate isoTime `json:"due_date"` + StartDate isoTime `json:"start_date"` + CreatedAt null.Time `json:"created_at"` + UpdatedAt null.Time `json:"updated_at"` + Expired bool `json:"expired"` +} + +type milestoneInput struct { + Title *string `json:"title"` + StateEvent *string `json:"state_event,omitempty"` + Description *string `json:"description"` + DueDate isoTime `json:"due_date"` +} + +func (s *milestoneService) Find(ctx context.Context, repo string, id int) (*scm.Milestone, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/milestones/%d", encode(repo), id) + out := new(milestone) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertMilestone(out), res, err +} + +func (s *milestoneService) List(ctx context.Context, repo string, opts scm.MilestoneListOptions) ([]*scm.Milestone, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/milestones?%s", encode(repo), encodeMilestoneListOptions(opts)) + out := []*milestone{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertMilestoneList(out), res, err +} + +func (s *milestoneService) Create(ctx context.Context, repo string, input *scm.MilestoneInput) (*scm.Milestone, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/milestones", encode(repo)) + dueDateIso := isoTime(input.DueDate) + in := &milestoneInput{ + Title: &input.Title, + Description: &input.Description, + DueDate: dueDateIso, + } + out := new(milestone) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertMilestone(out), res, err +} + +func (s *milestoneService) Delete(ctx context.Context, repo string, id int) (*scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/milestones/%d", encode(repo), id) + res, err := s.client.do(ctx, "DELETE", path, nil, nil) + return res, err +} + +func (s *milestoneService) Update(ctx context.Context, repo string, id int, input *scm.MilestoneInput) (*scm.Milestone, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/milestones/%d", encode(repo), id) + in := &milestoneInput{} + if input.Title != "" { + in.Title = &input.Title + } + if input.State != "" { + if input.State == "open" { + activate := "activate" + in.StateEvent = &activate + } else { + in.StateEvent = &input.State + } + } + if input.Description != "" { + in.Description = &input.Description + } + if !input.DueDate.IsZero() { + dueDateIso := isoTime(input.DueDate) + in.DueDate = dueDateIso + } + out := new(milestone) + res, err := s.client.do(ctx, "PATCH", path, in, out) + return convertMilestone(out), res, err +} + +func convertMilestoneList(from []*milestone) []*scm.Milestone { + var to []*scm.Milestone + for _, m := range from { + to = append(to, convertMilestone(m)) + } + return to +} + +func convertMilestone(from *milestone) *scm.Milestone { + if from == nil || from.Title == "" { + return nil + } + dueDate := time.Time(from.DueDate) + return &scm.Milestone{ + Number: from.ID, + ID: from.ID, + Title: from.Title, + Description: from.Description, + State: from.State, + DueDate: dueDate, + } +} diff --git a/scm/driver/gitlab/milestone_test.go b/scm/driver/gitlab/milestone_test.go new file mode 100644 index 000000000..98dfaa65e --- /dev/null +++ b/scm/driver/gitlab/milestone_test.go @@ -0,0 +1,187 @@ +package gitlab + +import ( + "context" + "encoding/json" + "io/ioutil" + "testing" + "time" + + "github.com/drone/go-scm/scm" + + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestMilestoneFind(t *testing.T) { + defer gock.Off() + + gock.New("https://gitlab.com"). + Get("/api/v4/projects/diaspora/diaspora/milestones/1"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/milestone.json") + + client := NewDefault() + got, res, err := client.Milestones.Find(context.Background(), "diaspora/diaspora", 1) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Milestone) + raw, err := ioutil.ReadFile("testdata/milestone.json.golden") + if err != nil { + t.Fatalf("ioutil.ReadFile: %v", err) + } + if err := json.Unmarshal(raw, want); err != nil { + t.Fatalf("json.Unmarshal: %v", err) + } + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} + +func TestMilestoneList(t *testing.T) { + defer gock.Off() + + gock.New("https://gitlab.com"). + Get("/api/v4/projects/diaspora/diaspora/milestones"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/milestones.json") + + client := NewDefault() + got, res, err := client.Milestones.List(context.Background(), "diaspora/diaspora", scm.MilestoneListOptions{}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Milestone{} + raw, err := ioutil.ReadFile("testdata/milestones.json.golden") + if err != nil { + t.Fatalf("ioutil.ReadFile: %v", err) + } + if err := json.Unmarshal(raw, &want); err != nil { + t.Fatalf("json.Unmarshal: %v", err) + } + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} + +func TestMilestoneCreate(t *testing.T) { + defer gock.Off() + + gock.New("https://gitlab.com"). + Post("/api/v4/projects/diaspora/diaspora/milestones"). + File("testdata/milestone_create.json"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/milestone.json") + + client := NewDefault() + dueDate, _ := time.Parse(scm.SearchTimeFormat, "2012-10-09T23:39:01Z") + input := &scm.MilestoneInput{ + Title: "v1.0", + Description: "Tracking milestone for version 1.0", + State: "open", + DueDate: dueDate, + } + got, res, err := client.Milestones.Create(context.Background(), "diaspora/diaspora", input) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Milestone) + raw, err := ioutil.ReadFile("testdata/milestone.json.golden") + if err != nil { + t.Fatalf("ioutil.ReadFile: %v", err) + } + if err := json.Unmarshal(raw, &want); err != nil { + t.Fatalf("json.Unmarshal: %v", err) + } + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} + +func TestMilestoneUpdate(t *testing.T) { + defer gock.Off() + + gock.New("https://gitlab.com"). + Patch("/api/v4/projects/diaspora/diaspora/milestones/1"). + File("testdata/milestone_update.json"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/milestone.json") + + client := NewDefault() + dueDate, _ := time.Parse(scm.SearchTimeFormat, "2012-10-09T23:39:01Z") + input := &scm.MilestoneInput{ + Title: "v1.0", + Description: "Tracking milestone for version 1.0", + State: "close", + DueDate: dueDate, + } + got, res, err := client.Milestones.Update(context.Background(), "diaspora/diaspora", 1, input) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Milestone) + raw, err := ioutil.ReadFile("testdata/milestone.json.golden") + if err != nil { + t.Fatalf("ioutil.ReadFile: %v", err) + } + if err := json.Unmarshal(raw, &want); err != nil { + t.Fatalf("json.Unmarshal: %v", err) + } + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} + +func TestMilestoneDelete(t *testing.T) { + defer gock.Off() + + gock.New("https://gitlab.com"). + Delete("/api/v4/projects/diaspora/diaspora/milestones/1"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders) + + client := NewDefault() + _, err := client.Milestones.Delete(context.Background(), "diaspora/diaspora", 1) + if err != nil { + t.Error(err) + return + } +} diff --git a/scm/driver/gitlab/pr.go b/scm/driver/gitlab/pr.go index 9a6ca0d6e..bb63590a6 100644 --- a/scm/driver/gitlab/pr.go +++ b/scm/driver/gitlab/pr.go @@ -52,15 +52,31 @@ func (s *pullService) ListComments(ctx context.Context, repo string, index int, return convertIssueCommentList(out), res, err } +func (s *pullService) ListCommits(ctx context.Context, repo string, number int, opts scm.ListOptions) ([]*scm.Commit, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/merge_requests/%d/commits?%s", encode(repo), number, encodeListOptions(opts)) + out := []*commit{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertCommitList(out), res, err +} + 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 } @@ -92,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"` @@ -110,6 +127,11 @@ type pr struct { Updated time.Time `json:"updated_at"` Closed time.Time Labels []string `json:"labels"` + DiffRefs struct { + BaseSha string `json:"base_sha"` + HeadSha string `json:"head_sha"` + StartSha string `json:"start_sha"` + } `json:"diff_refs"` } type changes struct { @@ -148,6 +170,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{ @@ -158,6 +181,9 @@ func convertPullRequest(from *pr) *scm.PullRequest { Created: from.Created, Updated: from.Updated, Labels: labels, + Base: scm.Reference{ + Sha: from.DiffRefs.BaseSha, + }, } } diff --git a/scm/driver/gitlab/pr_test.go b/scm/driver/gitlab/pr_test.go index 032e9a382..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). @@ -309,3 +305,32 @@ func TestPullCommentDelete(t *testing.T) { t.Run("Request", testRequest(res)) t.Run("Rate", testRate(res)) } + +func TestPullListCommits(t *testing.T) { + gock.New("https://gitlab.com"). + Get("/api/v4/projects/diaspora/diaspora/merge_requests/1347/commits"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/commits.json") + + client := NewDefault() + got, res, err := client.PullRequests.ListCommits(context.Background(), "diaspora/diaspora", 1347, scm.ListOptions{Page: 1, Size: 30}) + 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) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} diff --git a/scm/driver/gitlab/release.go b/scm/driver/gitlab/release.go new file mode 100644 index 000000000..874c728ee --- /dev/null +++ b/scm/driver/gitlab/release.go @@ -0,0 +1,109 @@ +package gitlab + +import ( + "context" + "fmt" + + "github.com/drone/go-scm/scm" +) + +type releaseService struct { + client *wrapper +} + +type release struct { + Title string `json:"name"` + Description string `json:"description"` + Tag string `json:"tag_name"` + Commit struct { + ID string `json:"id"` + } `json:"commit"` +} + +type releaseInput struct { + Title string `json:"name"` + Description string `json:"description"` + Tag string `json:"tag_name"` +} + +func (s *releaseService) Find(ctx context.Context, repo string, id int) (*scm.Release, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + +func (s *releaseService) FindByTag(ctx context.Context, repo string, tag string) (*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/releases/%s", encode(repo), tag) + out := new(release) + res, err := s.client.do(ctx, "GET", path, nil, out) + return convertRelease(out), res, err +} + +func (s *releaseService) List(ctx context.Context, repo string, opts scm.ReleaseListOptions) ([]*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/releases", encode(repo)) + out := []*release{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertReleaseList(out), res, err +} + +func (s *releaseService) Create(ctx context.Context, repo string, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/releases", encode(repo)) + in := &releaseInput{ + Title: input.Title, + Description: input.Description, + Tag: input.Tag, + } + out := new(release) + res, err := s.client.do(ctx, "POST", path, in, out) + return convertRelease(out), res, err +} + +func (s *releaseService) Delete(ctx context.Context, repo string, id int) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + +func (s *releaseService) DeleteByTag(ctx context.Context, repo string, tag string) (*scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/releases/%s", encode(repo), tag) + return s.client.do(ctx, "DELETE", path, nil, nil) +} + +func (s *releaseService) Update(ctx context.Context, repo string, id int, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + // this could be implemented by List and filter but would be to expensive + panic("gitlab only allows to update a release by tag") +} + +func (s *releaseService) UpdateByTag(ctx context.Context, repo string, tag string, input *scm.ReleaseInput) (*scm.Release, *scm.Response, error) { + path := fmt.Sprintf("api/v4/projects/%s/releases/%s", encode(repo), tag) + in := &releaseInput{} + if input.Title != "" { + in.Title = input.Title + } + if input.Description != "" { + in.Description = input.Description + } + if input.Tag != "" { + in.Tag = input.Tag + } + out := new(release) + res, err := s.client.do(ctx, "PUT", path, in, out) + return convertRelease(out), res, err +} + +func convertReleaseList(from []*release) []*scm.Release { + var to []*scm.Release + for _, m := range from { + to = append(to, convertRelease(m)) + } + return to +} + +func convertRelease(from *release) *scm.Release { + return &scm.Release{ + ID: 0, + Title: from.Title, + Description: from.Description, + Link: "", + Tag: from.Tag, + Commitish: from.Commit.ID, + Draft: false, // not supported by gitlab + Prerelease: false, // not supported by gitlab + } +} diff --git a/scm/driver/gitlab/release_test.go b/scm/driver/gitlab/release_test.go new file mode 100644 index 000000000..998654923 --- /dev/null +++ b/scm/driver/gitlab/release_test.go @@ -0,0 +1,191 @@ +package gitlab + +import ( + "context" + "encoding/json" + "io/ioutil" + "testing" + + "github.com/drone/go-scm/scm" + + "github.com/google/go-cmp/cmp" + "github.com/h2non/gock" +) + +func TestReleaseFindByTag(t *testing.T) { + defer gock.Off() + + gock.New("https://gitlab.com"). + Get("/api/v4/projects/diaspora/diaspora/releases/v1.0.1"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/release.json") + + client := NewDefault() + got, res, err := client.Releases.FindByTag(context.Background(), "diaspora/diaspora", "v1.0.1") + if err != nil { + t.Error(err) + return + } + + want := new(scm.Release) + raw, _ := ioutil.ReadFile("testdata/release.json.golden") + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + + data, _ := json.Marshal(got) + t.Log("got JSON:") + t.Log(string(data)) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} + +func TestReleaseList(t *testing.T) { + defer gock.Off() + + gock.New("https://gitlab.com"). + Get("/api/v4/projects/diaspora/diaspora/releases"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/releases.json") + + client := NewDefault() + got, res, err := client.Releases.List(context.Background(), "diaspora/diaspora", scm.ReleaseListOptions{}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Release{} + raw, _ := ioutil.ReadFile("testdata/releases.json.golden") + err = json.Unmarshal(raw, &want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + + data, _ := json.Marshal(got) + t.Log("got JSON:") + t.Log(string(data)) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} + +func TestReleaseCreate(t *testing.T) { + defer gock.Off() + + gock.New("https://gitlab.com"). + Post("/api/v4/projects/diaspora/diaspora/releases"). + File("testdata/release_create.json"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/release.json") + + client := NewDefault() + input := &scm.ReleaseInput{ + Title: "v1.0", + Description: "Tracking release for version 1.0", + Tag: "v1.0", + } + + got, res, err := client.Releases.Create(context.Background(), "diaspora/diaspora", input) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Release) + raw, _ := ioutil.ReadFile("testdata/release.json.golden") + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + + data, _ := json.Marshal(got) + t.Log("got JSON:") + t.Log(string(data)) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} + +func TestReleaseUpdateByTag(t *testing.T) { + defer gock.Off() + + gock.New("https://gitlab.com"). + Put("/api/v4/projects/diaspora/diaspora/releases/v1.0"). + File("testdata/release_create.json"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + File("testdata/release.json") + + client := NewDefault() + input := &scm.ReleaseInput{ + Title: "v1.0", + Description: "Tracking release for version 1.0", + Tag: "v1.0", + } + + got, res, err := client.Releases.UpdateByTag(context.Background(), "diaspora/diaspora", "v1.0", input) + if err != nil { + t.Error(err) + return + } + + want := new(scm.Release) + raw, _ := ioutil.ReadFile("testdata/release.json.golden") + err = json.Unmarshal(raw, want) + if err != nil { + t.Error(err) + return + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} + +func TestReleaseDeleteByTag(t *testing.T) { + defer gock.Off() + + gock.New("https://gitlab.com"). + Delete("/api/v4/projects/diaspora/diaspora/releases/v1.0"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders) + + client := NewDefault() + res, err := client.Releases.DeleteByTag(context.Background(), "diaspora/diaspora", "v1.0") + if err != nil { + t.Error(err) + return + } + + t.Run("Request", testRequest(res)) + t.Run("Rate", testRate(res)) +} diff --git a/scm/driver/gitlab/repo.go b/scm/driver/gitlab/repo.go index 4ed8b39e5..9a44bc3bc 100644 --- a/scm/driver/gitlab/repo.go +++ b/scm/driver/gitlab/repo.go @@ -22,6 +22,7 @@ type repository struct { PathNamespace string `json:"path_with_namespace"` DefaultBranch string `json:"default_branch"` Visibility string `json:"visibility"` + Archived bool `json:"archived"` WebURL string `json:"web_url"` SSHURL string `json:"ssh_url_to_repo"` HTTPURL string `json:"http_url_to_repo"` @@ -93,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) ListHooks(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Hook, *scm.Response, error) { path := fmt.Sprintf("api/v4/projects/%s/hooks?%s", encode(repo), encodeListOptions(opts)) out := []*hook{} @@ -162,7 +178,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{} @@ -172,7 +188,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{ @@ -180,8 +196,9 @@ func convertRepository(from *repository) *scm.Repository { Namespace: from.Namespace.Path, Name: from.Path, Branch: from.DefaultBranch, - Private: convertPrivate(from.Visibility), - Visibility: convertVisibility(from.Visibility), + Archived: from.Archived, + Private: scm.ConvertPrivate(from.Visibility), + Visibility: scm.ConvertVisibility(from.Visibility), Clone: from.HTTPURL, CloneSSH: from.SSHURL, Link: from.WebURL, @@ -300,28 +317,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/branch_create.json b/scm/driver/gitlab/testdata/branch_create.json new file mode 100644 index 000000000..2c82cc7a3 --- /dev/null +++ b/scm/driver/gitlab/testdata/branch_create.json @@ -0,0 +1,27 @@ +{ + "name": "yooo", + "commit": { + "id": "0efb1bed7c6a4871cb4ddb862ecc2111e11f31ee", + "short_id": "0efb1bed", + "created_at": "2021-04-07T08:16:54.000+00:00", + "parent_ids": [ + "4d8cf0b0d2a3f9dd54ec1f204a95f08a0f318199" + ], + "title": "message1", + "message": "message1", + "author_name": "tp honey", + "author_email": "tp@harness.io", + "authored_date": "2021-04-07T08:16:54.000+00:00", + "committer_name": "TP Honey", + "committer_email": "tp@harness.io", + "committed_date": "2021-04-07T08:16:54.000+00:00", + "web_url": "https://gitlab.com/tphoney/test_repo/-/commit/0efb1bed7c6a4871cb4ddb862ecc2111e11f31ee" + }, + "merged": true, + "protected": false, + "developers_can_push": false, + "developers_can_merge": false, + "can_push": true, + "default": false, + "web_url": "https://gitlab.com/tphoney/test_repo/-/tree/yooo" +} \ No newline at end of file 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/content.json.golden b/scm/driver/gitlab/testdata/content.json.golden index 73abcc029..0d3df102b 100644 --- a/scm/driver/gitlab/testdata/content.json.golden +++ b/scm/driver/gitlab/testdata/content.json.golden @@ -1,4 +1,6 @@ { "Path": "app/models/key.rb", - "Data": "cmVxdWlyZSAnZGlnZXN0L21kNScKCmNsYXNzIEtleSA8IEFjdGl2ZVJlY29yZDo6QmFzZQogIGluY2x1ZGUgR2l0bGFiOjpDdXJyZW50U2V0dGluZ3MKICBpbmNsdWRlIFNvcnRhYmxlCgogIGJlbG9uZ3NfdG8gOnVzZXIKCiAgYmVmb3JlX3ZhbGlkYXRpb24gOmdlbmVyYXRlX2ZpbmdlcnByaW50CgogIHZhbGlkYXRlcyA6dGl0bGUsCiAgICBwcmVzZW5jZTogdHJ1ZSwKICAgIGxlbmd0aDogeyBtYXhpbXVtOiAyNTUgfQoKICB2YWxpZGF0ZXMgOmtleSwKICAgIHByZXNlbmNlOiB0cnVlLAogICAgbGVuZ3RoOiB7IG1heGltdW06IDUwMDAgfSwKICAgIGZvcm1hdDogeyB3aXRoOiAvXEEoc3NofGVjZHNhKS0uKlxaLyB9CgogIHZhbGlkYXRlcyA6ZmluZ2VycHJpbnQsCiAgICB1bmlxdWVuZXNzOiB0cnVlLAogICAgcHJlc2VuY2U6IHsgbWVzc2FnZTogJ2Nhbm5vdCBiZSBnZW5lcmF0ZWQnIH0KCiAgdmFsaWRhdGUgOmtleV9tZWV0c19yZXN0cmljdGlvbnMKCiAgZGVsZWdhdGUgOm5hbWUsIDplbWFpbCwgdG86IDp1c2VyLCBwcmVmaXg6IHRydWUKCiAgYWZ0ZXJfY29tbWl0IDphZGRfdG9fc2hlbGwsIG9uOiA6Y3JlYXRlCiAgYWZ0ZXJfY3JlYXRlIDpwb3N0X2NyZWF0ZV9ob29rCiAgYWZ0ZXJfY3JlYXRlIDpyZWZyZXNoX3VzZXJfY2FjaGUKICBhZnRlcl9jb21taXQgOnJlbW92ZV9mcm9tX3NoZWxsLCBvbjogOmRlc3Ryb3kKICBhZnRlcl9kZXN0cm95IDpwb3N0X2Rlc3Ryb3lfaG9vawogIGFmdGVyX2Rlc3Ryb3kgOnJlZnJlc2hfdXNlcl9jYWNoZQoKICBkZWYga2V5PSh2YWx1ZSkKICAgIHZhbHVlJi5kZWxldGUhKCJcblxyIikKICAgIHZhbHVlLnN0cmlwISB1bmxlc3MgdmFsdWUuYmxhbms=" + "Data": "cmVxdWlyZSAnZGlnZXN0L21kNScKCmNsYXNzIEtleSA8IEFjdGl2ZVJlY29yZDo6QmFzZQogIGluY2x1ZGUgR2l0bGFiOjpDdXJyZW50U2V0dGluZ3MKICBpbmNsdWRlIFNvcnRhYmxlCgogIGJlbG9uZ3NfdG8gOnVzZXIKCiAgYmVmb3JlX3ZhbGlkYXRpb24gOmdlbmVyYXRlX2ZpbmdlcnByaW50CgogIHZhbGlkYXRlcyA6dGl0bGUsCiAgICBwcmVzZW5jZTogdHJ1ZSwKICAgIGxlbmd0aDogeyBtYXhpbXVtOiAyNTUgfQoKICB2YWxpZGF0ZXMgOmtleSwKICAgIHByZXNlbmNlOiB0cnVlLAogICAgbGVuZ3RoOiB7IG1heGltdW06IDUwMDAgfSwKICAgIGZvcm1hdDogeyB3aXRoOiAvXEEoc3NofGVjZHNhKS0uKlxaLyB9CgogIHZhbGlkYXRlcyA6ZmluZ2VycHJpbnQsCiAgICB1bmlxdWVuZXNzOiB0cnVlLAogICAgcHJlc2VuY2U6IHsgbWVzc2FnZTogJ2Nhbm5vdCBiZSBnZW5lcmF0ZWQnIH0KCiAgdmFsaWRhdGUgOmtleV9tZWV0c19yZXN0cmljdGlvbnMKCiAgZGVsZWdhdGUgOm5hbWUsIDplbWFpbCwgdG86IDp1c2VyLCBwcmVmaXg6IHRydWUKCiAgYWZ0ZXJfY29tbWl0IDphZGRfdG9fc2hlbGwsIG9uOiA6Y3JlYXRlCiAgYWZ0ZXJfY3JlYXRlIDpwb3N0X2NyZWF0ZV9ob29rCiAgYWZ0ZXJfY3JlYXRlIDpyZWZyZXNoX3VzZXJfY2FjaGUKICBhZnRlcl9jb21taXQgOnJlbW92ZV9mcm9tX3NoZWxsLCBvbjogOmRlc3Ryb3kKICBhZnRlcl9kZXN0cm95IDpwb3N0X2Rlc3Ryb3lfaG9vawogIGFmdGVyX2Rlc3Ryb3kgOnJlZnJlc2hfdXNlcl9jYWNoZQoKICBkZWYga2V5PSh2YWx1ZSkKICAgIHZhbHVlJi5kZWxldGUhKCJcblxyIikKICAgIHZhbHVlLnN0cmlwISB1bmxlc3MgdmFsdWUuYmxhbms=", + "Sha": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d", + "BlobID": "79f7bbd25901e8334750839545a9bd021f0e4c83" } \ No newline at end of file diff --git a/scm/driver/gitlab/testdata/content_list.json b/scm/driver/gitlab/testdata/content_list.json index 333176ee6..7a4d1b60b 100644 --- a/scm/driver/gitlab/testdata/content_list.json +++ b/scm/driver/gitlab/testdata/content_list.json @@ -1 +1,142 @@ -[{"id":"ff85b01e96cca1db128a3ea0b3643667f50e464f","name":"ansi2json","type":"tree","path":"lib/gitlab/ci/ansi2json","mode":"040000"},{"id":"b044e0902a1d468d0e59ca733da6c22c4710af20","name":"build","type":"tree","path":"lib/gitlab/ci/build","mode":"040000"},{"id":"80cecd7647164c63768f52b431509d04d7f7dcf6","name":"config","type":"tree","path":"lib/gitlab/ci/config","mode":"040000"},{"id":"1d53ca741903e40610728c07b637da21fbf9f394","name":"parsers","type":"tree","path":"lib/gitlab/ci/parsers","mode":"040000"},{"id":"1a8b0f4be2707c3d7bdede2865c4a2c8a4af99a9","name":"pipeline","type":"tree","path":"lib/gitlab/ci/pipeline","mode":"040000"},{"id":"42afb52861c8f807f6ccf95e98607638b6d30f22","name":"reports","type":"tree","path":"lib/gitlab/ci/reports","mode":"040000"},{"id":"1cf9d5d945923d8a3f820b5b39aa65431b271375","name":"status","type":"tree","path":"lib/gitlab/ci/status","mode":"040000"},{"id":"f02f0b133c976074cec2b3babc88966f2ef32374","name":"templates","type":"tree","path":"lib/gitlab/ci/templates","mode":"040000"},{"id":"f2f31cbc4e89da99530cd30d7fc5f4d989d05b90","name":"trace","type":"tree","path":"lib/gitlab/ci/trace","mode":"040000"},{"id":"8d06f84b4a11604dacb1e37eb3c99094f2bccbd8","name":"variables","type":"tree","path":"lib/gitlab/ci/variables","mode":"040000"},{"id":"eb5d78ebcd41aee923ad02c8fe4b340d87254d59","name":"ansi2html.rb","type":"blob","path":"lib/gitlab/ci/ansi2html.rb","mode":"100644"},{"id":"79114d35916cc46aff83b225c3fcef3e47fe0719","name":"ansi2json.rb","type":"blob","path":"lib/gitlab/ci/ansi2json.rb","mode":"100644"},{"id":"3fbfdffe277f296e8f116f078e80adbe072a158b","name":"charts.rb","type":"blob","path":"lib/gitlab/ci/charts.rb","mode":"100644"},{"id":"9c1e6277e95ee74775a45cadd3628bc05e777660","name":"config.rb","type":"blob","path":"lib/gitlab/ci/config.rb","mode":"100644"},{"id":"1d7e7ea0f9af2839512d89488f4873f0edd4a6dc","name":"cron_parser.rb","type":"blob","path":"lib/gitlab/ci/cron_parser.rb","mode":"100644"},{"id":"58d55b1bd6f394aeff2cb579efa48970b52f095b","name":"mask_secret.rb","type":"blob","path":"lib/gitlab/ci/mask_secret.rb","mode":"100644"},{"id":"1625cb841b694deea23c816761e09b4337affc03","name":"model.rb","type":"blob","path":"lib/gitlab/ci/model.rb","mode":"100644"},{"id":"c76cd5ff28512ed90616be13d9e776b83124eab2","name":"parsers.rb","type":"blob","path":"lib/gitlab/ci/parsers.rb","mode":"100644"},{"id":"941f7178dacf36fce67fdfa538f1d8ef50e5d6da","name":"trace.rb","type":"blob","path":"lib/gitlab/ci/trace.rb","mode":"100644"},{"id":"f6a3abefcfb350d9ff69560a579b3c9473612a8b","name":"yaml_processor.rb","type":"blob","path":"lib/gitlab/ci/yaml_processor.rb","mode":"100644"}] \ No newline at end of file +[ + { + "id": "ff85b01e96cca1db128a3ea0b3643667f50e464f", + "name": "ansi2json", + "type": "tree", + "path": "lib/gitlab/ci/ansi2json", + "mode": "040000" + }, + { + "id": "b044e0902a1d468d0e59ca733da6c22c4710af20", + "name": "build", + "type": "tree", + "path": "lib/gitlab/ci/build", + "mode": "040000" + }, + { + "id": "80cecd7647164c63768f52b431509d04d7f7dcf6", + "name": "config", + "type": "tree", + "path": "lib/gitlab/ci/config", + "mode": "040000" + }, + { + "id": "1d53ca741903e40610728c07b637da21fbf9f394", + "name": "parsers", + "type": "tree", + "path": "lib/gitlab/ci/parsers", + "mode": "040000" + }, + { + "id": "1a8b0f4be2707c3d7bdede2865c4a2c8a4af99a9", + "name": "pipeline", + "type": "tree", + "path": "lib/gitlab/ci/pipeline", + "mode": "040000" + }, + { + "id": "42afb52861c8f807f6ccf95e98607638b6d30f22", + "name": "reports", + "type": "tree", + "path": "lib/gitlab/ci/reports", + "mode": "040000" + }, + { + "id": "1cf9d5d945923d8a3f820b5b39aa65431b271375", + "name": "status", + "type": "tree", + "path": "lib/gitlab/ci/status", + "mode": "040000" + }, + { + "id": "f02f0b133c976074cec2b3babc88966f2ef32374", + "name": "templates", + "type": "tree", + "path": "lib/gitlab/ci/templates", + "mode": "040000" + }, + { + "id": "f2f31cbc4e89da99530cd30d7fc5f4d989d05b90", + "name": "trace", + "type": "tree", + "path": "lib/gitlab/ci/trace", + "mode": "040000" + }, + { + "id": "8d06f84b4a11604dacb1e37eb3c99094f2bccbd8", + "name": "variables", + "type": "tree", + "path": "lib/gitlab/ci/variables", + "mode": "040000" + }, + { + "id": "eb5d78ebcd41aee923ad02c8fe4b340d87254d59", + "name": "ansi2html.rb", + "type": "blob", + "path": "lib/gitlab/ci/ansi2html.rb", + "mode": "100644" + }, + { + "id": "79114d35916cc46aff83b225c3fcef3e47fe0719", + "name": "ansi2json.rb", + "type": "blob", + "path": "lib/gitlab/ci/ansi2json.rb", + "mode": "100644" + }, + { + "id": "3fbfdffe277f296e8f116f078e80adbe072a158b", + "name": "charts.rb", + "type": "blob", + "path": "lib/gitlab/ci/charts.rb", + "mode": "100644" + }, + { + "id": "9c1e6277e95ee74775a45cadd3628bc05e777660", + "name": "config.rb", + "type": "blob", + "path": "lib/gitlab/ci/config.rb", + "mode": "100644" + }, + { + "id": "1d7e7ea0f9af2839512d89488f4873f0edd4a6dc", + "name": "cron_parser.rb", + "type": "blob", + "path": "lib/gitlab/ci/cron_parser.rb", + "mode": "100644" + }, + { + "id": "58d55b1bd6f394aeff2cb579efa48970b52f095b", + "name": "mask_secret.rb", + "type": "blob", + "path": "lib/gitlab/ci/mask_secret.rb", + "mode": "100644" + }, + { + "id": "1625cb841b694deea23c816761e09b4337affc03", + "name": "model.rb", + "type": "blob", + "path": "lib/gitlab/ci/model.rb", + "mode": "100644" + }, + { + "id": "c76cd5ff28512ed90616be13d9e776b83124eab2", + "name": "parsers.rb", + "type": "blob", + "path": "lib/gitlab/ci/parsers.rb", + "mode": "100644" + }, + { + "id": "941f7178dacf36fce67fdfa538f1d8ef50e5d6da", + "name": "trace.rb", + "type": "blob", + "path": "lib/gitlab/ci/trace.rb", + "mode": "100644" + }, + { + "id": "f6a3abefcfb350d9ff69560a579b3c9473612a8b", + "name": "yaml_processor.rb", + "type": "blob", + "path": "lib/gitlab/ci/yaml_processor.rb", + "mode": "100644" + } +] \ No newline at end of file diff --git a/scm/driver/gitlab/testdata/content_update.json.fail b/scm/driver/gitlab/testdata/content_update.json.fail new file mode 100644 index 000000000..a92bd370f --- /dev/null +++ b/scm/driver/gitlab/testdata/content_update.json.fail @@ -0,0 +1,3 @@ +{ + "message": "You are attempting to update a file that has changed since you started editing it." +} \ No newline at end of file diff --git a/scm/driver/gitlab/testdata/emails.json b/scm/driver/gitlab/testdata/emails.json new file mode 100644 index 000000000..15ff44bab --- /dev/null +++ b/scm/driver/gitlab/testdata/emails.json @@ -0,0 +1,12 @@ +[ + { + "id": 1, + "email": "john@company.com", + "confirmed_at": "2021-03-26T19:07:56.248Z" + }, + { + "id": 3, + "email": "jane@company.com", + "confirmed_at": null + } +] \ No newline at end of file diff --git a/scm/driver/gitlab/testdata/emails.json.golden b/scm/driver/gitlab/testdata/emails.json.golden new file mode 100644 index 000000000..595eea801 --- /dev/null +++ b/scm/driver/gitlab/testdata/emails.json.golden @@ -0,0 +1,12 @@ +[ + { + "Value": "john@company.com", + "verified": true, + "primary": false + }, + { + "Value": "jane@company.com", + "verified": false, + "primary": false + } +] \ 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 4df0d2492..5864162c3 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 46cb6d7c4..cf605b9ee 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/milestone.json b/scm/driver/gitlab/testdata/milestone.json new file mode 100644 index 000000000..0cbf520b3 --- /dev/null +++ b/scm/driver/gitlab/testdata/milestone.json @@ -0,0 +1,13 @@ +{ + "id": 12, + "iid": 3, + "project_id": 16, + "title": "10.0", + "description": "Version", + "due_date": "2013-11-29", + "start_date": "2013-11-10", + "state": "active", + "updated_at": "2013-10-02T09:24:18Z", + "created_at": "2013-10-02T09:24:18Z", + "expired": false +} diff --git a/scm/driver/gitlab/testdata/milestone.json.golden b/scm/driver/gitlab/testdata/milestone.json.golden new file mode 100644 index 000000000..186481374 --- /dev/null +++ b/scm/driver/gitlab/testdata/milestone.json.golden @@ -0,0 +1,8 @@ +{ + "ID": 12, + "Number": 12, + "Title": "10.0", + "Description": "Version", + "DueDate": "2013-11-29T00:00:00Z", + "State": "active" +} diff --git a/scm/driver/gitlab/testdata/milestone_create.json b/scm/driver/gitlab/testdata/milestone_create.json new file mode 100644 index 000000000..efb5309fd --- /dev/null +++ b/scm/driver/gitlab/testdata/milestone_create.json @@ -0,0 +1,5 @@ +{ + "title": "v1.0", + "description": "Tracking milestone for version 1.0", + "due_date": "2012-10-09" +} diff --git a/scm/driver/gitlab/testdata/milestone_update.json b/scm/driver/gitlab/testdata/milestone_update.json new file mode 100644 index 000000000..a91bbbd16 --- /dev/null +++ b/scm/driver/gitlab/testdata/milestone_update.json @@ -0,0 +1,6 @@ +{ + "title": "v1.0", + "description": "Tracking milestone for version 1.0", + "state_event": "close", + "due_date": "2012-10-09" +} diff --git a/scm/driver/gitlab/testdata/milestones.json b/scm/driver/gitlab/testdata/milestones.json new file mode 100644 index 000000000..f6c9e76cf --- /dev/null +++ b/scm/driver/gitlab/testdata/milestones.json @@ -0,0 +1,15 @@ +[ + { + "id": 12, + "iid": 3, + "project_id": 16, + "title": "10.0", + "description": "Version", + "due_date": "2013-11-29", + "start_date": "2013-11-10", + "state": "active", + "updated_at": "2013-10-02T09:24:18Z", + "created_at": "2013-10-02T09:24:18Z", + "expired": false + } +] diff --git a/scm/driver/gitlab/testdata/milestones.json.golden b/scm/driver/gitlab/testdata/milestones.json.golden new file mode 100644 index 000000000..9fd157cca --- /dev/null +++ b/scm/driver/gitlab/testdata/milestones.json.golden @@ -0,0 +1,10 @@ +[ + { + "ID": 12, + "Number": 12, + "Title": "10.0", + "Description": "Version", + "DueDate": "2013-11-29T00:00:00Z", + "State": "active" + } +] diff --git a/scm/driver/gitlab/testdata/release.json b/scm/driver/gitlab/testdata/release.json new file mode 100644 index 000000000..2f32681eb --- /dev/null +++ b/scm/driver/gitlab/testdata/release.json @@ -0,0 +1,100 @@ +{ + "tag_name":"v0.1", + "description":"## CHANGELOG\r\n\r\n- Remove limit of 100 when searching repository code. !8671\r\n- Show error message when attempting to reopen an MR and there is an open MR for the same branch. !16447 (Akos Gyimesi)\r\n- Fix a bug where internal email pattern wasn't respected. !22516", + "name":"Awesome app v0.1 alpha", + "description_html":"\u003ch2 dir=\"auto\"\u003e\n\u003ca id=\"user-content-changelog\" class=\"anchor\" href=\"#changelog\" aria-hidden=\"true\"\u003e\u003c/a\u003eCHANGELOG\u003c/h2\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eRemove limit of 100 when searching repository code. !8671\u003c/li\u003e\n\u003cli\u003eShow error message when attempting to reopen an MR and there is an open MR for the same branch. !16447 (Akos Gyimesi)\u003c/li\u003e\n\u003cli\u003eFix a bug where internal email pattern wasn't respected. !22516\u003c/li\u003e\n\u003c/ul\u003e", + "created_at":"2019-01-03T01:55:18.203Z", + "released_at":"2019-01-03T01:55:18.203Z", + "author":{ + "id":1, + "name":"Administrator", + "username":"root", + "state":"active", + "avatar_url":"https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", + "web_url":"https://gitlab.example.com/root" + }, + "commit":{ + "id":"f8d3d94cbd347e924aa7b715845e439d00e80ca4", + "short_id":"f8d3d94c", + "title":"Initial commit", + "created_at":"2019-01-03T01:53:28.000Z", + "parent_ids":[ + + ], + "message":"Initial commit", + "author_name":"Administrator", + "author_email":"admin@example.com", + "authored_date":"2019-01-03T01:53:28.000Z", + "committer_name":"Administrator", + "committer_email":"admin@example.com", + "committed_date":"2019-01-03T01:53:28.000Z" + }, + "milestones": [ + { + "id":51, + "iid":1, + "project_id":24, + "title":"v1.0-rc", + "description":"Voluptate fugiat possimus quis quod aliquam expedita.", + "state":"closed", + "created_at":"2019-07-12T19:45:44.256Z", + "updated_at":"2019-07-12T19:45:44.256Z", + "due_date":"2019-08-16T11:00:00.256Z", + "start_date":"2019-07-30T12:00:00.256Z", + "web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/1", + "issue_stats": { + "total": 98, + "closed": 76 + } + }, + { + "id":52, + "iid":2, + "project_id":24, + "title":"v1.0", + "description":"Voluptate fugiat possimus quis quod aliquam expedita.", + "state":"closed", + "created_at":"2019-07-16T14:00:12.256Z", + "updated_at":"2019-07-16T14:00:12.256Z", + "due_date":"2019-08-16T11:00:00.256Z", + "start_date":"2019-07-30T12:00:00.256Z", + "web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/2", + "issue_stats": { + "total": 24, + "closed": 21 + } + } + ], + "commit_path":"/root/awesome-app/commit/588440f66559714280628a4f9799f0c4eb880a4a", + "tag_path":"/root/awesome-app/-/tags/v0.11.1", + "assets":{ + "count":5, + "sources":[ + { + "format":"zip", + "url":"https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.zip" + }, + { + "format":"tar.gz", + "url":"https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar.gz" + }, + { + "format":"tar.bz2", + "url":"https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar.bz2" + }, + { + "format":"tar", + "url":"https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar" + } + ], + "links":[ + { + "id":3, + "name":"hoge", + "url":"https://gitlab.example.com/root/awesome-app/-/tags/v0.11.1/binaries/linux-amd64", + "external":true, + "link_type":"other" + } + ] + } +} diff --git a/scm/driver/gitlab/testdata/release.json.golden b/scm/driver/gitlab/testdata/release.json.golden new file mode 100644 index 000000000..3ac087ded --- /dev/null +++ b/scm/driver/gitlab/testdata/release.json.golden @@ -0,0 +1,10 @@ +{ + "ID": 0, + "Title": "Awesome app v0.1 alpha", + "Description": "## CHANGELOG\r\n\r\n- Remove limit of 100 when searching repository code. !8671\r\n- Show error message when attempting to reopen an MR and there is an open MR for the same branch. !16447 (Akos Gyimesi)\r\n- Fix a bug where internal email pattern wasn't respected. !22516", + "Link": "", + "Tag": "v0.1", + "Commitish": "f8d3d94cbd347e924aa7b715845e439d00e80ca4", + "Draft": false, + "Prerelease": false +} diff --git a/scm/driver/gitlab/testdata/releases.json b/scm/driver/gitlab/testdata/releases.json new file mode 100644 index 000000000..c0a708965 --- /dev/null +++ b/scm/driver/gitlab/testdata/releases.json @@ -0,0 +1,167 @@ +[ + { + "tag_name":"v0.2", + "description":"## CHANGELOG\r\n\r\n- Escape label and milestone titles to prevent XSS in GFM autocomplete. !2740\r\n- Prevent private snippets from being embeddable.\r\n- Add subresources removal to member destroy service.", + "name":"Awesome app v0.2 beta", + "description_html":"\u003ch2 dir=\"auto\"\u003e\n\u003ca id=\"user-content-changelog\" class=\"anchor\" href=\"#changelog\" aria-hidden=\"true\"\u003e\u003c/a\u003eCHANGELOG\u003c/h2\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eEscape label and milestone titles to prevent XSS in GFM autocomplete. !2740\u003c/li\u003e\n\u003cli\u003ePrevent private snippets from being embeddable.\u003c/li\u003e\n\u003cli\u003eAdd subresources removal to member destroy service.\u003c/li\u003e\n\u003c/ul\u003e", + "created_at":"2019-01-03T01:56:19.539Z", + "released_at":"2019-01-03T01:56:19.539Z", + "author":{ + "id":1, + "name":"Administrator", + "username":"root", + "state":"active", + "avatar_url":"https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", + "web_url":"https://gitlab.example.com/root" + }, + "commit":{ + "id":"079e90101242458910cccd35eab0e211dfc359c0", + "short_id":"079e9010", + "title":"Update README.md", + "created_at":"2019-01-03T01:55:38.000Z", + "parent_ids":[ + "f8d3d94cbd347e924aa7b715845e439d00e80ca4" + ], + "message":"Update README.md", + "author_name":"Administrator", + "author_email":"admin@example.com", + "authored_date":"2019-01-03T01:55:38.000Z", + "committer_name":"Administrator", + "committer_email":"admin@example.com", + "committed_date":"2019-01-03T01:55:38.000Z" + }, + "milestones": [ + { + "id":51, + "iid":1, + "project_id":24, + "title":"v1.0-rc", + "description":"Voluptate fugiat possimus quis quod aliquam expedita.", + "state":"closed", + "created_at":"2019-07-12T19:45:44.256Z", + "updated_at":"2019-07-12T19:45:44.256Z", + "due_date":"2019-08-16T11:00:00.256Z", + "start_date":"2019-07-30T12:00:00.256Z", + "web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/1", + "issue_stats": { + "total": 98, + "closed": 76 + } + }, + { + "id":52, + "iid":2, + "project_id":24, + "title":"v1.0", + "description":"Voluptate fugiat possimus quis quod aliquam expedita.", + "state":"closed", + "created_at":"2019-07-16T14:00:12.256Z", + "updated_at":"2019-07-16T14:00:12.256Z", + "due_date":"2019-08-16T11:00:00.256Z", + "start_date":"2019-07-30T12:00:00.256Z", + "web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/2", + "issue_stats": { + "total": 24, + "closed": 21 + } + } + ], + "commit_path":"/root/awesome-app/commit/588440f66559714280628a4f9799f0c4eb880a4a", + "tag_path":"/root/awesome-app/-/tags/v0.11.1", + "assets":{ + "count":6, + "sources":[ + { + "format":"zip", + "url":"https://gitlab.example.com/root/awesome-app/-/archive/v0.2/awesome-app-v0.2.zip" + }, + { + "format":"tar.gz", + "url":"https://gitlab.example.com/root/awesome-app/-/archive/v0.2/awesome-app-v0.2.tar.gz" + }, + { + "format":"tar.bz2", + "url":"https://gitlab.example.com/root/awesome-app/-/archive/v0.2/awesome-app-v0.2.tar.bz2" + }, + { + "format":"tar", + "url":"https://gitlab.example.com/root/awesome-app/-/archive/v0.2/awesome-app-v0.2.tar" + } + ], + "links":[ + { + "id":2, + "name":"awesome-v0.2.msi", + "url":"http://192.168.10.15:3000/msi", + "external":true, + "link_type":"other" + }, + { + "id":1, + "name":"awesome-v0.2.dmg", + "url":"http://192.168.10.15:3000", + "external":true, + "link_type":"other" + } + ], + "evidence_file_path":"https://gitlab.example.com/root/awesome-app/-/releases/v0.2/evidence.json" + } + }, + { + "tag_name":"v0.1", + "description":"## CHANGELOG\r\n\r\n-Remove limit of 100 when searching repository code. !8671\r\n- Show error message when attempting to reopen an MR and there is an open MR for the same branch. !16447 (Akos Gyimesi)\r\n- Fix a bug where internal email pattern wasn't respected. !22516", + "name":"Awesome app v0.1 alpha", + "description_html":"\u003ch2 dir=\"auto\"\u003e\n\u003ca id=\"user-content-changelog\" class=\"anchor\" href=\"#changelog\" aria-hidden=\"true\"\u003e\u003c/a\u003eCHANGELOG\u003c/h2\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eRemove limit of 100 when searching repository code. !8671\u003c/li\u003e\n\u003cli\u003eShow error message when attempting to reopen an MR and there is an open MR for the same branch. !16447 (Akos Gyimesi)\u003c/li\u003e\n\u003cli\u003eFix a bug where internal email pattern wasn't respected. !22516\u003c/li\u003e\n\u003c/ul\u003e", + "created_at":"2019-01-03T01:55:18.203Z", + "released_at":"2019-01-03T01:55:18.203Z", + "author":{ + "id":1, + "name":"Administrator", + "username":"root", + "state":"active", + "avatar_url":"https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", + "web_url":"https://gitlab.example.com/root" + }, + "commit":{ + "id":"f8d3d94cbd347e924aa7b715845e439d00e80ca4", + "short_id":"f8d3d94c", + "title":"Initial commit", + "created_at":"2019-01-03T01:53:28.000Z", + "parent_ids":[ + + ], + "message":"Initial commit", + "author_name":"Administrator", + "author_email":"admin@example.com", + "authored_date":"2019-01-03T01:53:28.000Z", + "committer_name":"Administrator", + "committer_email":"admin@example.com", + "committed_date":"2019-01-03T01:53:28.000Z" + }, + "assets":{ + "count":4, + "sources":[ + { + "format":"zip", + "url":"https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.zip" + }, + { + "format":"tar.gz", + "url":"https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar.gz" + }, + { + "format":"tar.bz2", + "url":"https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar.bz2" + }, + { + "format":"tar", + "url":"https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar" + } + ], + "links":[ + + ], + "evidence_file_path":"https://gitlab.example.com/root/awesome-app/-/releases/v0.1/evidence.json" + } + } +] diff --git a/scm/driver/gitlab/testdata/releases.json.golden b/scm/driver/gitlab/testdata/releases.json.golden new file mode 100644 index 000000000..640ae4b7f --- /dev/null +++ b/scm/driver/gitlab/testdata/releases.json.golden @@ -0,0 +1,14 @@ +[ + { + "Title": "Awesome app v0.2 beta", + "Description": "## CHANGELOG\r\n\r\n- Escape label and milestone titles to prevent XSS in GFM autocomplete. !2740\r\n- Prevent private snippets from being embeddable.\r\n- Add subresources removal to member destroy service.", + "Tag": "v0.2", + "Commitish": "079e90101242458910cccd35eab0e211dfc359c0" + }, + { + "Title": "Awesome app v0.1 alpha", + "Description": "## CHANGELOG\r\n\r\n-Remove limit of 100 when searching repository code. !8671\r\n- Show error message when attempting to reopen an MR and there is an open MR for the same branch. !16447 (Akos Gyimesi)\r\n- Fix a bug where internal email pattern wasn't respected. !22516", + "Tag": "v0.1", + "Commitish": "f8d3d94cbd347e924aa7b715845e439d00e80ca4" + } +] 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 010c28001..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": "0001-01-01T00:00:00Z", + "Date": "2017-12-10T08:28:36Z", "Login": "", "Avatar": "" }, "Committer": { "Name": "Sid Sijbrandij", "Email": "noreply@gitlab.com", - "Date": "0001-01-01T00:00:00Z", + "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/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 2b6863cbb..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": "0001-01-01T00:00:00Z", + "Date": "2017-12-10T08:26:38Z", "Login": "", "Avatar": "" }, "Committer": { "Name": "Sid Sijbrandij", "Email": "noreply@gitlab.com", - "Date": "0001-01-01T00:00:00Z", + "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 b96828528..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": "0001-01-01T00:00:00Z", + "Date": "2017-12-10T08:26:38Z", "Login": "", "Avatar": "" }, "Committer": { "Name": "Sid Sijbrandij", "Email": "noreply@gitlab.com", - "Date": "0001-01-01T00:00:00Z", + "Date": "2017-12-10T08:26:38Z", "Login": "", "Avatar": "" }, diff --git a/scm/driver/gitlab/user.go b/scm/driver/gitlab/user.go index 454aea5c7..7f182bfca 100644 --- a/scm/driver/gitlab/user.go +++ b/scm/driver/gitlab/user.go @@ -41,13 +41,28 @@ func (s *userService) FindEmail(ctx context.Context) (string, *scm.Response, err return user.Email, res, err } +func (s *userService) ListEmail(ctx context.Context, opts scm.ListOptions) ([]*scm.Email, *scm.Response, error) { + path := fmt.Sprintf("api/v4/user/emails?%s", encodeListOptions(opts)) + out := []*email{} + res, err := s.client.do(ctx, "GET", path, nil, &out) + return convertEmailList(out), res, err +} + type user struct { + ID int `json:"id"` Username string `json:"username"` Name string `json:"name"` Email null.String `json:"email"` Avatar string `json:"avatar_url"` } +type email struct { + Email string `json:"email"` + Confirmed null.String `json:"confirmed_at"` +} + +// helper function to convert from the gitlab user structure to +// the common user structure. func convertUser(from *user) *scm.User { return &scm.User{ Avatar: from.Avatar, @@ -56,3 +71,22 @@ func convertUser(from *user) *scm.User { Name: from.Name, } } + +// helper function to convert from the gitlab email list to +// the common email structure. +func convertEmailList(from []*email) []*scm.Email { + to := []*scm.Email{} + for _, v := range from { + to = append(to, convertEmail(v)) + } + return to +} + +// helper function to convert from the gitlab email structure to +// the common email structure. +func convertEmail(from *email) *scm.Email { + return &scm.Email{ + Value: from.Email, + Verified: !from.Confirmed.IsZero(), + } +} diff --git a/scm/driver/gitlab/user_test.go b/scm/driver/gitlab/user_test.go index 7729592ef..217ae319c 100644 --- a/scm/driver/gitlab/user_test.go +++ b/scm/driver/gitlab/user_test.go @@ -143,3 +143,37 @@ func TestUserEmailFind(t *testing.T) { t.Run("Request", testRequest(res)) t.Run("Rate", testRate(res)) } + +func TestUserEmailList(t *testing.T) { + defer gock.Off() + + gock.New("https://gitlab.com"). + Get("/api/v4/user/emails"). + MatchParam("page", "1"). + MatchParam("per_page", "30"). + Reply(200). + Type("application/json"). + SetHeaders(mockHeaders). + SetHeaders(mockPageHeaders). + File("testdata/emails.json") + + client := NewDefault() + got, res, err := client.Users.ListEmail(context.Background(), scm.ListOptions{Size: 30, Page: 1}) + if err != nil { + t.Error(err) + return + } + + want := []*scm.Email{} + raw, _ := ioutil.ReadFile("testdata/emails.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)) +} diff --git a/scm/driver/gitlab/util.go b/scm/driver/gitlab/util.go index adc28ae30..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 { @@ -58,6 +93,9 @@ func encodeCommitListOptions(opts scm.CommitListOptions) string { if opts.Ref != "" { params.Set("ref_name", opts.Ref) } + if opts.Path != "" { + params.Set("path", opts.Path) + } return params.Encode() } @@ -96,3 +134,19 @@ func encodePullRequestListOptions(opts scm.PullRequestListOptions) string { } return params.Encode() } + +func encodeMilestoneListOptions(opts scm.MilestoneListOptions) string { + params := url.Values{} + if opts.Page != 0 { + params.Set("page", strconv.Itoa(opts.Page)) + } + if opts.Size != 0 { + params.Set("per_page", strconv.Itoa(opts.Size)) + } + if opts.Open && opts.Closed { + params.Set("state", "all") + } else if opts.Closed { + params.Set("state", "closed") + } + return params.Encode() +} diff --git a/scm/driver/gitlab/util_test.go b/scm/driver/gitlab/util_test.go index 6eedbac27..25fcbf933 100644 --- a/scm/driver/gitlab/util_test.go +++ b/scm/driver/gitlab/util_test.go @@ -39,8 +39,9 @@ func Test_encodeCommitListOptions(t *testing.T) { Page: 10, Size: 30, Ref: "master", + Path: "Readme.md", } - want := "page=10&per_page=30&ref_name=master" + want := "page=10&path=Readme.md&per_page=30&ref_name=master" got := encodeCommitListOptions(opts) if got != want { t.Errorf("Want encoded commit list options %q, got %q", want, got) diff --git a/scm/driver/gitlab/webhook.go b/scm/driver/gitlab/webhook.go index e3ee5ad73..c70569471 100644 --- a/scm/driver/gitlab/webhook.go +++ b/scm/driver/gitlab/webhook.go @@ -11,8 +11,10 @@ import ( "io/ioutil" "net/http" "strconv" + "time" "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/internal/null" ) type webhookService struct { @@ -35,6 +37,10 @@ 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) default: return nil, scm.ErrUnknownEvent } @@ -59,6 +65,39 @@ 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 parsePushHook(data []byte) (scm.Webhook, error) { src := new(pushHook) err := json.Unmarshal(data, src) @@ -114,10 +153,12 @@ func convertPushHook(src *pushHook) *scm.PushHook { Author: scm.Signature{ Name: c.Author.Name, Email: c.Author.Email, + Date: c.Timestamp.ValueOrZero(), }, Committer: scm.Signature{ Name: c.Author.Name, Email: c.Author.Email, + Date: c.Timestamp.ValueOrZero(), }, }) } @@ -202,6 +243,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 @@ -248,6 +361,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, @@ -266,6 +382,7 @@ 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, @@ -296,7 +413,19 @@ 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 +} + 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"` @@ -330,10 +459,10 @@ type ( HTTPURL string `json:"http_url"` } `json:"project"` Commits []struct { - ID string `json:"id"` - Message string `json:"message"` - Timestamp string `json:"timestamp"` - URL string `json:"url"` + ID string `json:"id"` + Message string `json:"message"` + Timestamp null.Time `json:"timestamp"` + URL string `json:"url"` Author struct { Name string `json:"name"` Email string `json:"email"` @@ -356,13 +485,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"` @@ -381,56 +507,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"` @@ -439,34 +538,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"` @@ -512,10 +621,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"` } @@ -775,6 +892,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"` diff --git a/scm/driver/gitlab/webhook_test.go b/scm/driver/gitlab/webhook_test.go index 1f153f20d..16041c67d 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,43 @@ 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), + }, } for _, test := range tests { diff --git a/scm/driver/gogs/content.go b/scm/driver/gogs/content.go index b6ebe830a..44918ccab 100644 --- a/scm/driver/gogs/content.go +++ b/scm/driver/gogs/content.go @@ -34,7 +34,7 @@ func (s *contentService) Update(ctx context.Context, repo, path string, params * return nil, scm.ErrNotSupported } -func (s *contentService) Delete(ctx context.Context, repo, path, ref string) (*scm.Response, error) { +func (s *contentService) Delete(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { return nil, scm.ErrNotSupported } diff --git a/scm/driver/gogs/content_test.go b/scm/driver/gogs/content_test.go index 0e3745703..8dd95de41 100644 --- a/scm/driver/gogs/content_test.go +++ b/scm/driver/gogs/content_test.go @@ -58,7 +58,7 @@ func TestContentUpdate(t *testing.T) { func TestContentDelete(t *testing.T) { client, _ := New("https://try.gogs.io") - _, err := client.Contents.Delete(context.Background(), "gogits/gogs", "README.md", "master") + _, err := client.Contents.Delete(context.Background(), "gogits/gogs", "README.md", &scm.ContentParams{}) if err != scm.ErrNotSupported { t.Errorf("Expect Not Supported error") } diff --git a/scm/driver/gogs/git.go b/scm/driver/gogs/git.go index 3956547de..30103cc7b 100644 --- a/scm/driver/gogs/git.go +++ b/scm/driver/gogs/git.go @@ -16,6 +16,10 @@ type gitService struct { client *wrapper } +func (s *gitService) CreateBranch(ctx context.Context, repo string, params *scm.ReferenceInput) (*scm.Response, error) { + return nil, scm.ErrNotSupported +} + func (s *gitService) FindBranch(ctx context.Context, repo, name string) (*scm.Reference, *scm.Response, error) { path := fmt.Sprintf("api/v1/repos/%s/branches/%s", repo, name) out := new(branch) @@ -24,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) @@ -41,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/gogs.go b/scm/driver/gogs/gogs.go index 073dc5e0c..41e3f429b 100644 --- a/scm/driver/gogs/gogs.go +++ b/scm/driver/gogs/gogs.go @@ -36,8 +36,10 @@ func New(uri string) (*scm.Client, error) { client.Git = &gitService{client} client.Issues = &issueService{client} client.Organizations = &organizationService{client} + client.Milestones = &milestoneService{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} diff --git a/scm/driver/gogs/milestone.go b/scm/driver/gogs/milestone.go new file mode 100644 index 000000000..71a78794b --- /dev/null +++ b/scm/driver/gogs/milestone.go @@ -0,0 +1,31 @@ +package gogs + +import ( + "context" + + "github.com/drone/go-scm/scm" +) + +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 +} diff --git a/scm/driver/gogs/pr.go b/scm/driver/gogs/pr.go index 1e851fdea..c2556ceb1 100644 --- a/scm/driver/gogs/pr.go +++ b/scm/driver/gogs/pr.go @@ -34,6 +34,10 @@ func (s *pullService) ListChanges(context.Context, string, int, scm.ListOptions) return nil, nil, scm.ErrNotSupported } +func (s *pullService) ListCommits(context.Context, string, int, scm.ListOptions) ([]*scm.Commit, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + func (s *pullService) Create(context.Context, string, *scm.PullRequestInput) (*scm.PullRequest, *scm.Response, error) { return nil, nil, scm.ErrNotSupported } diff --git a/scm/driver/gogs/pr_test.go b/scm/driver/gogs/pr_test.go index 3495ae165..88a4ae0a3 100644 --- a/scm/driver/gogs/pr_test.go +++ b/scm/driver/gogs/pr_test.go @@ -102,3 +102,11 @@ func TestPullRequestCommentDelete(t *testing.T) { t.Errorf("Expect Not Supported error") } } + +func TestPullRequestCommits(t *testing.T) { + client, _ := New("https://try.gogs.io") + _, _, err := client.PullRequests.ListCommits(context.Background(), "gogits/gogs", 1, scm.ListOptions{}) + if err != scm.ErrNotSupported { + t.Errorf("Expect Not Supported error") + } +} diff --git a/scm/driver/gogs/release.go b/scm/driver/gogs/release.go new file mode 100644 index 000000000..cf8ce092a --- /dev/null +++ b/scm/driver/gogs/release.go @@ -0,0 +1,42 @@ +package gogs + +import ( + "context" + "github.com/drone/go-scm/scm" +) + +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 +} diff --git a/scm/driver/gogs/repo.go b/scm/driver/gogs/repo.go index d2a29fb3c..0f645c1fd 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) ListHooks(ctx context.Context, repo string, _ scm.ListOptions) ([]*scm.Hook, *scm.Response, error) { path := fmt.Sprintf("api/v1/repos/%s/hooks", repo) out := []*hook{} diff --git a/scm/driver/gogs/user.go b/scm/driver/gogs/user.go index 77abd3c76..fa0618c92 100644 --- a/scm/driver/gogs/user.go +++ b/scm/driver/gogs/user.go @@ -33,6 +33,10 @@ func (s *userService) FindEmail(ctx context.Context) (string, *scm.Response, err return user.Email, res, err } +func (s *userService) ListEmail(context.Context, scm.ListOptions) ([]*scm.Email, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + // // native data structures // 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..28239d8d6 --- /dev/null +++ b/scm/driver/harness/org.go @@ -0,0 +1,57 @@ +// 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 + +} + +// +// 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..82f095d21 --- /dev/null +++ b/scm/driver/harness/repo.go @@ -0,0 +1,218 @@ +// 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) 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..8a88fc594 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_branch_updated.json @@ -0,0 +1,99 @@ +{ + "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, + "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..2b4f2a643 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_branch_updated.json.golden @@ -0,0 +1,48 @@ +{ + "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" + }, + "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..4f47de5fa --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_closed.json @@ -0,0 +1,96 @@ +{ + "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", + "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..8b5fc2143 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_closed.json.golden @@ -0,0 +1,48 @@ +{ + "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" + }, + "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..52ae75598 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_comment_created.json @@ -0,0 +1,64 @@ +{ + "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, + "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" + } + }, + "comment": { + "id": 1, + "text": "pr 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..cb96e2634 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_comment_created.json.golden @@ -0,0 +1,51 @@ +{ + "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": "", + "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" + }, + "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..f8cd669b8 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_merged.json @@ -0,0 +1,97 @@ +{ + "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", + "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..3bef4116c --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_merged.json.golden @@ -0,0 +1,48 @@ +{ + "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" + }, + "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..7c1715f19 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_opened.json @@ -0,0 +1,97 @@ +{ + "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, + "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..9ea430e3d --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_opened.json.golden @@ -0,0 +1,48 @@ +{ + "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" + }, + "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..a7408779f --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_reopened.json @@ -0,0 +1,97 @@ +{ + "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, + "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..32bc95964 --- /dev/null +++ b/scm/driver/harness/testdata/webhooks/pull_request_reopened.json.golden @@ -0,0 +1,48 @@ +{ + "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" + }, + "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..33be360b4 --- /dev/null +++ b/scm/driver/harness/webhook.go @@ -0,0 +1,388 @@ +// 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"` + SourceRepoID int `json:"source_repo_id"` + SourceBranch string `json:"source_branch"` + TargetRepoID int `json:"target_repo_id"` + TargetBranch string `json:"target_branch"` + 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"` + 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, + }, + } +} + +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, + Closed: pr.State != "open", + Source: pr.SourceBranch, + Target: pr.TargetBranch, + Merged: pr.State == "merged", + Fork: "fork", + Link: pr.PrURL, + Sha: commit.Sha, + Ref: ref.Name, + Author: convertUser(pr.Author), + } +} + +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/internal/null/time.go b/scm/driver/internal/null/time.go index 574209ad0..3182ce71f 100644 --- a/scm/driver/internal/null/time.go +++ b/scm/driver/internal/null/time.go @@ -63,3 +63,25 @@ func (t Time) ValueOrZero() time.Time { func (t Time) IsZero() bool { return !t.Valid || t.Time.IsZero() } + +// Ptr returns a pointer to this Time's value, +// or a nil pointer if this Time is zero. +func (t Time) Ptr() *time.Time { + if !t.Valid { + return nil + } + return &t.Time +} + +// NewTime creates a new Time. +func NewTime(t time.Time, valid bool) Time { + return Time{ + Time: t, + Valid: valid, + } +} + +// TimeFrom creates a new Time that will always be valid. +func TimeFrom(t time.Time) Time { + return NewTime(t, !t.IsZero()) +} \ No newline at end of file diff --git a/scm/driver/stash/content.go b/scm/driver/stash/content.go index b067825ec..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{ @@ -28,14 +30,29 @@ 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) { - return nil, scm.ErrNotSupported + namespace, repoName := scm.Split(repo) + endpoint := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/browse/%s", namespace, repoName, path) + in := &contentCreateUpdate{ + Message: params.Message, + Branch: params.Branch, + Content: params.Data, + } + return s.client.do(ctx, "PUT", endpoint, in, nil) } func (s *contentService) Update(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { - return nil, scm.ErrNotSupported + namespace, repoName := scm.Split(repo) + endpoint := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/browse/%s", namespace, repoName, path) + in := &contentCreateUpdate{ + Message: params.Message, + Branch: params.Branch, + Content: params.Data, + Sha: params.Sha, + } + return s.client.do(ctx, "PUT", endpoint, in, nil) } -func (s *contentService) Delete(ctx context.Context, repo, path, ref string) (*scm.Response, error) { +func (s *contentService) Delete(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) { return nil, scm.ErrNotSupported } @@ -53,6 +70,13 @@ type contents struct { Values []string `json:"values"` } +type contentCreateUpdate struct { + Branch string `json:"branch"` + Message string `json:"message"` + Content []byte `json:"content"` + Sha string `json:"sourceCommitId"` +} + func convertContentInfoList(from *contents) []*scm.ContentInfo { to := []*scm.ContentInfo{} for _, v := range from.Values { diff --git a/scm/driver/stash/content_test.go b/scm/driver/stash/content_test.go index e958df5c1..68f84f050 100644 --- a/scm/driver/stash/content_test.go +++ b/scm/driver/stash/content_test.go @@ -34,7 +34,29 @@ func TestContentFind(t *testing.T) { want := new(scm.Content) raw, _ := ioutil.ReadFile("testdata/content.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) + + if diff := cmp.Diff(got, want); diff != "" { + 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") @@ -43,24 +65,81 @@ func TestContentFind(t *testing.T) { } func TestContentCreate(t *testing.T) { - content := new(contentService) - _, err := content.Create(context.Background(), "atlassian/atlaskit", "README", nil) - if err != scm.ErrNotSupported { - t.Errorf("Expect Not Supported error") + defer gock.Off() + + gock.New("http://localhost:7990"). + Put("/rest/api/1.0/projects/octocat/repos/hello-world/browse/README"). + Reply(200). + Type("application/json"). + File("testdata/content_create.json") + + params := &scm.ContentParams{ + Message: "my commit message", + Data: []byte("bXkgbmV3IGZpbGUgY29udGVudHM="), + Signature: scm.Signature{ + Name: "Monalisa Octocat", + Email: "octocat@github.com", + }, + } + + client := NewDefault() + res, err := client.Contents.Create( + context.Background(), + "octocat/hello-world", + "README", + params, + ) + + if err != nil { + t.Error(err) + return + } + + if res.Status != 200 { + t.Errorf("Unexpected Results") } } func TestContentUpdate(t *testing.T) { - content := new(contentService) - _, err := content.Update(context.Background(), "atlassian/atlaskit", "README", nil) - if err != scm.ErrNotSupported { - t.Errorf("Expect Not Supported error") + defer gock.Off() + + gock.New("http://localhost:7990"). + Put("/rest/api/1.0/projects/octocat/repos/hello-world/browse/README"). + Reply(200). + Type("application/json"). + File("testdata/content_update.json") + + params := &scm.ContentParams{ + Message: "a new commit message", + Data: []byte("bXkgdXBkYXRlZCBmaWxlIGNvbnRlbnRz"), + BlobID: "95b966ae1c166bd92f8ae7d1c313e738c731dfc3", + Signature: scm.Signature{ + Name: "Monalisa Octocat", + Email: "octocat@github.com", + }, + } + + client := NewDefault() + res, err := client.Contents.Update( + context.Background(), + "octocat/hello-world", + "README", + params, + ) + + if err != nil { + t.Error(err) + return + } + + if res.Status != 200 { + t.Errorf("Unexpected Results") } } func TestContentDelete(t *testing.T) { content := new(contentService) - _, err := content.Delete(context.Background(), "atlassian/atlaskit", "README", "master") + _, err := content.Delete(context.Background(), "atlassian/atlaskit", "README", &scm.ContentParams{}) if err != scm.ErrNotSupported { t.Errorf("Expect Not Supported error") } @@ -90,7 +169,7 @@ func TestContentList(t *testing.T) { want := []*scm.ContentInfo{} raw, _ := ioutil.ReadFile("testdata/content_list.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") diff --git a/scm/driver/stash/git.go b/scm/driver/stash/git.go index bd1080d0b..221b59911 100644 --- a/scm/driver/stash/git.go +++ b/scm/driver/stash/git.go @@ -19,6 +19,17 @@ type gitService struct { client *wrapper } +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{ + Name: params.Name, + StartPoint: params.Sha, + } + return s.client.do(ctx, "POST", path, in, nil) + +} + func (s *gitService) FindBranch(ctx context.Context, repo, branch string) (*scm.Reference, *scm.Response, error) { namespace, name := scm.Split(repo) path := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/branches?filterText=%s", namespace, name, branch) @@ -68,8 +79,27 @@ 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) { - return nil, nil, scm.ErrNotSupported + namespace, name := scm.Split(repo) + var requestPath string + if 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?until=%s", namespace, name, opts.Ref) + } + out := new(commits) + res, err := s.client.do(ctx, "GET", requestPath, nil, out) + copyPagination(out.pagination, res) + return convertCommitList(out), res, err } func (s *gitService) ListTags(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Reference, *scm.Response, error) { @@ -147,6 +177,11 @@ type diffstat struct { } `json:"properties"` } +type createBranch struct { + Name string `json:"name"` + StartPoint string `json:"startPoint"` +} + type commit struct { ID string `json:"id"` DisplayID string `json:"displayId"` diff --git a/scm/driver/stash/git_test.go b/scm/driver/stash/git_test.go index 9d8209327..f93952ace 100644 --- a/scm/driver/stash/git_test.go +++ b/scm/driver/stash/git_test.go @@ -33,7 +33,7 @@ func TestGitFindCommit(t *testing.T) { want := new(scm.Commit) raw, _ := ioutil.ReadFile("testdata/commit.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -59,7 +59,7 @@ func TestGitFindBranch(t *testing.T) { want := new(scm.Reference) raw, _ := ioutil.ReadFile("testdata/branch.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -85,7 +85,7 @@ func TestGitFindTag(t *testing.T) { want := new(scm.Reference) raw, _ := ioutil.ReadFile("testdata/tag.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -94,10 +94,28 @@ func TestGitFindTag(t *testing.T) { } func TestGitListCommits(t *testing.T) { + defer gock.Off() + + 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") + client, _ := New("http://example.com:7990") - _, _, err := client.Git.ListCommits(context.Background(), "PRJ/my-repo", scm.CommitListOptions{Ref: "master", Page: 1, Size: 30}) - if err != scm.ErrNotSupported { - t.Errorf("Expect Not Supported error") + got, _, err := client.Git.ListCommits(context.Background(), "PRJ/my-repo", scm.CommitListOptions{}) + if err != nil { + t.Error(err) + } + + 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) } } @@ -119,7 +137,35 @@ func TestGitListBranches(t *testing.T) { want := []*scm.Reference{} raw, _ := ioutil.ReadFile("testdata/branches.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + // + // 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") @@ -147,7 +193,7 @@ func TestGitListTags(t *testing.T) { want := []*scm.Reference{} raw, _ := ioutil.ReadFile("testdata/tags.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -175,7 +221,7 @@ func TestGitListChanges(t *testing.T) { want := []*scm.Change{} raw, _ := ioutil.ReadFile("testdata/changes.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -203,10 +249,35 @@ func TestGitCompareChanges(t *testing.T) { want := []*scm.Change{} raw, _ := ioutil.ReadFile("testdata/compare.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") t.Log(diff) } } + +func TestCreateBranch(t *testing.T) { + defer gock.Off() + + gock.New("http://example.com:7990"). + Post("/rest/api/1.0/projects/PRJ/repos/my-repo/branches"). + Reply(201). + Type("application/json"). + File("testdata/branch_create.json") + + client, _ := New("http://example.com:7990") + params := &scm.ReferenceInput{ + Name: "Hello", + Sha: "312797ba52425353dec56871a255e2a36fc96344", + } + res, err := client.Git.CreateBranch(context.Background(), "PRJ/my-repo", params) + + if err != nil { + t.Errorf("Encountered err while creating branch " + err.Error()) + } + + if res.Status != 201 { + t.Errorf("The error response of branch creation is not 201") + } +} diff --git a/scm/driver/stash/integration/content_test.go b/scm/driver/stash/integration/content_test.go new file mode 100644 index 000000000..d6a22bbcb --- /dev/null +++ b/scm/driver/stash/integration/content_test.go @@ -0,0 +1,62 @@ +package integration + +import ( + "context" + "net/http" + "testing" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/stash" + "github.com/drone/go-scm/scm/transport" +) + +func TestCreateUpdateDeleteFileStash(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, + }, + } + // get latest commit first + currentCommit, commitErr := GetCurrentCommitOfBranch(client, "master") + if commitErr != nil { + t.Errorf("we got an error %v", commitErr) + } + // create a new file + createParams := scm.ContentParams{ + Message: "go-scm create crud file", + Data: []byte("hello"), + Branch: "master", + Sha: currentCommit, + } + createResponse, createErr := client.Contents.Create(context.Background(), repoID, "README5", &createParams) + if createErr != nil { + t.Errorf("Contents.Create we got an error %v", createErr) + } + if createResponse.Status != http.StatusOK { + t.Errorf("Contents.Create we did not get a 201 back %v", createResponse.Status) + } + // get latest commit first + currentCommit, commitErr = GetCurrentCommitOfBranch(client, "main") + if commitErr != nil { + t.Errorf("we got an error %v", commitErr) + } + // update the file + updateParams := scm.ContentParams{ + Message: "go-scm update crud file", + Data: []byte("updated test data"), + Branch: "master", + Sha: currentCommit, + } + updateResponse, updateErr := client.Contents.Update(context.Background(), repoID, "README5", &updateParams) + if updateErr != nil { + t.Errorf("Contents.Update we got an error %v", updateErr) + } + if updateResponse.Status != http.StatusOK { + t.Errorf("Contents.Update we did not get a 201 back %v", updateResponse.Status) + } +} diff --git a/scm/driver/stash/integration/git_test.go b/scm/driver/stash/integration/git_test.go new file mode 100644 index 000000000..d1607f8de --- /dev/null +++ b/scm/driver/stash/integration/git_test.go @@ -0,0 +1,118 @@ +package integration + +import ( + "context" + "net/http" + "testing" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/stash" + "github.com/drone/go-scm/scm/transport" +) + +func TestCreateBranch(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, + }, + } + + commitId, _ := GetCurrentCommitOfBranch(client, "master") + input := &scm.ReferenceInput{ + Name: "test_branch", + Sha: commitId, + } + response, listerr := client.Git.CreateBranch(context.Background(), repoID, input) + if listerr != nil { + t.Errorf("CreateBranch got an error %v", listerr) + } + if response.Status != http.StatusOK { + t.Errorf("CreateBranch did not get a 200 back %v", response.Status) + } +} + +func TestGetLatestCommitOfBranch(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: "master", 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) + } + } +} + +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/integration.go b/scm/driver/stash/integration/integration.go new file mode 100644 index 000000000..56cae697d --- /dev/null +++ b/scm/driver/stash/integration/integration.go @@ -0,0 +1,25 @@ +package integration + +import ( + "context" + "os" + + "github.com/drone/go-scm/scm" +) + +var ( + client *scm.Client + token = os.Getenv("BITBUCKET_SERVER_TOKEN") + + endpoint = "https://bitbucket.dev.harness.io/" + repoID = "har/scm-integration-test-repo" + username = os.Getenv("BITBUCKET_USERNAME") +) + +func GetCurrentCommitOfBranch(client *scm.Client, branch string) (string, error) { + commits, _, err := client.Git.ListCommits(context.Background(), repoID, scm.CommitListOptions{Ref: branch}) + if err != nil { + return "", err + } + return commits[0].Sha, nil +} diff --git a/scm/driver/stash/integration/repo_test.go b/scm/driver/stash/integration/repo_test.go new file mode 100644 index 000000000..927d4e85e --- /dev/null +++ b/scm/driver/stash/integration/repo_test.go @@ -0,0 +1,37 @@ +package integration + +import ( + "context" + "net/http" + "testing" + + "github.com/drone/go-scm/scm" + "github.com/drone/go-scm/scm/driver/stash" + "github.com/drone/go-scm/scm/transport" +) + +func TestListRepos(t *testing.T) { + if token == "" { + t.Skip("Skipping, Acceptance test") + } + client, _ = stash.New(endpoint) + client.Client = &http.Client{ + Transport: &transport.BasicAuth{ + Username: username, + Password: token, + }, + } + + repos, response, listerr := client.Repositories.List(context.Background(), scm.ListOptions{}) + if listerr != nil { + t.Errorf("List Repos got an error %v", listerr) + } + if response.Status != http.StatusOK { + t.Errorf("List Repos did not get a 200 back %v", response.Status) + } + + if len(repos) == 0 { + t.Errorf("Got Empty repo list") + } + +} diff --git a/scm/driver/stash/milestone.go b/scm/driver/stash/milestone.go new file mode 100644 index 000000000..e873f7b4e --- /dev/null +++ b/scm/driver/stash/milestone.go @@ -0,0 +1,31 @@ +package stash + +import ( + "context" + + "github.com/drone/go-scm/scm" +) + +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 +} diff --git a/scm/driver/stash/multipart.go b/scm/driver/stash/multipart.go new file mode 100644 index 000000000..4da89fdb7 --- /dev/null +++ b/scm/driver/stash/multipart.go @@ -0,0 +1,26 @@ +package stash + +import "mime/multipart" + +type MultipartWriter struct { + Writer *multipart.Writer + Error error +} + +func (mw *MultipartWriter) Write(f, v string) { + if mw.Error != nil { + return + } + if v == "" { + return + } + mw.Error = mw.Writer.WriteField(f, v) +} + +func (mw *MultipartWriter) Close() { + mw.Writer.Close() +} + +func (mw *MultipartWriter) FormDataContentType() string { + return mw.Writer.FormDataContentType() +} diff --git a/scm/driver/stash/pr.go b/scm/driver/stash/pr.go index a404c7acc..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 { @@ -65,6 +65,18 @@ func (s *pullService) ListComments(context.Context, string, int, scm.ListOptions return nil, nil, scm.ErrNotSupported } +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?%s", namespace, name, number, encodeListOptionsV2(opts)) + out := new(commits) + res, err := s.client.do(ctx, "GET", path, nil, out) + if !out.pagination.LastPage.Bool { + res.Page.First = 1 + res.Page.Next = opts.Page + 1 + } + return convertCommitList(out), res, err +} + func (s *pullService) Merge(ctx context.Context, repo string, number int) (*scm.Response, error) { namespace, name := scm.Split(repo) path := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/pull-requests/%d/merge", namespace, name, number) @@ -161,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 { @@ -209,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, @@ -218,6 +237,16 @@ func convertPullRequest(from *pr) *scm.PullRequest { Merged: from.State == "MERGED", Created: time.Unix(from.CreatedDate/1000, 0), Updated: time.Unix(from.UpdatedDate/1000, 0), + Head: scm.Reference{ + Name: from.FromRef.DisplayID, + Path: from.FromRef.ID, + Sha: from.FromRef.LatestCommit, + }, + Base: scm.Reference{ + Name: from.ToRef.DisplayID, + Path: from.ToRef.ID, + Sha: from.ToRef.LatestCommit, + }, Author: scm.User{ Login: from.Author.User.Slug, Name: from.Author.User.DisplayName, diff --git a/scm/driver/stash/pr_test.go b/scm/driver/stash/pr_test.go index b9695485e..4710f4867 100644 --- a/scm/driver/stash/pr_test.go +++ b/scm/driver/stash/pr_test.go @@ -33,7 +33,7 @@ func TestPullFind(t *testing.T) { want := new(scm.PullRequest) raw, _ := ioutil.ReadFile("testdata/pr.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -58,7 +58,7 @@ func TestPullFindComment(t *testing.T) { want := new(scm.Comment) raw, _ := ioutil.ReadFile("testdata/pr_comment.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -83,7 +83,7 @@ func TestPullList(t *testing.T) { want := []*scm.PullRequest{} raw, _ := ioutil.ReadFile("testdata/prs.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -110,7 +110,7 @@ func TestPullListChanges(t *testing.T) { want := []*scm.Change{} raw, _ := ioutil.ReadFile("testdata/pr_change.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -174,7 +174,7 @@ func TestPullCreate(t *testing.T) { want := new(scm.PullRequest) raw, _ := ioutil.ReadFile("testdata/pr.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -201,7 +201,32 @@ func TestPullCreateComment(t *testing.T) { want := new(scm.Comment) raw, _ := ioutil.ReadFile("testdata/pr_comment.json.golden") - json.Unmarshal(raw, &want) + _ = 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("http://example.com:7990"). + Get("rest/api/1.0/projects/PRJ/repos/my-repo/pull-requests/1/commits"). + Reply(200). + Type("application/json"). + File("testdata/commits.json") + + client, _ := New("http://example.com:7990") + got, _, err := client.PullRequests.ListCommits(context.Background(), "PRJ/my-repo", 1, scm.ListOptions{Size: 30, Page: 1}) + if err != nil { + t.Error(err) + } + + 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") diff --git a/scm/driver/stash/release.go b/scm/driver/stash/release.go new file mode 100644 index 000000000..8376200bb --- /dev/null +++ b/scm/driver/stash/release.go @@ -0,0 +1,43 @@ +package stash + +import ( + "context" + + "github.com/drone/go-scm/scm" +) + +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 +} diff --git a/scm/driver/stash/repo.go b/scm/driver/stash/repo.go index 17e17362e..f8093a145 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. @@ -137,10 +149,10 @@ func (s *repositoryService) FindPerms(ctx context.Context, repo string) (*scm.Pe }, nil, nil } // HACK: test if the user has write access to the repository. - _, name := scm.Split(repo) + namespace, _ := scm.Split(repo) repos, _, _ := s.listWrite(ctx, repo) for _, repo := range repos { - if repo.Name == name { + if repo.Namespace == namespace { return &scm.Perm{ Pull: true, Push: true, @@ -161,7 +173,31 @@ func (s *repositoryService) List(ctx context.Context, opts scm.ListOptions) ([]* path := fmt.Sprintf("rest/api/1.0/repos?%s", encodeListRoleOptions(opts)) out := new(repositories) res, err := s.client.do(ctx, "GET", path, nil, &out) - if !out.pagination.LastPage.Bool { + if res != nil && !out.pagination.LastPage.Bool { + res.Page.First = 1 + res.Page.Next = opts.Page + 1 + } + 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 } @@ -170,8 +206,8 @@ func (s *repositoryService) List(ctx context.Context, opts scm.ListOptions) ([]* // listWrite returns the user repository list. func (s *repositoryService) listWrite(ctx context.Context, repo string) ([]*scm.Repository, *scm.Response, error) { - namespace, name := scm.Split(repo) - path := fmt.Sprintf("rest/api/1.0/repos?size=1000&permission=REPO_WRITE&projectname=%s&name=%s", namespace, name) + _, name := scm.Split(repo) + path := fmt.Sprintf("rest/api/1.0/repos?size=1000&permission=REPO_WRITE&name=%s", name) out := new(repositories) res, err := s.client.do(ctx, "GET", path, nil, out) return convertRepositoryList(out), res, err @@ -183,7 +219,7 @@ func (s *repositoryService) ListHooks(ctx context.Context, repo string, opts scm path := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/webhooks?%s", namespace, name, encodeListOptions(opts)) out := new(hooks) res, err := s.client.do(ctx, "GET", path, nil, out) - if !out.pagination.LastPage.Bool { + if res != nil && !out.pagination.LastPage.Bool { res.Page.First = 1 res.Page.Next = opts.Page + 1 } diff --git a/scm/driver/stash/repo_test.go b/scm/driver/stash/repo_test.go index 57c6fdb1d..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 { @@ -33,7 +39,7 @@ func TestRepositoryFind(t *testing.T) { want := new(scm.Repository) raw, _ := ioutil.ReadFile("testdata/repo.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -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 { @@ -157,12 +175,17 @@ func TestRepositoryPerms_Write(t *testing.T) { Get("/rest/api/1.0/repos"). MatchParam("size", "1000"). MatchParam("permission", "REPO_WRITE"). - MatchParam("projectname", "PRJ"). MatchParam("name", "my-repo"). Reply(200). 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 { @@ -185,6 +208,57 @@ func TestRepositoryPerms_Write(t *testing.T) { } } +func TestRepositoryPermsDifferentProjectName_Write(t *testing.T) { + defer gock.Off() + + gock.New("http://example.com:7990"). + Get("/rest/api/1.0/projects/PRJ/repos/quux"). + Reply(200). + Type("application/json"). + File("testdata/repo.json") + + gock.New("http://example.com:7990"). + Get("/rest/api/1.0/projects/PRJ/repos/quux/webhooks"). + Reply(404). + Type("application/json") + + gock.New("http://example.com:7990"). + Get("/rest/api/1.0/repos"). + MatchParam("size", "1000"). + MatchParam("permission", "REPO_WRITE"). + MatchParam("name", "quux"). + Reply(200). + 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 { + t.Error(err) + } + + want := &scm.Perm{ + Pull: true, + Push: true, + Admin: false, + } + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } + + if gock.IsPending() { + t.Errorf("pending API requests") + } +} + func TestRepositoryPerms_Forbidden(t *testing.T) { defer gock.Off() @@ -237,7 +311,48 @@ func TestRepositoryList(t *testing.T) { want := []*scm.Repository{} raw, _ := ioutil.ReadFile("testdata/repos.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("Unexpected Results") + t.Log(diff) + } +} + +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") @@ -293,7 +408,7 @@ func TestRepositoryHookFind(t *testing.T) { want := new(scm.Hook) raw, _ := ioutil.ReadFile("testdata/webhook.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -320,7 +435,7 @@ func TestRepositoryHookList(t *testing.T) { want := []*scm.Hook{} raw, _ := ioutil.ReadFile("testdata/webhooks.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -357,7 +472,7 @@ func TestRepositoryHookCreate(t *testing.T) { want := new(scm.Hook) raw, _ := ioutil.ReadFile("testdata/webhook.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -394,7 +509,7 @@ func TestRepositoryHookUpdate(t *testing.T) { want := new(scm.Hook) raw, _ := ioutil.ReadFile("testdata/webhook.json.golden") - json.Unmarshal(raw, want) + _ = json.Unmarshal(raw, want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") diff --git a/scm/driver/stash/stash.go b/scm/driver/stash/stash.go index 3eada146e..62db1c7fd 100644 --- a/scm/driver/stash/stash.go +++ b/scm/driver/stash/stash.go @@ -9,7 +9,9 @@ import ( "bytes" "context" "encoding/json" + "fmt" "io" + "mime/multipart" "net/url" "strings" @@ -37,9 +39,11 @@ func New(uri string) (*scm.Client, error) { 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} @@ -64,16 +68,42 @@ func (c *wrapper) do(ctx context.Context, method, path string, in, out interface req := &scm.Request{ Method: method, Path: path, + Header: map[string][]string{ + "Accept": {"application/json"}, + "x-atlassian-token": {"no-check"}, + }, } // 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"}, + switch content := in.(type) { + case *contentCreateUpdate: + // add the content to the multipart + var b bytes.Buffer + mw := &MultipartWriter{Writer: multipart.NewWriter(&b)} + // add the other fields + // The Write function doesn't write the string value to multipart if it is Empty + mw.Write("content", string(content.Content)) + mw.Write("message", content.Message) + mw.Write("branch", content.Branch) + mw.Write("sourceCommitId", content.Sha) + if mw.Error != nil { + return nil, fmt.Errorf("error writing multipart-content. err: %s", mw.Error) + } + mw.Close() + // write the multipart response to the body + req.Body = &b + // write the content type that contains the length of the multipart + req.Header = map[string][]string{ + "Content-Type": {mw.FormDataContentType()}, + "x-atlassian-token": {"no-check"}, + } + default: + buf := new(bytes.Buffer) + json.NewEncoder(buf).Encode(in) + req.Header["Content-Type"] = []string{"application/json"} + req.Body = buf } - req.Body = buf } // execute the http request @@ -121,7 +151,9 @@ type pagination struct { // Error represents a Stash error. type Error struct { - Errors []struct { + Message string `json:"message"` + Status int `json:"status-code"` + Errors []struct { Message string `json:"message"` ExceptionName string `json:"exceptionName"` CurrentVersion int `json:"currentVersion"` @@ -131,6 +163,9 @@ type Error struct { func (e *Error) Error() string { if len(e.Errors) == 0 { + if len(e.Message) > 0 { + return fmt.Sprintf("bitbucket: status: %d message: %s", e.Status, e.Message) + } return "bitbucket: undefined error" } return e.Errors[0].Message diff --git a/scm/driver/stash/testdata/branch_create.json b/scm/driver/stash/testdata/branch_create.json new file mode 100644 index 000000000..90f12b96a --- /dev/null +++ b/scm/driver/stash/testdata/branch_create.json @@ -0,0 +1,10 @@ +{ + "ref": "refs/heads/Hello", + "node_id": "MDM6UmVmMzQ0NDI5MDA5OnJlZnMvaGVhZHMvSGVsbG8=", + "url": "https://api.github.com/repos/tphoney/scm-test/git/refs/heads/Hello", + "object": { + "sha": "312797ba52425353dec56871a255e2a36fc96344", + "type": "commit", + "url": "https://api.github.com/repos/tphoney/scm-test/git/commits/312797ba52425353dec56871a255e2a36fc96344" + } +} \ No newline at end of file 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/commits.json b/scm/driver/stash/testdata/commits.json index 9e26dfeeb..ac9da334b 100644 --- a/scm/driver/stash/testdata/commits.json +++ b/scm/driver/stash/testdata/commits.json @@ -1 +1,72 @@ -{} \ No newline at end of file +{ + "size": 1, + "limit": 25, + "isLastPage": true, + "values": [ +{ + "id": "131cb13f4aed12e725177bc4b7c28db67839bf9f", + "displayId": "131cb13f4ae", + "author": { + "name": "jcitizen", + "emailAddress": "jane@example.com", + "id": 1, + "displayName": "Jane Citizen", + "active": true, + "slug": "jcitizen", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "http://example.com:7990/users/jcitizen" + } + ] + } + }, + "authorTimestamp": 1530720102000, + "committer": { + "name": "jcitizen", + "emailAddress": "jane@example.com", + "id": 1, + "displayName": "Jane Citizen", + "active": true, + "slug": "jcitizen", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "http://example.com:7990/users/jcitizen" + } + ] + } + }, + "committerTimestamp": 1530720102000, + "message": "update files", + "parents": [ + { + "id": "4f4b0ef1714a5b6cafdaf2f53c7f5f5b38fb9348", + "displayId": "4f4b0ef1714", + "author": { + "name": "Jane Citizen", + "emailAddress": "jane@example.com" + }, + "authorTimestamp": 1530719890000, + "committer": { + "name": "Jane Citizen", + "emailAddress": "jane@example.com" + }, + "committerTimestamp": 1530719890000, + "message": "update files", + "parents": [ + { + "id": "f636fe22d302c852df1a68fff2d744039fe55b3d", + "displayId": "f636fe22d30" + } + ] + } + ] +} +], +"start": 0, +"authorCount": 1, +"totalCount": 1 +} \ No newline at end of file diff --git a/scm/driver/stash/testdata/commits.json.golden b/scm/driver/stash/testdata/commits.json.golden index 0637a088a..33d1ffec4 100644 --- a/scm/driver/stash/testdata/commits.json.golden +++ b/scm/driver/stash/testdata/commits.json.golden @@ -1 +1,21 @@ -[] \ No newline at end of file +[ + { + "Sha": "131cb13f4aed12e725177bc4b7c28db67839bf9f", + "Message": "update files", + "Author": { + "Name": "Jane Citizen", + "Email": "jane@example.com", + "Date": "2018-07-04T09:01:42-07:00", + "Login": "jcitizen", + "Avatar": "https://www.gravatar.com/avatar/9e26471d35a78862c17e467d87cddedf.jpg" + }, + "Committer": { + "Name": "Jane Citizen", + "Email": "jane@example.com", + "Date": "2018-07-04T09:01:42-07:00", + "Login": "jcitizen", + "Avatar": "https://www.gravatar.com/avatar/9e26471d35a78862c17e467d87cddedf.jpg" + }, + "Link": "" + } +] \ No newline at end of file diff --git a/scm/driver/stash/testdata/content_create.json b/scm/driver/stash/testdata/content_create.json new file mode 100644 index 000000000..7188f36c5 --- /dev/null +++ b/scm/driver/stash/testdata/content_create.json @@ -0,0 +1,21 @@ +{ + "id": "abcdef0123abcdef4567abcdef8987abcdef6543", + "displayId": "abcdef0123a", + "author": { + "name": "charlie", + "emailAddress": "charlie@example.com" + }, + "authorTimestamp": 1636089306104, + "committer": { + "name": "charlie", + "emailAddress": "charlie@example.com" + }, + "committerTimestamp": 1636089306104, + "message": "WIP on feature 1", + "parents": [ + { + "id": "abcdef0123abcdef4567abcdef8987abcdef6543", + "displayId": "abcdef0" + } + ] +} \ 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/content_update.json b/scm/driver/stash/testdata/content_update.json new file mode 100644 index 000000000..7188f36c5 --- /dev/null +++ b/scm/driver/stash/testdata/content_update.json @@ -0,0 +1,21 @@ +{ + "id": "abcdef0123abcdef4567abcdef8987abcdef6543", + "displayId": "abcdef0123a", + "author": { + "name": "charlie", + "emailAddress": "charlie@example.com" + }, + "authorTimestamp": 1636089306104, + "committer": { + "name": "charlie", + "emailAddress": "charlie@example.com" + }, + "committerTimestamp": 1636089306104, + "message": "WIP on feature 1", + "parents": [ + { + "id": "abcdef0123abcdef4567abcdef8987abcdef6543", + "displayId": "abcdef0" + } + ] +} \ No newline at end of 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/pr.json.golden b/scm/driver/stash/testdata/pr.json.golden index 8ec0d5d2f..72e48a411 100644 --- a/scm/driver/stash/testdata/pr.json.golden +++ b/scm/driver/stash/testdata/pr.json.golden @@ -10,6 +10,16 @@ "Link": "http://example.com:7990/projects/PRJ/repos/my-repo/pull-requests/1", "Closed": false, "Merged": false, + "Base": { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "5c64a07cd6c0f21b753bf261ef059c7e7633c50a" + }, + "Head": { + "Name": "feature/x", + "Path": "refs/heads/feature/x", + "Sha": "131cb13f4aed12e725177bc4b7c28db67839bf9f" + }, "Author": { "Login": "jcitizen", "Name": "Jane Citizen", diff --git a/scm/driver/stash/testdata/prs.json.golden b/scm/driver/stash/testdata/prs.json.golden index c9ede89d8..085a38788 100644 --- a/scm/driver/stash/testdata/prs.json.golden +++ b/scm/driver/stash/testdata/prs.json.golden @@ -11,6 +11,16 @@ "Link": "http://example.com:7990/projects/PRJ/repos/my-repo/pull-requests/1", "Closed": false, "Merged": false, + "Base": { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "5c64a07cd6c0f21b753bf261ef059c7e7633c50a" + }, + "Head": { + "Name": "feature/x", + "Path": "refs/heads/feature/x", + "Sha": "131cb13f4aed12e725177bc4b7c28db67839bf9f" + }, "Author": { "Login": "jcitizen", "Name": "Jane Citizen", 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.json b/scm/driver/stash/testdata/repos.json index 46f119c9b..68bc40157 100644 --- a/scm/driver/stash/testdata/repos.json +++ b/scm/driver/stash/testdata/repos.json @@ -43,6 +43,47 @@ } ] } + }, + { + "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 diff --git a/scm/driver/stash/testdata/repos.json.golden b/scm/driver/stash/testdata/repos.json.golden index ef009866b..18e4d4018 100644 --- a/scm/driver/stash/testdata/repos.json.golden +++ b/scm/driver/stash/testdata/repos.json.golden @@ -11,5 +11,18 @@ "Link": "http://example.com:7990/projects/PRJ/repos/my-repo/browse", "Created": "0001-01-01T00:00:00Z", "Updated": "0001-01-01T00:00:00Z" + }, + { + "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/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_declined.json.golden b/scm/driver/stash/testdata/webhooks/pr_declined.json.golden index 828961b05..936b70c82 100644 --- a/scm/driver/stash/testdata/webhooks/pr_declined.json.golden +++ b/scm/driver/stash/testdata/webhooks/pr_declined.json.golden @@ -25,6 +25,16 @@ "Link": "", "Closed": true, "Merged": false, + "Base": { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "823b2230a56056231c9425d63758fa87078a66b4" + }, + "Head": { + "Name": "develop", + "Path": "refs/heads/develop", + "Sha": "b9eaed50a03c073b20dfa82e5e753d295e7f0e56" + }, "Author": { "Login": "jcitizen", "Name": "Jane Citizen", diff --git a/scm/driver/stash/testdata/webhooks/pr_deleted.json.golden b/scm/driver/stash/testdata/webhooks/pr_deleted.json.golden index 9e26dfeeb..7852bd44a 100644 --- a/scm/driver/stash/testdata/webhooks/pr_deleted.json.golden +++ b/scm/driver/stash/testdata/webhooks/pr_deleted.json.golden @@ -1 +1,53 @@ -{} \ No newline at end of file +{ + "Action": "closed", + "Repo": { + "ID": "1", + "Namespace": "PRJ", + "Name": "my-repo", + "Perm": null, + "Branch": "master", + "Private": true, + "Clone": "", + "CloneSSH": "", + "Link": "", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 2, + "Title": "added LICENSE", + "Body": "added BSD license text", + "Sha": "b9eaed50a03c073b20dfa82e5e753d295e7f0e56", + "Ref": "refs/pull-requests/2/from", + "Source": "develop", + "Target": "master", + "Fork": "PRJ/my-repo", + "Link": "", + "Closed": true, + "Merged": false, + "Base": { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "823b2230a56056231c9425d63758fa87078a66b4" + }, + "Head": { + "Name": "develop", + "Path": "refs/heads/develop", + "Sha": "b9eaed50a03c073b20dfa82e5e753d295e7f0e56" + }, + "Author": { + "Login": "jcitizen", + "Name": "Jane Citizen", + "Email": "jane@example.com", + "Avatar": "https://www.gravatar.com/avatar/9e26471d35a78862c17e467d87cddedf.jpg" + }, + "Created": "2018-07-05T12:21:30-07:00", + "Updated": "2018-07-05T12:30:48-07:00" + }, + "Sender": { + "Login": "jcitizen", + "Name": "Jane Citizen", + "Email": "jane@example.com", + "Avatar": "https://www.gravatar.com/avatar/9e26471d35a78862c17e467d87cddedf.jpg" + } +} diff --git a/scm/driver/stash/testdata/webhooks/pr_from_ref_updated.json b/scm/driver/stash/testdata/webhooks/pr_from_ref_updated.json new file mode 100644 index 000000000..aaf938392 --- /dev/null +++ b/scm/driver/stash/testdata/webhooks/pr_from_ref_updated.json @@ -0,0 +1,159 @@ +{ + "eventKey": "pr:from_ref_updated", + "date": "2021-11-23T10:02:52+0000", + "actor": { + "name": "jcitizen", + "emailAddress": "jane@example.com", + "id": 1, + "displayName": "Jane Citizen", + "active": true, + "slug": "jcitizen", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "http://example.com:7990/users/jcitizen" + } + ] + } + }, + "pullRequest": { + "id": 2, + "version": 0, + "title": "added LICENSE", + "description": "added BSD license text", + "state": "OPEN", + "open": true, + "closed": false, + "createdDate": 1637591800463, + "updatedDate": 1637661772258, + "fromRef": { + "id": "refs/heads/feature-2", + "displayId": "feature-2", + "latestCommit": "c00d0f269a9844dd168f72f6a9d78a9cff49a318", + "type": "BRANCH", + "repository": { + "slug": "my-repo", + "id": 1, + "name": "my-repo", + "hierarchyId": "5aa23c1a1280b0c0acce", + "scmId": "git", + "state": "AVAILABLE", + "statusMessage": "Available", + "forkable": true, + "project": { + "key": "PRJ", + "id": 2, + "name": "PRJ", + "public": false, + "type": "NORMAL", + "links": { + "self": [ + { + "href": "http://example.com:7990/projects/PRJ" + } + ] + } + }, + "public": false, + "links": { + "clone": [ + { + "href": "http://example.com:7990/scm/prj/my-repo.git", + "name": "http" + }, + { + "href": "ssh://git@example.com:7999/prj/my-repo.git", + "name": "ssh" + } + ], + "self": [ + { + "href": "http://example.com:7990/projects/PRJ/repos/my-repo/browse" + } + ] + } + } + }, + "toRef": { + "id": "refs/heads/master", + "displayId": "master", + "type": "BRANCH", + "latestCommit": "823b2230a56056231c9425d63758fa87078a66b4", + "repository": { + "slug": "my-repo", + "id": 1, + "name": "my-repo", + "hierarchyId": "5aa23c1a1280b0c0acce", + "scmId": "git", + "state": "AVAILABLE", + "statusMessage": "Available", + "forkable": true, + "project": { + "key": "PRJ", + "id": 2, + "name": "PRJ", + "public": false, + "type": "NORMAL", + "links": { + "self": [ + { + "href": "http://example.com:7990/projects/PRJ" + } + ] + } + }, + "public": false, + "links": { + "clone": [ + { + "href": "http://example.com:7990/scm/prj/my-repo.git", + "name": "http" + }, + { + "href": "ssh://git@example.com:7999/prj/my-repo.git", + "name": "ssh" + } + ], + "self": [ + { + "href": "http://example.com:7990/projects/PRJ/repos/my-repo/browse" + } + ] + } + } + }, + "locked": false, + "author": { + "user": { + "name": "jcitizen", + "emailAddress": "jane@example.com", + "id": 1, + "displayName": "Jane Citizen", + "active": true, + "slug": "jcitizen", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "http://example.com:7990/users/jcitizen" + } + ] + } + }, + "role": "AUTHOR", + "approved": false, + "status": "UNAPPROVED" + }, + "reviewers": [], + "participants": [], + "links": { + "self": [ + { + "href": "http://example.com:7990/projects/PRJ/repos/my-repo/pull-requests/2" + } + ] + } + }, + "previousFromHash": "caf52ccb18c039cd9b930ed1f7b3edfb34cb92dd" +} diff --git a/scm/driver/stash/testdata/webhooks/pr_from_ref_updated.json.golden b/scm/driver/stash/testdata/webhooks/pr_from_ref_updated.json.golden new file mode 100644 index 000000000..ce48bb948 --- /dev/null +++ b/scm/driver/stash/testdata/webhooks/pr_from_ref_updated.json.golden @@ -0,0 +1,53 @@ +{ + "Action": "synchronized", + "Repo": { + "ID": "1", + "Namespace": "PRJ", + "Name": "my-repo", + "Perm": null, + "Branch": "master", + "Private": true, + "Clone": "http://example.com:7990/scm/prj/my-repo.git", + "CloneSSH": "ssh://git@example.com:7999/prj/my-repo.git", + "Link": "http://example.com:7990/projects/PRJ/repos/my-repo/browse", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 2, + "Title": "added LICENSE", + "Body": "added BSD license text", + "Sha": "c00d0f269a9844dd168f72f6a9d78a9cff49a318", + "Ref": "refs/pull-requests/2/from", + "Source": "feature-2", + "Target": "master", + "Fork": "PRJ/my-repo", + "Link": "http://example.com:7990/projects/PRJ/repos/my-repo/pull-requests/2", + "Closed": false, + "Merged": false, + "Base": { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "823b2230a56056231c9425d63758fa87078a66b4" + }, + "Head": { + "Name": "feature-2", + "Path": "refs/heads/feature-2", + "Sha": "c00d0f269a9844dd168f72f6a9d78a9cff49a318" + }, + "Author": { + "Login": "jcitizen", + "Name": "Jane Citizen", + "Email": "jane@example.com", + "Avatar": "https://www.gravatar.com/avatar/9e26471d35a78862c17e467d87cddedf.jpg" + }, + "Created": "2021-11-22T14:36:40Z", + "Updated": "2021-11-23T10:02:52Z" + }, + "Sender": { + "Login": "jcitizen", + "Name": "Jane Citizen", + "Email": "jane@example.com", + "Avatar": "https://www.gravatar.com/avatar/9e26471d35a78862c17e467d87cddedf.jpg" + } +} diff --git a/scm/driver/stash/testdata/webhooks/pr_merged.json.golden b/scm/driver/stash/testdata/webhooks/pr_merged.json.golden index 7f15cd419..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", @@ -25,6 +26,16 @@ "Link": "", "Closed": true, "Merged": true, + "Base": { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "823b2230a56056231c9425d63758fa87078a66b4" + }, + "Head": { + "Name": "develop", + "Path": "refs/heads/develop", + "Sha": "b9eaed50a03c073b20dfa82e5e753d295e7f0e56" + }, "Author": { "Login": "jcitizen", "Name": "Jane Citizen", diff --git a/scm/driver/stash/testdata/webhooks/pr_modified_meta.json b/scm/driver/stash/testdata/webhooks/pr_modified_meta.json new file mode 100644 index 000000000..a44e432b7 --- /dev/null +++ b/scm/driver/stash/testdata/webhooks/pr_modified_meta.json @@ -0,0 +1,224 @@ +{ + "eventKey": "pr:modified", + "date": "2021-11-24T14:43:48+0000", + "actor": { + "name": "jcitizen", + "emailAddress": "jane@example.com", + "id": 1, + "displayName": "Jane Citizen", + "active": true, + "slug": "jcitizen", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "http://example.com:7990/users/jcitizen" + } + ] + } + }, + "pullRequest": { + "id": 6, + "version": 1, + "title": "Clean README.md", + "description": "Removed old information out of `REAME.nd`.", + "state": "OPEN", + "open": true, + "closed": false, + "createdDate": 1637764009216, + "updatedDate": 1637765028112, + "fromRef": { + "id": "refs/heads/cleanup", + "displayId": "cleanup", + "latestCommit": "a268fca7b65055e13f60ac1a2c9a527615f113ca", + "type": "BRANCH", + "repository": { + "slug": "my-repo", + "id": 12, + "name": "My Repo", + "hierarchyId": "5aa23c1a1280b0c0acce", + "scmId": "git", + "state": "AVAILABLE", + "statusMessage": "Available", + "forkable": true, + "origin": { + "slug": "my-repo", + "id": 1, + "name": "My Repo", + "hierarchyId": "5aa23c1a1280b0c0acce", + "scmId": "git", + "state": "AVAILABLE", + "statusMessage": "Available", + "forkable": true, + "project": { + "key": "PRJ", + "id": 2, + "name": "Project", + "public": false, + "type": "NORMAL", + "links": { + "self": [ + { + "href": "http://example.com:7990/projects/PRJ" + } + ] + } + }, + "public": false, + "links": { + "clone": [ + { + "href": "ssh://git@example.com:7999/prj/my-repo.git", + "name": "ssh" + }, + { + "href": "http://example.com:7990/scm/prj/my-repo.git", + "name": "http" + } + ], + "self": [ + { + "href": "http://example.com:7990/projects/PRJ/repos/my-repo/browse" + } + ] + } + }, + "project": { + "key": "~jcitizen", + "id": 1, + "name": "Jane Citizen", + "type": "PERSONAL", + "owner": { + "name": "jcitizen", + "emailAddress": "jane@example.com", + "id": 2, + "displayName": "Jane Citizen", + "active": true, + "slug": "jcitizen", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "http://example.com:7990/users/jcitizen" + } + ] + } + }, + "links": { + "self": [ + { + "href": "http://example.com:7990/users/jcitizen" + } + ] + } + }, + "public": false, + "links": { + "clone": [ + { + "href": "http://example.com:7990/scm/~jcitizen/my-repo.git", + "name": "http" + }, + { + "href": "ssh://git@example.com:7999/~jcitizen/my-repo.git", + "name": "ssh" + } + ], + "self": [ + { + "href": "http://example.com:7990/users/jcitizen/repos/my-repo/browse" + } + ] + } + } + }, + "toRef": { + "id": "refs/heads/master", + "displayId": "master", + "latestCommit": "a4dae7792cf772d72149730091141ef48bba8697", + "type": "BRANCH", + "repository": { + "slug": "my-repo", + "id": 1, + "name": "My Repo", + "hierarchyId": "5aa23c1a1280b0c0acce", + "scmId": "git", + "state": "AVAILABLE", + "statusMessage": "Available", + "forkable": true, + "project": { + "key": "PRJ", + "id": 2, + "name": "Project", + "public": false, + "type": "NORMAL", + "links": { + "self": [ + { + "href": "http://example.com:7990/projects/PRJ" + } + ] + } + }, + "public": false, + "links": { + "clone": [ + { + "href": "ssh://git@example.com:7999/prj/my-repo.git", + "name": "ssh" + }, + { + "href": "http://example.com:7990/scm/prj/my-repo.git", + "name": "http" + } + ], + "self": [ + { + "href": "http://example.com:7990/projects/PRJ/repos/my-repo/browse" + } + ] + } + } + }, + "locked": false, + "author": { + "user": { + "name": "jcitizen", + "emailAddress": "jane@example.com", + "id": 1, + "displayName": "Jane Citizen", + "active": true, + "slug": "jcitizen", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "http://example.com:7990/users/jcitizen" + } + ] + } + }, + "role": "AUTHOR", + "approved": false, + "status": "UNAPPROVED" + }, + "reviewers": [], + "participants": [], + "links": { + "self": [ + { + "href": "http://example.com:7990/projects/PRJ/repos/my-repo/pull-requests/6" + } + ] + } + }, + "previousTitle": "Clean README.md", + "previousDescription": "Cleaned old info out of REAME.", + "previousTarget": { + "id": "refs/heads/master", + "displayId": "master", + "type": "BRANCH", + "latestCommit": "a4dae7792cf772d72149730091141ef48bba8697", + "latestChangeset": "a4dae7792cf772d72149730091141ef48bba8697" + } +} diff --git a/scm/driver/stash/testdata/webhooks/pr_modified_meta.json.golden b/scm/driver/stash/testdata/webhooks/pr_modified_meta.json.golden new file mode 100644 index 000000000..d901de8cc --- /dev/null +++ b/scm/driver/stash/testdata/webhooks/pr_modified_meta.json.golden @@ -0,0 +1,53 @@ +{ + "Action": "updated", + "Repo": { + "ID": "1", + "Namespace": "PRJ", + "Name": "my-repo", + "Perm": null, + "Branch": "master", + "Private": true, + "Clone": "http://example.com:7990/scm/prj/my-repo.git", + "CloneSSH": "ssh://git@example.com:7999/prj/my-repo.git", + "Link": "http://example.com:7990/projects/PRJ/repos/my-repo/browse", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 6, + "Title": "Clean README.md", + "Body": "Removed old information out of `REAME.nd`.", + "Sha": "a268fca7b65055e13f60ac1a2c9a527615f113ca", + "Ref": "refs/pull-requests/6/from", + "Source": "cleanup", + "Target": "master", + "Fork": "~jcitizen/my-repo", + "Link": "http://example.com:7990/projects/PRJ/repos/my-repo/pull-requests/6", + "Closed": false, + "Merged": false, + "Base": { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "a4dae7792cf772d72149730091141ef48bba8697" + }, + "Head": { + "Name": "cleanup", + "Path": "refs/heads/cleanup", + "Sha": "a268fca7b65055e13f60ac1a2c9a527615f113ca" + }, + "Author": { + "Login": "jcitizen", + "Name": "Jane Citizen", + "Email": "jane@example.com", + "Avatar": "https://www.gravatar.com/avatar/9e26471d35a78862c17e467d87cddedf.jpg" + }, + "Created": "2021-11-24T14:26:49Z", + "Updated": "2021-11-24T14:43:48Z" + }, + "Sender": { + "Login": "jcitizen", + "Name": "Jane Citizen", + "Email": "jane@example.com", + "Avatar": "https://www.gravatar.com/avatar/9e26471d35a78862c17e467d87cddedf.jpg" + } +} diff --git a/scm/driver/stash/testdata/webhooks/pr_modified_toref.json b/scm/driver/stash/testdata/webhooks/pr_modified_toref.json new file mode 100644 index 000000000..ff33036c6 --- /dev/null +++ b/scm/driver/stash/testdata/webhooks/pr_modified_toref.json @@ -0,0 +1,167 @@ +{ + "eventKey": "pr:modified", + "date": "2021-11-23T13:16:20+0000", + "actor": { + "name": "jcitizen", + "emailAddress": "jane@example.com", + "id": 1, + "displayName": "Jane Citizen", + "active": true, + "slug": "jcitizen", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "http://example.com:7990/users/jcitizen" + } + ] + } + }, + "pullRequest": { + "id": 2, + "version": 0, + "title": "added LICENSE", + "description": "added BSD license text", + "state": "OPEN", + "open": true, + "closed": false, + "createdDate": 1637591800463, + "updatedDate": 1637673380977, + "fromRef": { + "id": "refs/heads/feature-2", + "displayId": "feature-2", + "latestCommit": "c00d0f269a9844dd168f72f6a9d78a9cff49a318", + "type": "BRANCH", + "repository": { + "slug": "my-repo", + "id": 1, + "name": "my-repo", + "hierarchyId": "5aa23c1a1280b0c0acce", + "scmId": "git", + "state": "AVAILABLE", + "statusMessage": "Available", + "forkable": true, + "project": { + "key": "PRJ", + "id": 2, + "name": "PRJ", + "public": false, + "type": "NORMAL", + "links": { + "self": [ + { + "href": "http://example.com:7990/projects/PRJ" + } + ] + } + }, + "public": false, + "links": { + "clone": [ + { + "href": "http://example.com:7990/scm/prj/my-repo.git", + "name": "http" + }, + { + "href": "ssh://git@example.com:7999/prj/my-repo.git", + "name": "ssh" + } + ], + "self": [ + { + "href": "http://example.com:7990/projects/PRJ/repos/my-repo/browse" + } + ] + } + } + }, + "toRef": { + "id": "refs/heads/master", + "displayId": "master", + "latestCommit": "0667def9e377a8fa76ce67b6d4e53e21b246f030", + "type": "BRANCH", + "repository": { + "slug": "my-repo", + "id": 1, + "name": "my-repo", + "hierarchyId": "5aa23c1a1280b0c0acce", + "scmId": "git", + "state": "AVAILABLE", + "statusMessage": "Available", + "forkable": true, + "project": { + "key": "PRJ", + "id": 2, + "name": "PRJ", + "public": false, + "type": "NORMAL", + "links": { + "self": [ + { + "href": "http://example.com:7990/projects/PRJ" + } + ] + } + }, + "public": false, + "links": { + "clone": [ + { + "href": "http://example.com:7990/scm/prj/my-repo.git", + "name": "http" + }, + { + "href": "ssh://git@example.com:7999/prj/my-repo.git", + "name": "ssh" + } + ], + "self": [ + { + "href": "http://example.com:7990/projects/PRJ/repos/my-repo/browse" + } + ] + } + } + }, + "locked": false, + "author": { + "user": { + "name": "jcitizen", + "emailAddress": "jane@example.com", + "id": 1, + "displayName": "Jane Citizen", + "active": true, + "slug": "jcitizen", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "http://example.com:7990/users/jcitizen" + } + ] + } + }, + "role": "AUTHOR", + "approved": false, + "status": "UNAPPROVED" + }, + "reviewers": [], + "participants": [], + "links": { + "self": [ + { + "href": "http://example.com:7990/projects/PRJ/repos/my-repo/pull-requests/2" + } + ] + } + }, + "previousTitle": "old title", + "previousDescription": "old description", + "previousTarget": { + "id": "refs/heads/wrong", + "displayId": "wrong", + "type": "BRANCH", + "latestCommit": "2bbad782fd5453ded95fc5ce8b16839ff10615e0", + "latestChangeset": "2bbad782fd5453ded95fc5ce8b16839ff10615e0" + } +} diff --git a/scm/driver/stash/testdata/webhooks/pr_modified_toref.json.golden b/scm/driver/stash/testdata/webhooks/pr_modified_toref.json.golden new file mode 100644 index 000000000..c7d808d75 --- /dev/null +++ b/scm/driver/stash/testdata/webhooks/pr_modified_toref.json.golden @@ -0,0 +1,53 @@ +{ + "Action": "synchronized", + "Repo": { + "ID": "1", + "Namespace": "PRJ", + "Name": "my-repo", + "Perm": null, + "Branch": "master", + "Private": true, + "Clone": "http://example.com:7990/scm/prj/my-repo.git", + "CloneSSH": "ssh://git@example.com:7999/prj/my-repo.git", + "Link": "http://example.com:7990/projects/PRJ/repos/my-repo/browse", + "Created": "0001-01-01T00:00:00Z", + "Updated": "0001-01-01T00:00:00Z" + }, + "PullRequest": { + "Number": 2, + "Title": "added LICENSE", + "Body": "added BSD license text", + "Sha": "c00d0f269a9844dd168f72f6a9d78a9cff49a318", + "Ref": "refs/pull-requests/2/from", + "Source": "feature-2", + "Target": "master", + "Fork": "PRJ/my-repo", + "Link": "http://example.com:7990/projects/PRJ/repos/my-repo/pull-requests/2", + "Closed": false, + "Merged": false, + "Base": { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "0667def9e377a8fa76ce67b6d4e53e21b246f030" + }, + "Head": { + "Name": "feature-2", + "Path": "refs/heads/feature-2", + "Sha": "c00d0f269a9844dd168f72f6a9d78a9cff49a318" + }, + "Author": { + "Login": "jcitizen", + "Name": "Jane Citizen", + "Email": "jane@example.com", + "Avatar": "https://www.gravatar.com/avatar/9e26471d35a78862c17e467d87cddedf.jpg" + }, + "Created": "2021-11-22T14:36:40Z", + "Updated": "2021-11-23T13:16:20Z" + }, + "Sender": { + "Login": "jcitizen", + "Name": "Jane Citizen", + "Email": "jane@example.com", + "Avatar": "https://www.gravatar.com/avatar/9e26471d35a78862c17e467d87cddedf.jpg" + } +} diff --git a/scm/driver/stash/testdata/webhooks/pr_open.json.golden b/scm/driver/stash/testdata/webhooks/pr_open.json.golden index 5d29c8f49..cfed1a2ed 100644 --- a/scm/driver/stash/testdata/webhooks/pr_open.json.golden +++ b/scm/driver/stash/testdata/webhooks/pr_open.json.golden @@ -25,6 +25,16 @@ "Link": "", "Closed": false, "Merged": false, + "Base": { + "Name": "master", + "Path": "refs/heads/master", + "Sha": "823b2230a56056231c9425d63758fa87078a66b4" + }, + "Head": { + "Name": "develop", + "Path": "refs/heads/develop", + "Sha": "208b0a5c05eddadad01f2aed8802fe0c3b3eaf5e" + }, "Author": { "Login": "jcitizen", "Name": "Jane Citizen", 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/user.go b/scm/driver/stash/user.go index 4b7fa5b8a..aeab588be 100644 --- a/scm/driver/stash/user.go +++ b/scm/driver/stash/user.go @@ -20,7 +20,7 @@ type userService struct { } func (s *userService) Find(ctx context.Context) (*scm.User, *scm.Response, error) { - path := fmt.Sprintf("plugins/servlet/applinks/whoami") + path := "plugins/servlet/applinks/whoami" out := new(bytes.Buffer) res, err := s.client.do(ctx, "GET", path, nil, out) if err != nil { @@ -78,6 +78,10 @@ func (s *userService) FindEmail(ctx context.Context) (string, *scm.Response, err return email, res, err } +func (s *userService) ListEmail(context.Context, scm.ListOptions) ([]*scm.Email, *scm.Response, error) { + return nil, nil, scm.ErrNotSupported +} + type user struct { Name string `json:"name"` EmailAddress string `json:"emailAddress"` diff --git a/scm/driver/stash/user_test.go b/scm/driver/stash/user_test.go index 9e05e4d31..ac4df21ad 100644 --- a/scm/driver/stash/user_test.go +++ b/scm/driver/stash/user_test.go @@ -39,7 +39,7 @@ func TestUserFind(t *testing.T) { want := new(scm.User) raw, _ := ioutil.ReadFile("testdata/user.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -82,7 +82,7 @@ func TestUserLoginFind(t *testing.T) { want := new(scm.User) raw, _ := ioutil.ReadFile("testdata/user.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") @@ -117,7 +117,7 @@ func TestUserLoginFind_ViaSearch(t *testing.T) { want := new(scm.User) raw, _ := ioutil.ReadFile("testdata/user_search.json.golden") - json.Unmarshal(raw, &want) + _ = json.Unmarshal(raw, &want) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("Unexpected Results") 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.go b/scm/driver/stash/webhook.go index 84ef85cb1..31c130638 100644 --- a/scm/driver/stash/webhook.go +++ b/scm/driver/stash/webhook.go @@ -21,7 +21,6 @@ import ( // TODO(bradrydzewski) push hook does not include repository git+http link // TODO(bradrydzewski) push hook does not include repository git+ssh link // TODO(bradrydzewski) push hook does not include repository html link -// TODO(bradrydzewski) missing pull request synchrnoized webhook. See https://jira.atlassian.com/browse/BSERV-10279 // TODO(bradrydzewski) pr hook does not include repository git+http link // TODO(bradrydzewski) pr hook does not include repository git+ssh link // TODO(bradrydzewski) pr hook does not include repository html link @@ -42,7 +41,7 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo switch req.Header.Get("X-Event-Key") { case "repo:refs_changed": hook, err = s.parsePushHook(data) - case "pr:opened", "pr:declined", "pr:merged": + case "pr:opened", "pr:from_ref_updated", "pr:modified", "pr:declined", "pr:deleted", "pr:merged": hook, err = s.parsePullRequest(data) } if err != nil { @@ -100,8 +99,25 @@ func (s *webhookService) parsePullRequest(data []byte) (scm.Webhook, error) { switch src.EventKey { case "pr:opened": dst.Action = scm.ActionOpen + case "pr:from_ref_updated": + // The request includes field "previousFromHash", which could be compared + // to the FromRef.Latestcommit to ensure there is actually a change, + // but there is unlikely need for that. + dst.Action = scm.ActionSync + case "pr:modified": + // BitBucket Server (Stash) sends "pr:modified" for any edits to the PR, + // including edits to the title or description. Thus, return the hook + // action only when the target reference has changed (name or hash). + if src.PullRequest.ToRef.DisplayID == src.PreviousTarget.DisplayID && + src.PullRequest.ToRef.LatestCommit == src.PreviousTarget.LatestCommit { + dst.Action = scm.ActionUpdate + } else { + dst.Action = scm.ActionSync + } case "pr:declined": dst.Action = scm.ActionClose + case "pr:deleted": + dst.Action = scm.ActionClose case "pr:merged": dst.Action = scm.ActionMerge default: @@ -127,6 +143,16 @@ type pullRequestHook struct { Date string `json:"date"` Actor *user `json:"actor"` PullRequest *pr `json:"pullRequest"` + // only in pr:from_ref_updated + PreviousFromHash string `json:"previousFromHash"` + // only in pr:modified + PreviousTarget struct { + ID string `json:"id"` // "refs/heads/master" + DisplayID string `json:"displayId"` // "master" + Type string `json:"type"` // "BRANCH" + LatestCommit string `json:"latestCommit"` // "860c4eb4ed0f969b47144234ba13c31c498cca69" + LatestChangeset string `json:"latestChangeset"` // "860c4eb4ed0f969b47144234ba13c31c498cca69" + } `json:"previousTarget"` } type change struct { diff --git a/scm/driver/stash/webhook_test.go b/scm/driver/stash/webhook_test.go index e7f162185..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 // @@ -92,6 +99,30 @@ func TestWebhooks(t *testing.T) { after: "testdata/webhooks/pr_open.json.golden", obj: new(scm.PullRequestHook), }, + // pull request source branch updated + { + sig: "71295b197fa25f4356d2fb9965df3f2379d903d7", + event: "pr:from_ref_updated", + before: "testdata/webhooks/pr_from_ref_updated.json", + after: "testdata/webhooks/pr_from_ref_updated.json.golden", + obj: new(scm.PullRequestHook), + }, + // pull request modified, target branch updated + { + sig: "71295b197fa25f4356d2fb9965df3f2379d903d7", + event: "pr:modified", + before: "testdata/webhooks/pr_modified_toref.json", + after: "testdata/webhooks/pr_modified_toref.json.golden", + obj: new(scm.PullRequestHook), + }, + // pull request modified, no change to toref + { + sig: "71295b197fa25f4356d2fb9965df3f2379d903d7", + event: "pr:modified", + before: "testdata/webhooks/pr_modified_meta.json", + after: "testdata/webhooks/pr_modified_meta.json.golden", + obj: new(scm.PullRequestHook), + }, // pull request fulfilled (merged) { sig: "71295b197fa25f4356d2fb9965df3f2379d903d7", @@ -108,6 +139,14 @@ func TestWebhooks(t *testing.T) { after: "testdata/webhooks/pr_declined.json.golden", obj: new(scm.PullRequestHook), }, + // pull request deleted + { + sig: "71295b197fa25f4356d2fb9965df3f2379d903d7", + event: "pr:deleted", + before: "testdata/webhooks/pr_deleted.json", + after: "testdata/webhooks/pr_deleted.json.golden", + obj: new(scm.PullRequestHook), + }, } for _, test := range tests { @@ -144,7 +183,7 @@ func TestWebhooks(t *testing.T) { t.Log(diff) // debug only. remove once implemented - json.NewEncoder(os.Stdout).Encode(o) + _ = json.NewEncoder(os.Stdout).Encode(o) } switch event := o.(type) { diff --git a/scm/enrich/doc.go b/scm/enrich/doc.go new file mode 100644 index 000000000..4792e6e14 --- /dev/null +++ b/scm/enrich/doc.go @@ -0,0 +1,3 @@ +// Package normalize provides facilities for enriching +// data structures with missing information. +package enrich diff --git a/scm/enrich/webhook.go b/scm/enrich/webhook.go new file mode 100644 index 000000000..2dde306d2 --- /dev/null +++ b/scm/enrich/webhook.go @@ -0,0 +1,17 @@ +// Copyright 2022 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 enrich + +import ( + "context" + + "github.com/drone/go-scm/scm" +) + +// Webhook enriches the webhook payload with missing +// information not included in the webhook payload. +func Webhook(ctx context.Context, client *scm.Client, webhook *scm.Webhook) error { + return nil // TODO +} diff --git a/scm/enrich/webhook_test.go b/scm/enrich/webhook_test.go new file mode 100644 index 000000000..94fe1bca4 --- /dev/null +++ b/scm/enrich/webhook_test.go @@ -0,0 +1,5 @@ +// Copyright 2022 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 enrich diff --git a/scm/example_test.go b/scm/example_test.go index 7055616a2..f95aaff7d 100644 --- a/scm/example_test.go +++ b/scm/example_test.go @@ -91,7 +91,7 @@ func ExampleRepository_list() { } } -func ExampleBranch_find() { +func ExampleGitService_FindBranch() { client, err := github.New("https://api.github.com") if err != nil { log.Fatal(err) @@ -105,7 +105,7 @@ func ExampleBranch_find() { log.Println(branch.Name, branch.Sha) } -func ExampleBranch_list() { +func ExampleGitService_ListBranches() { client, err := github.New("https://api.github.com") if err != nil { log.Fatal(err) @@ -126,7 +126,7 @@ func ExampleBranch_list() { } } -func ExampleTag_find() { +func ExampleGitService_FindTag() { client, err := github.New("https://api.github.com") if err != nil { log.Fatal(err) @@ -140,7 +140,7 @@ func ExampleTag_find() { log.Println(tag.Name, tag.Sha) } -func ExampleTag_list() { +func ExampleGitService_ListTags() { client, err := github.New("https://api.github.com") if err != nil { log.Fatal(err) diff --git a/scm/git.go b/scm/git.go index a5bda8e1c..5f0d9892a 100644 --- a/scm/git.go +++ b/scm/git.go @@ -20,6 +20,12 @@ type ( Sha string } + // ReferenceInput provides a SHA for creating a reference. + ReferenceInput struct { + Name string + Sha string + } + // Commit represents a repository commit. Commit struct { Sha string @@ -35,6 +41,7 @@ type ( Ref string Page int Size int + Path string } // Signature identifies a git commit creator. @@ -51,6 +58,9 @@ type ( // 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 *ReferenceInput) (*Response, error) + // FindBranch finds a git branch by name. FindBranch(ctx context.Context, repo, name string) (*Reference, *Response, error) @@ -63,6 +73,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) @@ -78,4 +91,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/milestone.go b/scm/milestone.go new file mode 100644 index 000000000..a251c9dba --- /dev/null +++ b/scm/milestone.go @@ -0,0 +1,42 @@ +package scm + +import ( + "context" + "time" +) + +type ( + // MilestoneInput contains the information needed to create a milestone + MilestoneInput struct { + Title string + Description string + State string + DueDate time.Time + } + + // MilestoneListOptions provides options for querying a list of repository milestones. + MilestoneListOptions struct { + Page int + Size int + Open bool + Closed bool + } + + // MilestoneService provides access to creating, listing, updating, and deleting milestones + MilestoneService interface { + // Find returns the milestone for the given number in the given repository + Find(context.Context, string, int) (*Milestone, *Response, error) + + // List returns a list of milestones in the given repository + List(context.Context, string, MilestoneListOptions) ([]*Milestone, *Response, error) + + // Create creates a milestone in the given repository + Create(context.Context, string, *MilestoneInput) (*Milestone, *Response, error) + + // Update updates a milestone in the given repository + Update(context.Context, string, int, *MilestoneInput) (*Milestone, *Response, error) + + // Delete deletes a milestone in the given repository + Delete(context.Context, string, int) (*Response, error) + } +) diff --git a/scm/pr.go b/scm/pr.go index 65b2d5683..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 @@ -51,10 +53,13 @@ type ( // Change represents a changed file. Change struct { - Path string - Added bool - Renamed bool - Deleted bool + Path string + Added bool + Renamed bool + Deleted bool + Sha string + BlobID string + PrevFilePath string } Label struct { @@ -62,6 +67,17 @@ type ( Color string } + // Milestone the milestone + Milestone struct { + Number int + ID int + Title string + Description string + Link string + State string + DueDate time.Time + } + // PullRequestService provides access to pull request resources. PullRequestService interface { // Find returns the repository pull request by number. @@ -79,6 +95,9 @@ type ( // ListComments returns the pull request comment list. ListComments(context.Context, string, int, ListOptions) ([]*Comment, *Response, error) + // ListCommits returns the pull request commit list. + ListCommits(context.Context, string, int, ListOptions) ([]*Commit, *Response, error) + // Merge merges the repository pull request. Merge(context.Context, string, int) (*Response, error) diff --git a/scm/release.go b/scm/release.go new file mode 100644 index 000000000..68d6a058d --- /dev/null +++ b/scm/release.go @@ -0,0 +1,67 @@ +package scm + +import ( + "context" + "time" +) + +type ( + // Release the release + Release struct { + ID int + Title string + Description string + Link string + Tag string + Commitish string + Draft bool + Prerelease bool + Created time.Time + Published time.Time + } + + // ReleaseInput contains the information needed to create a release + ReleaseInput struct { + Title string + Description string + Tag string + Commitish string + Draft bool + Prerelease bool + } + + // ReleaseListOptions provides options for querying a list of repository releases. + ReleaseListOptions struct { + Page int + Size int + Open bool + Closed bool + } + + // ReleaseService provides access to creating, listing, updating, and deleting releases + ReleaseService interface { + // Find returns the release for the given number in the given repository + Find(context.Context, string, int) (*Release, *Response, error) + + // FindByTag returns the release for the given tag in the given repository + FindByTag(context.Context, string, string) (*Release, *Response, error) + + // List returns a list of releases in the given repository + List(context.Context, string, ReleaseListOptions) ([]*Release, *Response, error) + + // Create creates a release in the given repository + Create(context.Context, string, *ReleaseInput) (*Release, *Response, error) + + // Update updates a release in the given repository + Update(context.Context, string, int, *ReleaseInput) (*Release, *Response, error) + + // UpdateByTag deletes a release in the given repository by tag + UpdateByTag(context.Context, string, string, *ReleaseInput) (*Release, *Response, error) + + // Delete deletes a release in the given repository + Delete(context.Context, string, int) (*Response, error) + + // DeleteByTag deletes a release in the given repository by tag + DeleteByTag(context.Context, string, string) (*Response, error) + } +) diff --git a/scm/repo.go b/scm/repo.go index 8bcfa7231..8ec383c37 100644 --- a/scm/repo.go +++ b/scm/repo.go @@ -17,6 +17,7 @@ type ( Name string Perm *Perm Branch string + Archived bool Private bool Visibility Visibility Clone string @@ -119,6 +120,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) + // ListHooks returns a list or repository hooks. ListHooks(context.Context, string, ListOptions) ([]*Hook, *Response, error) diff --git a/scm/traverse/doc.go b/scm/traverse/doc.go new file mode 100644 index 000000000..845da57c3 --- /dev/null +++ b/scm/traverse/doc.go @@ -0,0 +1,3 @@ +// Package traverse provides facilities for traversing +// and combining the paginated results. +package traverse diff --git a/scm/traverse/repos.go b/scm/traverse/repos.go new file mode 100644 index 000000000..c417d2704 --- /dev/null +++ b/scm/traverse/repos.go @@ -0,0 +1,36 @@ +// Copyright 2022 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 traverse + +import ( + "context" + + "github.com/drone/go-scm/scm" +) + +// Repos returns the full repository list, traversing and +// combining paginated responses if necessary. +func Repos(ctx context.Context, client *scm.Client) ([]*scm.Repository, error) { + list := []*scm.Repository{} + opts := scm.ListOptions{Size: 100} + for { + result, meta, err := client.Repositories.List(ctx, opts) + if err != nil { + return nil, err + } + for _, src := range result { + if src != nil { + list = append(list, src) + } + } + opts.Page = meta.Page.Next + opts.URL = meta.Page.NextURL + + if opts.Page == 0 && opts.URL == "" { + break + } + } + return list, nil +} diff --git a/scm/traverse/repos_test.go b/scm/traverse/repos_test.go new file mode 100644 index 000000000..63cf67f35 --- /dev/null +++ b/scm/traverse/repos_test.go @@ -0,0 +1,5 @@ +// Copyright 2022 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 traverse diff --git a/scm/user.go b/scm/user.go index 93c40c469..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 @@ -20,6 +21,13 @@ type ( Updated time.Time } + // Email represents a user email. + Email struct { + Value string + Primary bool + Verified bool + } + // UserService provides access to user account resources. UserService interface { // Find returns the authenticated user. @@ -30,5 +38,8 @@ type ( // FindLogin returns the user account by username. FindLogin(context.Context, string) (*User, *Response, error) + + // ListEmail returns the user email list. + ListEmail(context.Context, ListOptions) ([]*Email, *Response, error) } ) diff --git a/scm/util.go b/scm/util.go index 6108feee8..6aa496834 100644 --- a/scm/util.go +++ b/scm/util.go @@ -14,6 +14,13 @@ import ( // from the git ref (e.g. refs/pulls/{d}/head) var re = regexp.MustCompile("\\d+") +// regular expressions to test whether or not a string is +// a sha1 or sha256 commit hash. +var ( + sha1 = regexp.MustCompile("^([a-f0-9]{40})$") + sha256 = regexp.MustCompile("^([a-f0-9]{64})$") +) + // Split splits the full repository name into segments. func Split(s string) (owner, name string) { parts := strings.SplitN(s, "/", 2) @@ -77,3 +84,30 @@ func IsPullRequest(ref string) bool { strings.HasPrefix(ref, "refs/pull-request/") || strings.HasPrefix(ref, "refs/merge-requests/") } + +// IsHash returns true if the string is a commit hash. +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 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 44b0ba181..c2b87ae74 100644 --- a/scm/util_test.go +++ b/scm/util_test.go @@ -193,3 +193,88 @@ func TestExtractPullRequest(t *testing.T) { } } } + +func TestIsHash(t *testing.T) { + tests := []struct { + name string + tag bool + }{ + { + name: "aacad6eca956c3a340ae5cd5856aa9c4a3755408", + tag: true, + }, + { + name: "3da541559918a808c2402bba5012f6c60b27661c", + tag: true, + }, + { + name: "f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b", + tag: true, + }, + // not a sha + { + name: "aacad6e", + tag: false, + }, + { + name: "master", + tag: false, + }, + { + name: "refs/heads/master", + tag: false, + }, + { + name: "issue/42", + tag: false, + }, + { + name: "feature/foo", + tag: false, + }, + } + for _, test := range tests { + if got, want := IsHash(test.name), test.tag; got != want { + t.Errorf("Got IsHash %v, want %v", got, want) + } + } +} + +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 b36c25feb..f6875f6f2 100644 --- a/scm/webhook.go +++ b/scm/webhook.go @@ -115,6 +115,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 + } + // SecretFunc provides the Webhook parser with the // secret key used to validate webhook authenticity. SecretFunc func(webhook Webhook) (string, error) @@ -140,3 +149,4 @@ 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 }