diff --git a/Makefile b/Makefile
index 4b937667c6..a581114b16 100644
--- a/Makefile
+++ b/Makefile
@@ -280,6 +280,10 @@ codegen-controller: install-controller-gen
object:headerFile=hack/boilerplate.go.txt \
paths=./...
+.PHONY: codegen-bitbucket-client
+codegen-bitbucket-client: install-oapi-codegen
+ cd pkg/gitprovider/bitbucket/cloud && $(OAPI_CODEGEN_LINK) --config spec/oapi-codegen.yaml spec/bitbucket.gen.json
+
.PHONY: codegen-schema-to-go
codegen-schema-to-go: install-goimports
npm install -g quicktype@23.0.176
diff --git a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-merge-pr.md b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-merge-pr.md
index 871f857436..2a8219c321 100644
--- a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-merge-pr.md
+++ b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-merge-pr.md
@@ -49,7 +49,11 @@ system to access the git repos.
:::warning
-The `wait` option is unreliable for repositories hosted by Bitbucket due to API limitations.
+The `wait` option is unreliable for repositories hosted by Bitbucket. The
+Bitbucket Cloud API does not provide a way to check merge eligibility before
+attempting a merge, so Kargo cannot determine in advance whether a PR is blocked
+by conflicts, failing checks, or other conditions. As a result, Kargo will
+attempt the merge regardless, which may fail unexpectedly.
:::
@@ -61,7 +65,7 @@ currently supported Git hosting providers.
| Provider | Supported Methods | Default |
| -------- | ----------------- | ------- |
| Azure |
- `noFastForward`
- `rebase`
- `rebaseMerge`
- `squash`
| First allowed strategy per the target branch's merge type policy; merge commit if no policy is configured |
-| BitBucket | Client does not yet support specifying a merge strategy | The repository's configured default merge strategy |
+| BitBucket | - `fast_forward`
- `merge_commit`
- `squash`
| The repository's configured default merge strategy |
| Gitea | - `fast-forward-only`
- `manually-merged`
- `merge`
- `rebase`
- `rebase-merge`
- `squash`
| `merge` |
| GitHub | | `merge` |
| GitLab | | Defers to the merge request and project-level squash settings |
diff --git a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-open-pr.md b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-open-pr.md
index 146a35f515..471945f336 100644
--- a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-open-pr.md
+++ b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-open-pr.md
@@ -10,8 +10,8 @@ specified source and target branches. This step is often used after a
[`git-push` step](git-push.md) and is commonly followed by a
[`git-wait-for-pr` step](git-wait-for-pr.md).
-At present, this feature only supports GitHub, Gitea, Azure DevOps, and
-GitLab pull/merge requests.
+At present, this feature only supports GitHub, Gitea, Azure DevOps, GitLab and
+BitBucket pull/merge requests.
## Credentials
diff --git a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-push.md b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-push.md
index d1a6713704..9c947c722f 100644
--- a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-push.md
+++ b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-push.md
@@ -106,7 +106,7 @@ system to access Git repositories.
| `generateTargetBranch` | `boolean` | N | Whether to push to a remote branch named like `kargo/promotion/`. If such a branch does not already exist, it will be created. A value of `true` is mutually exclusive with `targetBranch` and `tag`. If none of these are provided, the target branch will be the currently checked out branch. This option is useful when a subsequent promotion step will open a pull request against a Stage-specific branch. In such a case, the generated target branch pushed to by the `git-push` step can later be utilized as the source branch of the pull request. |
| `tag` | `string` | N | An tag to push to the remote repository. Mutually exclusive with `generateTargetBranch` and `targetBranch`. |
| `force` | `boolean` | N | Whether to force push to the target branch, overwriting any existing history. This is useful for scenarios where you want to completely replace the branch content (e.g., pushing rendered manifests that don't depend on previous state). **Use with caution** as this will overwrite any commits that exist on the remote branch but not in your local branch. Default is `false`. A value of `true` is mutually exclusive with `tag`. |
-| `provider` | `string` | N | The name of the Git provider to use. Currently 'azure', 'bitbucket', 'gitea', 'github', and 'gitlab' are supported. Kargo will try to infer the provider if it is not explicitly specified. This setting does not affect the push operation but helps generate the correct [`commitURL` output](#output) when working with repositories where the provider cannot be automatically determined, such as self-hosted instances. |
+| `provider` | `string` | N | The name of the Git provider to use. Currently `azure`, `bitbucket`, `gitea`, `github`, and `gitlab` are supported. Kargo will try to infer the provider if it is not explicitly specified. This setting does not affect the push operation but helps generate the correct [`commitURL` output](#output) when working with repositories where the provider cannot be automatically determined, such as self-hosted instances. |
## Output
diff --git a/go.mod b/go.mod
index 52b90e0f6a..f2d25ccd30 100644
--- a/go.mod
+++ b/go.mod
@@ -54,9 +54,9 @@ require (
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/jferrl/go-githubauth v1.5.1
github.com/kelseyhightower/envconfig v1.4.0
- github.com/klauspost/compress v1.18.6
- github.com/ktrysmt/go-bitbucket v0.9.87
+ github.com/klauspost/compress v1.18.5
github.com/microsoft/azure-devops-go-api/azuredevops/v7 v7.1.0
+ github.com/oapi-codegen/runtime v1.4.0
github.com/oklog/ulid/v2 v2.1.1
github.com/otiai10/copy v1.14.1
github.com/patrickmn/go-cache v2.1.0+incompatible
@@ -113,6 +113,7 @@ require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
github.com/Masterminds/squirrel v1.5.4 // indirect
+ github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 // indirect
@@ -211,14 +212,13 @@ require (
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
- github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
- github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/spdystream v0.5.1 // indirect
github.com/moby/term v0.5.2 // indirect
diff --git a/go.sum b/go.sum
index fb43073312..4c29aa46a9 100644
--- a/go.sum
+++ b/go.sum
@@ -52,8 +52,11 @@ github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
+github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78=
github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=
+github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
+github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
@@ -98,6 +101,7 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
+github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/bmatcuk/doublestar/v4 v4.9.2 h1:b0mc6WyRSYLjzofB2v/0cuDUZ+MqoGyH3r0dVij35GI=
github.com/bmatcuk/doublestar/v4 v4.9.2/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
@@ -358,6 +362,7 @@ github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
@@ -366,16 +371,14 @@ github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRt
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
-github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
+github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
+github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/ktrysmt/go-bitbucket v0.9.87 h1:eR7E4ndyKpO2+HdBwUlsC5K/40nEDpjMLEWsPLY97oQ=
-github.com/ktrysmt/go-bitbucket v0.9.87/go.mod h1:slSdGm9Vh3L2ZOU1r7Fu2B9rPJvsflYgneRCoPA83eY=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
@@ -389,10 +392,9 @@ github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
-github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
-github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
+github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
@@ -411,8 +413,6 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
-github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
-github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/moby/spdystream v0.5.1 h1:9sNYeYZUcci9R6/w7KDaFWEWeV4LStVG78Mpyq/Zm/Y=
@@ -433,6 +433,8 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
+github.com/oapi-codegen/runtime v1.4.0 h1:KLOSFOp7UzkbS7Cs1ms6NBEKYr0WmH2wZG0KKbd2er4=
+github.com/oapi-codegen/runtime v1.4.0/go.mod h1:5sw5fxCDmnOzKNYmkVNF8d34kyUeejJEY8HNT2WaPec=
github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=
github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
@@ -512,6 +514,7 @@ github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiT
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -661,7 +664,6 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
diff --git a/hack/tools.mk b/hack/tools.mk
index 14d78f8208..c973ad28b8 100644
--- a/hack/tools.mk
+++ b/hack/tools.mk
@@ -30,6 +30,7 @@ QUILL_VERSION ?= v0.5.1
PROTOC_GEN_DOC_VERSION ?= v1.5.1
SWAG_VERSION ?= $(shell grep github.com/swaggo/swag $(TOOLS_MOD_FILE) | awk '{print $$2}')
GO_SWAGGER_VERSION ?= $(shell grep github.com/go-swagger/go-swagger $(TOOLS_MOD_FILE) | awk '{print $$2}')
+OAPI_CODEGEN_VERSION ?= $(shell grep github.com/oapi-codegen/oapi-codegen $(TOOLS_MOD_FILE) | awk '{print $$2}')
TILT_VERSION ?= v0.36.3
CTLPTL_VERSION ?= v0.9.0
KIND_VERSION ?= v0.31.0
@@ -52,6 +53,7 @@ QUILL := $(BIN_DIR)/quill-$(OS)-$(ARCH)-$(QUILL_VERSION)
PROTOC_GEN_DOC := $(BIN_DIR)/protoc-gen-doc-$(OS)-$(ARCH)-$(PROTOC_GEN_DOC_VERSION)
SWAG := $(BIN_DIR)/swag-$(OS)-$(ARCH)-$(SWAG_VERSION)
GO_SWAGGER := $(BIN_DIR)/go-swagger-$(OS)-$(ARCH)-$(GO_SWAGGER_VERSION)
+OAPI_CODEGEN := $(BIN_DIR)/oapi-codegen-$(OS)-$(ARCH)-$(OAPI_CODEGEN_VERSION)
TILT := $(BIN_DIR)/tilt-$(OS)-$(ARCH)-$(TILT_VERSION)
CTLPTL := $(BIN_DIR)/ctlptl-$(OS)-$(ARCH)-$(CTLPTL_VERSION)
KIND := $(BIN_DIR)/kind-$(OS)-$(ARCH)-$(KIND_VERSION)
@@ -94,6 +96,9 @@ $(SWAG):
$(GO_SWAGGER):
$(call go-install-tool,$@,github.com/go-swagger/go-swagger/cmd/swagger,$(GO_SWAGGER_VERSION))
+$(OAPI_CODEGEN):
+ $(call go-install-tool,$@,github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen,$(OAPI_CODEGEN_VERSION))
+
$(TILT):
$(call install-tilt,$@,$(TILT_VERSION))
@@ -125,6 +130,7 @@ QUILL_LINK := $(BIN_DIR)/quill
PROTOC_GEN_DOC_LINK := $(BIN_DIR)/protoc-gen-doc
SWAG_LINK := $(BIN_DIR)/swag
GO_SWAGGER_LINK := $(BIN_DIR)/go-swagger
+OAPI_CODEGEN_LINK := $(BIN_DIR)/oapi-codegen
TILT_LINK := $(BIN_DIR)/tilt
CTLPTL_LINK := $(BIN_DIR)/ctlptl
KIND_LINK := $(BIN_DIR)/kind
@@ -179,6 +185,10 @@ $(SWAG_LINK): $(SWAG)
$(GO_SWAGGER_LINK): $(GO_SWAGGER)
$(call create-symlink,$(GO_SWAGGER),$(GO_SWAGGER_LINK))
+.PHONY: $(OAPI_CODEGEN_LINK)
+$(OAPI_CODEGEN_LINK): $(OAPI_CODEGEN)
+ $(call create-symlink,$(OAPI_CODEGEN),$(OAPI_CODEGEN_LINK))
+
.PHONY: $(TILT_LINK)
$(TILT_LINK): $(TILT)
$(call create-symlink,$(TILT),$(TILT_LINK))
@@ -203,7 +213,7 @@ $(JQ_LINK): $(JQ)
# Alias targets #
################################################################################
-TOOLS := install-golangci-lint install-helm install-goimports install-go-to-protobuf install-protoc-gen-gogo install-controller-gen install-protoc install-buf install-quill install-protoc-gen-doc install-swag install-go-swagger install-tilt install-ctlptl install-kind install-k3d install-jq
+TOOLS := install-golangci-lint install-helm install-goimports install-go-to-protobuf install-protoc-gen-gogo install-controller-gen install-protoc install-buf install-quill install-protoc-gen-doc install-swag install-go-swagger install-oapi-codegen install-tilt install-ctlptl install-kind install-k3d install-jq
.PHONY: install-tools
install-tools: $(TOOLS)
@@ -244,6 +254,9 @@ install-swag: $(SWAG) $(SWAG_LINK)
.PHONY: install-go-swagger
install-go-swagger: $(GO_SWAGGER) $(GO_SWAGGER_LINK)
+.PHONY: install-oapi-codegen
+install-oapi-codegen: $(OAPI_CODEGEN) $(OAPI_CODEGEN_LINK)
+
.PHONY: install-tilt
install-tilt: $(TILT) $(TILT_LINK)
diff --git a/hack/tools/go.mod b/hack/tools/go.mod
index b511392f69..aab059e77c 100644
--- a/hack/tools/go.mod
+++ b/hack/tools/go.mod
@@ -6,6 +6,7 @@ require (
github.com/bufbuild/buf v1.61.0
github.com/go-swagger/go-swagger v0.33.2
github.com/golangci/golangci-lint/v2 v2.10.1
+ github.com/oapi-codegen/oapi-codegen/v2 v2.6.0
github.com/swaggo/swag v1.16.6
golang.org/x/tools v0.42.0
helm.sh/helm/v3 v3.19.4
@@ -116,6 +117,7 @@ require (
github.com/docker/docker-credential-helpers v0.9.4 // indirect
github.com/docker/go-connections v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
+ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
github.com/ettle/strcase v0.2.0 // indirect
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
@@ -127,6 +129,7 @@ require (
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/fzipp/gocyclo v0.6.0 // indirect
+ github.com/getkin/kin-openapi v0.133.0 // indirect
github.com/ghostiam/protogetter v0.3.20 // indirect
github.com/go-chi/chi/v5 v5.2.3 // indirect
github.com/go-critic/go-critic v0.14.3 // indirect
@@ -209,6 +212,7 @@ require (
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
github.com/jjti/go-spancheck v0.6.5 // indirect
github.com/jmoiron/sqlx v1.4.0 // indirect
+ github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/julz/importas v0.2.0 // indirect
github.com/karamaru-alpha/copyloopvar v1.2.2 // indirect
@@ -234,6 +238,7 @@ require (
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/macabu/inamedparam v0.2.0 // indirect
+ github.com/mailru/easyjson v0.7.7 // indirect
github.com/manuelarte/embeddedstructfieldcheck v0.4.0 // indirect
github.com/manuelarte/funcorder v0.5.0 // indirect
github.com/maratori/testableexamples v1.0.1 // indirect
@@ -252,6 +257,7 @@ require (
github.com/moby/term v0.5.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
+ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/moricho/tparallel v0.3.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
@@ -262,10 +268,13 @@ require (
github.com/nishanths/exhaustive v0.12.0 // indirect
github.com/nishanths/predeclared v0.2.2 // indirect
github.com/nunnatsa/ginkgolinter v0.23.0 // indirect
+ github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect
+ github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
github.com/oklog/ulid/v2 v2.1.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
+ github.com/perimeterx/marshmallow v1.1.5 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/petermattis/goid v0.0.0-20250904145737-900bdf8bb490 // indirect
github.com/pkg/errors v0.9.1 // indirect
@@ -303,6 +312,8 @@ require (
github.com/sonatard/noctx v0.4.0 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/sourcegraph/go-diff v0.7.0 // indirect
+ github.com/speakeasy-api/jsonpath v0.6.0 // indirect
+ github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/cobra v1.10.2 // indirect
@@ -328,6 +339,8 @@ require (
github.com/uudashr/gocognit v1.2.0 // indirect
github.com/uudashr/iface v1.4.1 // indirect
github.com/vbatts/tar-split v0.12.1 // indirect
+ github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect
+ github.com/woodsbury/decimal128 v1.3.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xen0n/gosmopolitan v1.3.0 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
diff --git a/hack/tools/go.sum b/hack/tools/go.sum
index e58f4492a4..3729131474 100644
--- a/hack/tools/go.sum
+++ b/hack/tools/go.sum
@@ -177,6 +177,9 @@ github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0G
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/ckaznocha/intrange v0.3.1 h1:j1onQyXvHUsPWujDH6WIjhyH26gkRt/txNlV7LspvJs=
github.com/ckaznocha/intrange v0.3.1/go.mod h1:QVepyz1AkUoFQkpEqksSYpNpUo3c5W7nWh/s6SHIJJk=
github.com/cli/browser v1.3.0 h1:LejqCrpWr+1pRqmEPDGnTZOjsMe7sehifLynZJuqJpo=
@@ -242,6 +245,9 @@ github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQ
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58=
+github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 h1:PRxIJD8XjimM5aTknUK9w6DHLDox2r2M3DI4i2pnd3w=
+github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5qlB+mlV1okblJqcSMtR4c52UKxDiX9GRBS8+Q=
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q=
@@ -262,12 +268,16 @@ github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7Dlme
github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
+github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ=
+github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE=
github.com/ghostiam/protogetter v0.3.20 h1:oW7OPFit2FxZOpmMRPP9FffU4uUpfeE/rEdE1f+MzD0=
github.com/ghostiam/protogetter v0.3.20/go.mod h1:FjIu5Yfs6FT391m+Fjp3fbAYJ6rkL/J6ySpZBfnODuI=
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
@@ -339,8 +349,12 @@ github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpv
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-swagger/go-swagger v0.33.2 h1:L1dxjjI29MKSWpRT0xXTOOaI3jzDWws2vR9oQmtYBZU=
github.com/go-swagger/go-swagger v0.33.2/go.mod h1:1HGAWunq7SIuIPIWPHlZEDBURdzUk3BxSPr7x4dFHjc=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
+github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
+github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8=
github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU=
github.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s=
@@ -374,6 +388,15 @@ github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw=
github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golangci/asciicheck v0.5.0 h1:jczN/BorERZwK8oiFBOGvlGPknhvq0bjnysTj4nUfo0=
@@ -404,15 +427,19 @@ github.com/google/cel-go v0.26.1 h1:iPbVVEdkhTX++hpe3lzSk7D3G3QSYqLGoHOcEio+UXQ=
github.com/google/cel-go v0.26.1/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM=
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-containerregistry v0.20.6 h1:cvWX87UxxLgaH76b4hIvya6Dzz9qHB31qAwjAohdSTU=
github.com/google/go-containerregistry v0.20.6/go.mod h1:T0x8MuoAoKX/873bkeSfLD2FAkwCDf9/HZgsFJ02E2Y=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc=
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
@@ -461,8 +488,10 @@ github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jdx/go-netrc v1.0.0 h1:QbLMLyCZGj0NA8glAhxUpf1zDg6cxnWgMBbjq40W0gQ=
@@ -479,6 +508,8 @@ github.com/jjti/go-spancheck v0.6.5 h1:lmi7pKxa37oKYIMScialXUK6hP3iY5F1gu+mLBPgY
github.com/jjti/go-spancheck v0.6.5/go.mod h1:aEogkeatBrbYsyW6y5TgDfihCulDYciL1B7rG2vSsrU=
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/julz/importas v0.2.0 h1:y+MJN/UdL63QbFJHws9BVC5RpA2iq0kpjrFajTGivjQ=
@@ -495,8 +526,11 @@ github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3J
github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kulti/thelper v0.7.1 h1:fI8QITAoFVLx+y+vSyuLBP+rcVIB8jKooNSCT2EiI98=
@@ -532,6 +566,8 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/macabu/inamedparam v0.2.0 h1:VyPYpOc10nkhI2qeNUdh3Zket4fcZjEWe35poddBCpE=
github.com/macabu/inamedparam v0.2.0/go.mod h1:+Pee9/YfGe5LJ62pYXqB89lJ+0k5bsR8Wgz/C0Zlq3U=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/manuelarte/embeddedstructfieldcheck v0.4.0 h1:3mAIyaGRtjK6EO9E73JlXLtiy7ha80b2ZVGyacxgfww=
github.com/manuelarte/embeddedstructfieldcheck v0.4.0/go.mod h1:z8dFSyXqp+fC6NLDSljRJeNQJJDWnY7RoWFzV3PC6UM=
github.com/manuelarte/funcorder v0.5.0 h1:llMuHXXbg7tD0i/LNw8vGnkDTHFpTnWqKPI85Rknc+8=
@@ -582,6 +618,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI=
@@ -602,14 +640,31 @@ github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm
github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c=
github.com/nunnatsa/ginkgolinter v0.23.0 h1:x3o4DGYOWbBMP/VdNQKgSj+25aJKx2Pe6lHr8gBcgf8=
github.com/nunnatsa/ginkgolinter v0.23.0/go.mod h1:9qN1+0akwXEccwV1CAcCDfcoBlWXHB+ML9884pL4SZ4=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
+github.com/oapi-codegen/oapi-codegen/v2 v2.6.0 h1:4i+F2cvwBFZeplxCssNdLy3MhNzUD87mI3HnayHZkAU=
+github.com/oapi-codegen/oapi-codegen/v2 v2.6.0/go.mod h1:eWHeJSohQJIINJZzzQriVynfGsnlQVh0UkN2UYYcw4Q=
+github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY=
+github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw=
+github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c=
+github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o=
github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=
github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
+github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI=
github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
+github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
@@ -626,6 +681,8 @@ github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
+github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
+github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/petermattis/goid v0.0.0-20250904145737-900bdf8bb490 h1:QTvNkZ5ylY0PGgA+Lih+GdboMLY/G9SEGLMEGVjTVA4=
@@ -707,6 +764,7 @@ github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/segmentio/encoding v0.5.3 h1:OjMgICtcSFuNvQCdwqMCv9Tg7lEOXGwm1J5RPQccx6w=
github.com/segmentio/encoding v0.5.3/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0=
+github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
@@ -724,6 +782,10 @@ github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrel
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0=
github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs=
+github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8=
+github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw=
+github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU=
+github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg=
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
@@ -750,6 +812,7 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -781,6 +844,8 @@ github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+
github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw=
github.com/toqueteos/webbrowser v1.2.1 h1:O7IsnnU7XQyJ1nHMRfAktUUJOAZD3aQyUVnxzhWphCg=
github.com/toqueteos/webbrowser v1.2.1/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM=
+github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
+github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ultraware/funlen v0.2.0 h1:gCHmCn+d2/1SemTdYMiKLAHFYxTYz7z9VIDRaTGyLkI=
github.com/ultraware/funlen v0.2.0/go.mod h1:ZE0q4TsJ8T1SQcjmkhN/w+MceuatI6pBFSxxyteHIJA=
github.com/ultraware/whitespace v0.2.0 h1:TYowo2m9Nfj1baEQBjuHzvMRbp19i+RCcRYrSWoFa+g=
@@ -793,6 +858,10 @@ github.com/uudashr/iface v1.4.1 h1:J16Xl1wyNX9ofhpHmQ9h9gk5rnv2A6lX/2+APLTo0zU=
github.com/uudashr/iface v1.4.1/go.mod h1:pbeBPlbuU2qkNDn0mmfrxP2X+wjPMIQAy+r1MBXSXtg=
github.com/vbatts/tar-split v0.12.1 h1:CqKoORW7BUWBe7UL/iqTVvkTBOF8UvOMKOIZykxnnbo=
github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
+github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk=
+github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ=
+github.com/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0=
+github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xen0n/gosmopolitan v1.3.0 h1:zAZI1zefvo7gcpbCOrPSHJZJYA9ZgLfJqtKzZ5pHqQM=
@@ -917,14 +986,18 @@ golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
@@ -934,6 +1007,7 @@ golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -945,11 +1019,17 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -958,6 +1038,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -994,6 +1075,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
@@ -1019,21 +1101,35 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/hack/tools/tools.go b/hack/tools/tools.go
index 42b381e26f..ba5443b2bb 100644
--- a/hack/tools/tools.go
+++ b/hack/tools/tools.go
@@ -10,6 +10,7 @@ import (
_ "github.com/bufbuild/buf/cmd/buf"
_ "github.com/go-swagger/go-swagger/cmd/swagger"
_ "github.com/golangci/golangci-lint/v2/cmd/golangci-lint"
+ _ "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen"
_ "github.com/swaggo/swag/cmd/swag"
_ "golang.org/x/tools/cmd/goimports"
_ "helm.sh/helm/v3/cmd/helm"
diff --git a/pkg/gitprovider/bitbucket/bitbucket.go b/pkg/gitprovider/bitbucket/bitbucket.go
deleted file mode 100644
index 9c8e2dec1f..0000000000
--- a/pkg/gitprovider/bitbucket/bitbucket.go
+++ /dev/null
@@ -1,514 +0,0 @@
-package bitbucket
-
-import (
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "net/url"
- "strconv"
- "strings"
- "time"
-
- "github.com/hashicorp/go-cleanhttp"
- "github.com/ktrysmt/go-bitbucket"
-
- "github.com/akuity/kargo/pkg/gitprovider"
- "github.com/akuity/kargo/pkg/urls"
-)
-
-const (
- ProviderName = "bitbucket"
-
- // supportedHost is the hostname of the Bitbucket instance that this provider
- // supports. As of now, this provider only supports Bitbucket "Cloud", and not
- // self-hosted Bitbucket "Datacenter" instances.
- supportedHost = "bitbucket.org"
-
- // prStateOpen is the state of an open pull request.
- prStateOpen = "OPEN"
- // prStateMerged is the state of a merged pull request.
- prStateMerged = "MERGED"
- // prStateDeclined is the state of a declined pull request. This is also
- // known as "closed" in other Git providers.
- prStateDeclined = "DECLINED"
- // prStateSuperseded is the state of a superseded pull request. This is also
- // known as "closed" in other Git providers.
- prStateSuperseded = "SUPERSEDED"
-)
-
-var registration = gitprovider.Registration{
- Predicate: func(repoURL string) bool {
- u, err := url.Parse(repoURL)
- if err != nil {
- return false
- }
- return u.Hostname() == supportedHost
- },
- NewProvider: func(
- repoURL string,
- opts *gitprovider.Options,
- ) (gitprovider.Interface, error) {
- return NewProvider(repoURL, opts)
- },
-}
-
-func init() {
- gitprovider.Register(ProviderName, registration)
-}
-
-// pullRequestClient defines the interface for pull request operations.
-type pullRequestClient interface {
- Create(*bitbucket.PullRequestsOptions) (any, error)
- Gets(*bitbucket.PullRequestsOptions) (any, error)
- Get(*bitbucket.PullRequestsOptions) (any, error)
- GetCommit(*bitbucket.CommitsOptions) (any, error)
- Merge(*bitbucket.PullRequestsOptions) (any, error)
-}
-
-// provider is a Bitbucket-based implementation of gitprovider.Interface.
-type provider struct {
- owner string
- repoSlug string
- client pullRequestClient
-}
-
-// NewProvider returns a Bitbucket-based implementation of gitprovider.Interface.
-func NewProvider(
- repoURL string,
- opts *gitprovider.Options,
-) (p gitprovider.Interface, err error) {
- if opts == nil {
- opts = &gitprovider.Options{}
- }
-
- host, owner, repoSlug, err := parseRepoURL(repoURL)
- if err != nil {
- return nil, err
- }
-
- // The provider only supports Bitbucket "Cloud", and not self-hosted
- // Bitbucket "Datacenter" instances — these require a different API client.
- if host != supportedHost {
- return nil, fmt.Errorf("unsupported Bitbucket host %q", host)
- }
-
- // The go-bitbucket library may call log.Fatalf for certain error conditions,
- // which causes a panic. We recover from this to return a proper error.
- defer func() {
- if r := recover(); r != nil {
- p = nil
- err = fmt.Errorf("failed to create Bitbucket client: %v", r)
- }
- }()
-
- client := bitbucket.NewOAuthbearerToken(opts.Token)
- client.HttpClient = cleanhttp.DefaultClient()
-
- return &provider{
- owner: owner,
- repoSlug: repoSlug,
- client: &clientWrapper{
- Commits: client.Repositories.Commits,
- PullRequests: client.Repositories.PullRequests,
- },
- }, nil
-}
-
-// clientWrapper wraps a bitbucket.Client to implement the prClient interface
-type clientWrapper struct {
- *bitbucket.Commits
- *bitbucket.PullRequests
-}
-
-// CreatePullRequest implements gitprovider.Interface.
-func (p *provider) CreatePullRequest(
- ctx context.Context,
- opts *gitprovider.CreatePullRequestOpts,
-) (*gitprovider.PullRequest, error) {
- if opts == nil {
- opts = &gitprovider.CreatePullRequestOpts{}
- }
-
- createOpts := &bitbucket.PullRequestsOptions{
- Owner: p.owner,
- RepoSlug: p.repoSlug,
- Title: opts.Title,
- Description: opts.Description,
- SourceBranch: opts.Head,
- DestinationBranch: opts.Base,
- }
- createOpts.WithContext(ctx)
-
- resp, err := p.client.Create(createOpts)
- if err != nil {
- return nil, err
- }
-
- pr, err := toBitbucketPR(resp)
- if err != nil {
- return nil, err
- }
-
- if pr.MergeCommit.Hash != "" {
- fullSHA, err := p.getFullCommitSHA(ctx, pr.MergeCommit.Hash)
- if err != nil {
- return nil, err
- }
- pr.MergeCommit.Hash = fullSHA
- }
-
- return toProviderPR(pr, resp), nil
-}
-
-// GetPullRequest implements gitprovider.Interface.
-func (p *provider) GetPullRequest(
- ctx context.Context,
- id int64,
-) (*gitprovider.PullRequest, error) {
- getOpts := &bitbucket.PullRequestsOptions{
- Owner: p.owner,
- RepoSlug: p.repoSlug,
- ID: strconv.FormatInt(id, 10),
- }
- getOpts.WithContext(ctx)
-
- resp, err := p.client.Get(getOpts)
- if err != nil {
- return nil, err
- }
-
- pr, err := toBitbucketPR(resp)
- if err != nil {
- return nil, err
- }
-
- if pr.MergeCommit.Hash != "" {
- fullSHA, err := p.getFullCommitSHA(ctx, pr.MergeCommit.Hash)
- if err != nil {
- return nil, err
- }
- pr.MergeCommit.Hash = fullSHA
- }
-
- return toProviderPR(pr, resp), nil
-}
-
-// ListPullRequests implements gitprovider.Interface.
-func (p *provider) ListPullRequests(
- ctx context.Context,
- opts *gitprovider.ListPullRequestOptions,
-) ([]gitprovider.PullRequest, error) {
- if opts == nil {
- opts = &gitprovider.ListPullRequestOptions{}
- }
- if opts.State == "" {
- opts.State = gitprovider.PullRequestStateOpen
- }
-
- listOpts := &bitbucket.PullRequestsOptions{
- Owner: p.owner,
- RepoSlug: p.repoSlug,
- }
- listOpts.WithContext(ctx)
-
- switch opts.State {
- case gitprovider.PullRequestStateAny:
- listOpts.States = []string{prStateOpen, prStateMerged, prStateDeclined, prStateSuperseded}
- case gitprovider.PullRequestStateClosed:
- listOpts.States = []string{prStateMerged, prStateDeclined, prStateSuperseded}
- case gitprovider.PullRequestStateOpen:
- listOpts.States = []string{prStateOpen}
- default:
- return nil, fmt.Errorf("unknown pull request state %q", opts.State)
- }
-
- resp, err := p.client.Gets(listOpts)
- if err != nil {
- return nil, err
- }
-
- list, ok := resp.(map[string]any)
- if !ok {
- return nil, fmt.Errorf("unexpected type for list response: %T", resp)
- }
-
- rawPRs, ok := list["values"]
- if !ok {
- return nil, fmt.Errorf("list response missing 'values' field")
- }
-
- prList, ok := rawPRs.([]any)
- if !ok {
- return nil, fmt.Errorf("unexpected type for list values: %T", rawPRs)
- }
-
- // NB: The Bitbucket API doesn't support filtering by source/destination
- // branch or commit hash, so we have to filter client-side, which is
- // highly inefficient.
- var prs []gitprovider.PullRequest
- for _, pr := range prList {
- bbPR, err := toBitbucketPR(pr)
- if err != nil {
- continue
- }
-
- if opts.HeadBranch != "" && bbPR.Source.Branch.Name != opts.HeadBranch {
- continue
- }
-
- if opts.BaseBranch != "" && bbPR.Destination.Branch.Name != opts.BaseBranch {
- continue
- }
-
- if opts.HeadCommit != "" && bbPR.Source.Commit.Hash != opts.HeadCommit {
- continue
- }
-
- if bbPR.MergeCommit.Hash != "" {
- fullSHA, err := p.getFullCommitSHA(ctx, bbPR.MergeCommit.Hash)
- if err != nil {
- return nil, err
- }
- bbPR.MergeCommit.Hash = fullSHA
- }
-
- if converted := toProviderPR(bbPR, pr); converted != nil {
- prs = append(prs, *converted)
- }
- }
- return prs, nil
-}
-
-// MergePullRequest implements gitprovider.Interface.
-func (p *provider) MergePullRequest(
- _ context.Context,
- id int64,
- opts *gitprovider.MergePullRequestOpts,
-) (*gitprovider.PullRequest, bool, error) {
- if opts == nil {
- opts = &gitprovider.MergePullRequestOpts{}
- }
-
- // Get the PR to check its state
- prOpts := &bitbucket.PullRequestsOptions{
- Owner: p.owner,
- RepoSlug: p.repoSlug,
- ID: strconv.FormatInt(id, 10),
- }
-
- prResp, err := p.client.Get(prOpts)
- if err != nil {
- return nil, false, fmt.Errorf("error getting pull request %d: %w", id, err)
- }
-
- bbPR, err := toBitbucketPR(prResp)
- if err != nil {
- return nil, false, fmt.Errorf("error parsing pull request response: %w", err)
- }
-
- // Check if PR is already merged
- if bbPR.State == prStateMerged {
- return toProviderPR(bbPR, prResp), true, nil
- }
-
- // Check if PR is closed (any non-open state except merged)
- if bbPR.State != prStateOpen {
- // If it's not open and not merged, then it's closed
- return nil, false, fmt.Errorf(
- "pull request %d is closed but not merged (state: %s)", id, bbPR.State,
- )
- }
-
- // Check if PR is draft - cannot merge draft PRs
- if bbPR.Draft {
- return nil, false, nil
- }
-
- // TODO: The Bitbucket API lacks comprehensive merge eligibility checks. We
- // cannot reliably determine if a PR is mergeable due to conflicts, failing
- // checks, or other blocking conditions before attempting the merge. This
- // means we have no choice but to attempt the merge and hope for the best.
- //
- // See: https://jira.atlassian.com/browse/BCLOUD-22014
- //
- // This limitation makes the "wait" option unreliable for Bitbucket
- // repositories.
-
- // TODO(krancour): go-bitbucket does not expose the merge method/strategy as
- // an option. The merge will always use the repository's default merge
- // strategy, so simply fail if any merge strategy was specified. This is
- // strictly a limitation of the go-bitbucket library and not the Bitbucket API
- // itself, so this can be revisited in the future if the library adds support
- // for this or if we decide to implement this API call ourselves instead of
- // using the library.
- if opts.MergeMethod != "" {
- return nil, false, errors.New( // nolint: staticcheck
- "Kargo's Bitbucket client does not yet support specifying a merge method",
- )
- }
- mergeOpts := &bitbucket.PullRequestsOptions{
- Owner: p.owner,
- RepoSlug: p.repoSlug,
- ID: strconv.FormatInt(id, 10),
- }
-
- // TODO(krancour): The Bitbucket merge endpoint can return 202 for async
- // merges. The go-bitbucket library treats 202 as success (no error), but the
- // response body would be a polling URL, not a PR object. This would cause
- // toBitbucketPR to fail or produce incorrect results. If async merges are
- // encountered in practice, we'll need to detect the 202 and poll for
- // completion.
- mergeResp, err := p.client.Merge(mergeOpts)
- if err != nil {
- return nil, false, fmt.Errorf("error merging pull request %d: %w", id, err)
- }
-
- // Parse the merged PR response
- mergedBBPR, err := toBitbucketPR(mergeResp)
- if err != nil {
- return nil, false, fmt.Errorf("error parsing merged pull request response: %w", err)
- }
-
- // Per the Bitbucket API docs, the merge endpoint returns 200 only on
- // success (409 for conflicts, 555 for timeout — both surfaced as errors
- // above). A 200 response with a non-merged state would be unexpected.
- if mergedBBPR.State != prStateMerged {
- return nil, false,
- fmt.Errorf("unexpected state %q after merging pull request %d", mergedBBPR.State, id)
- }
-
- return toProviderPR(mergedBBPR, mergeResp), true, nil
-}
-
-// GetCommitURL implements gitprovider.Interface.
-func (p *provider) GetCommitURL(repoURL string, sha string) (string, error) {
- normalizedURL := urls.NormalizeGit(repoURL)
-
- parsedURL, err := url.Parse(normalizedURL)
- if err != nil {
- return "", fmt.Errorf("error processing repository URL: %s: %s", repoURL, err)
- }
-
- commitURL := fmt.Sprintf("https://%s%s/commits/%s", parsedURL.Host, parsedURL.Path, sha)
-
- return commitURL, nil
-}
-
-func (p *provider) getFullCommitSHA(ctx context.Context, shortSHA string) (string, error) {
- if shortSHA == "" {
- return "", nil
- }
-
- commitOpts := &bitbucket.CommitsOptions{
- Owner: p.owner,
- RepoSlug: p.repoSlug,
- Revision: shortSHA,
- }
- commitOpts.WithContext(ctx)
-
- resp, err := p.client.GetCommit(commitOpts)
- if err != nil {
- return "", err
- }
-
- commitResp, ok := resp.(map[string]any)
- if !ok {
- return "", fmt.Errorf("unexpected commit response type: %T", resp)
- }
-
- hash, ok := commitResp["hash"].(string)
- if !ok || hash == "" {
- return "", fmt.Errorf("commit response missing 'hash' field")
- }
- return hash, nil
-}
-
-// bitbucketPR represents the structure of a Bitbucket pull request.
-// See: https://developer.atlassian.com/cloud/bitbucket/rest/api-group-pullrequests/#api-repositories-workspace-repo-slug-pullrequests-pull-request-id-get
-// nolint:lll
-type bitbucketPR struct {
- ID int64 `json:"id"`
- State string `json:"state"`
- Links struct {
- HTML struct {
- Href string `json:"href"`
- } `json:"html"`
- } `json:"links"`
- Source struct {
- Branch struct {
- Name string `json:"name"`
- } `json:"branch"`
- Commit struct {
- Hash string `json:"hash"`
- } `json:"commit"`
- } `json:"source"`
- Destination struct {
- Branch struct {
- Name string `json:"name"`
- } `json:"branch"`
- Commit struct {
- Hash string `json:"hash"`
- } `json:"commit"`
- } `json:"destination"`
- MergeCommit struct {
- Hash string `json:"hash"`
- } `json:"merge_commit"`
- Draft bool `json:"draft"`
- CreatedOn string `json:"created_on"`
-}
-
-// toBitbucketPR converts a raw response to a bitbucketPR type.
-func toBitbucketPR(resp any) (*bitbucketPR, error) {
- b, err := json.Marshal(resp)
- if err != nil {
- return nil, fmt.Errorf("marshal PR response: %w", err)
- }
- var pr bitbucketPR
- if err = json.Unmarshal(b, &pr); err != nil {
- return nil, fmt.Errorf("unmarshal PR response: %w", err)
- }
- return &pr, nil
-}
-
-// toProviderPR converts a bitbucketPR to a gitprovider.PullRequest.
-func toProviderPR(pr *bitbucketPR, raw any) *gitprovider.PullRequest {
- if pr == nil {
- return nil
- }
-
- var createdAt *time.Time
- if ts, err := time.Parse("2006-01-02T15:04:05Z", pr.CreatedOn); err == nil {
- createdAt = &ts
- }
-
- return &gitprovider.PullRequest{
- Number: pr.ID,
- URL: pr.Links.HTML.Href,
- Open: pr.State == prStateOpen,
- Merged: pr.State == prStateMerged,
- // NB: As a sign of true craftsmanship, or lack thereof, the Bitbucket
- // API returns a short commit SHA as merge commit hash. To get the full
- // commit SHA, we need to fetch the commit details separately.
- MergeCommitSHA: pr.MergeCommit.Hash,
- HeadSHA: pr.Source.Commit.Hash,
- CreatedAt: createdAt,
- Object: raw,
- }
-}
-
-// parseRepoURL extracts host, owner and repo slug from a repository URL
-func parseRepoURL(repoURL string) (host, owner, slug string, err error) {
- u, err := url.Parse(urls.NormalizeGit(repoURL))
- if err != nil {
- return "", "", "", fmt.Errorf("parse Bitbucket URL %q: %w", repoURL, err)
- }
-
- path := strings.TrimPrefix(u.Path, "/")
- parts := strings.Split(path, "/")
- if len(parts) != 2 {
- return "", "", "", fmt.Errorf("invalid repository path in URL %q", u)
- }
-
- return u.Hostname(), parts[0], parts[1], nil
-}
diff --git a/pkg/gitprovider/bitbucket/bitbucket_test.go b/pkg/gitprovider/bitbucket/bitbucket_test.go
deleted file mode 100644
index 2b58f9794c..0000000000
--- a/pkg/gitprovider/bitbucket/bitbucket_test.go
+++ /dev/null
@@ -1,1312 +0,0 @@
-package bitbucket
-
-import (
- "errors"
- "testing"
-
- "github.com/ktrysmt/go-bitbucket"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-
- "github.com/akuity/kargo/pkg/gitprovider"
-)
-
-type mockPullRequestClient struct {
- createFunc func(opt *bitbucket.PullRequestsOptions) (any, error)
- getsFunc func(opt *bitbucket.PullRequestsOptions) (any, error)
- getFunc func(opt *bitbucket.PullRequestsOptions) (any, error)
- getCommitFunc func(opt *bitbucket.CommitsOptions) (any, error)
- mergeFunc func(opt *bitbucket.PullRequestsOptions) (any, error)
-}
-
-func (m *mockPullRequestClient) Create(
- opt *bitbucket.PullRequestsOptions,
-) (any, error) {
- return m.createFunc(opt)
-}
-
-func (m *mockPullRequestClient) Gets(
- opt *bitbucket.PullRequestsOptions,
-) (any, error) {
- return m.getsFunc(opt)
-}
-
-func (m *mockPullRequestClient) Get(
- opt *bitbucket.PullRequestsOptions,
-) (any, error) {
- return m.getFunc(opt)
-}
-
-func (m *mockPullRequestClient) GetCommit(opt *bitbucket.CommitsOptions) (any, error) {
- return m.getCommitFunc(opt)
-}
-
-func (m *mockPullRequestClient) Merge(
- opt *bitbucket.PullRequestsOptions,
-) (any, error) {
- return m.mergeFunc(opt)
-}
-
-func TestNewProvider(t *testing.T) {
- t.Run("successful creation", func(t *testing.T) {
- provider, err := NewProvider("https://bitbucket.org/owner/repo", &gitprovider.Options{Token: "token"})
- assert.NoError(t, err)
- assert.NotNil(t, provider)
- })
-
- t.Run("successful creation with nil options", func(t *testing.T) {
- provider, err := NewProvider("https://bitbucket.org/owner/repo", nil)
- assert.NoError(t, err)
- assert.NotNil(t, provider)
- })
-
- t.Run("error with invalid URL", func(t *testing.T) {
- provider, err := NewProvider("://invalid-url", &gitprovider.Options{Token: "token"})
- assert.Error(t, err)
- assert.Nil(t, provider)
- })
-
- t.Run("error with unsupported host", func(t *testing.T) {
- provider, err := NewProvider("https://not-bitbucket.org/owner/repo", &gitprovider.Options{Token: "token"})
- assert.Error(t, err)
- assert.Nil(t, provider)
- })
-
- t.Run("error with invalid path", func(t *testing.T) {
- provider, err := NewProvider("https://bitbucket.org/invalid-path", &gitprovider.Options{Token: "token"})
- assert.Error(t, err)
- assert.Nil(t, provider)
- })
-}
-
-func TestCreatePullRequest(t *testing.T) {
- t.Run("successful creation", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- createFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{
- "id": int64(1),
- "state": prStateOpen,
- "links": map[string]any{
- "html": map[string]any{
- "href": "https://bitbucket.org/owner/repo/pull-requests/1",
- },
- },
- "source": map[string]any{
- "branch": map[string]any{
- "name": "feature-branch",
- },
- "commit": map[string]any{
- "hash": "abcdef1234567890",
- },
- },
- "destination": map[string]any{
- "branch": map[string]any{
- "name": "main",
- },
- },
- "created_on": "2023-01-01T12:00:00Z",
- }, nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- opts := &gitprovider.CreatePullRequestOpts{
- Title: "Test PR",
- Description: "PR description",
- Head: "feature-branch",
- Base: "main",
- }
- pr, err := provider.CreatePullRequest(ctx, opts)
- assert.NoError(t, err)
- assert.NotNil(t, pr)
- assert.Equal(t, int64(1), pr.Number)
- assert.Equal(t, "https://bitbucket.org/owner/repo/pull-requests/1", pr.URL)
- assert.Equal(t, "abcdef1234567890", pr.HeadSHA)
- assert.True(t, pr.Open)
- assert.False(t, pr.Merged)
- })
-
- t.Run("successful creation with nil options", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- createFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{
- "id": int64(1),
- "state": prStateOpen,
- }, nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- pr, err := provider.CreatePullRequest(ctx, nil)
- assert.NoError(t, err)
- assert.NotNil(t, pr)
- assert.Equal(t, int64(1), pr.Number)
- })
-
- t.Run("creation with merge commit", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- createFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{
- "id": int64(1),
- "state": prStateOpen,
- "merge_commit": map[string]any{
- "hash": "short123",
- },
- }, nil
- },
- getCommitFunc: func(*bitbucket.CommitsOptions) (any, error) {
- return map[string]any{
- "hash": "full1234567890abcdef",
- }, nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- pr, err := provider.CreatePullRequest(ctx, nil)
- assert.NoError(t, err)
- assert.NotNil(t, pr)
- assert.Equal(t, "full1234567890abcdef", pr.MergeCommitSHA)
- })
-
- t.Run("error during creation", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- createFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return nil, errors.New("creation failed")
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- pr, err := provider.CreatePullRequest(ctx, nil)
- assert.Error(t, err)
- assert.Nil(t, pr)
- })
-
- t.Run("error converting PR response", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- createFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- // Return something that can't be properly unmarshaled
- return make(chan int), nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- pr, err := provider.CreatePullRequest(ctx, nil)
- assert.Error(t, err)
- assert.Nil(t, pr)
- })
-
- t.Run("error getting full commit SHA", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- createFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{
- "id": int64(1),
- "state": prStateOpen,
- "merge_commit": map[string]any{
- "hash": "short123",
- },
- }, nil
- },
- getCommitFunc: func(*bitbucket.CommitsOptions) (any, error) {
- return nil, errors.New("commit fetch failed")
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- pr, err := provider.CreatePullRequest(ctx, nil)
- assert.Error(t, err)
- assert.Nil(t, pr)
- })
-}
-
-func TestGetPullRequest(t *testing.T) {
- t.Run("successful retrieval", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getFunc: func(opt *bitbucket.PullRequestsOptions) (any, error) {
- assert.Equal(t, "1", opt.ID)
- return map[string]any{
- "id": int64(1),
- "state": prStateOpen,
- "links": map[string]any{
- "html": map[string]any{
- "href": "https://bitbucket.org/owner/repo/pull-requests/1",
- },
- },
- "source": map[string]any{
- "branch": map[string]any{
- "name": "feature-branch",
- },
- "commit": map[string]any{
- "hash": "abcdef1234567890",
- },
- },
- "destination": map[string]any{
- "branch": map[string]any{
- "name": "main",
- },
- },
- "created_on": "2023-01-01T12:00:00Z",
- }, nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- pr, err := provider.GetPullRequest(ctx, 1)
- assert.NoError(t, err)
- assert.NotNil(t, pr)
- assert.Equal(t, int64(1), pr.Number)
- assert.Equal(t, "https://bitbucket.org/owner/repo/pull-requests/1", pr.URL)
- assert.Equal(t, "abcdef1234567890", pr.HeadSHA)
- assert.True(t, pr.Open)
- assert.False(t, pr.Merged)
- assert.NotNil(t, pr.CreatedAt)
- })
-
- t.Run("retrieval of merged PR", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{
- "id": int64(1),
- "state": prStateMerged,
- "merge_commit": map[string]any{
- "hash": "short123",
- },
- }, nil
- },
- getCommitFunc: func(*bitbucket.CommitsOptions) (any, error) {
- return map[string]any{
- "hash": "full1234567890abcdef",
- }, nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- pr, err := provider.GetPullRequest(ctx, 1)
- assert.NoError(t, err)
- assert.NotNil(t, pr)
- assert.False(t, pr.Open)
- assert.True(t, pr.Merged)
- assert.Equal(t, "full1234567890abcdef", pr.MergeCommitSHA)
- })
-
- t.Run("error during retrieval", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return nil, errors.New("retrieval failed")
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- pr, err := provider.GetPullRequest(ctx, 1)
- assert.Error(t, err)
- assert.Nil(t, pr)
- })
-
- t.Run("error converting PR response", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- // Return something that can't be properly unmarshaled
- return make(chan int), nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- pr, err := provider.GetPullRequest(ctx, 1)
- assert.Error(t, err)
- assert.Nil(t, pr)
- })
-}
-
-func TestListPullRequests(t *testing.T) {
- t.Run("list open PRs by default", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getsFunc: func(opt *bitbucket.PullRequestsOptions) (any, error) {
- assert.Equal(t, []string{prStateOpen}, opt.States)
- return map[string]any{"values": []any{
- map[string]any{"id": int64(1), "state": prStateOpen},
- map[string]any{"id": int64(2), "state": prStateOpen},
- }}, nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- prs, err := provider.ListPullRequests(ctx, nil)
- assert.NoError(t, err)
- assert.Len(t, prs, 2)
- })
-
- t.Run("list all PRs", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getsFunc: func(opt *bitbucket.PullRequestsOptions) (any, error) {
- assert.Contains(t, opt.States, prStateOpen)
- assert.Contains(t, opt.States, prStateMerged)
- assert.Contains(t, opt.States, prStateDeclined)
- assert.Contains(t, opt.States, prStateSuperseded)
- return map[string]any{"values": []any{
- map[string]any{"id": int64(1), "state": prStateOpen},
- map[string]any{"id": int64(2), "state": prStateMerged},
- map[string]any{"id": int64(3), "state": prStateDeclined},
- map[string]any{"id": int64(4), "state": prStateSuperseded},
- }}, nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- prs, err := provider.ListPullRequests(ctx, &gitprovider.ListPullRequestOptions{
- State: gitprovider.PullRequestStateAny,
- })
- assert.NoError(t, err)
- assert.Len(t, prs, 4)
- })
-
- t.Run("list closed PRs", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getsFunc: func(opt *bitbucket.PullRequestsOptions) (any, error) {
- assert.Contains(t, opt.States, prStateMerged)
- assert.Contains(t, opt.States, prStateDeclined)
- assert.Contains(t, opt.States, prStateSuperseded)
- assert.NotContains(t, opt.States, prStateOpen)
- return map[string]any{"values": []any{
- map[string]any{"id": int64(2), "state": prStateMerged},
- map[string]any{"id": int64(3), "state": prStateDeclined},
- map[string]any{"id": int64(4), "state": prStateSuperseded},
- }}, nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- prs, err := provider.ListPullRequests(ctx, &gitprovider.ListPullRequestOptions{
- State: gitprovider.PullRequestStateClosed,
- })
- assert.NoError(t, err)
- assert.Len(t, prs, 3)
- })
-
- t.Run("filter by head branch", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getsFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{"values": []any{
- map[string]any{
- "id": int64(1),
- "state": prStateOpen,
- "source": map[string]any{
- "branch": map[string]any{
- "name": "feature-1",
- },
- "commit": map[string]any{
- "hash": "hash1",
- },
- },
- "destination": map[string]any{
- "branch": map[string]any{
- "name": "main",
- },
- },
- },
- map[string]any{
- "id": int64(2),
- "state": prStateOpen,
- "source": map[string]any{
- "branch": map[string]any{
- "name": "feature-2",
- },
- "commit": map[string]any{
- "hash": "hash2",
- },
- },
- "destination": map[string]any{
- "branch": map[string]any{
- "name": "main",
- },
- },
- },
- }}, nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- prs, err := provider.ListPullRequests(ctx, &gitprovider.ListPullRequestOptions{
- HeadBranch: "feature-1",
- })
- assert.NoError(t, err)
- assert.Len(t, prs, 1)
- assert.Equal(t, int64(1), prs[0].Number)
- })
-
- t.Run("filter by base branch", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getsFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{"values": []any{
- map[string]any{
- "id": int64(1),
- "state": prStateOpen,
- "source": map[string]any{
- "branch": map[string]any{
- "name": "feature-1",
- },
- "commit": map[string]any{
- "hash": "hash1",
- },
- },
- "destination": map[string]any{
- "branch": map[string]any{
- "name": "main",
- },
- },
- },
- map[string]any{
- "id": int64(2),
- "state": prStateOpen,
- "source": map[string]any{
- "branch": map[string]any{
- "name": "feature-2",
- },
- "commit": map[string]any{
- "hash": "hash2",
- },
- },
- "destination": map[string]any{
- "branch": map[string]any{
- "name": "dev",
- },
- },
- },
- }}, nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- prs, err := provider.ListPullRequests(ctx, &gitprovider.ListPullRequestOptions{
- BaseBranch: "dev",
- })
- assert.NoError(t, err)
- assert.Len(t, prs, 1)
- assert.Equal(t, int64(2), prs[0].Number)
- })
-
- t.Run("filter by head commit", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getsFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{"values": []any{
- map[string]any{
- "id": int64(1),
- "state": prStateOpen,
- "source": map[string]any{
- "branch": map[string]any{
- "name": "feature-1",
- },
- "commit": map[string]any{
- "hash": "specific-hash",
- },
- },
- },
- map[string]any{
- "id": int64(2),
- "state": prStateOpen,
- "source": map[string]any{
- "branch": map[string]any{
- "name": "feature-2",
- },
- "commit": map[string]any{
- "hash": "other-hash",
- },
- },
- },
- }}, nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- prs, err := provider.ListPullRequests(ctx, &gitprovider.ListPullRequestOptions{
- HeadCommit: "specific-hash",
- })
- assert.NoError(t, err)
- assert.Len(t, prs, 1)
- assert.Equal(t, int64(1), prs[0].Number)
- })
-
- t.Run("PR with merge commit", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getsFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{"values": []any{
- map[string]any{
- "id": int64(1),
- "state": prStateMerged,
- "merge_commit": map[string]any{
- "hash": "short123",
- },
- },
- }}, nil
- },
- getCommitFunc: func(*bitbucket.CommitsOptions) (any, error) {
- return map[string]any{
- "hash": "full1234567890abcdef",
- }, nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- prs, err := provider.ListPullRequests(ctx, nil)
- assert.NoError(t, err)
- assert.Len(t, prs, 1)
- assert.Equal(t, "full1234567890abcdef", prs[0].MergeCommitSHA)
- })
-
- t.Run("error during list", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getsFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return nil, errors.New("list failed")
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- prs, err := provider.ListPullRequests(ctx, nil)
- assert.Error(t, err)
- assert.Nil(t, prs)
- })
-
- t.Run("invalid response format", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getsFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return "not a map", nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- prs, err := provider.ListPullRequests(ctx, nil)
- assert.Error(t, err)
- assert.Nil(t, prs)
- })
-
- t.Run("missing values field", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getsFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{}, nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- prs, err := provider.ListPullRequests(ctx, nil)
- assert.Error(t, err)
- assert.Nil(t, prs)
- })
-
- t.Run("invalid values type", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getsFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{"values": "not an array"}, nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- prs, err := provider.ListPullRequests(ctx, nil)
- assert.Error(t, err)
- assert.Nil(t, prs)
- })
-
- t.Run("invalid state", func(t *testing.T) {
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- }
-
- ctx := t.Context()
- prs, err := provider.ListPullRequests(ctx, &gitprovider.ListPullRequestOptions{
- State: "invalid-state",
- })
- assert.Error(t, err)
- assert.Nil(t, prs)
- })
-}
-
-func TestMergePullRequest(t *testing.T) {
- testCases := []struct {
- name string
- prNumber int64
- mergeOpts *gitprovider.MergePullRequestOpts
- mockClient *mockPullRequestClient
- expectedMerged bool
- expectError bool
- errorContains string
- }{
- {
- name: "error getting PR",
- prNumber: 999,
- mockClient: &mockPullRequestClient{
- getFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return nil, errors.New("get PR failed")
- },
- },
- expectError: true,
- errorContains: "error getting pull request",
- },
- {
- name: "error parsing PR response",
- prNumber: 999,
- mockClient: &mockPullRequestClient{
- getFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return "not a valid response", nil
- },
- },
- expectError: true,
- errorContains: "error parsing pull request response",
- },
- {
- name: "PR already merged",
- prNumber: 123,
- mockClient: &mockPullRequestClient{
- getFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{
- "id": int64(123),
- "state": prStateMerged,
- "links": map[string]any{
- "html": map[string]any{
- "href": "https://bitbucket.org/owner/repo/pull-requests/123",
- },
- },
- "merge_commit": map[string]any{
- "hash": "merge_sha",
- },
- "source": map[string]any{
- "commit": map[string]any{
- "hash": "head_sha",
- },
- },
- }, nil
- },
- },
- expectedMerged: true,
- },
- {
- name: "PR declined",
- prNumber: 456,
- mockClient: &mockPullRequestClient{
- getFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{
- "id": int64(456),
- "state": prStateDeclined,
- }, nil
- },
- },
- expectError: true,
- errorContains: "closed but not merged",
- },
- {
- name: "PR is draft",
- prNumber: 333,
- mockClient: &mockPullRequestClient{
- getFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{
- "id": int64(333),
- "state": prStateOpen,
- "draft": true,
- }, nil
- },
- },
- },
- {
- name: "merge method specified",
- prNumber: 100,
- mergeOpts: &gitprovider.MergePullRequestOpts{MergeMethod: "squash"},
- mockClient: &mockPullRequestClient{
- getFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{
- "id": int64(100),
- "state": prStateOpen,
- }, nil
- },
- },
- expectError: true,
- errorContains: "does not yet support specifying a merge method",
- },
- {
- name: "merge operation fails",
- prNumber: 888,
- mockClient: &mockPullRequestClient{
- getFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{
- "id": int64(888),
- "state": prStateOpen,
- }, nil
- },
- mergeFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return nil, errors.New("merge failed")
- },
- },
- expectError: true,
- errorContains: "error merging pull request",
- },
- {
- name: "error parsing merge response",
- prNumber: 777,
- mockClient: &mockPullRequestClient{
- getFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{
- "id": int64(777),
- "state": prStateOpen,
- }, nil
- },
- mergeFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return "not a valid response", nil
- },
- },
- expectError: true,
- errorContains: "error parsing merged pull request response",
- },
- {
- name: "successful merge",
- prNumber: 1234,
- mockClient: &mockPullRequestClient{
- getFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{
- "id": int64(1234),
- "state": prStateOpen,
- "links": map[string]any{
- "html": map[string]any{
- "href": "https://bitbucket.org/owner/repo/pull-requests/1234",
- },
- },
- "source": map[string]any{
- "commit": map[string]any{
- "hash": "head_sha",
- },
- },
- }, nil
- },
- mergeFunc: func(*bitbucket.PullRequestsOptions) (any, error) {
- return map[string]any{
- "id": int64(1234),
- "state": prStateMerged,
- "links": map[string]any{
- "html": map[string]any{
- "href": "https://bitbucket.org/owner/repo/pull-requests/1234",
- },
- },
- "merge_commit": map[string]any{
- "hash": "merge_sha",
- },
- "source": map[string]any{
- "commit": map[string]any{
- "hash": "head_sha",
- },
- },
- }, nil
- },
- },
- expectedMerged: true,
- },
- }
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- p := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: tc.mockClient,
- }
-
- pr, merged, err := p.MergePullRequest(t.Context(), tc.prNumber, tc.mergeOpts)
-
- if tc.expectError {
- require.Error(t, err)
- require.Contains(t, err.Error(), tc.errorContains)
- require.False(t, merged)
- require.Nil(t, pr)
- return
- }
-
- require.NoError(t, err)
- require.Equal(t, tc.expectedMerged, merged)
- if tc.expectedMerged {
- require.NotNil(t, pr)
- require.Equal(t, tc.prNumber, pr.Number)
- }
- })
- }
-}
-
-func TestGetFullCommitSHA(t *testing.T) {
- t.Run("successful retrieval", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getCommitFunc: func(opt *bitbucket.CommitsOptions) (any, error) {
- assert.Equal(t, "short123", opt.Revision)
- return map[string]any{
- "hash": "full1234567890abcdef",
- }, nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- sha, err := provider.getFullCommitSHA(ctx, "short123")
- assert.NoError(t, err)
- assert.Equal(t, "full1234567890abcdef", sha)
- })
-
- t.Run("empty SHA input", func(t *testing.T) {
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- }
-
- ctx := t.Context()
- sha, err := provider.getFullCommitSHA(ctx, "")
- assert.NoError(t, err)
- assert.Equal(t, "", sha)
- })
-
- t.Run("error during retrieval", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getCommitFunc: func(*bitbucket.CommitsOptions) (any, error) {
- return nil, errors.New("retrieval failed")
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- sha, err := provider.getFullCommitSHA(ctx, "short123")
- assert.Error(t, err)
- assert.Equal(t, "", sha)
- })
-
- t.Run("invalid response format", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getCommitFunc: func(*bitbucket.CommitsOptions) (any, error) {
- return "not a map", nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- sha, err := provider.getFullCommitSHA(ctx, "short123")
- assert.Error(t, err)
- assert.Equal(t, "", sha)
- })
-
- t.Run("missing hash field", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getCommitFunc: func(*bitbucket.CommitsOptions) (any, error) {
- return map[string]any{}, nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- sha, err := provider.getFullCommitSHA(ctx, "short123")
- assert.Error(t, err)
- assert.Equal(t, "", sha)
- })
-
- t.Run("invalid hash type", func(t *testing.T) {
- mockClient := &mockPullRequestClient{
- getCommitFunc: func(*bitbucket.CommitsOptions) (any, error) {
- return map[string]any{
- "hash": 12345, // Not a string
- }, nil
- },
- }
- provider := &provider{
- owner: "owner",
- repoSlug: "repo",
- client: mockClient,
- }
-
- ctx := t.Context()
- sha, err := provider.getFullCommitSHA(ctx, "short123")
- assert.Error(t, err)
- assert.Equal(t, "", sha)
- })
-}
-
-func TestParseRepoURL(t *testing.T) {
- tests := []struct {
- name string
- url string
- wantHost string
- wantOwner string
- wantSlug string
- wantErr bool
- }{
- {
- name: "valid URL",
- url: "https://bitbucket.org/owner/repo",
- wantHost: "bitbucket.org",
- wantOwner: "owner",
- wantSlug: "repo",
- wantErr: false,
- },
- {
- name: "valid URL with trailing slash",
- url: "https://bitbucket.org/owner/repo/",
- wantHost: "bitbucket.org",
- wantOwner: "owner",
- wantSlug: "repo",
- wantErr: false,
- },
- {
- name: "valid URL with .git suffix",
- url: "https://bitbucket.org/owner/repo.git",
- wantHost: "bitbucket.org",
- wantOwner: "owner",
- wantSlug: "repo",
- wantErr: false,
- },
- {
- name: "valid SSH URL",
- url: "git@bitbucket.org:owner/repo.git",
- wantHost: "bitbucket.org",
- wantOwner: "owner",
- wantSlug: "repo",
- wantErr: false,
- },
- {
- name: "invalid URL format",
- url: "://invalid-url",
- wantErr: true,
- },
- {
- name: "missing repository name",
- url: "https://bitbucket.org/owner",
- wantErr: true,
- },
- {
- name: "too many path segments",
- url: "https://bitbucket.org/owner/repo/extra",
- wantErr: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- host, owner, slug, err := parseRepoURL(tt.url)
- if tt.wantErr {
- assert.Error(t, err)
- return
- }
- require.NoError(t, err)
- assert.Equal(t, tt.wantHost, host)
- assert.Equal(t, tt.wantOwner, owner)
- assert.Equal(t, tt.wantSlug, slug)
- })
- }
-}
-
-func Test_toBitbucketPR(t *testing.T) {
- t.Run("valid conversion", func(t *testing.T) {
- resp := map[string]any{
- "id": int64(1),
- "state": prStateOpen,
- "links": map[string]any{
- "html": map[string]any{
- "href": "https://bitbucket.org/owner/repo/pull-requests/1",
- },
- },
- "source": map[string]any{
- "branch": map[string]any{
- "name": "feature-branch",
- },
- "commit": map[string]any{
- "hash": "abcdef1234567890",
- },
- },
- "destination": map[string]any{
- "branch": map[string]any{
- "name": "main",
- },
- "commit": map[string]any{
- "hash": "1234567890abcdef",
- },
- },
- "merge_commit": map[string]any{
- "hash": "merged1234567890",
- },
- "created_on": "2023-01-01T12:00:00Z",
- }
-
- pr, err := toBitbucketPR(resp)
- require.NoError(t, err)
- assert.Equal(t, int64(1), pr.ID)
- assert.Equal(t, prStateOpen, pr.State)
- assert.Equal(t, "https://bitbucket.org/owner/repo/pull-requests/1", pr.Links.HTML.Href)
- assert.Equal(t, "feature-branch", pr.Source.Branch.Name)
- assert.Equal(t, "abcdef1234567890", pr.Source.Commit.Hash)
- assert.Equal(t, "main", pr.Destination.Branch.Name)
- assert.Equal(t, "1234567890abcdef", pr.Destination.Commit.Hash)
- assert.Equal(t, "merged1234567890", pr.MergeCommit.Hash)
- assert.Equal(t, "2023-01-01T12:00:00Z", pr.CreatedOn)
- })
-
- t.Run("invalid input type", func(t *testing.T) {
- pr, err := toBitbucketPR(make(chan int))
- assert.Error(t, err)
- assert.Nil(t, pr)
- })
-}
-
-func Test_toProviderPR(t *testing.T) {
- t.Run("valid conversion: open PR", func(t *testing.T) {
- bbPR := &bitbucketPR{
- ID: 1,
- State: prStateOpen,
- Links: struct {
- HTML struct {
- Href string `json:"href"`
- } `json:"html"`
- }{
- HTML: struct {
- Href string `json:"href"`
- }{
- Href: "https://bitbucket.org/owner/repo/pull-requests/1",
- },
- },
- Source: struct {
- Branch struct {
- Name string `json:"name"`
- } `json:"branch"`
- Commit struct {
- Hash string `json:"hash"`
- } `json:"commit"`
- }{
- Branch: struct {
- Name string `json:"name"`
- }{
- Name: "feature-branch",
- },
- Commit: struct {
- Hash string `json:"hash"`
- }{
- Hash: "abcdef1234567890",
- },
- },
- CreatedOn: "2023-01-01T12:00:00Z",
- }
-
- raw := map[string]any{"id": 1}
- pr := toProviderPR(bbPR, raw)
- require.NotNil(t, pr)
- assert.Equal(t, int64(1), pr.Number)
- assert.Equal(t, "https://bitbucket.org/owner/repo/pull-requests/1", pr.URL)
- assert.Equal(t, "abcdef1234567890", pr.HeadSHA)
- assert.True(t, pr.Open)
- assert.False(t, pr.Merged)
- assert.NotNil(t, pr.CreatedAt)
- assert.Equal(t, raw, pr.Object)
- })
-
- t.Run("valid conversion: merged PR", func(t *testing.T) {
- bbPR := &bitbucketPR{
- ID: 1,
- State: prStateMerged,
- MergeCommit: struct {
- Hash string `json:"hash"`
- }{
- Hash: "merged1234567890",
- },
- CreatedOn: "2023-01-01T12:00:00Z",
- }
-
- pr := toProviderPR(bbPR, nil)
- require.NotNil(t, pr)
- assert.False(t, pr.Open)
- assert.True(t, pr.Merged)
- assert.Equal(t, "merged1234567890", pr.MergeCommitSHA)
- })
-
- t.Run("nil input", func(t *testing.T) {
- pr := toProviderPR(nil, nil)
- assert.Nil(t, pr)
- })
-
- t.Run("invalid date", func(t *testing.T) {
- bbPR := &bitbucketPR{
- ID: 1,
- CreatedOn: "not-a-date",
- }
-
- pr := toProviderPR(bbPR, nil)
- require.NotNil(t, pr)
- assert.Nil(t, pr.CreatedAt)
- })
-}
-
-func Test_registration(t *testing.T) {
- t.Run("predicate matches bitbucket.org URL", func(t *testing.T) {
- result := registration.Predicate("https://bitbucket.org/owner/repo")
- assert.True(t, result)
- })
-
- t.Run("predicate doesn't match other URLs", func(t *testing.T) {
- result := registration.Predicate("https://github.com/owner/repo")
- assert.False(t, result)
- })
-
- t.Run("predicate handles invalid URLs", func(t *testing.T) {
- result := registration.Predicate("://invalid-url")
- assert.False(t, result)
- })
-
- t.Run("NewProvider factory works", func(t *testing.T) {
- provider, err := registration.NewProvider("https://bitbucket.org/owner/repo", nil)
- assert.NoError(t, err)
- assert.NotNil(t, provider)
- })
-}
-
-func TestGetCommitURL(t *testing.T) {
- testCases := []struct {
- repoURL string
- sha string
- expectedCommitURL string
- }{
- {
- repoURL: "ssh://git@bitbucket.org/akuity/kargo.git",
- sha: "sha",
- expectedCommitURL: "https://bitbucket.org/akuity/kargo/commits/sha",
- },
- {
- repoURL: "git@bitbucket.org:akuity/kargo.git",
- sha: "sha",
- expectedCommitURL: "https://bitbucket.org/akuity/kargo/commits/sha",
- },
- {
- repoURL: "https://username@bitbucket.org/akuity/kargo",
- sha: "sha",
- expectedCommitURL: "https://bitbucket.org/akuity/kargo/commits/sha",
- },
- {
- repoURL: "http://bitbucket.org/akuity/kargo.git",
- sha: "sha",
- expectedCommitURL: "https://bitbucket.org/akuity/kargo/commits/sha",
- },
- }
-
- prov := &provider{}
-
- for _, testCase := range testCases {
- t.Run(testCase.repoURL, func(t *testing.T) {
- commitURL, err := prov.GetCommitURL(testCase.repoURL, testCase.sha)
- require.NoError(t, err)
- require.Equal(t, testCase.expectedCommitURL, commitURL)
- })
- }
-}
diff --git a/pkg/gitprovider/bitbucket/cloud/provider.go b/pkg/gitprovider/bitbucket/cloud/provider.go
new file mode 100644
index 0000000000..3cb3cefb20
--- /dev/null
+++ b/pkg/gitprovider/bitbucket/cloud/provider.go
@@ -0,0 +1,484 @@
+package cloud
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "github.com/hashicorp/go-cleanhttp"
+
+ "github.com/akuity/kargo/pkg/gitprovider"
+ "github.com/akuity/kargo/pkg/urls"
+)
+
+const (
+ // ProviderName is the name used to register the Bitbucket Cloud provider.
+ ProviderName = "bitbucket"
+
+ // Host is the hostname of the Bitbucket Cloud instance.
+ Host = "bitbucket.org"
+
+ // apiBaseURL is the base URL for the Bitbucket Cloud REST API.
+ apiBaseURL = "https://api.bitbucket.org/2.0"
+)
+
+var registration = gitprovider.Registration{
+ Predicate: func(repoURL string) bool {
+ u, err := url.Parse(repoURL)
+ if err != nil {
+ return false
+ }
+ return u.Hostname() == Host
+ },
+ NewProvider: func(
+ repoURL string,
+ opts *gitprovider.Options,
+ ) (gitprovider.Interface, error) {
+ return NewProvider(repoURL, opts)
+ },
+}
+
+func init() {
+ gitprovider.Register(ProviderName, registration)
+}
+
+// provider is a Bitbucket Cloud implementation of gitprovider.Interface.
+type provider struct {
+ owner string
+ repoSlug string
+ client ClientWithResponsesInterface
+}
+
+// NewProvider returns a Bitbucket Cloud implementation of gitprovider.Interface.
+func NewProvider(
+ repoURL string,
+ opts *gitprovider.Options,
+) (gitprovider.Interface, error) {
+ if opts == nil {
+ opts = &gitprovider.Options{}
+ }
+
+ _, owner, repoSlug, err := parseRepoURL(repoURL)
+ if err != nil {
+ return nil, err
+ }
+
+ token := opts.Token
+ client, err := NewClientWithResponses(
+ apiBaseURL,
+ WithHTTPClient(cleanhttp.DefaultClient()),
+ WithRequestEditorFn(func(_ context.Context, req *http.Request) error {
+ req.Header.Set("Authorization", "Bearer "+token)
+ return nil
+ }),
+ )
+ if err != nil {
+ return nil, fmt.Errorf("error creating Bitbucket Cloud API client: %w", err)
+ }
+
+ return &provider{
+ owner: owner,
+ repoSlug: repoSlug,
+ client: client,
+ }, nil
+}
+
+// CreatePullRequest implements gitprovider.Interface.
+func (p *provider) CreatePullRequest(
+ ctx context.Context,
+ opts *gitprovider.CreatePullRequestOpts,
+) (*gitprovider.PullRequest, error) {
+ if opts == nil {
+ opts = &gitprovider.CreatePullRequestOpts{}
+ }
+
+ title := opts.Title
+ body := Pullrequest{Type: "pullrequest", Title: &title}
+ if opts.Description != "" {
+ body.Set("description", opts.Description)
+ }
+
+ srcBranch := opts.Head
+ dstBranch := opts.Base
+ body.Source = &PullrequestEndpoint{
+ Branch: &struct {
+ DefaultMergeStrategy *string `json:"default_merge_strategy,omitempty"`
+ MergeStrategies *[]PullrequestEndpointBranchMergeStrategies `json:"merge_strategies,omitempty"`
+ Name *string `json:"name,omitempty"`
+ }{Name: &srcBranch},
+ }
+ body.Destination = &PullrequestEndpoint{
+ Branch: &struct {
+ DefaultMergeStrategy *string `json:"default_merge_strategy,omitempty"`
+ MergeStrategies *[]PullrequestEndpointBranchMergeStrategies `json:"merge_strategies,omitempty"`
+ Name *string `json:"name,omitempty"`
+ }{Name: &dstBranch},
+ }
+
+ resp, err := p.client.PostRepositoriesWorkspaceRepoSlugPullrequestsWithResponse(
+ ctx,
+ p.owner,
+ p.repoSlug,
+ body,
+ )
+ if err != nil {
+ return nil, fmt.Errorf("error creating pull request: %w", err)
+ }
+ if resp.JSON201 == nil {
+ return nil, fmt.Errorf(
+ "unexpected response %d creating pull request", resp.StatusCode(),
+ )
+ }
+ if err = p.resolveFullMergeCommitSHA(ctx, resp.JSON201); err != nil {
+ return nil, err
+ }
+ return toProviderPR(resp.JSON201), nil
+}
+
+// GetPullRequest implements gitprovider.Interface.
+func (p *provider) GetPullRequest(
+ ctx context.Context,
+ id int64,
+) (*gitprovider.PullRequest, error) {
+ resp, err := p.client.GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdWithResponse(
+ ctx,
+ p.owner,
+ p.repoSlug,
+ int(id),
+ )
+ if err != nil {
+ return nil, fmt.Errorf("error getting pull request %d: %w", id, err)
+ }
+ if resp.JSON200 == nil {
+ return nil, fmt.Errorf(
+ "unexpected response %d getting pull request %d", resp.StatusCode(), id,
+ )
+ }
+ if err = p.resolveFullMergeCommitSHA(ctx, resp.JSON200); err != nil {
+ return nil, err
+ }
+ return toProviderPR(resp.JSON200), nil
+}
+
+// ListPullRequests implements gitprovider.Interface.
+func (p *provider) ListPullRequests(
+ ctx context.Context,
+ opts *gitprovider.ListPullRequestOptions,
+) ([]gitprovider.PullRequest, error) {
+ if opts == nil {
+ opts = &gitprovider.ListPullRequestOptions{}
+ }
+ if opts.State == "" {
+ opts.State = gitprovider.PullRequestStateOpen
+ }
+
+ var states []string
+ switch opts.State {
+ case gitprovider.PullRequestStateAny:
+ states = []string{
+ string(PullrequestStateOPEN),
+ string(PullrequestStateMERGED),
+ string(PullrequestStateDECLINED),
+ string(PullrequestStateSUPERSEDED),
+ }
+ case gitprovider.PullRequestStateClosed:
+ states = []string{
+ string(PullrequestStateMERGED),
+ string(PullrequestStateDECLINED),
+ string(PullrequestStateSUPERSEDED),
+ }
+ case gitprovider.PullRequestStateOpen:
+ states = []string{string(PullrequestStateOPEN)}
+ default:
+ return nil, fmt.Errorf("unknown pull request state %q", opts.State)
+ }
+
+ resp, err := p.client.GetRepositoriesWorkspaceRepoSlugPullrequestsWithResponse(
+ ctx,
+ p.owner,
+ p.repoSlug,
+ &GetRepositoriesWorkspaceRepoSlugPullrequestsParams{},
+ withStates(states),
+ )
+ if err != nil {
+ return nil, fmt.Errorf("error listing pull requests: %w", err)
+ }
+ if resp.JSON200 == nil {
+ return nil, fmt.Errorf(
+ "unexpected response %d listing pull requests", resp.StatusCode(),
+ )
+ }
+
+ // NB: The Bitbucket API doesn't support filtering by source/destination
+ // branch or commit hash, so we have to filter client-side, which is
+ // highly inefficient.
+ var result []gitprovider.PullRequest
+ if resp.JSON200.Values == nil {
+ return result, nil
+ }
+ values := *resp.JSON200.Values
+ for i := range values {
+ pr := &values[i]
+ if opts.HeadBranch != "" {
+ branchName := ""
+ if pr.Source != nil &&
+ pr.Source.Branch != nil &&
+ pr.Source.Branch.Name != nil {
+ branchName = *pr.Source.Branch.Name
+ }
+ if branchName != opts.HeadBranch {
+ continue
+ }
+ }
+ if opts.BaseBranch != "" {
+ branchName := ""
+ if pr.Destination != nil &&
+ pr.Destination.Branch != nil &&
+ pr.Destination.Branch.Name != nil {
+ branchName = *pr.Destination.Branch.Name
+ }
+ if branchName != opts.BaseBranch {
+ continue
+ }
+ }
+ if opts.HeadCommit != "" {
+ commitHash := ""
+ if pr.Source != nil &&
+ pr.Source.Commit != nil &&
+ pr.Source.Commit.Hash != nil {
+ commitHash = *pr.Source.Commit.Hash
+ }
+ if commitHash != opts.HeadCommit {
+ continue
+ }
+ }
+ if err = p.resolveFullMergeCommitSHA(ctx, pr); err != nil {
+ return nil, err
+ }
+ result = append(result, *toProviderPR(pr))
+ }
+ return result, nil
+}
+
+// MergePullRequest implements gitprovider.Interface.
+func (p *provider) MergePullRequest(
+ ctx context.Context,
+ id int64,
+ opts *gitprovider.MergePullRequestOpts,
+) (*gitprovider.PullRequest, bool, error) {
+ if opts == nil {
+ opts = &gitprovider.MergePullRequestOpts{}
+ }
+
+ prID := int(id)
+
+ getResp, err := p.client.GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdWithResponse(
+ ctx,
+ p.owner,
+ p.repoSlug,
+ prID,
+ )
+ if err != nil {
+ return nil, false, fmt.Errorf("error getting pull request %d: %w", id, err)
+ }
+ if getResp.JSON200 == nil {
+ return nil, false, fmt.Errorf(
+ "unexpected response %d getting pull request %d", getResp.StatusCode(), id,
+ )
+ }
+ pr := getResp.JSON200
+
+ var state PullrequestState
+ if pr.State != nil {
+ state = *pr.State
+ }
+
+ if state == PullrequestStateMERGED {
+ return toProviderPR(pr), true, nil
+ }
+
+ if state != PullrequestStateOPEN {
+ return nil, false, fmt.Errorf(
+ "pull request %d is closed but not merged (state: %s)", id, state,
+ )
+ }
+
+ if pr.Draft != nil && *pr.Draft {
+ return nil, false, nil
+ }
+
+ // TODO: The Bitbucket API lacks comprehensive merge eligibility checks. We
+ // cannot reliably determine if a PR is mergeable due to conflicts, failing
+ // checks, or other blocking conditions before attempting the merge. This
+ // means we have no choice but to attempt the merge and hope for the best.
+ //
+ // See: https://jira.atlassian.com/browse/BCLOUD-22014
+ //
+ // This limitation makes the "wait" option unreliable for Bitbucket
+ // repositories.
+
+ var mergeStrategy *PullrequestMergeParametersMergeStrategy
+ if opts.MergeMethod != "" {
+ s := PullrequestMergeParametersMergeStrategy(opts.MergeMethod)
+ if !s.Valid() {
+ return nil, false, fmt.Errorf("unsupported merge strategy %q", opts.MergeMethod)
+ }
+ mergeStrategy = &s
+ }
+
+ mergeBody := PullrequestMergeParameters{
+ Type: "pullrequestMergeParameters",
+ MergeStrategy: mergeStrategy,
+ }
+
+ mergeResp, err := p.client.PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeWithResponse(
+ ctx,
+ p.owner,
+ p.repoSlug,
+ prID,
+ &PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams{},
+ mergeBody,
+ )
+ if err != nil {
+ return nil, false, fmt.Errorf("error merging pull request %d: %w", id, err)
+ }
+
+ if mergeResp.StatusCode() == http.StatusAccepted {
+ return nil, false, fmt.Errorf(
+ "pull request %d merge was accepted asynchronously and cannot be awaited", id,
+ )
+ }
+
+ if mergeResp.JSON200 == nil {
+ return nil, false, fmt.Errorf(
+ "unexpected response %d merging pull request %d", mergeResp.StatusCode(), id,
+ )
+ }
+
+ mergedPR := mergeResp.JSON200
+ var mergedState PullrequestState
+ if mergedPR.State != nil {
+ mergedState = *mergedPR.State
+ }
+
+ // Per the Bitbucket API docs, the merge endpoint returns 200 only on
+ // success (409 for conflicts, 555 for timeout). A 200 response with a
+ // non-merged state would be unexpected.
+ if mergedState != PullrequestStateMERGED {
+ return nil, false, fmt.Errorf(
+ "unexpected state %q after merging pull request %d", mergedState, id,
+ )
+ }
+
+ return toProviderPR(mergedPR), true, nil
+}
+
+// GetCommitURL implements gitprovider.Interface.
+func (p *provider) GetCommitURL(repoURL string, sha string) (string, error) {
+ normalizedURL := urls.NormalizeGit(repoURL)
+ parsedURL, err := url.Parse(normalizedURL)
+ if err != nil {
+ return "", fmt.Errorf("error processing repository URL: %s: %s", repoURL, err)
+ }
+ return fmt.Sprintf("https://%s%s/commits/%s", parsedURL.Host, parsedURL.Path, sha), nil
+}
+
+// resolveFullMergeCommitSHA replaces the (possibly short) merge commit hash on
+// pr with the full SHA. Bitbucket returns a short hash in the pull request
+// response, so a separate commit lookup is required.
+func (p *provider) resolveFullMergeCommitSHA(ctx context.Context, pr *Pullrequest) error {
+ if pr.MergeCommit == nil || pr.MergeCommit.Hash == nil || *pr.MergeCommit.Hash == "" {
+ return nil
+ }
+ resp, err := p.client.GetRepositoriesWorkspaceRepoSlugCommitCommitWithResponse(
+ ctx,
+ p.owner,
+ p.repoSlug,
+ *pr.MergeCommit.Hash,
+ )
+ if err != nil {
+ return fmt.Errorf("error getting commit: %w", err)
+ }
+ if resp.JSON200 == nil || resp.JSON200.Hash == nil {
+ return fmt.Errorf("unexpected response %d getting commit", resp.StatusCode())
+ }
+ pr.MergeCommit.Hash = resp.JSON200.Hash
+ return nil
+}
+
+// toProviderPR converts a Pullrequest to a gitprovider.PullRequest.
+func toProviderPR(pr *Pullrequest) *gitprovider.PullRequest {
+ if pr == nil {
+ return nil
+ }
+
+ var id int64
+ if pr.Id != nil {
+ id = int64(*pr.Id)
+ }
+
+ var state PullrequestState
+ if pr.State != nil {
+ state = *pr.State
+ }
+
+ var prURL string
+ if pr.Links != nil && pr.Links.Html != nil && pr.Links.Html.Href != nil {
+ prURL = *pr.Links.Html.Href
+ }
+
+ var headSHA string
+ if pr.Source != nil && pr.Source.Commit != nil && pr.Source.Commit.Hash != nil {
+ headSHA = *pr.Source.Commit.Hash
+ }
+
+ var mergeCommitSHA string
+ if pr.MergeCommit != nil && pr.MergeCommit.Hash != nil {
+ mergeCommitSHA = *pr.MergeCommit.Hash
+ }
+
+ return &gitprovider.PullRequest{
+ Number: id,
+ URL: prURL,
+ Open: state == PullrequestStateOPEN,
+ Merged: state == PullrequestStateMERGED,
+ // NB: As a sign of true craftsmanship, or lack thereof, the Bitbucket
+ // API returns a short commit SHA as merge commit hash. To get the full
+ // commit SHA, we need to fetch the commit details separately.
+ MergeCommitSHA: mergeCommitSHA,
+ HeadSHA: headSHA,
+ CreatedAt: pr.CreatedOn,
+ Object: pr,
+ }
+}
+
+// withStates returns a RequestEditorFn that overrides the state query params.
+// The Bitbucket API supports multiple state filters via repeated ?state= params,
+// but the generated params struct only supports a single value.
+func withStates(states []string) RequestEditorFn {
+ return func(_ context.Context, req *http.Request) error {
+ q := req.URL.Query()
+ q.Del("state")
+ for _, s := range states {
+ q.Add("state", s)
+ }
+ req.URL.RawQuery = q.Encode()
+ return nil
+ }
+}
+
+// parseRepoURL extracts host, owner and repo slug from a Bitbucket Cloud repository URL.
+func parseRepoURL(repoURL string) (host, owner, slug string, err error) {
+ u, err := url.Parse(urls.NormalizeGit(repoURL))
+ if err != nil {
+ return "", "", "", fmt.Errorf("parse Bitbucket Cloud URL %q: %w", repoURL, err)
+ }
+ path := strings.TrimPrefix(u.Path, "/")
+ parts := strings.Split(path, "/")
+ if len(parts) != 2 {
+ return "", "", "", fmt.Errorf("invalid repository path in URL %q", u)
+ }
+ return u.Hostname(), parts[0], parts[1], nil
+}
diff --git a/pkg/gitprovider/bitbucket/cloud/provider_test.go b/pkg/gitprovider/bitbucket/cloud/provider_test.go
new file mode 100644
index 0000000000..d2c0ad1490
--- /dev/null
+++ b/pkg/gitprovider/bitbucket/cloud/provider_test.go
@@ -0,0 +1,1167 @@
+package cloud
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "io"
+ "net/http"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/akuity/kargo/pkg/gitprovider"
+)
+
+// mockClient implements ClientWithResponsesInterface for testing.
+type mockClient struct {
+ getCommitFunc func(
+ ctx context.Context,
+ workspace, repoSlug, commit string,
+ reqEditors ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugCommitCommitResponse, error)
+
+ listPRsFunc func(
+ ctx context.Context,
+ workspace, repoSlug string,
+ params *GetRepositoriesWorkspaceRepoSlugPullrequestsParams,
+ reqEditors ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsResponse, error)
+
+ createPRFunc func(
+ ctx context.Context,
+ workspace, repoSlug string,
+ body PostRepositoriesWorkspaceRepoSlugPullrequestsJSONRequestBody,
+ reqEditors ...RequestEditorFn,
+ ) (*PostRepositoriesWorkspaceRepoSlugPullrequestsResponse, error)
+
+ getPRFunc func(
+ ctx context.Context,
+ workspace, repoSlug string,
+ pullRequestId int,
+ reqEditors ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse, error)
+
+ mergePRFunc func(
+ ctx context.Context,
+ workspace, repoSlug string,
+ pullRequestId int,
+ params *PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams,
+ body PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeJSONRequestBody,
+ reqEditors ...RequestEditorFn,
+ ) (*PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse, error)
+}
+
+func (m *mockClient) GetRepositoriesWorkspaceRepoSlugCommitCommitWithResponse(
+ ctx context.Context,
+ workspace, repoSlug, commit string,
+ reqEditors ...RequestEditorFn,
+) (*GetRepositoriesWorkspaceRepoSlugCommitCommitResponse, error) {
+ return m.getCommitFunc(ctx, workspace, repoSlug, commit, reqEditors...)
+}
+
+func (m *mockClient) GetRepositoriesWorkspaceRepoSlugPullrequestsWithResponse(
+ ctx context.Context,
+ workspace, repoSlug string,
+ params *GetRepositoriesWorkspaceRepoSlugPullrequestsParams,
+ reqEditors ...RequestEditorFn,
+) (*GetRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ return m.listPRsFunc(ctx, workspace, repoSlug, params, reqEditors...)
+}
+
+func (m *mockClient) PostRepositoriesWorkspaceRepoSlugPullrequestsWithBodyWithResponse(
+ _ context.Context,
+ _, _ string,
+ _ string,
+ _ io.Reader,
+ _ ...RequestEditorFn,
+) (*PostRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ return nil, errors.New("not implemented")
+}
+
+func (m *mockClient) PostRepositoriesWorkspaceRepoSlugPullrequestsWithResponse(
+ ctx context.Context,
+ workspace, repoSlug string,
+ body PostRepositoriesWorkspaceRepoSlugPullrequestsJSONRequestBody,
+ reqEditors ...RequestEditorFn,
+) (*PostRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ return m.createPRFunc(ctx, workspace, repoSlug, body, reqEditors...)
+}
+
+func (m *mockClient) GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdWithResponse(
+ ctx context.Context,
+ workspace, repoSlug string,
+ pullRequestId int,
+ reqEditors ...RequestEditorFn,
+) (*GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse, error) {
+ return m.getPRFunc(ctx, workspace, repoSlug, pullRequestId, reqEditors...)
+}
+
+func (m *mockClient) PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeWithBodyWithResponse(
+ _ context.Context,
+ _, _ string,
+ _ int,
+ _ *PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams,
+ _ string,
+ _ io.Reader,
+ _ ...RequestEditorFn,
+) (*PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse, error) {
+ return nil, errors.New("not implemented")
+}
+
+func (m *mockClient) PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeWithResponse(
+ ctx context.Context,
+ workspace, repoSlug string,
+ pullRequestId int,
+ params *PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams,
+ body PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeJSONRequestBody,
+ reqEditors ...RequestEditorFn,
+) (*PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse, error) {
+ return m.mergePRFunc(ctx, workspace, repoSlug, pullRequestId, params, body, reqEditors...)
+}
+
+// prFromJSON unmarshals a Pullrequest from JSON, for use in test cases.
+func prFromJSON(t *testing.T, s string) *Pullrequest {
+ t.Helper()
+ var pr Pullrequest
+ require.NoError(t, json.Unmarshal([]byte(s), &pr))
+ return &pr
+}
+
+// statesFromEditors applies request editors to a fake request and returns the
+// state query params — used to verify which states were passed to the list API.
+func statesFromEditors(reqEditors []RequestEditorFn) []string {
+ req, _ := http.NewRequest(http.MethodGet, "http://api.bitbucket.org/test", nil)
+ for _, ed := range reqEditors {
+ _ = ed(context.Background(), req)
+ }
+ return req.URL.Query()["state"]
+}
+
+func strPtr(s string) *string { return &s }
+func intPtr(i int) *int { return &i }
+
+func statePtr(s PullrequestState) *PullrequestState { return &s }
+
+func Test_registration(t *testing.T) {
+ t.Run("predicate matches bitbucket.org", func(t *testing.T) {
+ assert.True(t, registration.Predicate("https://bitbucket.org/owner/repo"))
+ })
+
+ t.Run("predicate does not match self-hosted URLs", func(t *testing.T) {
+ assert.False(t, registration.Predicate("https://bitbucket.example.com/projects/PROJ/repos/repo"))
+ })
+
+ t.Run("predicate does not match other providers", func(t *testing.T) {
+ assert.False(t, registration.Predicate("https://github.com/owner/repo"))
+ })
+
+ t.Run("predicate handles invalid URLs", func(t *testing.T) {
+ assert.False(t, registration.Predicate("://invalid-url"))
+ })
+
+ t.Run("NewProvider factory works", func(t *testing.T) {
+ p, err := registration.NewProvider("https://bitbucket.org/owner/repo", nil)
+ assert.NoError(t, err)
+ assert.NotNil(t, p)
+ })
+}
+
+func TestNewProvider(t *testing.T) {
+ t.Run("successful creation", func(t *testing.T) {
+ provider, err := NewProvider("https://bitbucket.org/owner/repo", &gitprovider.Options{Token: "token"})
+ assert.NoError(t, err)
+ assert.NotNil(t, provider)
+ })
+
+ t.Run("successful creation with nil options", func(t *testing.T) {
+ provider, err := NewProvider("https://bitbucket.org/owner/repo", nil)
+ assert.NoError(t, err)
+ assert.NotNil(t, provider)
+ })
+
+ t.Run("error with invalid URL", func(t *testing.T) {
+ provider, err := NewProvider("://invalid-url", &gitprovider.Options{Token: "token"})
+ assert.Error(t, err)
+ assert.Nil(t, provider)
+ })
+
+ t.Run("error with invalid path", func(t *testing.T) {
+ provider, err := NewProvider("https://bitbucket.org/invalid-path", &gitprovider.Options{Token: "token"})
+ assert.Error(t, err)
+ assert.Nil(t, provider)
+ })
+}
+
+func TestCreatePullRequest(t *testing.T) {
+ t.Run("successful creation", func(t *testing.T) {
+ mc := &mockClient{
+ createPRFunc: func(
+ _ context.Context,
+ _, _ string,
+ body PostRepositoriesWorkspaceRepoSlugPullrequestsJSONRequestBody,
+ _ ...RequestEditorFn,
+ ) (*PostRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ require.NotNil(t, body.Title)
+ assert.Equal(t, "Test PR", *body.Title)
+ assert.Equal(t, "PR description", body.AdditionalProperties["description"])
+ require.NotNil(t, body.Source)
+ require.NotNil(t, body.Source.Branch)
+ require.NotNil(t, body.Source.Branch.Name)
+ assert.Equal(t, "feature-branch", *body.Source.Branch.Name)
+ require.NotNil(t, body.Destination)
+ require.NotNil(t, body.Destination.Branch)
+ require.NotNil(t, body.Destination.Branch.Name)
+ assert.Equal(t, "main", *body.Destination.Branch.Name)
+ return &PostRepositoriesWorkspaceRepoSlugPullrequestsResponse{
+ JSON201: prFromJSON(t, `{
+ "id": 1,
+ "state": "OPEN",
+ "links": {"html": {"href": "https://bitbucket.org/owner/repo/pull-requests/1"}},
+ "source": {
+ "branch": {"name": "feature-branch"},
+ "commit": {"hash": "abcdef1234567890"}
+ },
+ "created_on": "2023-01-01T12:00:00Z",
+ "type": "pullrequest"
+ }`),
+ }, nil
+ },
+ }
+ p := &provider{client: mc}
+ pr, err := p.CreatePullRequest(t.Context(), &gitprovider.CreatePullRequestOpts{
+ Title: "Test PR",
+ Description: "PR description",
+ Head: "feature-branch",
+ Base: "main",
+ })
+ assert.NoError(t, err)
+ require.NotNil(t, pr)
+ assert.Equal(t, int64(1), pr.Number)
+ assert.Equal(t, "https://bitbucket.org/owner/repo/pull-requests/1", pr.URL)
+ assert.Equal(t, "abcdef1234567890", pr.HeadSHA)
+ assert.True(t, pr.Open)
+ assert.False(t, pr.Merged)
+ })
+
+ t.Run("successful creation with nil options", func(t *testing.T) {
+ mc := &mockClient{
+ createPRFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ PostRepositoriesWorkspaceRepoSlugPullrequestsJSONRequestBody,
+ _ ...RequestEditorFn,
+ ) (*PostRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ return &PostRepositoriesWorkspaceRepoSlugPullrequestsResponse{
+ JSON201: &Pullrequest{Id: intPtr(1), State: statePtr(PullrequestStateOPEN)},
+ }, nil
+ },
+ }
+ p := &provider{client: mc}
+ pr, err := p.CreatePullRequest(t.Context(), nil)
+ assert.NoError(t, err)
+ require.NotNil(t, pr)
+ assert.Equal(t, int64(1), pr.Number)
+ })
+
+ t.Run("creation with merge commit resolves full SHA", func(t *testing.T) {
+ mc := &mockClient{
+ createPRFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ PostRepositoriesWorkspaceRepoSlugPullrequestsJSONRequestBody,
+ _ ...RequestEditorFn,
+ ) (*PostRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ return &PostRepositoriesWorkspaceRepoSlugPullrequestsResponse{
+ JSON201: &Pullrequest{
+ Id: intPtr(1),
+ State: statePtr(PullrequestStateOPEN),
+ MergeCommit: &struct {
+ Hash *string `json:"hash,omitempty"`
+ }{Hash: strPtr("short123")},
+ },
+ }, nil
+ },
+ getCommitFunc: func(
+ _ context.Context,
+ _, _, commit string,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugCommitCommitResponse, error) {
+ assert.Equal(t, "short123", commit)
+ return &GetRepositoriesWorkspaceRepoSlugCommitCommitResponse{
+ JSON200: &Commit{Hash: strPtr("full1234567890abcdef")},
+ }, nil
+ },
+ }
+ p := &provider{client: mc}
+ pr, err := p.CreatePullRequest(t.Context(), nil)
+ assert.NoError(t, err)
+ require.NotNil(t, pr)
+ assert.Equal(t, "full1234567890abcdef", pr.MergeCommitSHA)
+ })
+
+ t.Run("error during creation", func(t *testing.T) {
+ mc := &mockClient{
+ createPRFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ PostRepositoriesWorkspaceRepoSlugPullrequestsJSONRequestBody,
+ _ ...RequestEditorFn,
+ ) (*PostRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ return nil, errors.New("creation failed")
+ },
+ }
+ p := &provider{client: mc}
+ pr, err := p.CreatePullRequest(t.Context(), nil)
+ assert.Error(t, err)
+ assert.Nil(t, pr)
+ })
+
+ t.Run("error getting full commit SHA", func(t *testing.T) {
+ mc := &mockClient{
+ createPRFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ PostRepositoriesWorkspaceRepoSlugPullrequestsJSONRequestBody,
+ _ ...RequestEditorFn,
+ ) (*PostRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ return &PostRepositoriesWorkspaceRepoSlugPullrequestsResponse{
+ JSON201: &Pullrequest{
+ Id: intPtr(1),
+ State: statePtr(PullrequestStateOPEN),
+ MergeCommit: &struct {
+ Hash *string `json:"hash,omitempty"`
+ }{Hash: strPtr("short123")},
+ },
+ }, nil
+ },
+ getCommitFunc: func(
+ _ context.Context,
+ _, _, _ string,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugCommitCommitResponse, error) {
+ return nil, errors.New("commit fetch failed")
+ },
+ }
+ p := &provider{client: mc}
+ pr, err := p.CreatePullRequest(t.Context(), nil)
+ assert.Error(t, err)
+ assert.Nil(t, pr)
+ })
+}
+
+func TestGetPullRequest(t *testing.T) {
+ t.Run("successful retrieval", func(t *testing.T) {
+ mc := &mockClient{
+ getPRFunc: func(
+ _ context.Context,
+ _, _ string,
+ pullRequestId int,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse, error) {
+ assert.Equal(t, 1, pullRequestId)
+ return &GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse{
+ JSON200: prFromJSON(t, `{
+ "id": 1,
+ "state": "OPEN",
+ "links": {"html": {"href": "https://bitbucket.org/owner/repo/pull-requests/1"}},
+ "source": {
+ "branch": {"name": "feature-branch"},
+ "commit": {"hash": "abcdef1234567890"}
+ },
+ "created_on": "2023-01-01T12:00:00Z",
+ "type": "pullrequest"
+ }`),
+ }, nil
+ },
+ }
+ p := &provider{client: mc}
+ pr, err := p.GetPullRequest(t.Context(), 1)
+ assert.NoError(t, err)
+ require.NotNil(t, pr)
+ assert.Equal(t, int64(1), pr.Number)
+ assert.Equal(t, "https://bitbucket.org/owner/repo/pull-requests/1", pr.URL)
+ assert.Equal(t, "abcdef1234567890", pr.HeadSHA)
+ assert.True(t, pr.Open)
+ assert.False(t, pr.Merged)
+ assert.NotNil(t, pr.CreatedAt)
+ })
+
+ t.Run("retrieval of merged PR resolves full SHA", func(t *testing.T) {
+ mc := &mockClient{
+ getPRFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ int,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse, error) {
+ return &GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse{
+ JSON200: &Pullrequest{
+ Id: intPtr(1),
+ State: statePtr(PullrequestStateMERGED),
+ MergeCommit: &struct {
+ Hash *string `json:"hash,omitempty"`
+ }{Hash: strPtr("short123")},
+ },
+ }, nil
+ },
+ getCommitFunc: func(
+ _ context.Context,
+ _, _, _ string,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugCommitCommitResponse, error) {
+ return &GetRepositoriesWorkspaceRepoSlugCommitCommitResponse{
+ JSON200: &Commit{Hash: strPtr("full1234567890abcdef")},
+ }, nil
+ },
+ }
+ p := &provider{client: mc}
+ pr, err := p.GetPullRequest(t.Context(), 1)
+ assert.NoError(t, err)
+ require.NotNil(t, pr)
+ assert.False(t, pr.Open)
+ assert.True(t, pr.Merged)
+ assert.Equal(t, "full1234567890abcdef", pr.MergeCommitSHA)
+ })
+
+ t.Run("error during retrieval", func(t *testing.T) {
+ mc := &mockClient{
+ getPRFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ int,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse, error) {
+ return nil, errors.New("retrieval failed")
+ },
+ }
+ p := &provider{client: mc}
+ pr, err := p.GetPullRequest(t.Context(), 1)
+ assert.Error(t, err)
+ assert.Nil(t, pr)
+ })
+}
+
+func TestListPullRequests(t *testing.T) {
+ t.Run("list open PRs by default", func(t *testing.T) {
+ mc := &mockClient{
+ listPRsFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ *GetRepositoriesWorkspaceRepoSlugPullrequestsParams,
+ reqEditors ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ assert.Equal(t, []string{"OPEN"}, statesFromEditors(reqEditors))
+ values := []Pullrequest{
+ {Id: intPtr(1), State: statePtr(PullrequestStateOPEN)},
+ {Id: intPtr(2), State: statePtr(PullrequestStateOPEN)},
+ }
+ return &GetRepositoriesWorkspaceRepoSlugPullrequestsResponse{
+ JSON200: &PaginatedPullrequests{Values: &values},
+ }, nil
+ },
+ }
+ p := &provider{client: mc}
+ prs, err := p.ListPullRequests(t.Context(), nil)
+ assert.NoError(t, err)
+ assert.Len(t, prs, 2)
+ })
+
+ t.Run("list all PRs", func(t *testing.T) {
+ mc := &mockClient{
+ listPRsFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ *GetRepositoriesWorkspaceRepoSlugPullrequestsParams,
+ reqEditors ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ states := statesFromEditors(reqEditors)
+ assert.Contains(t, states, "OPEN")
+ assert.Contains(t, states, "MERGED")
+ assert.Contains(t, states, "DECLINED")
+ assert.Contains(t, states, "SUPERSEDED")
+ values := []Pullrequest{
+ {Id: intPtr(1), State: statePtr(PullrequestStateOPEN)},
+ {Id: intPtr(2), State: statePtr(PullrequestStateMERGED)},
+ {Id: intPtr(3), State: statePtr(PullrequestStateDECLINED)},
+ {Id: intPtr(4), State: statePtr(PullrequestStateSUPERSEDED)},
+ }
+ return &GetRepositoriesWorkspaceRepoSlugPullrequestsResponse{
+ JSON200: &PaginatedPullrequests{Values: &values},
+ }, nil
+ },
+ }
+ p := &provider{client: mc}
+ prs, err := p.ListPullRequests(t.Context(), &gitprovider.ListPullRequestOptions{
+ State: gitprovider.PullRequestStateAny,
+ })
+ assert.NoError(t, err)
+ assert.Len(t, prs, 4)
+ })
+
+ t.Run("list closed PRs", func(t *testing.T) {
+ mc := &mockClient{
+ listPRsFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ *GetRepositoriesWorkspaceRepoSlugPullrequestsParams,
+ reqEditors ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ states := statesFromEditors(reqEditors)
+ assert.Contains(t, states, "MERGED")
+ assert.Contains(t, states, "DECLINED")
+ assert.Contains(t, states, "SUPERSEDED")
+ assert.NotContains(t, states, "OPEN")
+ values := []Pullrequest{
+ {Id: intPtr(2), State: statePtr(PullrequestStateMERGED)},
+ {Id: intPtr(3), State: statePtr(PullrequestStateDECLINED)},
+ {Id: intPtr(4), State: statePtr(PullrequestStateSUPERSEDED)},
+ }
+ return &GetRepositoriesWorkspaceRepoSlugPullrequestsResponse{
+ JSON200: &PaginatedPullrequests{Values: &values},
+ }, nil
+ },
+ }
+ p := &provider{client: mc}
+ prs, err := p.ListPullRequests(t.Context(), &gitprovider.ListPullRequestOptions{
+ State: gitprovider.PullRequestStateClosed,
+ })
+ assert.NoError(t, err)
+ assert.Len(t, prs, 3)
+ })
+
+ t.Run("filter by head branch", func(t *testing.T) {
+ mc := &mockClient{
+ listPRsFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ *GetRepositoriesWorkspaceRepoSlugPullrequestsParams,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ values := []Pullrequest{
+ {
+ Id: intPtr(1),
+ State: statePtr(PullrequestStateOPEN),
+ Source: &PullrequestEndpoint{Branch: &struct {
+ DefaultMergeStrategy *string `json:"default_merge_strategy,omitempty"`
+ MergeStrategies *[]PullrequestEndpointBranchMergeStrategies `json:"merge_strategies,omitempty"`
+ Name *string `json:"name,omitempty"`
+ }{Name: strPtr("feature-1")}},
+ },
+ {
+ Id: intPtr(2),
+ State: statePtr(PullrequestStateOPEN),
+ Source: &PullrequestEndpoint{Branch: &struct {
+ DefaultMergeStrategy *string `json:"default_merge_strategy,omitempty"`
+ MergeStrategies *[]PullrequestEndpointBranchMergeStrategies `json:"merge_strategies,omitempty"`
+ Name *string `json:"name,omitempty"`
+ }{Name: strPtr("feature-2")}},
+ },
+ }
+ return &GetRepositoriesWorkspaceRepoSlugPullrequestsResponse{
+ JSON200: &PaginatedPullrequests{Values: &values},
+ }, nil
+ },
+ }
+ p := &provider{client: mc}
+ prs, err := p.ListPullRequests(t.Context(), &gitprovider.ListPullRequestOptions{
+ HeadBranch: "feature-1",
+ })
+ assert.NoError(t, err)
+ assert.Len(t, prs, 1)
+ assert.Equal(t, int64(1), prs[0].Number)
+ })
+
+ t.Run("filter by base branch", func(t *testing.T) {
+ mc := &mockClient{
+ listPRsFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ *GetRepositoriesWorkspaceRepoSlugPullrequestsParams,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ values := []Pullrequest{
+ {
+ Id: intPtr(1),
+ State: statePtr(PullrequestStateOPEN),
+ Destination: &PullrequestEndpoint{Branch: &struct {
+ DefaultMergeStrategy *string `json:"default_merge_strategy,omitempty"`
+ MergeStrategies *[]PullrequestEndpointBranchMergeStrategies `json:"merge_strategies,omitempty"`
+ Name *string `json:"name,omitempty"`
+ }{Name: strPtr("main")}},
+ },
+ {
+ Id: intPtr(2),
+ State: statePtr(PullrequestStateOPEN),
+ Destination: &PullrequestEndpoint{Branch: &struct {
+ DefaultMergeStrategy *string `json:"default_merge_strategy,omitempty"`
+ MergeStrategies *[]PullrequestEndpointBranchMergeStrategies `json:"merge_strategies,omitempty"`
+ Name *string `json:"name,omitempty"`
+ }{Name: strPtr("dev")}},
+ },
+ }
+ return &GetRepositoriesWorkspaceRepoSlugPullrequestsResponse{
+ JSON200: &PaginatedPullrequests{Values: &values},
+ }, nil
+ },
+ }
+ p := &provider{client: mc}
+ prs, err := p.ListPullRequests(t.Context(), &gitprovider.ListPullRequestOptions{
+ BaseBranch: "dev",
+ })
+ assert.NoError(t, err)
+ assert.Len(t, prs, 1)
+ assert.Equal(t, int64(2), prs[0].Number)
+ })
+
+ t.Run("filter by head commit", func(t *testing.T) {
+ mc := &mockClient{
+ listPRsFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ *GetRepositoriesWorkspaceRepoSlugPullrequestsParams,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ values := []Pullrequest{
+ {
+ Id: intPtr(1),
+ State: statePtr(PullrequestStateOPEN),
+ Source: &PullrequestEndpoint{
+ Commit: &struct {
+ Hash *string `json:"hash,omitempty"`
+ }{Hash: strPtr("specific-hash")},
+ },
+ },
+ {
+ Id: intPtr(2),
+ State: statePtr(PullrequestStateOPEN),
+ Source: &PullrequestEndpoint{
+ Commit: &struct {
+ Hash *string `json:"hash,omitempty"`
+ }{Hash: strPtr("other-hash")},
+ },
+ },
+ }
+ return &GetRepositoriesWorkspaceRepoSlugPullrequestsResponse{
+ JSON200: &PaginatedPullrequests{Values: &values},
+ }, nil
+ },
+ }
+ p := &provider{client: mc}
+ prs, err := p.ListPullRequests(t.Context(), &gitprovider.ListPullRequestOptions{
+ HeadCommit: "specific-hash",
+ })
+ assert.NoError(t, err)
+ assert.Len(t, prs, 1)
+ assert.Equal(t, int64(1), prs[0].Number)
+ })
+
+ t.Run("PR with merge commit resolves full SHA", func(t *testing.T) {
+ mc := &mockClient{
+ listPRsFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ *GetRepositoriesWorkspaceRepoSlugPullrequestsParams,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ values := []Pullrequest{{
+ Id: intPtr(1),
+ State: statePtr(PullrequestStateMERGED),
+ MergeCommit: &struct {
+ Hash *string `json:"hash,omitempty"`
+ }{Hash: strPtr("short123")},
+ }}
+ return &GetRepositoriesWorkspaceRepoSlugPullrequestsResponse{
+ JSON200: &PaginatedPullrequests{Values: &values},
+ }, nil
+ },
+ getCommitFunc: func(
+ _ context.Context,
+ _, _, _ string,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugCommitCommitResponse, error) {
+ return &GetRepositoriesWorkspaceRepoSlugCommitCommitResponse{
+ JSON200: &Commit{Hash: strPtr("full1234567890abcdef")},
+ }, nil
+ },
+ }
+ p := &provider{client: mc}
+ prs, err := p.ListPullRequests(t.Context(), nil)
+ assert.NoError(t, err)
+ assert.Len(t, prs, 1)
+ assert.Equal(t, "full1234567890abcdef", prs[0].MergeCommitSHA)
+ })
+
+ t.Run("error during list", func(t *testing.T) {
+ mc := &mockClient{
+ listPRsFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ *GetRepositoriesWorkspaceRepoSlugPullrequestsParams,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ return nil, errors.New("list failed")
+ },
+ }
+ p := &provider{client: mc}
+ prs, err := p.ListPullRequests(t.Context(), nil)
+ assert.Error(t, err)
+ assert.Nil(t, prs)
+ })
+
+ t.Run("invalid state", func(t *testing.T) {
+ p := &provider{client: &mockClient{}}
+ prs, err := p.ListPullRequests(t.Context(), &gitprovider.ListPullRequestOptions{
+ State: "invalid-state",
+ })
+ assert.Error(t, err)
+ assert.Nil(t, prs)
+ })
+}
+
+func TestMergePullRequest(t *testing.T) {
+ testCases := []struct {
+ name string
+ prNumber int64
+ mergeOpts *gitprovider.MergePullRequestOpts
+ mockClient *mockClient
+ expectedMerged bool
+ expectError bool
+ errorContains string
+ }{
+ {
+ name: "error getting PR",
+ prNumber: 999,
+ mockClient: &mockClient{
+ getPRFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ int,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse, error) {
+ return nil, errors.New("get PR failed")
+ },
+ },
+ expectError: true,
+ errorContains: "error getting pull request",
+ },
+ {
+ name: "PR already merged",
+ prNumber: 123,
+ mockClient: &mockClient{
+ getPRFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ int,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse, error) {
+ return &GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse{
+ JSON200: &Pullrequest{
+ Id: intPtr(123),
+ State: statePtr(PullrequestStateMERGED),
+ MergeCommit: &struct {
+ Hash *string `json:"hash,omitempty"`
+ }{Hash: strPtr("merge_sha")},
+ },
+ }, nil
+ },
+ },
+ expectedMerged: true,
+ },
+ {
+ name: "PR declined",
+ prNumber: 456,
+ mockClient: &mockClient{
+ getPRFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ int,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse, error) {
+ return &GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse{
+ JSON200: &Pullrequest{Id: intPtr(456), State: statePtr(PullrequestStateDECLINED)},
+ }, nil
+ },
+ },
+ expectError: true,
+ errorContains: "closed but not merged",
+ },
+ {
+ name: "PR is draft",
+ prNumber: 333,
+ mockClient: &mockClient{
+ getPRFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ int,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse, error) {
+ isDraft := true
+ return &GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse{
+ JSON200: &Pullrequest{
+ Id: intPtr(333),
+ State: statePtr(PullrequestStateOPEN),
+ Draft: &isDraft,
+ },
+ }, nil
+ },
+ },
+ },
+ {
+ name: "unsupported merge strategy",
+ prNumber: 100,
+ mergeOpts: &gitprovider.MergePullRequestOpts{MergeMethod: "rebase"},
+ mockClient: &mockClient{
+ getPRFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ int,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse, error) {
+ return &GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse{
+ JSON200: &Pullrequest{Id: intPtr(100), State: statePtr(PullrequestStateOPEN)},
+ }, nil
+ },
+ },
+ expectError: true,
+ errorContains: "unsupported merge strategy",
+ },
+ {
+ name: "merge operation fails",
+ prNumber: 888,
+ mockClient: &mockClient{
+ getPRFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ int,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse, error) {
+ return &GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse{
+ JSON200: &Pullrequest{Id: intPtr(888), State: statePtr(PullrequestStateOPEN)},
+ }, nil
+ },
+ mergePRFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ int,
+ _ *PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams,
+ _ PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeJSONRequestBody,
+ _ ...RequestEditorFn,
+ ) (*PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse, error) {
+ return nil, errors.New("merge failed")
+ },
+ },
+ expectError: true,
+ errorContains: "error merging pull request",
+ },
+ {
+ name: "successful merge with strategy",
+ prNumber: 200,
+ mergeOpts: &gitprovider.MergePullRequestOpts{MergeMethod: "squash"},
+ mockClient: &mockClient{
+ getPRFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ int,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse, error) {
+ return &GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse{
+ JSON200: &Pullrequest{Id: intPtr(200), State: statePtr(PullrequestStateOPEN)},
+ }, nil
+ },
+ mergePRFunc: func(
+ _ context.Context,
+ _, _ string,
+ pullRequestId int,
+ _ *PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams,
+ body PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeJSONRequestBody,
+ _ ...RequestEditorFn,
+ ) (*PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse, error) {
+ assert.Equal(t, 200, pullRequestId)
+ require.NotNil(t, body.MergeStrategy)
+ assert.Equal(t, Squash, *body.MergeStrategy)
+ return &PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse{
+ JSON200: &Pullrequest{Id: intPtr(200), State: statePtr(PullrequestStateMERGED)},
+ }, nil
+ },
+ },
+ expectedMerged: true,
+ },
+ {
+ name: "successful merge",
+ prNumber: 1234,
+ mockClient: &mockClient{
+ getPRFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ int,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse, error) {
+ return &GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse{
+ JSON200: &Pullrequest{Id: intPtr(1234), State: statePtr(PullrequestStateOPEN)},
+ }, nil
+ },
+ mergePRFunc: func(
+ _ context.Context,
+ _, _ string,
+ _ int,
+ _ *PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams,
+ _ PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeJSONRequestBody,
+ _ ...RequestEditorFn,
+ ) (*PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse, error) {
+ return &PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse{
+ JSON200: &Pullrequest{
+ Id: intPtr(1234),
+ State: statePtr(PullrequestStateMERGED),
+ MergeCommit: &struct {
+ Hash *string `json:"hash,omitempty"`
+ }{Hash: strPtr("merge_sha")},
+ },
+ }, nil
+ },
+ },
+ expectedMerged: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ p := &provider{client: tc.mockClient}
+ pr, merged, err := p.MergePullRequest(t.Context(), tc.prNumber, tc.mergeOpts)
+ if tc.expectError {
+ require.Error(t, err)
+ require.Contains(t, err.Error(), tc.errorContains)
+ require.False(t, merged)
+ require.Nil(t, pr)
+ return
+ }
+ require.NoError(t, err)
+ require.Equal(t, tc.expectedMerged, merged)
+ if tc.expectedMerged {
+ require.NotNil(t, pr)
+ require.Equal(t, tc.prNumber, pr.Number)
+ }
+ })
+ }
+}
+
+func TestResolveFullMergeCommitSHA(t *testing.T) {
+ t.Run("no-op when merge commit is nil", func(t *testing.T) {
+ p := &provider{client: &mockClient{}}
+ pr := &Pullrequest{}
+ err := p.resolveFullMergeCommitSHA(t.Context(), pr)
+ assert.NoError(t, err)
+ assert.Nil(t, pr.MergeCommit)
+ })
+
+ t.Run("no-op when merge commit hash is empty", func(t *testing.T) {
+ p := &provider{client: &mockClient{}}
+ pr := &Pullrequest{
+ MergeCommit: &struct {
+ Hash *string `json:"hash,omitempty"`
+ }{Hash: strPtr("")},
+ }
+ err := p.resolveFullMergeCommitSHA(t.Context(), pr)
+ assert.NoError(t, err)
+ })
+
+ t.Run("resolves short SHA to full SHA", func(t *testing.T) {
+ mc := &mockClient{
+ getCommitFunc: func(
+ _ context.Context,
+ _, _, commit string,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugCommitCommitResponse, error) {
+ assert.Equal(t, "short123", commit)
+ return &GetRepositoriesWorkspaceRepoSlugCommitCommitResponse{
+ JSON200: &Commit{Hash: strPtr("full1234567890abcdef")},
+ }, nil
+ },
+ }
+ p := &provider{client: mc}
+ pr := &Pullrequest{
+ MergeCommit: &struct {
+ Hash *string `json:"hash,omitempty"`
+ }{Hash: strPtr("short123")},
+ }
+ err := p.resolveFullMergeCommitSHA(t.Context(), pr)
+ assert.NoError(t, err)
+ require.NotNil(t, pr.MergeCommit.Hash)
+ assert.Equal(t, "full1234567890abcdef", *pr.MergeCommit.Hash)
+ })
+
+ t.Run("error from getCommit is propagated", func(t *testing.T) {
+ mc := &mockClient{
+ getCommitFunc: func(
+ _ context.Context,
+ _, _, _ string,
+ _ ...RequestEditorFn,
+ ) (*GetRepositoriesWorkspaceRepoSlugCommitCommitResponse, error) {
+ return nil, errors.New("retrieval failed")
+ },
+ }
+ p := &provider{client: mc}
+ pr := &Pullrequest{
+ MergeCommit: &struct {
+ Hash *string `json:"hash,omitempty"`
+ }{Hash: strPtr("short123")},
+ }
+ err := p.resolveFullMergeCommitSHA(t.Context(), pr)
+ assert.Error(t, err)
+ })
+}
+
+func TestParseRepoURL(t *testing.T) {
+ tests := []struct {
+ name string
+ url string
+ wantHost string
+ wantOwner string
+ wantSlug string
+ wantErr bool
+ }{
+ {
+ name: "valid URL",
+ url: "https://bitbucket.org/owner/repo",
+ wantHost: "bitbucket.org",
+ wantOwner: "owner",
+ wantSlug: "repo",
+ },
+ {
+ name: "valid URL with trailing slash",
+ url: "https://bitbucket.org/owner/repo/",
+ wantHost: "bitbucket.org",
+ wantOwner: "owner",
+ wantSlug: "repo",
+ },
+ {
+ name: "valid URL with .git suffix",
+ url: "https://bitbucket.org/owner/repo.git",
+ wantHost: "bitbucket.org",
+ wantOwner: "owner",
+ wantSlug: "repo",
+ },
+ {
+ name: "valid SSH URL",
+ url: "git@bitbucket.org:owner/repo.git",
+ wantHost: "bitbucket.org",
+ wantOwner: "owner",
+ wantSlug: "repo",
+ },
+ {
+ name: "invalid URL format",
+ url: "://invalid-url",
+ wantErr: true,
+ },
+ {
+ name: "missing repository name",
+ url: "https://bitbucket.org/owner",
+ wantErr: true,
+ },
+ {
+ name: "too many path segments",
+ url: "https://bitbucket.org/owner/repo/extra",
+ wantErr: true,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ host, owner, slug, err := parseRepoURL(tt.url)
+ if tt.wantErr {
+ assert.Error(t, err)
+ return
+ }
+ require.NoError(t, err)
+ assert.Equal(t, tt.wantHost, host)
+ assert.Equal(t, tt.wantOwner, owner)
+ assert.Equal(t, tt.wantSlug, slug)
+ })
+ }
+}
+
+func Test_toProviderPR(t *testing.T) {
+ t.Run("valid conversion: open PR", func(t *testing.T) {
+ bbPR := prFromJSON(t, `{
+ "id": 1,
+ "state": "OPEN",
+ "links": {"html": {"href": "https://bitbucket.org/owner/repo/pull-requests/1"}},
+ "source": {"commit": {"hash": "abcdef1234567890"}},
+ "created_on": "2023-01-01T12:00:00Z",
+ "type": "pullrequest"
+ }`)
+ pr := toProviderPR(bbPR)
+ require.NotNil(t, pr)
+ assert.Equal(t, int64(1), pr.Number)
+ assert.Equal(t, "https://bitbucket.org/owner/repo/pull-requests/1", pr.URL)
+ assert.Equal(t, "abcdef1234567890", pr.HeadSHA)
+ assert.True(t, pr.Open)
+ assert.False(t, pr.Merged)
+ assert.NotNil(t, pr.CreatedAt)
+ assert.Equal(t, bbPR, pr.Object)
+ })
+
+ t.Run("valid conversion: merged PR", func(t *testing.T) {
+ bbPR := &Pullrequest{
+ Id: intPtr(1),
+ State: statePtr(PullrequestStateMERGED),
+ MergeCommit: &struct {
+ Hash *string `json:"hash,omitempty"`
+ }{Hash: strPtr("merged1234567890")},
+ }
+ pr := toProviderPR(bbPR)
+ require.NotNil(t, pr)
+ assert.False(t, pr.Open)
+ assert.True(t, pr.Merged)
+ assert.Equal(t, "merged1234567890", pr.MergeCommitSHA)
+ })
+
+ t.Run("nil input", func(t *testing.T) {
+ assert.Nil(t, toProviderPR(nil))
+ })
+
+ t.Run("no created_on", func(t *testing.T) {
+ pr := toProviderPR(&Pullrequest{Id: intPtr(1)})
+ require.NotNil(t, pr)
+ assert.Nil(t, pr.CreatedAt)
+ })
+}
+
+func TestGetCommitURL(t *testing.T) {
+ testCases := []struct {
+ repoURL string
+ sha string
+ expectedCommitURL string
+ }{
+ {
+ repoURL: "ssh://git@bitbucket.org/akuity/kargo.git",
+ sha: "sha",
+ expectedCommitURL: "https://bitbucket.org/akuity/kargo/commits/sha",
+ },
+ {
+ repoURL: "git@bitbucket.org:akuity/kargo.git",
+ sha: "sha",
+ expectedCommitURL: "https://bitbucket.org/akuity/kargo/commits/sha",
+ },
+ {
+ repoURL: "https://username@bitbucket.org/akuity/kargo",
+ sha: "sha",
+ expectedCommitURL: "https://bitbucket.org/akuity/kargo/commits/sha",
+ },
+ {
+ repoURL: "http://bitbucket.org/akuity/kargo.git",
+ sha: "sha",
+ expectedCommitURL: "https://bitbucket.org/akuity/kargo/commits/sha",
+ },
+ }
+
+ p := &provider{}
+ for _, tc := range testCases {
+ t.Run(tc.repoURL, func(t *testing.T) {
+ commitURL, err := p.GetCommitURL(tc.repoURL, tc.sha)
+ require.NoError(t, err)
+ require.Equal(t, tc.expectedCommitURL, commitURL)
+ })
+ }
+}
diff --git a/pkg/gitprovider/bitbucket/cloud/spec/bitbucket.gen.json b/pkg/gitprovider/bitbucket/cloud/spec/bitbucket.gen.json
new file mode 100644
index 0000000000..5bfbb31a88
--- /dev/null
+++ b/pkg/gitprovider/bitbucket/cloud/spec/bitbucket.gen.json
@@ -0,0 +1,1840 @@
+{
+ "openapi": "3.0.0",
+ "info": {
+ "title": "Bitbucket API",
+ "description": "Code against the Bitbucket API to automate simple tasks, embed Bitbucket data into your own site, build mobile or desktop apps, or even add custom UI add-ons into Bitbucket itself using the Connect framework.",
+ "version": "2.0",
+ "termsOfService": "https://www.atlassian.com/legal/customer-agreement",
+ "contact": {
+ "name": "Bitbucket Support",
+ "url": "https://support.atlassian.com/bitbucket-cloud/",
+ "email": "support@bitbucket.org"
+ }
+ },
+ "servers": [
+ {
+ "url": "https://api.bitbucket.org/2.0"
+ }
+ ],
+ "paths": {
+ "/repositories/{workspace}/{repo_slug}/pullrequests": {
+ "get": {
+ "tags": [
+ "Pullrequests"
+ ],
+ "description": "Returns all pull requests on the specified repository.\n\nBy default only open pull requests are returned. This can be controlled\nusing the `state` query parameter. To retrieve pull requests that are\nin one of multiple states, repeat the `state` parameter for each\nindividual state.\n\nThis endpoint also supports filtering and sorting of the results. See\n[filtering and sorting](/cloud/bitbucket/rest/intro/#filtering) for more details.",
+ "summary": "List pull requests",
+ "responses": {
+ "200": {
+ "description": "All pull requests on the specified repository.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/paginated_pullrequests"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "If the repository is private and the request was not authenticated."
+ },
+ "404": {
+ "description": "If the specified repository does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/error"
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "state",
+ "in": "query",
+ "description": "Only return pull requests that are in this state. This parameter can be repeated.",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "OPEN",
+ "MERGED",
+ "DECLINED",
+ "SUPERSEDED"
+ ]
+ }
+ }
+ ],
+ "security": [
+ {
+ "oauth2": [
+ "pullrequest"
+ ]
+ },
+ {
+ "basic": []
+ },
+ {
+ "api_key": []
+ }
+ ],
+ "x-atlassian-oauth2-scopes": [
+ {
+ "state": "Current",
+ "scheme": "oauth2",
+ "scopes": [
+ "read:pullrequest:bitbucket"
+ ]
+ }
+ ],
+ "x-atlassian-auth-types": [
+ "forge-oauth2",
+ "api-token"
+ ]
+ },
+ "post": {
+ "tags": [
+ "Pullrequests"
+ ],
+ "description": "Creates a new pull request where the destination repository is\nthis repository and the author is the authenticated user.\n\nThe minimum required fields to create a pull request are `title` and\n`source`, specified by a branch name.\n\n```\ncurl https://api.bitbucket.org/2.0/repositories/my-workspace/my-repository/pullrequests \\\n -u my-username:my-password \\\n --request POST \\\n --header 'Content-Type: application/json' \\\n --data '{\n \"title\": \"My Title\",\n \"source\": {\n \"branch\": {\n \"name\": \"staging\"\n }\n }\n }'\n```\n\nIf the pull request's `destination` is not specified, it will default\nto the `repository.mainbranch`. To open a pull request to a\ndifferent branch, say from a feature branch to a staging branch,\nspecify a `destination` (same format as the `source`):\n\n```\n{\n \"title\": \"My Title\",\n \"source\": {\n \"branch\": {\n \"name\": \"my-feature-branch\"\n }\n },\n \"destination\": {\n \"branch\": {\n \"name\": \"staging\"\n }\n }\n}\n```\n\nReviewers can be specified by adding an array of user objects as the\n`reviewers` property.\n\n```\n{\n \"title\": \"My Title\",\n \"source\": {\n \"branch\": {\n \"name\": \"my-feature-branch\"\n }\n },\n \"reviewers\": [\n {\n \"uuid\": \"{504c3b62-8120-4f0c-a7bc-87800b9d6f70}\"\n }\n ]\n}\n```\n\nOther fields:\n\n* `description` - a string\n* `close_source_branch` - boolean that specifies if the source branch should be closed upon merging\n* `draft` - boolean that specifies whether the pull request is a draft",
+ "summary": "Create a pull request",
+ "responses": {
+ "201": {
+ "description": "The newly created pull request.",
+ "headers": {
+ "Location": {
+ "description": "The URL of new newly created pull request.",
+ "schema": {
+ "type": "string"
+ }
+ }
+ },
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/pullrequest"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "If the input document was invalid, or if the caller lacks the privilege to create repositories under the targeted account.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/error"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "If the request was not authenticated.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/error"
+ }
+ }
+ }
+ }
+ },
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/pullrequest"
+ }
+ }
+ },
+ "description": "The new pull request.\n\nThe request URL you POST to becomes the destination repository URL. For this reason, you must specify an explicit source repository in the request object if you want to pull from a different repository (fork).\n\nSince not all elements are required or even mutable, you only need to include the elements you want to initialize, such as the source branch and the title."
+ },
+ "security": [
+ {
+ "oauth2": [
+ "pullrequest:write"
+ ]
+ },
+ {
+ "basic": []
+ },
+ {
+ "api_key": []
+ }
+ ],
+ "x-atlassian-oauth2-scopes": [
+ {
+ "state": "Current",
+ "scheme": "oauth2",
+ "scopes": [
+ "read:pullrequest:bitbucket",
+ "write:pullrequest:bitbucket"
+ ]
+ }
+ ],
+ "x-atlassian-auth-types": [
+ "forge-oauth2",
+ "api-token"
+ ]
+ },
+ "parameters": [
+ {
+ "name": "repo_slug",
+ "in": "path",
+ "description": "This can either be the repository slug or the UUID of the repository,\nsurrounded by curly-braces, for example: `{repository UUID}`.\n",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "workspace",
+ "in": "path",
+ "description": "This can either be the workspace ID (slug) or the workspace UUID\nsurrounded by curly-braces, for example: `{workspace UUID}`.\n",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ]
+ },
+ "/repositories/{workspace}/{repo_slug}/pullrequests/{pull_request_id}": {
+ "get": {
+ "tags": [
+ "Pullrequests"
+ ],
+ "description": "Returns the specified pull request.",
+ "summary": "Get a pull request",
+ "responses": {
+ "200": {
+ "description": "The pull request object",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/pullrequest"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "If the repository is private and the request was not authenticated."
+ },
+ "404": {
+ "description": "If the repository or pull request does not exist",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/error"
+ }
+ }
+ }
+ }
+ },
+ "security": [
+ {
+ "oauth2": [
+ "pullrequest"
+ ]
+ },
+ {
+ "basic": []
+ },
+ {
+ "api_key": []
+ }
+ ],
+ "x-atlassian-oauth2-scopes": [
+ {
+ "state": "Current",
+ "scheme": "oauth2",
+ "scopes": [
+ "read:pullrequest:bitbucket"
+ ]
+ }
+ ],
+ "x-atlassian-auth-types": [
+ "forge-oauth2",
+ "api-token"
+ ]
+ },
+ "parameters": [
+ {
+ "name": "pull_request_id",
+ "in": "path",
+ "description": "The id of the pull request.",
+ "required": true,
+ "schema": {
+ "type": "integer"
+ }
+ },
+ {
+ "name": "repo_slug",
+ "in": "path",
+ "description": "This can either be the repository slug or the UUID of the repository,\nsurrounded by curly-braces, for example: `{repository UUID}`.\n",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "workspace",
+ "in": "path",
+ "description": "This can either be the workspace ID (slug) or the workspace UUID\nsurrounded by curly-braces, for example: `{workspace UUID}`.\n",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ]
+ },
+ "/repositories/{workspace}/{repo_slug}/pullrequests/{pull_request_id}/merge": {
+ "post": {
+ "tags": [
+ "Pullrequests"
+ ],
+ "description": "Merges the pull request.",
+ "summary": "Merge a pull request",
+ "responses": {
+ "200": {
+ "description": "The pull request object.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/pullrequest"
+ }
+ }
+ }
+ },
+ "202": {
+ "description": "In the Location header, the URL to poll for the pull request merge status"
+ },
+ "409": {
+ "description": "Unable to merge because one of the refs involved changed while attempting to merge"
+ },
+ "555": {
+ "description": "If the merge took too long and timed out.\nIn this case the caller should retry the request later",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/error"
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "async",
+ "in": "query",
+ "description": "Default value is false.\n\n\nWhen set to true, runs merge asynchronously and\nimmediately returns a 202 with polling link to\nthe task-status API in the Location header.\n\n\nWhen set to false, runs merge and waits for it to\ncomplete, returning 200 when it succeeds. If the\nduration of the merge exceeds a timeout threshold,\nthe API returns a 202 with polling link to the\ntask-status API in the Location header.",
+ "required": false,
+ "schema": {
+ "type": "boolean"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/pullrequest_merge_parameters"
+ }
+ }
+ }
+ },
+ "security": [
+ {
+ "oauth2": [
+ "pullrequest:write"
+ ]
+ },
+ {
+ "basic": []
+ },
+ {
+ "api_key": []
+ }
+ ],
+ "x-atlassian-oauth2-scopes": [
+ {
+ "state": "Current",
+ "scheme": "oauth2",
+ "scopes": [
+ "read:pullrequest:bitbucket",
+ "write:pullrequest:bitbucket"
+ ]
+ }
+ ],
+ "x-atlassian-auth-types": [
+ "forge-oauth2",
+ "api-token"
+ ]
+ },
+ "parameters": [
+ {
+ "name": "pull_request_id",
+ "in": "path",
+ "description": "The id of the pull request.",
+ "required": true,
+ "schema": {
+ "type": "integer"
+ }
+ },
+ {
+ "name": "repo_slug",
+ "in": "path",
+ "description": "This can either be the repository slug or the UUID of the repository,\nsurrounded by curly-braces, for example: `{repository UUID}`.\n",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "workspace",
+ "in": "path",
+ "description": "This can either be the workspace ID (slug) or the workspace UUID\nsurrounded by curly-braces, for example: `{workspace UUID}`.\n",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ]
+ },
+ "/repositories/{workspace}/{repo_slug}/commit/{commit}": {
+ "get": {
+ "tags": [
+ "Commits"
+ ],
+ "description": "Returns the specified commit.",
+ "summary": "Get a commit",
+ "responses": {
+ "200": {
+ "description": "The commit object",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/commit"
+ },
+ "examples": {
+ "response": {
+ "value": {
+ "rendered": {
+ "message": {
+ "raw": "Add a GEORDI_OUTPUT_DIR setting",
+ "markup": "markdown",
+ "html": "Add a GEORDI_OUTPUT_DIR setting
",
+ "type": "rendered"
+ }
+ },
+ "hash": "f7591a13eda445d9a9167f98eb870319f4b6c2d8",
+ "repository": {
+ "name": "geordi",
+ "type": "repository",
+ "full_name": "bitbucket/geordi",
+ "links": {
+ "self": {
+ "href": "https://api.bitbucket.org/2.0/repositories/bitbucket/geordi"
+ },
+ "html": {
+ "href": "https://bitbucket.org/bitbucket/geordi"
+ },
+ "avatar": {
+ "href": "https://bytebucket.org/ravatar/%7B85d08b4e-571d-44e9-a507-fa476535aa98%7D?ts=1730260"
+ }
+ },
+ "uuid": "{85d08b4e-571d-44e9-a507-fa476535aa98}"
+ },
+ "links": {
+ "self": {
+ "href": "https://api.bitbucket.org/2.0/repositories/bitbucket/geordi/commit/f7591a13eda445d9a9167f98eb870319f4b6c2d8"
+ },
+ "comments": {
+ "href": "https://api.bitbucket.org/2.0/repositories/bitbucket/geordi/commit/f7591a13eda445d9a9167f98eb870319f4b6c2d8/comments"
+ },
+ "patch": {
+ "href": "https://api.bitbucket.org/2.0/repositories/bitbucket/geordi/patch/f7591a13eda445d9a9167f98eb870319f4b6c2d8"
+ },
+ "html": {
+ "href": "https://bitbucket.org/bitbucket/geordi/commits/f7591a13eda445d9a9167f98eb870319f4b6c2d8"
+ },
+ "diff": {
+ "href": "https://api.bitbucket.org/2.0/repositories/bitbucket/geordi/diff/f7591a13eda445d9a9167f98eb870319f4b6c2d8"
+ },
+ "approve": {
+ "href": "https://api.bitbucket.org/2.0/repositories/bitbucket/geordi/commit/f7591a13eda445d9a9167f98eb870319f4b6c2d8/approve"
+ },
+ "statuses": {
+ "href": "https://api.bitbucket.org/2.0/repositories/bitbucket/geordi/commit/f7591a13eda445d9a9167f98eb870319f4b6c2d8/statuses"
+ }
+ },
+ "author": {
+ "raw": "Brodie Rao ",
+ "type": "author",
+ "user": {
+ "display_name": "Brodie Rao",
+ "uuid": "{9484702e-c663-4afd-aefb-c93a8cd31c28}",
+ "links": {
+ "self": {
+ "href": "https://api.bitbucket.org/2.0/users/%7B9484702e-c663-4afd-aefb-c93a8cd31c28%7D"
+ },
+ "html": {
+ "href": "https://bitbucket.org/%7B9484702e-c663-4afd-aefb-c93a8cd31c28%7D/"
+ },
+ "avatar": {
+ "href": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/557058:3aae1e05-702a-41e5-81c8-f36f29afb6ca/613070db-28b0-421f-8dba-ae8a87e2a5c7/128"
+ }
+ },
+ "type": "user",
+ "nickname": "brodie",
+ "account_id": "557058:3aae1e05-702a-41e5-81c8-f36f29afb6ca"
+ }
+ },
+ "summary": {
+ "raw": "Add a GEORDI_OUTPUT_DIR setting",
+ "markup": "markdown",
+ "html": "Add a GEORDI_OUTPUT_DIR setting
",
+ "type": "rendered"
+ },
+ "participants": [],
+ "parents": [
+ {
+ "type": "commit",
+ "hash": "f06941fec4ef6bcb0c2456927a0cf258fa4f899b",
+ "links": {
+ "self": {
+ "href": "https://api.bitbucket.org/2.0/repositories/bitbucket/geordi/commit/f06941fec4ef6bcb0c2456927a0cf258fa4f899b"
+ },
+ "html": {
+ "href": "https://bitbucket.org/bitbucket/geordi/commits/f06941fec4ef6bcb0c2456927a0cf258fa4f899b"
+ }
+ }
+ }
+ ],
+ "date": "2012-07-16T19:37:54+00:00",
+ "message": "Add a GEORDI_OUTPUT_DIR setting",
+ "type": "commit"
+ }
+ }
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "If the specified commit or repository does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/error"
+ }
+ }
+ }
+ }
+ },
+ "security": [
+ {
+ "oauth2": [
+ "repository"
+ ]
+ },
+ {
+ "basic": []
+ },
+ {
+ "api_key": []
+ }
+ ],
+ "x-atlassian-oauth2-scopes": [
+ {
+ "state": "Current",
+ "scheme": "oauth2",
+ "scopes": [
+ "read:repository:bitbucket"
+ ]
+ }
+ ],
+ "x-atlassian-auth-types": [
+ "forge-oauth2",
+ "api-token"
+ ]
+ },
+ "parameters": [
+ {
+ "name": "commit",
+ "in": "path",
+ "description": "The commit's SHA1.",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "repo_slug",
+ "in": "path",
+ "description": "This can either be the repository slug or the UUID of the repository,\nsurrounded by curly-braces, for example: `{repository UUID}`.\n",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "workspace",
+ "in": "path",
+ "description": "This can either be the workspace ID (slug) or the workspace UUID\nsurrounded by curly-braces, for example: `{workspace UUID}`.\n",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ]
+ }
+ },
+ "components": {
+ "schemas": {
+ "base_commit": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/object"
+ },
+ {
+ "type": "object",
+ "title": "Base Commit",
+ "description": "The common base type for both repository and snippet commits.",
+ "properties": {
+ "hash": {
+ "type": "string",
+ "pattern": "[0-9a-f]{7,}?"
+ },
+ "date": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "author": {
+ "$ref": "#/components/schemas/author"
+ },
+ "committer": {
+ "$ref": "#/components/schemas/committer"
+ },
+ "message": {
+ "type": "string"
+ },
+ "summary": {
+ "type": "object",
+ "properties": {
+ "raw": {
+ "type": "string",
+ "description": "The text as it was typed by a user."
+ },
+ "markup": {
+ "type": "string",
+ "description": "The type of markup language the raw content is to be interpreted in.",
+ "enum": [
+ "markdown",
+ "creole",
+ "plaintext"
+ ]
+ },
+ "html": {
+ "type": "string",
+ "description": "The user's content rendered as HTML."
+ }
+ },
+ "additionalProperties": false
+ },
+ "parents": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/base_commit"
+ },
+ "minItems": 0
+ }
+ },
+ "additionalProperties": true
+ }
+ ]
+ },
+ "team_links": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/account_links"
+ },
+ {
+ "type": "object",
+ "title": "Team Links",
+ "description": "Links related to a Team.",
+ "properties": {
+ "self": {
+ "$ref": "#/components/schemas/link"
+ },
+ "html": {
+ "$ref": "#/components/schemas/link"
+ },
+ "members": {
+ "$ref": "#/components/schemas/link"
+ },
+ "projects": {
+ "$ref": "#/components/schemas/link"
+ },
+ "repositories": {
+ "$ref": "#/components/schemas/link"
+ }
+ },
+ "additionalProperties": true
+ }
+ ]
+ },
+ "committer": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/object"
+ },
+ {
+ "type": "object",
+ "title": "Committer",
+ "description": "The committer of a change in a repository",
+ "properties": {
+ "raw": {
+ "type": "string",
+ "description": "The raw committer value from the repository. This may be the only value available if the committer does not match a user in Bitbucket."
+ },
+ "user": {
+ "$ref": "#/components/schemas/account"
+ }
+ },
+ "additionalProperties": true
+ }
+ ]
+ },
+ "ref": {
+ "type": "object",
+ "title": "Ref",
+ "description": "A ref object, representing a branch or tag in a repository.",
+ "properties": {
+ "type": {
+ "type": "string"
+ },
+ "links": {
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "commits": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "html": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "name": {
+ "type": "string",
+ "description": "The name of the ref."
+ },
+ "target": {
+ "$ref": "#/components/schemas/commit"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": true
+ },
+ "account": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/object"
+ },
+ {
+ "type": "object",
+ "title": "Account",
+ "description": "An account object.",
+ "properties": {
+ "links": {
+ "$ref": "#/components/schemas/account_links"
+ },
+ "created_on": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "display_name": {
+ "type": "string"
+ },
+ "uuid": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": true
+ }
+ ]
+ },
+ "pullrequest": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/object"
+ },
+ {
+ "type": "object",
+ "title": "Pull Request",
+ "description": "A pull request object.",
+ "properties": {
+ "links": {
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "html": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "commits": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "approve": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "diff": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "diffstat": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "comments": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "activity": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "merge": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "decline": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "id": {
+ "type": "integer",
+ "description": "The pull request's unique ID. Note that pull request IDs are only unique within their associated repository."
+ },
+ "title": {
+ "type": "string",
+ "description": "Title of the pull request."
+ },
+ "rendered": {
+ "type": "object",
+ "title": "Rendered Pull Request Markup",
+ "description": "User provided pull request text, interpreted in a markup language and rendered in HTML",
+ "properties": {
+ "title": {
+ "type": "object",
+ "properties": {
+ "raw": {
+ "type": "string",
+ "description": "The text as it was typed by a user."
+ },
+ "markup": {
+ "type": "string",
+ "description": "The type of markup language the raw content is to be interpreted in.",
+ "enum": [
+ "markdown",
+ "creole",
+ "plaintext"
+ ]
+ },
+ "html": {
+ "type": "string",
+ "description": "The user's content rendered as HTML."
+ }
+ },
+ "additionalProperties": false
+ },
+ "description": {
+ "type": "object",
+ "properties": {
+ "raw": {
+ "type": "string",
+ "description": "The text as it was typed by a user."
+ },
+ "markup": {
+ "type": "string",
+ "description": "The type of markup language the raw content is to be interpreted in.",
+ "enum": [
+ "markdown",
+ "creole",
+ "plaintext"
+ ]
+ },
+ "html": {
+ "type": "string",
+ "description": "The user's content rendered as HTML."
+ }
+ },
+ "additionalProperties": false
+ },
+ "reason": {
+ "type": "object",
+ "properties": {
+ "raw": {
+ "type": "string",
+ "description": "The text as it was typed by a user."
+ },
+ "markup": {
+ "type": "string",
+ "description": "The type of markup language the raw content is to be interpreted in.",
+ "enum": [
+ "markdown",
+ "creole",
+ "plaintext"
+ ]
+ },
+ "html": {
+ "type": "string",
+ "description": "The user's content rendered as HTML."
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "summary": {
+ "type": "object",
+ "properties": {
+ "raw": {
+ "type": "string",
+ "description": "The text as it was typed by a user."
+ },
+ "markup": {
+ "type": "string",
+ "description": "The type of markup language the raw content is to be interpreted in.",
+ "enum": [
+ "markdown",
+ "creole",
+ "plaintext"
+ ]
+ },
+ "html": {
+ "type": "string",
+ "description": "The user's content rendered as HTML."
+ }
+ },
+ "additionalProperties": false
+ },
+ "state": {
+ "type": "string",
+ "description": "The pull request's current status.",
+ "enum": [
+ "OPEN",
+ "DRAFT",
+ "QUEUED",
+ "MERGED",
+ "DECLINED",
+ "SUPERSEDED"
+ ]
+ },
+ "author": {
+ "$ref": "#/components/schemas/account"
+ },
+ "source": {
+ "$ref": "#/components/schemas/pullrequest_endpoint"
+ },
+ "destination": {
+ "$ref": "#/components/schemas/pullrequest_endpoint"
+ },
+ "merge_commit": {
+ "type": "object",
+ "title": "Pull Request Commit",
+ "properties": {
+ "hash": {
+ "type": "string",
+ "pattern": "[0-9a-f]{7,}?"
+ }
+ },
+ "additionalProperties": false
+ },
+ "comment_count": {
+ "type": "integer",
+ "description": "The number of comments for a specific pull request.",
+ "minimum": 0
+ },
+ "task_count": {
+ "type": "integer",
+ "description": "The number of open tasks for a specific pull request.",
+ "minimum": 0
+ },
+ "close_source_branch": {
+ "type": "boolean",
+ "description": "A boolean flag indicating if merging the pull request closes the source branch."
+ },
+ "closed_by": {
+ "$ref": "#/components/schemas/account"
+ },
+ "reason": {
+ "type": "string",
+ "description": "Explains why a pull request was declined. This field is only applicable to pull requests in rejected state."
+ },
+ "created_on": {
+ "type": "string",
+ "description": "The ISO8601 timestamp the request was created.",
+ "format": "date-time"
+ },
+ "updated_on": {
+ "type": "string",
+ "description": "The ISO8601 timestamp the request was last updated.",
+ "format": "date-time"
+ },
+ "reviewers": {
+ "type": "array",
+ "description": "The list of users that were added as reviewers on this pull request when it was created. For performance reasons, the API only includes this list on a pull request's `self` URL.",
+ "items": {
+ "$ref": "#/components/schemas/account"
+ }
+ },
+ "participants": {
+ "type": "array",
+ "description": " The list of users that are collaborating on this pull request.\n Collaborators are user that:\n\n * are added to the pull request as a reviewer (part of the reviewers\n list)\n * are not explicit reviewers, but have commented on the pull request\n * are not explicit reviewers, but have approved the pull request\n\n Each user is wrapped in an object that indicates the user's role and\n whether they have approved the pull request. For performance reasons,\n the API only returns this list when an API requests a pull request by\n id.\n ",
+ "items": {
+ "$ref": "#/components/schemas/participant"
+ }
+ },
+ "draft": {
+ "type": "boolean",
+ "description": "A boolean flag indicating whether the pull request is a draft."
+ },
+ "queued": {
+ "type": "boolean",
+ "description": "A boolean flag indicating whether the pull request is queued"
+ }
+ },
+ "additionalProperties": true
+ }
+ ]
+ },
+ "author": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/object"
+ },
+ {
+ "type": "object",
+ "title": "Author",
+ "description": "The author of a change in a repository",
+ "properties": {
+ "raw": {
+ "type": "string",
+ "description": "The raw author value from the repository. This may be the only value available if the author does not match a user in Bitbucket."
+ },
+ "user": {
+ "$ref": "#/components/schemas/account"
+ }
+ },
+ "additionalProperties": true
+ }
+ ]
+ },
+ "branch": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/ref"
+ },
+ {
+ "type": "object",
+ "title": "Branch",
+ "description": "A branch object, representing a branch in a repository.",
+ "properties": {
+ "merge_strategies": {
+ "type": "array",
+ "description": "Available merge strategies for pull requests targeting this branch.",
+ "items": {
+ "type": "string",
+ "enum": [
+ "merge_commit",
+ "squash",
+ "fast_forward",
+ "squash_fast_forward",
+ "rebase_fast_forward",
+ "rebase_merge"
+ ]
+ }
+ },
+ "default_merge_strategy": {
+ "type": "string",
+ "description": "The default merge strategy for pull requests targeting this branch."
+ }
+ },
+ "additionalProperties": true
+ }
+ ]
+ },
+ "repository": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/object"
+ },
+ {
+ "type": "object",
+ "title": "Repository",
+ "description": "A Bitbucket repository.",
+ "properties": {
+ "links": {
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "html": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "avatar": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "pullrequests": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "commits": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "forks": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "watchers": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "downloads": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "clone": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "hooks": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "uuid": {
+ "type": "string",
+ "description": "The repository's immutable id. This can be used as a substitute for the slug segment in URLs. Doing this guarantees your URLs will survive renaming of the repository by its owner, or even transfer of the repository to a different user."
+ },
+ "full_name": {
+ "type": "string",
+ "description": "The concatenation of the repository owner's username and the slugified name, e.g. \"evzijst/interruptingcow\". This is the same string used in Bitbucket URLs."
+ },
+ "is_private": {
+ "type": "boolean"
+ },
+ "parent": {
+ "$ref": "#/components/schemas/repository"
+ },
+ "scm": {
+ "type": "string",
+ "enum": [
+ "git"
+ ]
+ },
+ "owner": {
+ "$ref": "#/components/schemas/account"
+ },
+ "name": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "created_on": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "updated_on": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "size": {
+ "type": "integer"
+ },
+ "language": {
+ "type": "string"
+ },
+ "has_issues": {
+ "type": "boolean",
+ "description": "\nThe issue tracker for this repository is enabled. Issue Tracker\nfeatures are not supported for repositories in workspaces\nadministered through admin.atlassian.com.\n"
+ },
+ "has_wiki": {
+ "type": "boolean",
+ "description": "\nThe wiki for this repository is enabled. Wiki\nfeatures are not supported for repositories in workspaces\nadministered through admin.atlassian.com.\n"
+ },
+ "fork_policy": {
+ "type": "string",
+ "description": "\nControls the rules for forking this repository.\n\n* **allow_forks**: unrestricted forking\n* **no_public_forks**: restrict forking to private forks (forks cannot\n be made public later)\n* **no_forks**: deny all forking\n",
+ "enum": [
+ "allow_forks",
+ "no_public_forks",
+ "no_forks"
+ ]
+ },
+ "project": {
+ "$ref": "#/components/schemas/project"
+ },
+ "mainbranch": {
+ "$ref": "#/components/schemas/branch"
+ }
+ },
+ "additionalProperties": true
+ }
+ ]
+ },
+ "paginated_pullrequests": {
+ "type": "object",
+ "title": "Paginated Pull Requests",
+ "description": "A paginated list of pullrequests.",
+ "properties": {
+ "size": {
+ "type": "integer",
+ "description": "Total number of objects in the response. This is an optional element that is not provided in all responses, as it can be expensive to compute.",
+ "minimum": 0
+ },
+ "page": {
+ "type": "integer",
+ "description": "Page number of the current results. This is an optional element that is not provided in all responses.",
+ "minimum": 1
+ },
+ "pagelen": {
+ "type": "integer",
+ "description": "Current number of objects on the existing page. The default value is 10 with 100 being the maximum allowed value. Individual APIs may enforce different values.",
+ "minimum": 1
+ },
+ "next": {
+ "type": "string",
+ "description": "Link to the next page if it exists. The last page of a collection does not have this value. Use this link to navigate the result set and refrain from constructing your own URLs.",
+ "format": "uri"
+ },
+ "previous": {
+ "type": "string",
+ "description": "Link to previous page if it exists. A collections first page does not have this value. This is an optional element that is not provided in all responses. Some result sets strictly support forward navigation and never provide previous links. Clients must anticipate that backwards navigation is not always available. Use this link to navigate the result set and refrain from constructing your own URLs.",
+ "format": "uri"
+ },
+ "values": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/pullrequest"
+ },
+ "minItems": 0,
+ "uniqueItems": true
+ }
+ },
+ "additionalProperties": false
+ },
+ "pullrequest_endpoint": {
+ "type": "object",
+ "title": "Pull Request Endpoint",
+ "properties": {
+ "repository": {
+ "$ref": "#/components/schemas/repository"
+ },
+ "branch": {
+ "type": "object",
+ "title": "Pull Request Branch",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "merge_strategies": {
+ "type": "array",
+ "description": "Available merge strategies, when this endpoint is the destination of the pull request.",
+ "items": {
+ "type": "string",
+ "enum": [
+ "merge_commit",
+ "squash",
+ "fast_forward",
+ "squash_fast_forward",
+ "rebase_fast_forward",
+ "rebase_merge"
+ ]
+ }
+ },
+ "default_merge_strategy": {
+ "type": "string",
+ "description": "The default merge strategy, when this endpoint is the destination of the pull request."
+ }
+ },
+ "additionalProperties": false
+ },
+ "commit": {
+ "type": "object",
+ "title": "Pull Request Commit",
+ "properties": {
+ "hash": {
+ "type": "string",
+ "pattern": "[0-9a-f]{7,}?"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "team": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/account"
+ },
+ {
+ "type": "object",
+ "title": "Team",
+ "description": "A team object.",
+ "properties": {
+ "links": {
+ "$ref": "#/components/schemas/team_links"
+ }
+ },
+ "additionalProperties": true
+ }
+ ]
+ },
+ "project": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/object"
+ },
+ {
+ "type": "object",
+ "title": "Project",
+ "description": "A Bitbucket project.\n Projects are used by teams to organize repositories.",
+ "properties": {
+ "links": {
+ "type": "object",
+ "properties": {
+ "html": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "avatar": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "uuid": {
+ "type": "string",
+ "description": "The project's immutable id."
+ },
+ "key": {
+ "type": "string",
+ "description": "The project's key."
+ },
+ "owner": {
+ "$ref": "#/components/schemas/team"
+ },
+ "name": {
+ "type": "string",
+ "description": "The name of the project."
+ },
+ "description": {
+ "type": "string"
+ },
+ "is_private": {
+ "type": "boolean",
+ "description": "\nIndicates whether the project is publicly accessible, or whether it is\nprivate to the team and consequently only visible to team members.\nNote that private projects cannot contain public repositories."
+ },
+ "created_on": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "updated_on": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "has_publicly_visible_repos": {
+ "type": "boolean",
+ "description": "\nIndicates whether the project contains publicly visible repositories.\nNote that private projects cannot contain public repositories."
+ }
+ },
+ "additionalProperties": true
+ }
+ ]
+ },
+ "commit": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/base_commit"
+ },
+ {
+ "type": "object",
+ "title": "Commit",
+ "description": "A repository commit object.",
+ "properties": {
+ "repository": {
+ "$ref": "#/components/schemas/repository"
+ },
+ "participants": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/participant"
+ },
+ "minItems": 0
+ }
+ },
+ "additionalProperties": true
+ }
+ ]
+ },
+ "error": {
+ "type": "object",
+ "title": "Error",
+ "description": "Base type for most resource objects. It defines the common `type` element that identifies an object's type. It also identifies the element as Swagger's `discriminator`.",
+ "properties": {
+ "type": {
+ "type": "string"
+ },
+ "error": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string"
+ },
+ "detail": {
+ "type": "string"
+ },
+ "data": {
+ "type": "object",
+ "description": "Optional structured data that is endpoint-specific.",
+ "properties": {},
+ "additionalProperties": true
+ }
+ },
+ "required": [
+ "message"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": true
+ },
+ "participant": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/object"
+ },
+ {
+ "type": "object",
+ "title": "Participant",
+ "description": "Object describing a user's role on resources like commits or pull requests.",
+ "properties": {
+ "user": {
+ "$ref": "#/components/schemas/account"
+ },
+ "role": {
+ "type": "string",
+ "enum": [
+ "PARTICIPANT",
+ "REVIEWER"
+ ]
+ },
+ "approved": {
+ "type": "boolean"
+ },
+ "state": {
+ "type": "string",
+ "enum": [
+ "approved",
+ "changes_requested",
+ null
+ ]
+ },
+ "participated_on": {
+ "type": "string",
+ "description": "The ISO8601 timestamp of the participant's action. For approvers, this is the time of their approval. For commenters and pull request reviewers who are not approvers, this is the time they last commented, or null if they have not commented.",
+ "format": "date-time"
+ }
+ },
+ "additionalProperties": true
+ }
+ ]
+ },
+ "account_links": {
+ "type": "object",
+ "title": "Account Links",
+ "description": "Links related to an Account.",
+ "properties": {
+ "avatar": {
+ "$ref": "#/components/schemas/link"
+ }
+ },
+ "additionalProperties": true
+ },
+ "link": {
+ "type": "object",
+ "title": "Link",
+ "description": "A link to a resource related to this object.",
+ "properties": {
+ "href": {
+ "type": "string",
+ "format": "uri"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "object": {
+ "type": "object",
+ "description": "Base type for most resource objects. It defines the common `type` element that identifies an object's type. It also identifies the element as Swagger's `discriminator`.",
+ "properties": {
+ "type": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": true,
+ "discriminator": {
+ "propertyName": "type"
+ }
+ },
+ "pullrequest_merge_parameters": {
+ "type": "object",
+ "title": "Pull Request Merge Parameters",
+ "description": "The metadata that describes a pull request merge.",
+ "properties": {
+ "type": {
+ "type": "string"
+ },
+ "message": {
+ "type": "string",
+ "description": "The commit message that will be used on the resulting commit. Note that the size of the message is limited to 128 KiB."
+ },
+ "close_source_branch": {
+ "type": "boolean",
+ "description": "Whether the source branch should be deleted. If this is not provided, we fallback to the value used when the pull request was created, which defaults to False"
+ },
+ "merge_strategy": {
+ "type": "string",
+ "description": "The merge strategy that will be used to merge the pull request.",
+ "enum": [
+ "merge_commit",
+ "squash",
+ "fast_forward",
+ "squash_fast_forward",
+ "rebase_fast_forward",
+ "rebase_merge"
+ ],
+ "default": "merge_commit"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": true
+ }
+ }
+ }
+}
diff --git a/pkg/gitprovider/bitbucket/cloud/spec/oapi-codegen.yaml b/pkg/gitprovider/bitbucket/cloud/spec/oapi-codegen.yaml
new file mode 100644
index 0000000000..b1bdc1b07f
--- /dev/null
+++ b/pkg/gitprovider/bitbucket/cloud/spec/oapi-codegen.yaml
@@ -0,0 +1,10 @@
+package: cloud
+
+generate:
+ models: true
+ client: true
+
+output: zz_bitbucket_cloud_client.gen.go
+
+output-options:
+ skip-prune: false
diff --git a/pkg/gitprovider/bitbucket/cloud/zz_bitbucket_cloud_client.gen.go b/pkg/gitprovider/bitbucket/cloud/zz_bitbucket_cloud_client.gen.go
new file mode 100644
index 0000000000..312578fbf5
--- /dev/null
+++ b/pkg/gitprovider/bitbucket/cloud/zz_bitbucket_cloud_client.gen.go
@@ -0,0 +1,4526 @@
+// Package cloud provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.6.0 DO NOT EDIT.
+package cloud
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+ "time"
+
+ "github.com/oapi-codegen/runtime"
+)
+
+const (
+ Api_keyScopes = "api_key.Scopes"
+ BasicScopes = "basic.Scopes"
+ Oauth2Scopes = "oauth2.Scopes"
+)
+
+// Defines values for BaseCommitSummaryMarkup.
+const (
+ BaseCommitSummaryMarkupCreole BaseCommitSummaryMarkup = "creole"
+ BaseCommitSummaryMarkupMarkdown BaseCommitSummaryMarkup = "markdown"
+ BaseCommitSummaryMarkupPlaintext BaseCommitSummaryMarkup = "plaintext"
+)
+
+// Valid indicates whether the value is a known member of the BaseCommitSummaryMarkup enum.
+func (e BaseCommitSummaryMarkup) Valid() bool {
+ switch e {
+ case BaseCommitSummaryMarkupCreole:
+ return true
+ case BaseCommitSummaryMarkupMarkdown:
+ return true
+ case BaseCommitSummaryMarkupPlaintext:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for BranchMergeStrategies.
+const (
+ BranchMergeStrategiesFastForward BranchMergeStrategies = "fast_forward"
+ BranchMergeStrategiesMergeCommit BranchMergeStrategies = "merge_commit"
+ BranchMergeStrategiesRebaseFastForward BranchMergeStrategies = "rebase_fast_forward"
+ BranchMergeStrategiesRebaseMerge BranchMergeStrategies = "rebase_merge"
+ BranchMergeStrategiesSquash BranchMergeStrategies = "squash"
+ BranchMergeStrategiesSquashFastForward BranchMergeStrategies = "squash_fast_forward"
+)
+
+// Valid indicates whether the value is a known member of the BranchMergeStrategies enum.
+func (e BranchMergeStrategies) Valid() bool {
+ switch e {
+ case BranchMergeStrategiesFastForward:
+ return true
+ case BranchMergeStrategiesMergeCommit:
+ return true
+ case BranchMergeStrategiesRebaseFastForward:
+ return true
+ case BranchMergeStrategiesRebaseMerge:
+ return true
+ case BranchMergeStrategiesSquash:
+ return true
+ case BranchMergeStrategiesSquashFastForward:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for CommitSummaryMarkup.
+const (
+ CommitSummaryMarkupCreole CommitSummaryMarkup = "creole"
+ CommitSummaryMarkupMarkdown CommitSummaryMarkup = "markdown"
+ CommitSummaryMarkupPlaintext CommitSummaryMarkup = "plaintext"
+)
+
+// Valid indicates whether the value is a known member of the CommitSummaryMarkup enum.
+func (e CommitSummaryMarkup) Valid() bool {
+ switch e {
+ case CommitSummaryMarkupCreole:
+ return true
+ case CommitSummaryMarkupMarkdown:
+ return true
+ case CommitSummaryMarkupPlaintext:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for ParticipantRole.
+const (
+ PARTICIPANT ParticipantRole = "PARTICIPANT"
+ REVIEWER ParticipantRole = "REVIEWER"
+)
+
+// Valid indicates whether the value is a known member of the ParticipantRole enum.
+func (e ParticipantRole) Valid() bool {
+ switch e {
+ case PARTICIPANT:
+ return true
+ case REVIEWER:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for ParticipantState.
+const (
+ Approved ParticipantState = "approved"
+ ChangesRequested ParticipantState = "changes_requested"
+ LessThannil ParticipantState = ""
+)
+
+// Valid indicates whether the value is a known member of the ParticipantState enum.
+func (e ParticipantState) Valid() bool {
+ switch e {
+ case Approved:
+ return true
+ case ChangesRequested:
+ return true
+ case LessThannil:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for PullrequestRenderedDescriptionMarkup.
+const (
+ PullrequestRenderedDescriptionMarkupCreole PullrequestRenderedDescriptionMarkup = "creole"
+ PullrequestRenderedDescriptionMarkupMarkdown PullrequestRenderedDescriptionMarkup = "markdown"
+ PullrequestRenderedDescriptionMarkupPlaintext PullrequestRenderedDescriptionMarkup = "plaintext"
+)
+
+// Valid indicates whether the value is a known member of the PullrequestRenderedDescriptionMarkup enum.
+func (e PullrequestRenderedDescriptionMarkup) Valid() bool {
+ switch e {
+ case PullrequestRenderedDescriptionMarkupCreole:
+ return true
+ case PullrequestRenderedDescriptionMarkupMarkdown:
+ return true
+ case PullrequestRenderedDescriptionMarkupPlaintext:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for PullrequestRenderedReasonMarkup.
+const (
+ PullrequestRenderedReasonMarkupCreole PullrequestRenderedReasonMarkup = "creole"
+ PullrequestRenderedReasonMarkupMarkdown PullrequestRenderedReasonMarkup = "markdown"
+ PullrequestRenderedReasonMarkupPlaintext PullrequestRenderedReasonMarkup = "plaintext"
+)
+
+// Valid indicates whether the value is a known member of the PullrequestRenderedReasonMarkup enum.
+func (e PullrequestRenderedReasonMarkup) Valid() bool {
+ switch e {
+ case PullrequestRenderedReasonMarkupCreole:
+ return true
+ case PullrequestRenderedReasonMarkupMarkdown:
+ return true
+ case PullrequestRenderedReasonMarkupPlaintext:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for PullrequestRenderedTitleMarkup.
+const (
+ PullrequestRenderedTitleMarkupCreole PullrequestRenderedTitleMarkup = "creole"
+ PullrequestRenderedTitleMarkupMarkdown PullrequestRenderedTitleMarkup = "markdown"
+ PullrequestRenderedTitleMarkupPlaintext PullrequestRenderedTitleMarkup = "plaintext"
+)
+
+// Valid indicates whether the value is a known member of the PullrequestRenderedTitleMarkup enum.
+func (e PullrequestRenderedTitleMarkup) Valid() bool {
+ switch e {
+ case PullrequestRenderedTitleMarkupCreole:
+ return true
+ case PullrequestRenderedTitleMarkupMarkdown:
+ return true
+ case PullrequestRenderedTitleMarkupPlaintext:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for PullrequestState.
+const (
+ PullrequestStateDECLINED PullrequestState = "DECLINED"
+ PullrequestStateDRAFT PullrequestState = "DRAFT"
+ PullrequestStateMERGED PullrequestState = "MERGED"
+ PullrequestStateOPEN PullrequestState = "OPEN"
+ PullrequestStateQUEUED PullrequestState = "QUEUED"
+ PullrequestStateSUPERSEDED PullrequestState = "SUPERSEDED"
+)
+
+// Valid indicates whether the value is a known member of the PullrequestState enum.
+func (e PullrequestState) Valid() bool {
+ switch e {
+ case PullrequestStateDECLINED:
+ return true
+ case PullrequestStateDRAFT:
+ return true
+ case PullrequestStateMERGED:
+ return true
+ case PullrequestStateOPEN:
+ return true
+ case PullrequestStateQUEUED:
+ return true
+ case PullrequestStateSUPERSEDED:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for PullrequestSummaryMarkup.
+const (
+ PullrequestSummaryMarkupCreole PullrequestSummaryMarkup = "creole"
+ PullrequestSummaryMarkupMarkdown PullrequestSummaryMarkup = "markdown"
+ PullrequestSummaryMarkupPlaintext PullrequestSummaryMarkup = "plaintext"
+)
+
+// Valid indicates whether the value is a known member of the PullrequestSummaryMarkup enum.
+func (e PullrequestSummaryMarkup) Valid() bool {
+ switch e {
+ case PullrequestSummaryMarkupCreole:
+ return true
+ case PullrequestSummaryMarkupMarkdown:
+ return true
+ case PullrequestSummaryMarkupPlaintext:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for PullrequestEndpointBranchMergeStrategies.
+const (
+ PullrequestEndpointBranchMergeStrategiesFastForward PullrequestEndpointBranchMergeStrategies = "fast_forward"
+ PullrequestEndpointBranchMergeStrategiesMergeCommit PullrequestEndpointBranchMergeStrategies = "merge_commit"
+ PullrequestEndpointBranchMergeStrategiesRebaseFastForward PullrequestEndpointBranchMergeStrategies = "rebase_fast_forward"
+ PullrequestEndpointBranchMergeStrategiesRebaseMerge PullrequestEndpointBranchMergeStrategies = "rebase_merge"
+ PullrequestEndpointBranchMergeStrategiesSquash PullrequestEndpointBranchMergeStrategies = "squash"
+ PullrequestEndpointBranchMergeStrategiesSquashFastForward PullrequestEndpointBranchMergeStrategies = "squash_fast_forward"
+)
+
+// Valid indicates whether the value is a known member of the PullrequestEndpointBranchMergeStrategies enum.
+func (e PullrequestEndpointBranchMergeStrategies) Valid() bool {
+ switch e {
+ case PullrequestEndpointBranchMergeStrategiesFastForward:
+ return true
+ case PullrequestEndpointBranchMergeStrategiesMergeCommit:
+ return true
+ case PullrequestEndpointBranchMergeStrategiesRebaseFastForward:
+ return true
+ case PullrequestEndpointBranchMergeStrategiesRebaseMerge:
+ return true
+ case PullrequestEndpointBranchMergeStrategiesSquash:
+ return true
+ case PullrequestEndpointBranchMergeStrategiesSquashFastForward:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for PullrequestMergeParametersMergeStrategy.
+const (
+ FastForward PullrequestMergeParametersMergeStrategy = "fast_forward"
+ MergeCommit PullrequestMergeParametersMergeStrategy = "merge_commit"
+ RebaseFastForward PullrequestMergeParametersMergeStrategy = "rebase_fast_forward"
+ RebaseMerge PullrequestMergeParametersMergeStrategy = "rebase_merge"
+ Squash PullrequestMergeParametersMergeStrategy = "squash"
+ SquashFastForward PullrequestMergeParametersMergeStrategy = "squash_fast_forward"
+)
+
+// Valid indicates whether the value is a known member of the PullrequestMergeParametersMergeStrategy enum.
+func (e PullrequestMergeParametersMergeStrategy) Valid() bool {
+ switch e {
+ case FastForward:
+ return true
+ case MergeCommit:
+ return true
+ case RebaseFastForward:
+ return true
+ case RebaseMerge:
+ return true
+ case Squash:
+ return true
+ case SquashFastForward:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for RepositoryForkPolicy.
+const (
+ AllowForks RepositoryForkPolicy = "allow_forks"
+ NoForks RepositoryForkPolicy = "no_forks"
+ NoPublicForks RepositoryForkPolicy = "no_public_forks"
+)
+
+// Valid indicates whether the value is a known member of the RepositoryForkPolicy enum.
+func (e RepositoryForkPolicy) Valid() bool {
+ switch e {
+ case AllowForks:
+ return true
+ case NoForks:
+ return true
+ case NoPublicForks:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for RepositoryScm.
+const (
+ Git RepositoryScm = "git"
+)
+
+// Valid indicates whether the value is a known member of the RepositoryScm enum.
+func (e RepositoryScm) Valid() bool {
+ switch e {
+ case Git:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for GetRepositoriesWorkspaceRepoSlugPullrequestsParamsState.
+const (
+ GetRepositoriesWorkspaceRepoSlugPullrequestsParamsStateDECLINED GetRepositoriesWorkspaceRepoSlugPullrequestsParamsState = "DECLINED"
+ GetRepositoriesWorkspaceRepoSlugPullrequestsParamsStateMERGED GetRepositoriesWorkspaceRepoSlugPullrequestsParamsState = "MERGED"
+ GetRepositoriesWorkspaceRepoSlugPullrequestsParamsStateOPEN GetRepositoriesWorkspaceRepoSlugPullrequestsParamsState = "OPEN"
+ GetRepositoriesWorkspaceRepoSlugPullrequestsParamsStateSUPERSEDED GetRepositoriesWorkspaceRepoSlugPullrequestsParamsState = "SUPERSEDED"
+)
+
+// Valid indicates whether the value is a known member of the GetRepositoriesWorkspaceRepoSlugPullrequestsParamsState enum.
+func (e GetRepositoriesWorkspaceRepoSlugPullrequestsParamsState) Valid() bool {
+ switch e {
+ case GetRepositoriesWorkspaceRepoSlugPullrequestsParamsStateDECLINED:
+ return true
+ case GetRepositoriesWorkspaceRepoSlugPullrequestsParamsStateMERGED:
+ return true
+ case GetRepositoriesWorkspaceRepoSlugPullrequestsParamsStateOPEN:
+ return true
+ case GetRepositoriesWorkspaceRepoSlugPullrequestsParamsStateSUPERSEDED:
+ return true
+ default:
+ return false
+ }
+}
+
+// Account defines model for account.
+type Account struct {
+ CreatedOn *time.Time `json:"created_on,omitempty"`
+ DisplayName *string `json:"display_name,omitempty"`
+
+ // Links Links related to an Account.
+ Links *AccountLinks `json:"links,omitempty"`
+ Type string `json:"type"`
+ Uuid *string `json:"uuid,omitempty"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// AccountLinks Links related to an Account.
+type AccountLinks struct {
+ // Avatar A link to a resource related to this object.
+ Avatar *Link `json:"avatar,omitempty"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// Author defines model for author.
+type Author struct {
+ // Raw The raw author value from the repository. This may be the only value available if the author does not match a user in Bitbucket.
+ Raw *string `json:"raw,omitempty"`
+ Type string `json:"type"`
+ User *Account `json:"user,omitempty"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// BaseCommit defines model for base_commit.
+type BaseCommit struct {
+ Author *Author `json:"author,omitempty"`
+ Committer *Committer `json:"committer,omitempty"`
+ Date *time.Time `json:"date,omitempty"`
+ Hash *string `json:"hash,omitempty"`
+ Message *string `json:"message,omitempty"`
+ Parents *[]BaseCommit `json:"parents,omitempty"`
+ Summary *struct {
+ // Html The user's content rendered as HTML.
+ Html *string `json:"html,omitempty"`
+
+ // Markup The type of markup language the raw content is to be interpreted in.
+ Markup *BaseCommitSummaryMarkup `json:"markup,omitempty"`
+
+ // Raw The text as it was typed by a user.
+ Raw *string `json:"raw,omitempty"`
+ } `json:"summary,omitempty"`
+ Type string `json:"type"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// BaseCommitSummaryMarkup The type of markup language the raw content is to be interpreted in.
+type BaseCommitSummaryMarkup string
+
+// Branch defines model for branch.
+type Branch struct {
+ // DefaultMergeStrategy The default merge strategy for pull requests targeting this branch.
+ DefaultMergeStrategy *string `json:"default_merge_strategy,omitempty"`
+ Links *struct {
+ // Commits A link to a resource related to this object.
+ Commits *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"commits,omitempty"`
+
+ // Html A link to a resource related to this object.
+ Html *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"html,omitempty"`
+
+ // Self A link to a resource related to this object.
+ Self *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"self,omitempty"`
+ } `json:"links,omitempty"`
+
+ // MergeStrategies Available merge strategies for pull requests targeting this branch.
+ MergeStrategies *[]BranchMergeStrategies `json:"merge_strategies,omitempty"`
+
+ // Name The name of the ref.
+ Name *string `json:"name,omitempty"`
+ Target *Commit `json:"target,omitempty"`
+ Type string `json:"type"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// BranchMergeStrategies defines model for Branch.MergeStrategies.
+type BranchMergeStrategies string
+
+// Commit defines model for commit.
+type Commit struct {
+ Author *Author `json:"author,omitempty"`
+ Committer *Committer `json:"committer,omitempty"`
+ Date *time.Time `json:"date,omitempty"`
+ Hash *string `json:"hash,omitempty"`
+ Message *string `json:"message,omitempty"`
+ Parents *[]BaseCommit `json:"parents,omitempty"`
+ Participants *[]Participant `json:"participants,omitempty"`
+ Repository *Repository `json:"repository,omitempty"`
+ Summary *struct {
+ // Html The user's content rendered as HTML.
+ Html *string `json:"html,omitempty"`
+
+ // Markup The type of markup language the raw content is to be interpreted in.
+ Markup *CommitSummaryMarkup `json:"markup,omitempty"`
+
+ // Raw The text as it was typed by a user.
+ Raw *string `json:"raw,omitempty"`
+ } `json:"summary,omitempty"`
+ Type string `json:"type"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// CommitSummaryMarkup The type of markup language the raw content is to be interpreted in.
+type CommitSummaryMarkup string
+
+// Committer defines model for committer.
+type Committer struct {
+ // Raw The raw committer value from the repository. This may be the only value available if the committer does not match a user in Bitbucket.
+ Raw *string `json:"raw,omitempty"`
+ Type string `json:"type"`
+ User *Account `json:"user,omitempty"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// Error Base type for most resource objects. It defines the common `type` element that identifies an object's type. It also identifies the element as Swagger's `discriminator`.
+type Error struct {
+ Error *struct {
+ // Data Optional structured data that is endpoint-specific.
+ Data *map[string]interface{} `json:"data,omitempty"`
+ Detail *string `json:"detail,omitempty"`
+ Message string `json:"message"`
+ } `json:"error,omitempty"`
+ Type string `json:"type"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// Link A link to a resource related to this object.
+type Link struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+}
+
+// Object Base type for most resource objects. It defines the common `type` element that identifies an object's type. It also identifies the element as Swagger's `discriminator`.
+type Object struct {
+ Type string `json:"type"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// PaginatedPullrequests A paginated list of pullrequests.
+type PaginatedPullrequests struct {
+ // Next Link to the next page if it exists. The last page of a collection does not have this value. Use this link to navigate the result set and refrain from constructing your own URLs.
+ Next *string `json:"next,omitempty"`
+
+ // Page Page number of the current results. This is an optional element that is not provided in all responses.
+ Page *int `json:"page,omitempty"`
+
+ // Pagelen Current number of objects on the existing page. The default value is 10 with 100 being the maximum allowed value. Individual APIs may enforce different values.
+ Pagelen *int `json:"pagelen,omitempty"`
+
+ // Previous Link to previous page if it exists. A collections first page does not have this value. This is an optional element that is not provided in all responses. Some result sets strictly support forward navigation and never provide previous links. Clients must anticipate that backwards navigation is not always available. Use this link to navigate the result set and refrain from constructing your own URLs.
+ Previous *string `json:"previous,omitempty"`
+
+ // Size Total number of objects in the response. This is an optional element that is not provided in all responses, as it can be expensive to compute.
+ Size *int `json:"size,omitempty"`
+ Values *[]Pullrequest `json:"values,omitempty"`
+}
+
+// Participant defines model for participant.
+type Participant struct {
+ Approved *bool `json:"approved,omitempty"`
+
+ // ParticipatedOn The ISO8601 timestamp of the participant's action. For approvers, this is the time of their approval. For commenters and pull request reviewers who are not approvers, this is the time they last commented, or null if they have not commented.
+ ParticipatedOn *time.Time `json:"participated_on,omitempty"`
+ Role *ParticipantRole `json:"role,omitempty"`
+ State *ParticipantState `json:"state,omitempty"`
+ Type string `json:"type"`
+ User *Account `json:"user,omitempty"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// ParticipantRole defines model for Participant.Role.
+type ParticipantRole string
+
+// ParticipantState defines model for Participant.State.
+type ParticipantState string
+
+// Project defines model for project.
+type Project struct {
+ CreatedOn *time.Time `json:"created_on,omitempty"`
+ Description *string `json:"description,omitempty"`
+
+ // HasPubliclyVisibleRepos
+ // Indicates whether the project contains publicly visible repositories.
+ // Note that private projects cannot contain public repositories.
+ HasPubliclyVisibleRepos *bool `json:"has_publicly_visible_repos,omitempty"`
+
+ // IsPrivate
+ // Indicates whether the project is publicly accessible, or whether it is
+ // private to the team and consequently only visible to team members.
+ // Note that private projects cannot contain public repositories.
+ IsPrivate *bool `json:"is_private,omitempty"`
+
+ // Key The project's key.
+ Key *string `json:"key,omitempty"`
+ Links *struct {
+ // Avatar A link to a resource related to this object.
+ Avatar *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"avatar,omitempty"`
+
+ // Html A link to a resource related to this object.
+ Html *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"html,omitempty"`
+ } `json:"links,omitempty"`
+
+ // Name The name of the project.
+ Name *string `json:"name,omitempty"`
+ Owner *Team `json:"owner,omitempty"`
+ Type string `json:"type"`
+ UpdatedOn *time.Time `json:"updated_on,omitempty"`
+
+ // Uuid The project's immutable id.
+ Uuid *string `json:"uuid,omitempty"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// Pullrequest defines model for pullrequest.
+type Pullrequest struct {
+ Author *Account `json:"author,omitempty"`
+
+ // CloseSourceBranch A boolean flag indicating if merging the pull request closes the source branch.
+ CloseSourceBranch *bool `json:"close_source_branch,omitempty"`
+ ClosedBy *Account `json:"closed_by,omitempty"`
+
+ // CommentCount The number of comments for a specific pull request.
+ CommentCount *int `json:"comment_count,omitempty"`
+
+ // CreatedOn The ISO8601 timestamp the request was created.
+ CreatedOn *time.Time `json:"created_on,omitempty"`
+ Destination *PullrequestEndpoint `json:"destination,omitempty"`
+
+ // Draft A boolean flag indicating whether the pull request is a draft.
+ Draft *bool `json:"draft,omitempty"`
+
+ // Id The pull request's unique ID. Note that pull request IDs are only unique within their associated repository.
+ Id *int `json:"id,omitempty"`
+ Links *struct {
+ // Activity A link to a resource related to this object.
+ Activity *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"activity,omitempty"`
+
+ // Approve A link to a resource related to this object.
+ Approve *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"approve,omitempty"`
+
+ // Comments A link to a resource related to this object.
+ Comments *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"comments,omitempty"`
+
+ // Commits A link to a resource related to this object.
+ Commits *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"commits,omitempty"`
+
+ // Decline A link to a resource related to this object.
+ Decline *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"decline,omitempty"`
+
+ // Diff A link to a resource related to this object.
+ Diff *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"diff,omitempty"`
+
+ // Diffstat A link to a resource related to this object.
+ Diffstat *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"diffstat,omitempty"`
+
+ // Html A link to a resource related to this object.
+ Html *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"html,omitempty"`
+
+ // Merge A link to a resource related to this object.
+ Merge *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"merge,omitempty"`
+
+ // Self A link to a resource related to this object.
+ Self *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"self,omitempty"`
+ } `json:"links,omitempty"`
+ MergeCommit *struct {
+ Hash *string `json:"hash,omitempty"`
+ } `json:"merge_commit,omitempty"`
+
+ // Participants The list of users that are collaborating on this pull request.
+ // Collaborators are user that:
+ //
+ // * are added to the pull request as a reviewer (part of the reviewers
+ // list)
+ // * are not explicit reviewers, but have commented on the pull request
+ // * are not explicit reviewers, but have approved the pull request
+ //
+ // Each user is wrapped in an object that indicates the user's role and
+ // whether they have approved the pull request. For performance reasons,
+ // the API only returns this list when an API requests a pull request by
+ // id.
+ //
+ Participants *[]Participant `json:"participants,omitempty"`
+
+ // Queued A boolean flag indicating whether the pull request is queued
+ Queued *bool `json:"queued,omitempty"`
+
+ // Reason Explains why a pull request was declined. This field is only applicable to pull requests in rejected state.
+ Reason *string `json:"reason,omitempty"`
+
+ // Rendered User provided pull request text, interpreted in a markup language and rendered in HTML
+ Rendered *struct {
+ Description *struct {
+ // Html The user's content rendered as HTML.
+ Html *string `json:"html,omitempty"`
+
+ // Markup The type of markup language the raw content is to be interpreted in.
+ Markup *PullrequestRenderedDescriptionMarkup `json:"markup,omitempty"`
+
+ // Raw The text as it was typed by a user.
+ Raw *string `json:"raw,omitempty"`
+ } `json:"description,omitempty"`
+ Reason *struct {
+ // Html The user's content rendered as HTML.
+ Html *string `json:"html,omitempty"`
+
+ // Markup The type of markup language the raw content is to be interpreted in.
+ Markup *PullrequestRenderedReasonMarkup `json:"markup,omitempty"`
+
+ // Raw The text as it was typed by a user.
+ Raw *string `json:"raw,omitempty"`
+ } `json:"reason,omitempty"`
+ Title *struct {
+ // Html The user's content rendered as HTML.
+ Html *string `json:"html,omitempty"`
+
+ // Markup The type of markup language the raw content is to be interpreted in.
+ Markup *PullrequestRenderedTitleMarkup `json:"markup,omitempty"`
+
+ // Raw The text as it was typed by a user.
+ Raw *string `json:"raw,omitempty"`
+ } `json:"title,omitempty"`
+ } `json:"rendered,omitempty"`
+
+ // Reviewers The list of users that were added as reviewers on this pull request when it was created. For performance reasons, the API only includes this list on a pull request's `self` URL.
+ Reviewers *[]Account `json:"reviewers,omitempty"`
+ Source *PullrequestEndpoint `json:"source,omitempty"`
+
+ // State The pull request's current status.
+ State *PullrequestState `json:"state,omitempty"`
+ Summary *struct {
+ // Html The user's content rendered as HTML.
+ Html *string `json:"html,omitempty"`
+
+ // Markup The type of markup language the raw content is to be interpreted in.
+ Markup *PullrequestSummaryMarkup `json:"markup,omitempty"`
+
+ // Raw The text as it was typed by a user.
+ Raw *string `json:"raw,omitempty"`
+ } `json:"summary,omitempty"`
+
+ // TaskCount The number of open tasks for a specific pull request.
+ TaskCount *int `json:"task_count,omitempty"`
+
+ // Title Title of the pull request.
+ Title *string `json:"title,omitempty"`
+ Type string `json:"type"`
+
+ // UpdatedOn The ISO8601 timestamp the request was last updated.
+ UpdatedOn *time.Time `json:"updated_on,omitempty"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// PullrequestRenderedDescriptionMarkup The type of markup language the raw content is to be interpreted in.
+type PullrequestRenderedDescriptionMarkup string
+
+// PullrequestRenderedReasonMarkup The type of markup language the raw content is to be interpreted in.
+type PullrequestRenderedReasonMarkup string
+
+// PullrequestRenderedTitleMarkup The type of markup language the raw content is to be interpreted in.
+type PullrequestRenderedTitleMarkup string
+
+// PullrequestState The pull request's current status.
+type PullrequestState string
+
+// PullrequestSummaryMarkup The type of markup language the raw content is to be interpreted in.
+type PullrequestSummaryMarkup string
+
+// PullrequestEndpoint defines model for pullrequest_endpoint.
+type PullrequestEndpoint struct {
+ Branch *struct {
+ // DefaultMergeStrategy The default merge strategy, when this endpoint is the destination of the pull request.
+ DefaultMergeStrategy *string `json:"default_merge_strategy,omitempty"`
+
+ // MergeStrategies Available merge strategies, when this endpoint is the destination of the pull request.
+ MergeStrategies *[]PullrequestEndpointBranchMergeStrategies `json:"merge_strategies,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"branch,omitempty"`
+ Commit *struct {
+ Hash *string `json:"hash,omitempty"`
+ } `json:"commit,omitempty"`
+ Repository *Repository `json:"repository,omitempty"`
+}
+
+// PullrequestEndpointBranchMergeStrategies defines model for PullrequestEndpoint.Branch.MergeStrategies.
+type PullrequestEndpointBranchMergeStrategies string
+
+// PullrequestMergeParameters The metadata that describes a pull request merge.
+type PullrequestMergeParameters struct {
+ // CloseSourceBranch Whether the source branch should be deleted. If this is not provided, we fallback to the value used when the pull request was created, which defaults to False
+ CloseSourceBranch *bool `json:"close_source_branch,omitempty"`
+
+ // MergeStrategy The merge strategy that will be used to merge the pull request.
+ MergeStrategy *PullrequestMergeParametersMergeStrategy `json:"merge_strategy,omitempty"`
+
+ // Message The commit message that will be used on the resulting commit. Note that the size of the message is limited to 128 KiB.
+ Message *string `json:"message,omitempty"`
+ Type string `json:"type"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// PullrequestMergeParametersMergeStrategy The merge strategy that will be used to merge the pull request.
+type PullrequestMergeParametersMergeStrategy string
+
+// Ref A ref object, representing a branch or tag in a repository.
+type Ref struct {
+ Links *struct {
+ // Commits A link to a resource related to this object.
+ Commits *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"commits,omitempty"`
+
+ // Html A link to a resource related to this object.
+ Html *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"html,omitempty"`
+
+ // Self A link to a resource related to this object.
+ Self *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"self,omitempty"`
+ } `json:"links,omitempty"`
+
+ // Name The name of the ref.
+ Name *string `json:"name,omitempty"`
+ Target *Commit `json:"target,omitempty"`
+ Type string `json:"type"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// Repository defines model for repository.
+type Repository struct {
+ CreatedOn *time.Time `json:"created_on,omitempty"`
+ Description *string `json:"description,omitempty"`
+
+ // ForkPolicy
+ // Controls the rules for forking this repository.
+ //
+ // * **allow_forks**: unrestricted forking
+ // * **no_public_forks**: restrict forking to private forks (forks cannot
+ // be made public later)
+ // * **no_forks**: deny all forking
+ ForkPolicy *RepositoryForkPolicy `json:"fork_policy,omitempty"`
+
+ // FullName The concatenation of the repository owner's username and the slugified name, e.g. "evzijst/interruptingcow". This is the same string used in Bitbucket URLs.
+ FullName *string `json:"full_name,omitempty"`
+
+ // HasIssues
+ // The issue tracker for this repository is enabled. Issue Tracker
+ // features are not supported for repositories in workspaces
+ // administered through admin.atlassian.com.
+ HasIssues *bool `json:"has_issues,omitempty"`
+
+ // HasWiki
+ // The wiki for this repository is enabled. Wiki
+ // features are not supported for repositories in workspaces
+ // administered through admin.atlassian.com.
+ HasWiki *bool `json:"has_wiki,omitempty"`
+ IsPrivate *bool `json:"is_private,omitempty"`
+ Language *string `json:"language,omitempty"`
+ Links *struct {
+ // Avatar A link to a resource related to this object.
+ Avatar *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"avatar,omitempty"`
+ Clone *[]struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"clone,omitempty"`
+
+ // Commits A link to a resource related to this object.
+ Commits *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"commits,omitempty"`
+
+ // Downloads A link to a resource related to this object.
+ Downloads *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"downloads,omitempty"`
+
+ // Forks A link to a resource related to this object.
+ Forks *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"forks,omitempty"`
+
+ // Hooks A link to a resource related to this object.
+ Hooks *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"hooks,omitempty"`
+
+ // Html A link to a resource related to this object.
+ Html *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"html,omitempty"`
+
+ // Pullrequests A link to a resource related to this object.
+ Pullrequests *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"pullrequests,omitempty"`
+
+ // Self A link to a resource related to this object.
+ Self *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"self,omitempty"`
+
+ // Watchers A link to a resource related to this object.
+ Watchers *struct {
+ Href *string `json:"href,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"watchers,omitempty"`
+ } `json:"links,omitempty"`
+ Mainbranch *Branch `json:"mainbranch,omitempty"`
+ Name *string `json:"name,omitempty"`
+ Owner *Account `json:"owner,omitempty"`
+ Parent *Repository `json:"parent,omitempty"`
+ Project *Project `json:"project,omitempty"`
+ Scm *RepositoryScm `json:"scm,omitempty"`
+ Size *int `json:"size,omitempty"`
+ Type string `json:"type"`
+ UpdatedOn *time.Time `json:"updated_on,omitempty"`
+
+ // Uuid The repository's immutable id. This can be used as a substitute for the slug segment in URLs. Doing this guarantees your URLs will survive renaming of the repository by its owner, or even transfer of the repository to a different user.
+ Uuid *string `json:"uuid,omitempty"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// RepositoryForkPolicy
+// Controls the rules for forking this repository.
+//
+// - **allow_forks**: unrestricted forking
+// - **no_public_forks**: restrict forking to private forks (forks cannot
+// be made public later)
+// - **no_forks**: deny all forking
+type RepositoryForkPolicy string
+
+// RepositoryScm defines model for Repository.Scm.
+type RepositoryScm string
+
+// Team defines model for team.
+type Team struct {
+ CreatedOn *time.Time `json:"created_on,omitempty"`
+ DisplayName *string `json:"display_name,omitempty"`
+ Links *TeamLinks `json:"links,omitempty"`
+ Type string `json:"type"`
+ Uuid *string `json:"uuid,omitempty"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// TeamLinks defines model for team_links.
+type TeamLinks struct {
+ // Avatar A link to a resource related to this object.
+ Avatar *Link `json:"avatar,omitempty"`
+
+ // Html A link to a resource related to this object.
+ Html *Link `json:"html,omitempty"`
+
+ // Members A link to a resource related to this object.
+ Members *Link `json:"members,omitempty"`
+
+ // Projects A link to a resource related to this object.
+ Projects *Link `json:"projects,omitempty"`
+
+ // Repositories A link to a resource related to this object.
+ Repositories *Link `json:"repositories,omitempty"`
+
+ // Self A link to a resource related to this object.
+ Self *Link `json:"self,omitempty"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// GetRepositoriesWorkspaceRepoSlugPullrequestsParams defines parameters for GetRepositoriesWorkspaceRepoSlugPullrequests.
+type GetRepositoriesWorkspaceRepoSlugPullrequestsParams struct {
+ // State Only return pull requests that are in this state. This parameter can be repeated.
+ State *GetRepositoriesWorkspaceRepoSlugPullrequestsParamsState `form:"state,omitempty" json:"state,omitempty"`
+}
+
+// GetRepositoriesWorkspaceRepoSlugPullrequestsParamsState defines parameters for GetRepositoriesWorkspaceRepoSlugPullrequests.
+type GetRepositoriesWorkspaceRepoSlugPullrequestsParamsState string
+
+// PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams defines parameters for PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMerge.
+type PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams struct {
+ // Async Default value is false.
+ //
+ //
+ // When set to true, runs merge asynchronously and
+ // immediately returns a 202 with polling link to
+ // the task-status API in the Location header.
+ //
+ //
+ // When set to false, runs merge and waits for it to
+ // complete, returning 200 when it succeeds. If the
+ // duration of the merge exceeds a timeout threshold,
+ // the API returns a 202 with polling link to the
+ // task-status API in the Location header.
+ Async *bool `form:"async,omitempty" json:"async,omitempty"`
+}
+
+// PostRepositoriesWorkspaceRepoSlugPullrequestsJSONRequestBody defines body for PostRepositoriesWorkspaceRepoSlugPullrequests for application/json ContentType.
+type PostRepositoriesWorkspaceRepoSlugPullrequestsJSONRequestBody = Pullrequest
+
+// PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeJSONRequestBody defines body for PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMerge for application/json ContentType.
+type PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeJSONRequestBody = PullrequestMergeParameters
+
+// Getter for additional properties for Account. Returns the specified
+// element and whether it was found
+func (a Account) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for Account
+func (a *Account) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for Account to handle AdditionalProperties
+func (a *Account) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["created_on"]; found {
+ err = json.Unmarshal(raw, &a.CreatedOn)
+ if err != nil {
+ return fmt.Errorf("error reading 'created_on': %w", err)
+ }
+ delete(object, "created_on")
+ }
+
+ if raw, found := object["display_name"]; found {
+ err = json.Unmarshal(raw, &a.DisplayName)
+ if err != nil {
+ return fmt.Errorf("error reading 'display_name': %w", err)
+ }
+ delete(object, "display_name")
+ }
+
+ if raw, found := object["links"]; found {
+ err = json.Unmarshal(raw, &a.Links)
+ if err != nil {
+ return fmt.Errorf("error reading 'links': %w", err)
+ }
+ delete(object, "links")
+ }
+
+ if raw, found := object["type"]; found {
+ err = json.Unmarshal(raw, &a.Type)
+ if err != nil {
+ return fmt.Errorf("error reading 'type': %w", err)
+ }
+ delete(object, "type")
+ }
+
+ if raw, found := object["uuid"]; found {
+ err = json.Unmarshal(raw, &a.Uuid)
+ if err != nil {
+ return fmt.Errorf("error reading 'uuid': %w", err)
+ }
+ delete(object, "uuid")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for Account to handle AdditionalProperties
+func (a Account) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.CreatedOn != nil {
+ object["created_on"], err = json.Marshal(a.CreatedOn)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'created_on': %w", err)
+ }
+ }
+
+ if a.DisplayName != nil {
+ object["display_name"], err = json.Marshal(a.DisplayName)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'display_name': %w", err)
+ }
+ }
+
+ if a.Links != nil {
+ object["links"], err = json.Marshal(a.Links)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'links': %w", err)
+ }
+ }
+
+ object["type"], err = json.Marshal(a.Type)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'type': %w", err)
+ }
+
+ if a.Uuid != nil {
+ object["uuid"], err = json.Marshal(a.Uuid)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'uuid': %w", err)
+ }
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// Getter for additional properties for AccountLinks. Returns the specified
+// element and whether it was found
+func (a AccountLinks) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for AccountLinks
+func (a *AccountLinks) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for AccountLinks to handle AdditionalProperties
+func (a *AccountLinks) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["avatar"]; found {
+ err = json.Unmarshal(raw, &a.Avatar)
+ if err != nil {
+ return fmt.Errorf("error reading 'avatar': %w", err)
+ }
+ delete(object, "avatar")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for AccountLinks to handle AdditionalProperties
+func (a AccountLinks) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.Avatar != nil {
+ object["avatar"], err = json.Marshal(a.Avatar)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'avatar': %w", err)
+ }
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// Getter for additional properties for Author. Returns the specified
+// element and whether it was found
+func (a Author) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for Author
+func (a *Author) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for Author to handle AdditionalProperties
+func (a *Author) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["raw"]; found {
+ err = json.Unmarshal(raw, &a.Raw)
+ if err != nil {
+ return fmt.Errorf("error reading 'raw': %w", err)
+ }
+ delete(object, "raw")
+ }
+
+ if raw, found := object["type"]; found {
+ err = json.Unmarshal(raw, &a.Type)
+ if err != nil {
+ return fmt.Errorf("error reading 'type': %w", err)
+ }
+ delete(object, "type")
+ }
+
+ if raw, found := object["user"]; found {
+ err = json.Unmarshal(raw, &a.User)
+ if err != nil {
+ return fmt.Errorf("error reading 'user': %w", err)
+ }
+ delete(object, "user")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for Author to handle AdditionalProperties
+func (a Author) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.Raw != nil {
+ object["raw"], err = json.Marshal(a.Raw)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'raw': %w", err)
+ }
+ }
+
+ object["type"], err = json.Marshal(a.Type)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'type': %w", err)
+ }
+
+ if a.User != nil {
+ object["user"], err = json.Marshal(a.User)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'user': %w", err)
+ }
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// Getter for additional properties for BaseCommit. Returns the specified
+// element and whether it was found
+func (a BaseCommit) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for BaseCommit
+func (a *BaseCommit) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for BaseCommit to handle AdditionalProperties
+func (a *BaseCommit) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["author"]; found {
+ err = json.Unmarshal(raw, &a.Author)
+ if err != nil {
+ return fmt.Errorf("error reading 'author': %w", err)
+ }
+ delete(object, "author")
+ }
+
+ if raw, found := object["committer"]; found {
+ err = json.Unmarshal(raw, &a.Committer)
+ if err != nil {
+ return fmt.Errorf("error reading 'committer': %w", err)
+ }
+ delete(object, "committer")
+ }
+
+ if raw, found := object["date"]; found {
+ err = json.Unmarshal(raw, &a.Date)
+ if err != nil {
+ return fmt.Errorf("error reading 'date': %w", err)
+ }
+ delete(object, "date")
+ }
+
+ if raw, found := object["hash"]; found {
+ err = json.Unmarshal(raw, &a.Hash)
+ if err != nil {
+ return fmt.Errorf("error reading 'hash': %w", err)
+ }
+ delete(object, "hash")
+ }
+
+ if raw, found := object["message"]; found {
+ err = json.Unmarshal(raw, &a.Message)
+ if err != nil {
+ return fmt.Errorf("error reading 'message': %w", err)
+ }
+ delete(object, "message")
+ }
+
+ if raw, found := object["parents"]; found {
+ err = json.Unmarshal(raw, &a.Parents)
+ if err != nil {
+ return fmt.Errorf("error reading 'parents': %w", err)
+ }
+ delete(object, "parents")
+ }
+
+ if raw, found := object["summary"]; found {
+ err = json.Unmarshal(raw, &a.Summary)
+ if err != nil {
+ return fmt.Errorf("error reading 'summary': %w", err)
+ }
+ delete(object, "summary")
+ }
+
+ if raw, found := object["type"]; found {
+ err = json.Unmarshal(raw, &a.Type)
+ if err != nil {
+ return fmt.Errorf("error reading 'type': %w", err)
+ }
+ delete(object, "type")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for BaseCommit to handle AdditionalProperties
+func (a BaseCommit) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.Author != nil {
+ object["author"], err = json.Marshal(a.Author)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'author': %w", err)
+ }
+ }
+
+ if a.Committer != nil {
+ object["committer"], err = json.Marshal(a.Committer)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'committer': %w", err)
+ }
+ }
+
+ if a.Date != nil {
+ object["date"], err = json.Marshal(a.Date)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'date': %w", err)
+ }
+ }
+
+ if a.Hash != nil {
+ object["hash"], err = json.Marshal(a.Hash)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'hash': %w", err)
+ }
+ }
+
+ if a.Message != nil {
+ object["message"], err = json.Marshal(a.Message)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'message': %w", err)
+ }
+ }
+
+ if a.Parents != nil {
+ object["parents"], err = json.Marshal(a.Parents)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'parents': %w", err)
+ }
+ }
+
+ if a.Summary != nil {
+ object["summary"], err = json.Marshal(a.Summary)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'summary': %w", err)
+ }
+ }
+
+ object["type"], err = json.Marshal(a.Type)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'type': %w", err)
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// Getter for additional properties for Branch. Returns the specified
+// element and whether it was found
+func (a Branch) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for Branch
+func (a *Branch) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for Branch to handle AdditionalProperties
+func (a *Branch) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["default_merge_strategy"]; found {
+ err = json.Unmarshal(raw, &a.DefaultMergeStrategy)
+ if err != nil {
+ return fmt.Errorf("error reading 'default_merge_strategy': %w", err)
+ }
+ delete(object, "default_merge_strategy")
+ }
+
+ if raw, found := object["links"]; found {
+ err = json.Unmarshal(raw, &a.Links)
+ if err != nil {
+ return fmt.Errorf("error reading 'links': %w", err)
+ }
+ delete(object, "links")
+ }
+
+ if raw, found := object["merge_strategies"]; found {
+ err = json.Unmarshal(raw, &a.MergeStrategies)
+ if err != nil {
+ return fmt.Errorf("error reading 'merge_strategies': %w", err)
+ }
+ delete(object, "merge_strategies")
+ }
+
+ if raw, found := object["name"]; found {
+ err = json.Unmarshal(raw, &a.Name)
+ if err != nil {
+ return fmt.Errorf("error reading 'name': %w", err)
+ }
+ delete(object, "name")
+ }
+
+ if raw, found := object["target"]; found {
+ err = json.Unmarshal(raw, &a.Target)
+ if err != nil {
+ return fmt.Errorf("error reading 'target': %w", err)
+ }
+ delete(object, "target")
+ }
+
+ if raw, found := object["type"]; found {
+ err = json.Unmarshal(raw, &a.Type)
+ if err != nil {
+ return fmt.Errorf("error reading 'type': %w", err)
+ }
+ delete(object, "type")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for Branch to handle AdditionalProperties
+func (a Branch) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.DefaultMergeStrategy != nil {
+ object["default_merge_strategy"], err = json.Marshal(a.DefaultMergeStrategy)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'default_merge_strategy': %w", err)
+ }
+ }
+
+ if a.Links != nil {
+ object["links"], err = json.Marshal(a.Links)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'links': %w", err)
+ }
+ }
+
+ if a.MergeStrategies != nil {
+ object["merge_strategies"], err = json.Marshal(a.MergeStrategies)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'merge_strategies': %w", err)
+ }
+ }
+
+ if a.Name != nil {
+ object["name"], err = json.Marshal(a.Name)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'name': %w", err)
+ }
+ }
+
+ if a.Target != nil {
+ object["target"], err = json.Marshal(a.Target)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'target': %w", err)
+ }
+ }
+
+ object["type"], err = json.Marshal(a.Type)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'type': %w", err)
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// Getter for additional properties for Commit. Returns the specified
+// element and whether it was found
+func (a Commit) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for Commit
+func (a *Commit) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for Commit to handle AdditionalProperties
+func (a *Commit) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["author"]; found {
+ err = json.Unmarshal(raw, &a.Author)
+ if err != nil {
+ return fmt.Errorf("error reading 'author': %w", err)
+ }
+ delete(object, "author")
+ }
+
+ if raw, found := object["committer"]; found {
+ err = json.Unmarshal(raw, &a.Committer)
+ if err != nil {
+ return fmt.Errorf("error reading 'committer': %w", err)
+ }
+ delete(object, "committer")
+ }
+
+ if raw, found := object["date"]; found {
+ err = json.Unmarshal(raw, &a.Date)
+ if err != nil {
+ return fmt.Errorf("error reading 'date': %w", err)
+ }
+ delete(object, "date")
+ }
+
+ if raw, found := object["hash"]; found {
+ err = json.Unmarshal(raw, &a.Hash)
+ if err != nil {
+ return fmt.Errorf("error reading 'hash': %w", err)
+ }
+ delete(object, "hash")
+ }
+
+ if raw, found := object["message"]; found {
+ err = json.Unmarshal(raw, &a.Message)
+ if err != nil {
+ return fmt.Errorf("error reading 'message': %w", err)
+ }
+ delete(object, "message")
+ }
+
+ if raw, found := object["parents"]; found {
+ err = json.Unmarshal(raw, &a.Parents)
+ if err != nil {
+ return fmt.Errorf("error reading 'parents': %w", err)
+ }
+ delete(object, "parents")
+ }
+
+ if raw, found := object["participants"]; found {
+ err = json.Unmarshal(raw, &a.Participants)
+ if err != nil {
+ return fmt.Errorf("error reading 'participants': %w", err)
+ }
+ delete(object, "participants")
+ }
+
+ if raw, found := object["repository"]; found {
+ err = json.Unmarshal(raw, &a.Repository)
+ if err != nil {
+ return fmt.Errorf("error reading 'repository': %w", err)
+ }
+ delete(object, "repository")
+ }
+
+ if raw, found := object["summary"]; found {
+ err = json.Unmarshal(raw, &a.Summary)
+ if err != nil {
+ return fmt.Errorf("error reading 'summary': %w", err)
+ }
+ delete(object, "summary")
+ }
+
+ if raw, found := object["type"]; found {
+ err = json.Unmarshal(raw, &a.Type)
+ if err != nil {
+ return fmt.Errorf("error reading 'type': %w", err)
+ }
+ delete(object, "type")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for Commit to handle AdditionalProperties
+func (a Commit) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.Author != nil {
+ object["author"], err = json.Marshal(a.Author)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'author': %w", err)
+ }
+ }
+
+ if a.Committer != nil {
+ object["committer"], err = json.Marshal(a.Committer)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'committer': %w", err)
+ }
+ }
+
+ if a.Date != nil {
+ object["date"], err = json.Marshal(a.Date)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'date': %w", err)
+ }
+ }
+
+ if a.Hash != nil {
+ object["hash"], err = json.Marshal(a.Hash)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'hash': %w", err)
+ }
+ }
+
+ if a.Message != nil {
+ object["message"], err = json.Marshal(a.Message)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'message': %w", err)
+ }
+ }
+
+ if a.Parents != nil {
+ object["parents"], err = json.Marshal(a.Parents)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'parents': %w", err)
+ }
+ }
+
+ if a.Participants != nil {
+ object["participants"], err = json.Marshal(a.Participants)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'participants': %w", err)
+ }
+ }
+
+ if a.Repository != nil {
+ object["repository"], err = json.Marshal(a.Repository)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'repository': %w", err)
+ }
+ }
+
+ if a.Summary != nil {
+ object["summary"], err = json.Marshal(a.Summary)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'summary': %w", err)
+ }
+ }
+
+ object["type"], err = json.Marshal(a.Type)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'type': %w", err)
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// Getter for additional properties for Committer. Returns the specified
+// element and whether it was found
+func (a Committer) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for Committer
+func (a *Committer) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for Committer to handle AdditionalProperties
+func (a *Committer) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["raw"]; found {
+ err = json.Unmarshal(raw, &a.Raw)
+ if err != nil {
+ return fmt.Errorf("error reading 'raw': %w", err)
+ }
+ delete(object, "raw")
+ }
+
+ if raw, found := object["type"]; found {
+ err = json.Unmarshal(raw, &a.Type)
+ if err != nil {
+ return fmt.Errorf("error reading 'type': %w", err)
+ }
+ delete(object, "type")
+ }
+
+ if raw, found := object["user"]; found {
+ err = json.Unmarshal(raw, &a.User)
+ if err != nil {
+ return fmt.Errorf("error reading 'user': %w", err)
+ }
+ delete(object, "user")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for Committer to handle AdditionalProperties
+func (a Committer) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.Raw != nil {
+ object["raw"], err = json.Marshal(a.Raw)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'raw': %w", err)
+ }
+ }
+
+ object["type"], err = json.Marshal(a.Type)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'type': %w", err)
+ }
+
+ if a.User != nil {
+ object["user"], err = json.Marshal(a.User)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'user': %w", err)
+ }
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// Getter for additional properties for Error. Returns the specified
+// element and whether it was found
+func (a Error) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for Error
+func (a *Error) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for Error to handle AdditionalProperties
+func (a *Error) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["error"]; found {
+ err = json.Unmarshal(raw, &a.Error)
+ if err != nil {
+ return fmt.Errorf("error reading 'error': %w", err)
+ }
+ delete(object, "error")
+ }
+
+ if raw, found := object["type"]; found {
+ err = json.Unmarshal(raw, &a.Type)
+ if err != nil {
+ return fmt.Errorf("error reading 'type': %w", err)
+ }
+ delete(object, "type")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for Error to handle AdditionalProperties
+func (a Error) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.Error != nil {
+ object["error"], err = json.Marshal(a.Error)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'error': %w", err)
+ }
+ }
+
+ object["type"], err = json.Marshal(a.Type)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'type': %w", err)
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// Getter for additional properties for Object. Returns the specified
+// element and whether it was found
+func (a Object) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for Object
+func (a *Object) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for Object to handle AdditionalProperties
+func (a *Object) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["type"]; found {
+ err = json.Unmarshal(raw, &a.Type)
+ if err != nil {
+ return fmt.Errorf("error reading 'type': %w", err)
+ }
+ delete(object, "type")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for Object to handle AdditionalProperties
+func (a Object) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ object["type"], err = json.Marshal(a.Type)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'type': %w", err)
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// Getter for additional properties for Participant. Returns the specified
+// element and whether it was found
+func (a Participant) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for Participant
+func (a *Participant) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for Participant to handle AdditionalProperties
+func (a *Participant) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["approved"]; found {
+ err = json.Unmarshal(raw, &a.Approved)
+ if err != nil {
+ return fmt.Errorf("error reading 'approved': %w", err)
+ }
+ delete(object, "approved")
+ }
+
+ if raw, found := object["participated_on"]; found {
+ err = json.Unmarshal(raw, &a.ParticipatedOn)
+ if err != nil {
+ return fmt.Errorf("error reading 'participated_on': %w", err)
+ }
+ delete(object, "participated_on")
+ }
+
+ if raw, found := object["role"]; found {
+ err = json.Unmarshal(raw, &a.Role)
+ if err != nil {
+ return fmt.Errorf("error reading 'role': %w", err)
+ }
+ delete(object, "role")
+ }
+
+ if raw, found := object["state"]; found {
+ err = json.Unmarshal(raw, &a.State)
+ if err != nil {
+ return fmt.Errorf("error reading 'state': %w", err)
+ }
+ delete(object, "state")
+ }
+
+ if raw, found := object["type"]; found {
+ err = json.Unmarshal(raw, &a.Type)
+ if err != nil {
+ return fmt.Errorf("error reading 'type': %w", err)
+ }
+ delete(object, "type")
+ }
+
+ if raw, found := object["user"]; found {
+ err = json.Unmarshal(raw, &a.User)
+ if err != nil {
+ return fmt.Errorf("error reading 'user': %w", err)
+ }
+ delete(object, "user")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for Participant to handle AdditionalProperties
+func (a Participant) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.Approved != nil {
+ object["approved"], err = json.Marshal(a.Approved)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'approved': %w", err)
+ }
+ }
+
+ if a.ParticipatedOn != nil {
+ object["participated_on"], err = json.Marshal(a.ParticipatedOn)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'participated_on': %w", err)
+ }
+ }
+
+ if a.Role != nil {
+ object["role"], err = json.Marshal(a.Role)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'role': %w", err)
+ }
+ }
+
+ if a.State != nil {
+ object["state"], err = json.Marshal(a.State)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'state': %w", err)
+ }
+ }
+
+ object["type"], err = json.Marshal(a.Type)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'type': %w", err)
+ }
+
+ if a.User != nil {
+ object["user"], err = json.Marshal(a.User)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'user': %w", err)
+ }
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// Getter for additional properties for Project. Returns the specified
+// element and whether it was found
+func (a Project) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for Project
+func (a *Project) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for Project to handle AdditionalProperties
+func (a *Project) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["created_on"]; found {
+ err = json.Unmarshal(raw, &a.CreatedOn)
+ if err != nil {
+ return fmt.Errorf("error reading 'created_on': %w", err)
+ }
+ delete(object, "created_on")
+ }
+
+ if raw, found := object["description"]; found {
+ err = json.Unmarshal(raw, &a.Description)
+ if err != nil {
+ return fmt.Errorf("error reading 'description': %w", err)
+ }
+ delete(object, "description")
+ }
+
+ if raw, found := object["has_publicly_visible_repos"]; found {
+ err = json.Unmarshal(raw, &a.HasPubliclyVisibleRepos)
+ if err != nil {
+ return fmt.Errorf("error reading 'has_publicly_visible_repos': %w", err)
+ }
+ delete(object, "has_publicly_visible_repos")
+ }
+
+ if raw, found := object["is_private"]; found {
+ err = json.Unmarshal(raw, &a.IsPrivate)
+ if err != nil {
+ return fmt.Errorf("error reading 'is_private': %w", err)
+ }
+ delete(object, "is_private")
+ }
+
+ if raw, found := object["key"]; found {
+ err = json.Unmarshal(raw, &a.Key)
+ if err != nil {
+ return fmt.Errorf("error reading 'key': %w", err)
+ }
+ delete(object, "key")
+ }
+
+ if raw, found := object["links"]; found {
+ err = json.Unmarshal(raw, &a.Links)
+ if err != nil {
+ return fmt.Errorf("error reading 'links': %w", err)
+ }
+ delete(object, "links")
+ }
+
+ if raw, found := object["name"]; found {
+ err = json.Unmarshal(raw, &a.Name)
+ if err != nil {
+ return fmt.Errorf("error reading 'name': %w", err)
+ }
+ delete(object, "name")
+ }
+
+ if raw, found := object["owner"]; found {
+ err = json.Unmarshal(raw, &a.Owner)
+ if err != nil {
+ return fmt.Errorf("error reading 'owner': %w", err)
+ }
+ delete(object, "owner")
+ }
+
+ if raw, found := object["type"]; found {
+ err = json.Unmarshal(raw, &a.Type)
+ if err != nil {
+ return fmt.Errorf("error reading 'type': %w", err)
+ }
+ delete(object, "type")
+ }
+
+ if raw, found := object["updated_on"]; found {
+ err = json.Unmarshal(raw, &a.UpdatedOn)
+ if err != nil {
+ return fmt.Errorf("error reading 'updated_on': %w", err)
+ }
+ delete(object, "updated_on")
+ }
+
+ if raw, found := object["uuid"]; found {
+ err = json.Unmarshal(raw, &a.Uuid)
+ if err != nil {
+ return fmt.Errorf("error reading 'uuid': %w", err)
+ }
+ delete(object, "uuid")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for Project to handle AdditionalProperties
+func (a Project) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.CreatedOn != nil {
+ object["created_on"], err = json.Marshal(a.CreatedOn)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'created_on': %w", err)
+ }
+ }
+
+ if a.Description != nil {
+ object["description"], err = json.Marshal(a.Description)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'description': %w", err)
+ }
+ }
+
+ if a.HasPubliclyVisibleRepos != nil {
+ object["has_publicly_visible_repos"], err = json.Marshal(a.HasPubliclyVisibleRepos)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'has_publicly_visible_repos': %w", err)
+ }
+ }
+
+ if a.IsPrivate != nil {
+ object["is_private"], err = json.Marshal(a.IsPrivate)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'is_private': %w", err)
+ }
+ }
+
+ if a.Key != nil {
+ object["key"], err = json.Marshal(a.Key)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'key': %w", err)
+ }
+ }
+
+ if a.Links != nil {
+ object["links"], err = json.Marshal(a.Links)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'links': %w", err)
+ }
+ }
+
+ if a.Name != nil {
+ object["name"], err = json.Marshal(a.Name)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'name': %w", err)
+ }
+ }
+
+ if a.Owner != nil {
+ object["owner"], err = json.Marshal(a.Owner)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'owner': %w", err)
+ }
+ }
+
+ object["type"], err = json.Marshal(a.Type)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'type': %w", err)
+ }
+
+ if a.UpdatedOn != nil {
+ object["updated_on"], err = json.Marshal(a.UpdatedOn)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'updated_on': %w", err)
+ }
+ }
+
+ if a.Uuid != nil {
+ object["uuid"], err = json.Marshal(a.Uuid)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'uuid': %w", err)
+ }
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// Getter for additional properties for Pullrequest. Returns the specified
+// element and whether it was found
+func (a Pullrequest) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for Pullrequest
+func (a *Pullrequest) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for Pullrequest to handle AdditionalProperties
+func (a *Pullrequest) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["author"]; found {
+ err = json.Unmarshal(raw, &a.Author)
+ if err != nil {
+ return fmt.Errorf("error reading 'author': %w", err)
+ }
+ delete(object, "author")
+ }
+
+ if raw, found := object["close_source_branch"]; found {
+ err = json.Unmarshal(raw, &a.CloseSourceBranch)
+ if err != nil {
+ return fmt.Errorf("error reading 'close_source_branch': %w", err)
+ }
+ delete(object, "close_source_branch")
+ }
+
+ if raw, found := object["closed_by"]; found {
+ err = json.Unmarshal(raw, &a.ClosedBy)
+ if err != nil {
+ return fmt.Errorf("error reading 'closed_by': %w", err)
+ }
+ delete(object, "closed_by")
+ }
+
+ if raw, found := object["comment_count"]; found {
+ err = json.Unmarshal(raw, &a.CommentCount)
+ if err != nil {
+ return fmt.Errorf("error reading 'comment_count': %w", err)
+ }
+ delete(object, "comment_count")
+ }
+
+ if raw, found := object["created_on"]; found {
+ err = json.Unmarshal(raw, &a.CreatedOn)
+ if err != nil {
+ return fmt.Errorf("error reading 'created_on': %w", err)
+ }
+ delete(object, "created_on")
+ }
+
+ if raw, found := object["destination"]; found {
+ err = json.Unmarshal(raw, &a.Destination)
+ if err != nil {
+ return fmt.Errorf("error reading 'destination': %w", err)
+ }
+ delete(object, "destination")
+ }
+
+ if raw, found := object["draft"]; found {
+ err = json.Unmarshal(raw, &a.Draft)
+ if err != nil {
+ return fmt.Errorf("error reading 'draft': %w", err)
+ }
+ delete(object, "draft")
+ }
+
+ if raw, found := object["id"]; found {
+ err = json.Unmarshal(raw, &a.Id)
+ if err != nil {
+ return fmt.Errorf("error reading 'id': %w", err)
+ }
+ delete(object, "id")
+ }
+
+ if raw, found := object["links"]; found {
+ err = json.Unmarshal(raw, &a.Links)
+ if err != nil {
+ return fmt.Errorf("error reading 'links': %w", err)
+ }
+ delete(object, "links")
+ }
+
+ if raw, found := object["merge_commit"]; found {
+ err = json.Unmarshal(raw, &a.MergeCommit)
+ if err != nil {
+ return fmt.Errorf("error reading 'merge_commit': %w", err)
+ }
+ delete(object, "merge_commit")
+ }
+
+ if raw, found := object["participants"]; found {
+ err = json.Unmarshal(raw, &a.Participants)
+ if err != nil {
+ return fmt.Errorf("error reading 'participants': %w", err)
+ }
+ delete(object, "participants")
+ }
+
+ if raw, found := object["queued"]; found {
+ err = json.Unmarshal(raw, &a.Queued)
+ if err != nil {
+ return fmt.Errorf("error reading 'queued': %w", err)
+ }
+ delete(object, "queued")
+ }
+
+ if raw, found := object["reason"]; found {
+ err = json.Unmarshal(raw, &a.Reason)
+ if err != nil {
+ return fmt.Errorf("error reading 'reason': %w", err)
+ }
+ delete(object, "reason")
+ }
+
+ if raw, found := object["rendered"]; found {
+ err = json.Unmarshal(raw, &a.Rendered)
+ if err != nil {
+ return fmt.Errorf("error reading 'rendered': %w", err)
+ }
+ delete(object, "rendered")
+ }
+
+ if raw, found := object["reviewers"]; found {
+ err = json.Unmarshal(raw, &a.Reviewers)
+ if err != nil {
+ return fmt.Errorf("error reading 'reviewers': %w", err)
+ }
+ delete(object, "reviewers")
+ }
+
+ if raw, found := object["source"]; found {
+ err = json.Unmarshal(raw, &a.Source)
+ if err != nil {
+ return fmt.Errorf("error reading 'source': %w", err)
+ }
+ delete(object, "source")
+ }
+
+ if raw, found := object["state"]; found {
+ err = json.Unmarshal(raw, &a.State)
+ if err != nil {
+ return fmt.Errorf("error reading 'state': %w", err)
+ }
+ delete(object, "state")
+ }
+
+ if raw, found := object["summary"]; found {
+ err = json.Unmarshal(raw, &a.Summary)
+ if err != nil {
+ return fmt.Errorf("error reading 'summary': %w", err)
+ }
+ delete(object, "summary")
+ }
+
+ if raw, found := object["task_count"]; found {
+ err = json.Unmarshal(raw, &a.TaskCount)
+ if err != nil {
+ return fmt.Errorf("error reading 'task_count': %w", err)
+ }
+ delete(object, "task_count")
+ }
+
+ if raw, found := object["title"]; found {
+ err = json.Unmarshal(raw, &a.Title)
+ if err != nil {
+ return fmt.Errorf("error reading 'title': %w", err)
+ }
+ delete(object, "title")
+ }
+
+ if raw, found := object["type"]; found {
+ err = json.Unmarshal(raw, &a.Type)
+ if err != nil {
+ return fmt.Errorf("error reading 'type': %w", err)
+ }
+ delete(object, "type")
+ }
+
+ if raw, found := object["updated_on"]; found {
+ err = json.Unmarshal(raw, &a.UpdatedOn)
+ if err != nil {
+ return fmt.Errorf("error reading 'updated_on': %w", err)
+ }
+ delete(object, "updated_on")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for Pullrequest to handle AdditionalProperties
+func (a Pullrequest) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.Author != nil {
+ object["author"], err = json.Marshal(a.Author)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'author': %w", err)
+ }
+ }
+
+ if a.CloseSourceBranch != nil {
+ object["close_source_branch"], err = json.Marshal(a.CloseSourceBranch)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'close_source_branch': %w", err)
+ }
+ }
+
+ if a.ClosedBy != nil {
+ object["closed_by"], err = json.Marshal(a.ClosedBy)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'closed_by': %w", err)
+ }
+ }
+
+ if a.CommentCount != nil {
+ object["comment_count"], err = json.Marshal(a.CommentCount)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'comment_count': %w", err)
+ }
+ }
+
+ if a.CreatedOn != nil {
+ object["created_on"], err = json.Marshal(a.CreatedOn)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'created_on': %w", err)
+ }
+ }
+
+ if a.Destination != nil {
+ object["destination"], err = json.Marshal(a.Destination)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'destination': %w", err)
+ }
+ }
+
+ if a.Draft != nil {
+ object["draft"], err = json.Marshal(a.Draft)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'draft': %w", err)
+ }
+ }
+
+ if a.Id != nil {
+ object["id"], err = json.Marshal(a.Id)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'id': %w", err)
+ }
+ }
+
+ if a.Links != nil {
+ object["links"], err = json.Marshal(a.Links)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'links': %w", err)
+ }
+ }
+
+ if a.MergeCommit != nil {
+ object["merge_commit"], err = json.Marshal(a.MergeCommit)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'merge_commit': %w", err)
+ }
+ }
+
+ if a.Participants != nil {
+ object["participants"], err = json.Marshal(a.Participants)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'participants': %w", err)
+ }
+ }
+
+ if a.Queued != nil {
+ object["queued"], err = json.Marshal(a.Queued)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'queued': %w", err)
+ }
+ }
+
+ if a.Reason != nil {
+ object["reason"], err = json.Marshal(a.Reason)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'reason': %w", err)
+ }
+ }
+
+ if a.Rendered != nil {
+ object["rendered"], err = json.Marshal(a.Rendered)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'rendered': %w", err)
+ }
+ }
+
+ if a.Reviewers != nil {
+ object["reviewers"], err = json.Marshal(a.Reviewers)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'reviewers': %w", err)
+ }
+ }
+
+ if a.Source != nil {
+ object["source"], err = json.Marshal(a.Source)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'source': %w", err)
+ }
+ }
+
+ if a.State != nil {
+ object["state"], err = json.Marshal(a.State)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'state': %w", err)
+ }
+ }
+
+ if a.Summary != nil {
+ object["summary"], err = json.Marshal(a.Summary)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'summary': %w", err)
+ }
+ }
+
+ if a.TaskCount != nil {
+ object["task_count"], err = json.Marshal(a.TaskCount)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'task_count': %w", err)
+ }
+ }
+
+ if a.Title != nil {
+ object["title"], err = json.Marshal(a.Title)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'title': %w", err)
+ }
+ }
+
+ object["type"], err = json.Marshal(a.Type)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'type': %w", err)
+ }
+
+ if a.UpdatedOn != nil {
+ object["updated_on"], err = json.Marshal(a.UpdatedOn)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'updated_on': %w", err)
+ }
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// Getter for additional properties for PullrequestMergeParameters. Returns the specified
+// element and whether it was found
+func (a PullrequestMergeParameters) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for PullrequestMergeParameters
+func (a *PullrequestMergeParameters) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for PullrequestMergeParameters to handle AdditionalProperties
+func (a *PullrequestMergeParameters) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["close_source_branch"]; found {
+ err = json.Unmarshal(raw, &a.CloseSourceBranch)
+ if err != nil {
+ return fmt.Errorf("error reading 'close_source_branch': %w", err)
+ }
+ delete(object, "close_source_branch")
+ }
+
+ if raw, found := object["merge_strategy"]; found {
+ err = json.Unmarshal(raw, &a.MergeStrategy)
+ if err != nil {
+ return fmt.Errorf("error reading 'merge_strategy': %w", err)
+ }
+ delete(object, "merge_strategy")
+ }
+
+ if raw, found := object["message"]; found {
+ err = json.Unmarshal(raw, &a.Message)
+ if err != nil {
+ return fmt.Errorf("error reading 'message': %w", err)
+ }
+ delete(object, "message")
+ }
+
+ if raw, found := object["type"]; found {
+ err = json.Unmarshal(raw, &a.Type)
+ if err != nil {
+ return fmt.Errorf("error reading 'type': %w", err)
+ }
+ delete(object, "type")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for PullrequestMergeParameters to handle AdditionalProperties
+func (a PullrequestMergeParameters) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.CloseSourceBranch != nil {
+ object["close_source_branch"], err = json.Marshal(a.CloseSourceBranch)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'close_source_branch': %w", err)
+ }
+ }
+
+ if a.MergeStrategy != nil {
+ object["merge_strategy"], err = json.Marshal(a.MergeStrategy)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'merge_strategy': %w", err)
+ }
+ }
+
+ if a.Message != nil {
+ object["message"], err = json.Marshal(a.Message)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'message': %w", err)
+ }
+ }
+
+ object["type"], err = json.Marshal(a.Type)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'type': %w", err)
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// Getter for additional properties for Ref. Returns the specified
+// element and whether it was found
+func (a Ref) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for Ref
+func (a *Ref) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for Ref to handle AdditionalProperties
+func (a *Ref) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["links"]; found {
+ err = json.Unmarshal(raw, &a.Links)
+ if err != nil {
+ return fmt.Errorf("error reading 'links': %w", err)
+ }
+ delete(object, "links")
+ }
+
+ if raw, found := object["name"]; found {
+ err = json.Unmarshal(raw, &a.Name)
+ if err != nil {
+ return fmt.Errorf("error reading 'name': %w", err)
+ }
+ delete(object, "name")
+ }
+
+ if raw, found := object["target"]; found {
+ err = json.Unmarshal(raw, &a.Target)
+ if err != nil {
+ return fmt.Errorf("error reading 'target': %w", err)
+ }
+ delete(object, "target")
+ }
+
+ if raw, found := object["type"]; found {
+ err = json.Unmarshal(raw, &a.Type)
+ if err != nil {
+ return fmt.Errorf("error reading 'type': %w", err)
+ }
+ delete(object, "type")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for Ref to handle AdditionalProperties
+func (a Ref) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.Links != nil {
+ object["links"], err = json.Marshal(a.Links)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'links': %w", err)
+ }
+ }
+
+ if a.Name != nil {
+ object["name"], err = json.Marshal(a.Name)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'name': %w", err)
+ }
+ }
+
+ if a.Target != nil {
+ object["target"], err = json.Marshal(a.Target)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'target': %w", err)
+ }
+ }
+
+ object["type"], err = json.Marshal(a.Type)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'type': %w", err)
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// Getter for additional properties for Repository. Returns the specified
+// element and whether it was found
+func (a Repository) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for Repository
+func (a *Repository) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for Repository to handle AdditionalProperties
+func (a *Repository) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["created_on"]; found {
+ err = json.Unmarshal(raw, &a.CreatedOn)
+ if err != nil {
+ return fmt.Errorf("error reading 'created_on': %w", err)
+ }
+ delete(object, "created_on")
+ }
+
+ if raw, found := object["description"]; found {
+ err = json.Unmarshal(raw, &a.Description)
+ if err != nil {
+ return fmt.Errorf("error reading 'description': %w", err)
+ }
+ delete(object, "description")
+ }
+
+ if raw, found := object["fork_policy"]; found {
+ err = json.Unmarshal(raw, &a.ForkPolicy)
+ if err != nil {
+ return fmt.Errorf("error reading 'fork_policy': %w", err)
+ }
+ delete(object, "fork_policy")
+ }
+
+ if raw, found := object["full_name"]; found {
+ err = json.Unmarshal(raw, &a.FullName)
+ if err != nil {
+ return fmt.Errorf("error reading 'full_name': %w", err)
+ }
+ delete(object, "full_name")
+ }
+
+ if raw, found := object["has_issues"]; found {
+ err = json.Unmarshal(raw, &a.HasIssues)
+ if err != nil {
+ return fmt.Errorf("error reading 'has_issues': %w", err)
+ }
+ delete(object, "has_issues")
+ }
+
+ if raw, found := object["has_wiki"]; found {
+ err = json.Unmarshal(raw, &a.HasWiki)
+ if err != nil {
+ return fmt.Errorf("error reading 'has_wiki': %w", err)
+ }
+ delete(object, "has_wiki")
+ }
+
+ if raw, found := object["is_private"]; found {
+ err = json.Unmarshal(raw, &a.IsPrivate)
+ if err != nil {
+ return fmt.Errorf("error reading 'is_private': %w", err)
+ }
+ delete(object, "is_private")
+ }
+
+ if raw, found := object["language"]; found {
+ err = json.Unmarshal(raw, &a.Language)
+ if err != nil {
+ return fmt.Errorf("error reading 'language': %w", err)
+ }
+ delete(object, "language")
+ }
+
+ if raw, found := object["links"]; found {
+ err = json.Unmarshal(raw, &a.Links)
+ if err != nil {
+ return fmt.Errorf("error reading 'links': %w", err)
+ }
+ delete(object, "links")
+ }
+
+ if raw, found := object["mainbranch"]; found {
+ err = json.Unmarshal(raw, &a.Mainbranch)
+ if err != nil {
+ return fmt.Errorf("error reading 'mainbranch': %w", err)
+ }
+ delete(object, "mainbranch")
+ }
+
+ if raw, found := object["name"]; found {
+ err = json.Unmarshal(raw, &a.Name)
+ if err != nil {
+ return fmt.Errorf("error reading 'name': %w", err)
+ }
+ delete(object, "name")
+ }
+
+ if raw, found := object["owner"]; found {
+ err = json.Unmarshal(raw, &a.Owner)
+ if err != nil {
+ return fmt.Errorf("error reading 'owner': %w", err)
+ }
+ delete(object, "owner")
+ }
+
+ if raw, found := object["parent"]; found {
+ err = json.Unmarshal(raw, &a.Parent)
+ if err != nil {
+ return fmt.Errorf("error reading 'parent': %w", err)
+ }
+ delete(object, "parent")
+ }
+
+ if raw, found := object["project"]; found {
+ err = json.Unmarshal(raw, &a.Project)
+ if err != nil {
+ return fmt.Errorf("error reading 'project': %w", err)
+ }
+ delete(object, "project")
+ }
+
+ if raw, found := object["scm"]; found {
+ err = json.Unmarshal(raw, &a.Scm)
+ if err != nil {
+ return fmt.Errorf("error reading 'scm': %w", err)
+ }
+ delete(object, "scm")
+ }
+
+ if raw, found := object["size"]; found {
+ err = json.Unmarshal(raw, &a.Size)
+ if err != nil {
+ return fmt.Errorf("error reading 'size': %w", err)
+ }
+ delete(object, "size")
+ }
+
+ if raw, found := object["type"]; found {
+ err = json.Unmarshal(raw, &a.Type)
+ if err != nil {
+ return fmt.Errorf("error reading 'type': %w", err)
+ }
+ delete(object, "type")
+ }
+
+ if raw, found := object["updated_on"]; found {
+ err = json.Unmarshal(raw, &a.UpdatedOn)
+ if err != nil {
+ return fmt.Errorf("error reading 'updated_on': %w", err)
+ }
+ delete(object, "updated_on")
+ }
+
+ if raw, found := object["uuid"]; found {
+ err = json.Unmarshal(raw, &a.Uuid)
+ if err != nil {
+ return fmt.Errorf("error reading 'uuid': %w", err)
+ }
+ delete(object, "uuid")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for Repository to handle AdditionalProperties
+func (a Repository) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.CreatedOn != nil {
+ object["created_on"], err = json.Marshal(a.CreatedOn)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'created_on': %w", err)
+ }
+ }
+
+ if a.Description != nil {
+ object["description"], err = json.Marshal(a.Description)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'description': %w", err)
+ }
+ }
+
+ if a.ForkPolicy != nil {
+ object["fork_policy"], err = json.Marshal(a.ForkPolicy)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'fork_policy': %w", err)
+ }
+ }
+
+ if a.FullName != nil {
+ object["full_name"], err = json.Marshal(a.FullName)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'full_name': %w", err)
+ }
+ }
+
+ if a.HasIssues != nil {
+ object["has_issues"], err = json.Marshal(a.HasIssues)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'has_issues': %w", err)
+ }
+ }
+
+ if a.HasWiki != nil {
+ object["has_wiki"], err = json.Marshal(a.HasWiki)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'has_wiki': %w", err)
+ }
+ }
+
+ if a.IsPrivate != nil {
+ object["is_private"], err = json.Marshal(a.IsPrivate)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'is_private': %w", err)
+ }
+ }
+
+ if a.Language != nil {
+ object["language"], err = json.Marshal(a.Language)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'language': %w", err)
+ }
+ }
+
+ if a.Links != nil {
+ object["links"], err = json.Marshal(a.Links)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'links': %w", err)
+ }
+ }
+
+ if a.Mainbranch != nil {
+ object["mainbranch"], err = json.Marshal(a.Mainbranch)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'mainbranch': %w", err)
+ }
+ }
+
+ if a.Name != nil {
+ object["name"], err = json.Marshal(a.Name)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'name': %w", err)
+ }
+ }
+
+ if a.Owner != nil {
+ object["owner"], err = json.Marshal(a.Owner)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'owner': %w", err)
+ }
+ }
+
+ if a.Parent != nil {
+ object["parent"], err = json.Marshal(a.Parent)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'parent': %w", err)
+ }
+ }
+
+ if a.Project != nil {
+ object["project"], err = json.Marshal(a.Project)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'project': %w", err)
+ }
+ }
+
+ if a.Scm != nil {
+ object["scm"], err = json.Marshal(a.Scm)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'scm': %w", err)
+ }
+ }
+
+ if a.Size != nil {
+ object["size"], err = json.Marshal(a.Size)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'size': %w", err)
+ }
+ }
+
+ object["type"], err = json.Marshal(a.Type)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'type': %w", err)
+ }
+
+ if a.UpdatedOn != nil {
+ object["updated_on"], err = json.Marshal(a.UpdatedOn)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'updated_on': %w", err)
+ }
+ }
+
+ if a.Uuid != nil {
+ object["uuid"], err = json.Marshal(a.Uuid)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'uuid': %w", err)
+ }
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// Getter for additional properties for Team. Returns the specified
+// element and whether it was found
+func (a Team) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for Team
+func (a *Team) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for Team to handle AdditionalProperties
+func (a *Team) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["created_on"]; found {
+ err = json.Unmarshal(raw, &a.CreatedOn)
+ if err != nil {
+ return fmt.Errorf("error reading 'created_on': %w", err)
+ }
+ delete(object, "created_on")
+ }
+
+ if raw, found := object["display_name"]; found {
+ err = json.Unmarshal(raw, &a.DisplayName)
+ if err != nil {
+ return fmt.Errorf("error reading 'display_name': %w", err)
+ }
+ delete(object, "display_name")
+ }
+
+ if raw, found := object["links"]; found {
+ err = json.Unmarshal(raw, &a.Links)
+ if err != nil {
+ return fmt.Errorf("error reading 'links': %w", err)
+ }
+ delete(object, "links")
+ }
+
+ if raw, found := object["type"]; found {
+ err = json.Unmarshal(raw, &a.Type)
+ if err != nil {
+ return fmt.Errorf("error reading 'type': %w", err)
+ }
+ delete(object, "type")
+ }
+
+ if raw, found := object["uuid"]; found {
+ err = json.Unmarshal(raw, &a.Uuid)
+ if err != nil {
+ return fmt.Errorf("error reading 'uuid': %w", err)
+ }
+ delete(object, "uuid")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for Team to handle AdditionalProperties
+func (a Team) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.CreatedOn != nil {
+ object["created_on"], err = json.Marshal(a.CreatedOn)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'created_on': %w", err)
+ }
+ }
+
+ if a.DisplayName != nil {
+ object["display_name"], err = json.Marshal(a.DisplayName)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'display_name': %w", err)
+ }
+ }
+
+ if a.Links != nil {
+ object["links"], err = json.Marshal(a.Links)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'links': %w", err)
+ }
+ }
+
+ object["type"], err = json.Marshal(a.Type)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'type': %w", err)
+ }
+
+ if a.Uuid != nil {
+ object["uuid"], err = json.Marshal(a.Uuid)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'uuid': %w", err)
+ }
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// Getter for additional properties for TeamLinks. Returns the specified
+// element and whether it was found
+func (a TeamLinks) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for TeamLinks
+func (a *TeamLinks) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for TeamLinks to handle AdditionalProperties
+func (a *TeamLinks) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["avatar"]; found {
+ err = json.Unmarshal(raw, &a.Avatar)
+ if err != nil {
+ return fmt.Errorf("error reading 'avatar': %w", err)
+ }
+ delete(object, "avatar")
+ }
+
+ if raw, found := object["html"]; found {
+ err = json.Unmarshal(raw, &a.Html)
+ if err != nil {
+ return fmt.Errorf("error reading 'html': %w", err)
+ }
+ delete(object, "html")
+ }
+
+ if raw, found := object["members"]; found {
+ err = json.Unmarshal(raw, &a.Members)
+ if err != nil {
+ return fmt.Errorf("error reading 'members': %w", err)
+ }
+ delete(object, "members")
+ }
+
+ if raw, found := object["projects"]; found {
+ err = json.Unmarshal(raw, &a.Projects)
+ if err != nil {
+ return fmt.Errorf("error reading 'projects': %w", err)
+ }
+ delete(object, "projects")
+ }
+
+ if raw, found := object["repositories"]; found {
+ err = json.Unmarshal(raw, &a.Repositories)
+ if err != nil {
+ return fmt.Errorf("error reading 'repositories': %w", err)
+ }
+ delete(object, "repositories")
+ }
+
+ if raw, found := object["self"]; found {
+ err = json.Unmarshal(raw, &a.Self)
+ if err != nil {
+ return fmt.Errorf("error reading 'self': %w", err)
+ }
+ delete(object, "self")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for TeamLinks to handle AdditionalProperties
+func (a TeamLinks) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.Avatar != nil {
+ object["avatar"], err = json.Marshal(a.Avatar)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'avatar': %w", err)
+ }
+ }
+
+ if a.Html != nil {
+ object["html"], err = json.Marshal(a.Html)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'html': %w", err)
+ }
+ }
+
+ if a.Members != nil {
+ object["members"], err = json.Marshal(a.Members)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'members': %w", err)
+ }
+ }
+
+ if a.Projects != nil {
+ object["projects"], err = json.Marshal(a.Projects)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'projects': %w", err)
+ }
+ }
+
+ if a.Repositories != nil {
+ object["repositories"], err = json.Marshal(a.Repositories)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'repositories': %w", err)
+ }
+ }
+
+ if a.Self != nil {
+ object["self"], err = json.Marshal(a.Self)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'self': %w", err)
+ }
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetRepositoriesWorkspaceRepoSlugCommitCommit request
+ GetRepositoriesWorkspaceRepoSlugCommitCommit(ctx context.Context, workspace string, repoSlug string, commit string, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // GetRepositoriesWorkspaceRepoSlugPullrequests request
+ GetRepositoriesWorkspaceRepoSlugPullrequests(ctx context.Context, workspace string, repoSlug string, params *GetRepositoriesWorkspaceRepoSlugPullrequestsParams, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // PostRepositoriesWorkspaceRepoSlugPullrequestsWithBody request with any body
+ PostRepositoriesWorkspaceRepoSlugPullrequestsWithBody(ctx context.Context, workspace string, repoSlug string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ PostRepositoriesWorkspaceRepoSlugPullrequests(ctx context.Context, workspace string, repoSlug string, body PostRepositoriesWorkspaceRepoSlugPullrequestsJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestId request
+ GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestId(ctx context.Context, workspace string, repoSlug string, pullRequestId int, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeWithBody request with any body
+ PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeWithBody(ctx context.Context, workspace string, repoSlug string, pullRequestId int, params *PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMerge(ctx context.Context, workspace string, repoSlug string, pullRequestId int, params *PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams, body PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetRepositoriesWorkspaceRepoSlugCommitCommit(ctx context.Context, workspace string, repoSlug string, commit string, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetRepositoriesWorkspaceRepoSlugCommitCommitRequest(c.Server, workspace, repoSlug, commit)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) GetRepositoriesWorkspaceRepoSlugPullrequests(ctx context.Context, workspace string, repoSlug string, params *GetRepositoriesWorkspaceRepoSlugPullrequestsParams, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetRepositoriesWorkspaceRepoSlugPullrequestsRequest(c.Server, workspace, repoSlug, params)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostRepositoriesWorkspaceRepoSlugPullrequestsWithBody(ctx context.Context, workspace string, repoSlug string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostRepositoriesWorkspaceRepoSlugPullrequestsRequestWithBody(c.Server, workspace, repoSlug, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostRepositoriesWorkspaceRepoSlugPullrequests(ctx context.Context, workspace string, repoSlug string, body PostRepositoriesWorkspaceRepoSlugPullrequestsJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostRepositoriesWorkspaceRepoSlugPullrequestsRequest(c.Server, workspace, repoSlug, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestId(ctx context.Context, workspace string, repoSlug string, pullRequestId int, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdRequest(c.Server, workspace, repoSlug, pullRequestId)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeWithBody(ctx context.Context, workspace string, repoSlug string, pullRequestId int, params *PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeRequestWithBody(c.Server, workspace, repoSlug, pullRequestId, params, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMerge(ctx context.Context, workspace string, repoSlug string, pullRequestId int, params *PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams, body PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeRequest(c.Server, workspace, repoSlug, pullRequestId, params, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetRepositoriesWorkspaceRepoSlugCommitCommitRequest generates requests for GetRepositoriesWorkspaceRepoSlugCommitCommit
+func NewGetRepositoriesWorkspaceRepoSlugCommitCommitRequest(server string, workspace string, repoSlug string, commit string) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "workspace", workspace, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ var pathParam1 string
+
+ pathParam1, err = runtime.StyleParamWithOptions("simple", false, "repo_slug", repoSlug, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ var pathParam2 string
+
+ pathParam2, err = runtime.StyleParamWithOptions("simple", false, "commit", commit, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/repositories/%s/%s/commit/%s", pathParam0, pathParam1, pathParam2)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest("GET", queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewGetRepositoriesWorkspaceRepoSlugPullrequestsRequest generates requests for GetRepositoriesWorkspaceRepoSlugPullrequests
+func NewGetRepositoriesWorkspaceRepoSlugPullrequestsRequest(server string, workspace string, repoSlug string, params *GetRepositoriesWorkspaceRepoSlugPullrequestsParams) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "workspace", workspace, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ var pathParam1 string
+
+ pathParam1, err = runtime.StyleParamWithOptions("simple", false, "repo_slug", repoSlug, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/repositories/%s/%s/pullrequests", pathParam0, pathParam1)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ if params != nil {
+ queryValues := queryURL.Query()
+
+ if params.State != nil {
+
+ if queryFrag, err := runtime.StyleParamWithOptions("form", true, "state", *params.State, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "string", Format: ""}); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
+ }
+ }
+
+ }
+
+ queryURL.RawQuery = queryValues.Encode()
+ }
+
+ req, err := http.NewRequest("GET", queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewPostRepositoriesWorkspaceRepoSlugPullrequestsRequest calls the generic PostRepositoriesWorkspaceRepoSlugPullrequests builder with application/json body
+func NewPostRepositoriesWorkspaceRepoSlugPullrequestsRequest(server string, workspace string, repoSlug string, body PostRepositoriesWorkspaceRepoSlugPullrequestsJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewPostRepositoriesWorkspaceRepoSlugPullrequestsRequestWithBody(server, workspace, repoSlug, "application/json", bodyReader)
+}
+
+// NewPostRepositoriesWorkspaceRepoSlugPullrequestsRequestWithBody generates requests for PostRepositoriesWorkspaceRepoSlugPullrequests with any type of body
+func NewPostRepositoriesWorkspaceRepoSlugPullrequestsRequestWithBody(server string, workspace string, repoSlug string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "workspace", workspace, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ var pathParam1 string
+
+ pathParam1, err = runtime.StyleParamWithOptions("simple", false, "repo_slug", repoSlug, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/repositories/%s/%s/pullrequests", pathParam0, pathParam1)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest("POST", queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewGetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdRequest generates requests for GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestId
+func NewGetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdRequest(server string, workspace string, repoSlug string, pullRequestId int) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "workspace", workspace, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ var pathParam1 string
+
+ pathParam1, err = runtime.StyleParamWithOptions("simple", false, "repo_slug", repoSlug, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ var pathParam2 string
+
+ pathParam2, err = runtime.StyleParamWithOptions("simple", false, "pull_request_id", pullRequestId, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "integer", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/repositories/%s/%s/pullrequests/%s", pathParam0, pathParam1, pathParam2)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest("GET", queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewPostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeRequest calls the generic PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMerge builder with application/json body
+func NewPostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeRequest(server string, workspace string, repoSlug string, pullRequestId int, params *PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams, body PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewPostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeRequestWithBody(server, workspace, repoSlug, pullRequestId, params, "application/json", bodyReader)
+}
+
+// NewPostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeRequestWithBody generates requests for PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMerge with any type of body
+func NewPostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeRequestWithBody(server string, workspace string, repoSlug string, pullRequestId int, params *PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "workspace", workspace, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ var pathParam1 string
+
+ pathParam1, err = runtime.StyleParamWithOptions("simple", false, "repo_slug", repoSlug, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ var pathParam2 string
+
+ pathParam2, err = runtime.StyleParamWithOptions("simple", false, "pull_request_id", pullRequestId, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "integer", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/repositories/%s/%s/pullrequests/%s/merge", pathParam0, pathParam1, pathParam2)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ if params != nil {
+ queryValues := queryURL.Query()
+
+ if params.Async != nil {
+
+ if queryFrag, err := runtime.StyleParamWithOptions("form", true, "async", *params.Async, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "boolean", Format: ""}); err != nil {
+ return nil, err
+ } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ return nil, err
+ } else {
+ for k, v := range parsed {
+ for _, v2 := range v {
+ queryValues.Add(k, v2)
+ }
+ }
+ }
+
+ }
+
+ queryURL.RawQuery = queryValues.Encode()
+ }
+
+ req, err := http.NewRequest("POST", queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetRepositoriesWorkspaceRepoSlugCommitCommitWithResponse request
+ GetRepositoriesWorkspaceRepoSlugCommitCommitWithResponse(ctx context.Context, workspace string, repoSlug string, commit string, reqEditors ...RequestEditorFn) (*GetRepositoriesWorkspaceRepoSlugCommitCommitResponse, error)
+
+ // GetRepositoriesWorkspaceRepoSlugPullrequestsWithResponse request
+ GetRepositoriesWorkspaceRepoSlugPullrequestsWithResponse(ctx context.Context, workspace string, repoSlug string, params *GetRepositoriesWorkspaceRepoSlugPullrequestsParams, reqEditors ...RequestEditorFn) (*GetRepositoriesWorkspaceRepoSlugPullrequestsResponse, error)
+
+ // PostRepositoriesWorkspaceRepoSlugPullrequestsWithBodyWithResponse request with any body
+ PostRepositoriesWorkspaceRepoSlugPullrequestsWithBodyWithResponse(ctx context.Context, workspace string, repoSlug string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostRepositoriesWorkspaceRepoSlugPullrequestsResponse, error)
+
+ PostRepositoriesWorkspaceRepoSlugPullrequestsWithResponse(ctx context.Context, workspace string, repoSlug string, body PostRepositoriesWorkspaceRepoSlugPullrequestsJSONRequestBody, reqEditors ...RequestEditorFn) (*PostRepositoriesWorkspaceRepoSlugPullrequestsResponse, error)
+
+ // GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdWithResponse request
+ GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdWithResponse(ctx context.Context, workspace string, repoSlug string, pullRequestId int, reqEditors ...RequestEditorFn) (*GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse, error)
+
+ // PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeWithBodyWithResponse request with any body
+ PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeWithBodyWithResponse(ctx context.Context, workspace string, repoSlug string, pullRequestId int, params *PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse, error)
+
+ PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeWithResponse(ctx context.Context, workspace string, repoSlug string, pullRequestId int, params *PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams, body PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeJSONRequestBody, reqEditors ...RequestEditorFn) (*PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse, error)
+}
+
+type GetRepositoriesWorkspaceRepoSlugCommitCommitResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Commit
+ JSON404 *Error
+}
+
+// Status returns HTTPResponse.Status
+func (r GetRepositoriesWorkspaceRepoSlugCommitCommitResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetRepositoriesWorkspaceRepoSlugCommitCommitResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+type GetRepositoriesWorkspaceRepoSlugPullrequestsResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *PaginatedPullrequests
+ JSON404 *Error
+}
+
+// Status returns HTTPResponse.Status
+func (r GetRepositoriesWorkspaceRepoSlugPullrequestsResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetRepositoriesWorkspaceRepoSlugPullrequestsResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+type PostRepositoriesWorkspaceRepoSlugPullrequestsResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON201 *Pullrequest
+ JSON400 *Error
+ JSON401 *Error
+}
+
+// Status returns HTTPResponse.Status
+func (r PostRepositoriesWorkspaceRepoSlugPullrequestsResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r PostRepositoriesWorkspaceRepoSlugPullrequestsResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+type GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Pullrequest
+ JSON404 *Error
+}
+
+// Status returns HTTPResponse.Status
+func (r GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+type PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Pullrequest
+ JSON555 *Error
+}
+
+// Status returns HTTPResponse.Status
+func (r PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// GetRepositoriesWorkspaceRepoSlugCommitCommitWithResponse request returning *GetRepositoriesWorkspaceRepoSlugCommitCommitResponse
+func (c *ClientWithResponses) GetRepositoriesWorkspaceRepoSlugCommitCommitWithResponse(ctx context.Context, workspace string, repoSlug string, commit string, reqEditors ...RequestEditorFn) (*GetRepositoriesWorkspaceRepoSlugCommitCommitResponse, error) {
+ rsp, err := c.GetRepositoriesWorkspaceRepoSlugCommitCommit(ctx, workspace, repoSlug, commit, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetRepositoriesWorkspaceRepoSlugCommitCommitResponse(rsp)
+}
+
+// GetRepositoriesWorkspaceRepoSlugPullrequestsWithResponse request returning *GetRepositoriesWorkspaceRepoSlugPullrequestsResponse
+func (c *ClientWithResponses) GetRepositoriesWorkspaceRepoSlugPullrequestsWithResponse(ctx context.Context, workspace string, repoSlug string, params *GetRepositoriesWorkspaceRepoSlugPullrequestsParams, reqEditors ...RequestEditorFn) (*GetRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ rsp, err := c.GetRepositoriesWorkspaceRepoSlugPullrequests(ctx, workspace, repoSlug, params, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetRepositoriesWorkspaceRepoSlugPullrequestsResponse(rsp)
+}
+
+// PostRepositoriesWorkspaceRepoSlugPullrequestsWithBodyWithResponse request with arbitrary body returning *PostRepositoriesWorkspaceRepoSlugPullrequestsResponse
+func (c *ClientWithResponses) PostRepositoriesWorkspaceRepoSlugPullrequestsWithBodyWithResponse(ctx context.Context, workspace string, repoSlug string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ rsp, err := c.PostRepositoriesWorkspaceRepoSlugPullrequestsWithBody(ctx, workspace, repoSlug, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostRepositoriesWorkspaceRepoSlugPullrequestsResponse(rsp)
+}
+
+func (c *ClientWithResponses) PostRepositoriesWorkspaceRepoSlugPullrequestsWithResponse(ctx context.Context, workspace string, repoSlug string, body PostRepositoriesWorkspaceRepoSlugPullrequestsJSONRequestBody, reqEditors ...RequestEditorFn) (*PostRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ rsp, err := c.PostRepositoriesWorkspaceRepoSlugPullrequests(ctx, workspace, repoSlug, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostRepositoriesWorkspaceRepoSlugPullrequestsResponse(rsp)
+}
+
+// GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdWithResponse request returning *GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse
+func (c *ClientWithResponses) GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdWithResponse(ctx context.Context, workspace string, repoSlug string, pullRequestId int, reqEditors ...RequestEditorFn) (*GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse, error) {
+ rsp, err := c.GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestId(ctx, workspace, repoSlug, pullRequestId, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse(rsp)
+}
+
+// PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeWithBodyWithResponse request with arbitrary body returning *PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse
+func (c *ClientWithResponses) PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeWithBodyWithResponse(ctx context.Context, workspace string, repoSlug string, pullRequestId int, params *PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse, error) {
+ rsp, err := c.PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeWithBody(ctx, workspace, repoSlug, pullRequestId, params, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse(rsp)
+}
+
+func (c *ClientWithResponses) PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeWithResponse(ctx context.Context, workspace string, repoSlug string, pullRequestId int, params *PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeParams, body PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeJSONRequestBody, reqEditors ...RequestEditorFn) (*PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse, error) {
+ rsp, err := c.PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMerge(ctx, workspace, repoSlug, pullRequestId, params, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse(rsp)
+}
+
+// ParseGetRepositoriesWorkspaceRepoSlugCommitCommitResponse parses an HTTP response from a GetRepositoriesWorkspaceRepoSlugCommitCommitWithResponse call
+func ParseGetRepositoriesWorkspaceRepoSlugCommitCommitResponse(rsp *http.Response) (*GetRepositoriesWorkspaceRepoSlugCommitCommitResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetRepositoriesWorkspaceRepoSlugCommitCommitResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest Commit
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
+ var dest Error
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON404 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseGetRepositoriesWorkspaceRepoSlugPullrequestsResponse parses an HTTP response from a GetRepositoriesWorkspaceRepoSlugPullrequestsWithResponse call
+func ParseGetRepositoriesWorkspaceRepoSlugPullrequestsResponse(rsp *http.Response) (*GetRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetRepositoriesWorkspaceRepoSlugPullrequestsResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest PaginatedPullrequests
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
+ var dest Error
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON404 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParsePostRepositoriesWorkspaceRepoSlugPullrequestsResponse parses an HTTP response from a PostRepositoriesWorkspaceRepoSlugPullrequestsWithResponse call
+func ParsePostRepositoriesWorkspaceRepoSlugPullrequestsResponse(rsp *http.Response) (*PostRepositoriesWorkspaceRepoSlugPullrequestsResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &PostRepositoriesWorkspaceRepoSlugPullrequestsResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 201:
+ var dest Pullrequest
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON201 = &dest
+
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
+ var dest Error
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON400 = &dest
+
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401:
+ var dest Error
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON401 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseGetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse parses an HTTP response from a GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdWithResponse call
+func ParseGetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse(rsp *http.Response) (*GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest Pullrequest
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
+ var dest Error
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON404 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParsePostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse parses an HTTP response from a PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeWithResponse call
+func ParsePostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse(rsp *http.Response) (*PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &PostRepositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergeResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest Pullrequest
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 555:
+ var dest Error
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON555 = &dest
+
+ }
+
+ return response, nil
+}
diff --git a/pkg/gitprovider/bitbucket/pr_integration_test.go b/pkg/gitprovider/bitbucket/pr_integration_test.go
deleted file mode 100644
index 334b44fc91..0000000000
--- a/pkg/gitprovider/bitbucket/pr_integration_test.go
+++ /dev/null
@@ -1,38 +0,0 @@
-//go:build integration && bitbucket
-
-package bitbucket
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-
- "github.com/akuity/kargo/pkg/gitprovider"
- gptest "github.com/akuity/kargo/pkg/gitprovider/testing"
-)
-
-func TestCreateAndMergePullRequest(t *testing.T) {
- repoURL := gptest.RequireEnv(t, "TEST_BITBUCKET_REPO_URL")
- token := gptest.RequireEnv(t, "TEST_BITBUCKET_TOKEN")
-
- repoCfg := gptest.RepoConfig{
- RepoURL: repoURL,
- Token: token,
- GitUsername: gptest.RequireEnv(t, "TEST_BITBUCKET_USERNAME"),
- }
-
- prov, err := NewProvider(repoURL, &gitprovider.Options{Token: token})
- require.NoError(t, err)
-
- gptest.RunPRTests(t, repoCfg, prov, []gptest.PRTestCase{
- {
- Name: "unspecified merge method",
- ExpectedParents: 2, // Repo default is merge commit
- },
- {
- Name: "explicit merge method",
- MergeMethod: "squash",
- ExpectMergeErr: true, // Library limitation
- },
- })
-}
diff --git a/pkg/promotion/runner/builtin/git_pr_merger.go b/pkg/promotion/runner/builtin/git_pr_merger.go
index 37287ffac9..92f8a7823c 100644
--- a/pkg/promotion/runner/builtin/git_pr_merger.go
+++ b/pkg/promotion/runner/builtin/git_pr_merger.go
@@ -14,11 +14,11 @@ import (
"github.com/akuity/kargo/pkg/promotion"
"github.com/akuity/kargo/pkg/x/promotion/runner/builtin"
- _ "github.com/akuity/kargo/pkg/gitprovider/azure" // Azure provider registration
- _ "github.com/akuity/kargo/pkg/gitprovider/bitbucket" // Bitbucket provider registration
- _ "github.com/akuity/kargo/pkg/gitprovider/gitea" // Gitea provider registration
- _ "github.com/akuity/kargo/pkg/gitprovider/github" // GitHub provider registration
- _ "github.com/akuity/kargo/pkg/gitprovider/gitlab" // GitLab provider registration
+ _ "github.com/akuity/kargo/pkg/gitprovider/azure" // Azure provider registration
+ _ "github.com/akuity/kargo/pkg/gitprovider/bitbucket/cloud" // Bitbucket Cloud provider registration
+ _ "github.com/akuity/kargo/pkg/gitprovider/gitea" // Gitea provider registration
+ _ "github.com/akuity/kargo/pkg/gitprovider/github" // GitHub provider registration
+ _ "github.com/akuity/kargo/pkg/gitprovider/gitlab" // GitLab provider registration
)
const stepKindGitMergePR = "git-merge-pr"
diff --git a/pkg/promotion/runner/builtin/git_pr_opener.go b/pkg/promotion/runner/builtin/git_pr_opener.go
index ccb1bd6c5b..8f377ce9dd 100644
--- a/pkg/promotion/runner/builtin/git_pr_opener.go
+++ b/pkg/promotion/runner/builtin/git_pr_opener.go
@@ -16,11 +16,11 @@ import (
"github.com/akuity/kargo/pkg/promotion"
"github.com/akuity/kargo/pkg/x/promotion/runner/builtin"
- _ "github.com/akuity/kargo/pkg/gitprovider/azure" // Azure provider registration
- _ "github.com/akuity/kargo/pkg/gitprovider/bitbucket" // Bitbucket provider registration
- _ "github.com/akuity/kargo/pkg/gitprovider/gitea" // Gitea provider registration
- _ "github.com/akuity/kargo/pkg/gitprovider/github" // GitHub provider registration
- _ "github.com/akuity/kargo/pkg/gitprovider/gitlab" // GitLab provider registration
+ _ "github.com/akuity/kargo/pkg/gitprovider/azure" // Azure provider registration
+ _ "github.com/akuity/kargo/pkg/gitprovider/bitbucket/cloud" // Bitbucket Cloud provider registration
+ _ "github.com/akuity/kargo/pkg/gitprovider/gitea" // Gitea provider registration
+ _ "github.com/akuity/kargo/pkg/gitprovider/github" // GitHub provider registration
+ _ "github.com/akuity/kargo/pkg/gitprovider/gitlab" // GitLab provider registration
)
const stepKindGitOpenPR = "git-open-pr"
diff --git a/pkg/promotion/runner/builtin/git_pr_waiter.go b/pkg/promotion/runner/builtin/git_pr_waiter.go
index 36ac69a784..ec6dbd22a8 100644
--- a/pkg/promotion/runner/builtin/git_pr_waiter.go
+++ b/pkg/promotion/runner/builtin/git_pr_waiter.go
@@ -13,11 +13,11 @@ import (
"github.com/akuity/kargo/pkg/promotion"
"github.com/akuity/kargo/pkg/x/promotion/runner/builtin"
- _ "github.com/akuity/kargo/pkg/gitprovider/azure" // Azure provider registration
- _ "github.com/akuity/kargo/pkg/gitprovider/bitbucket" // Bitbucket provider registration
- _ "github.com/akuity/kargo/pkg/gitprovider/gitea" // Gitea provider registration
- _ "github.com/akuity/kargo/pkg/gitprovider/github" // GitHub provider registration
- _ "github.com/akuity/kargo/pkg/gitprovider/gitlab" // GitLab provider registration
+ _ "github.com/akuity/kargo/pkg/gitprovider/azure" // Azure provider registration
+ _ "github.com/akuity/kargo/pkg/gitprovider/bitbucket/cloud" // Bitbucket Cloud provider registration
+ _ "github.com/akuity/kargo/pkg/gitprovider/gitea" // Gitea provider registration
+ _ "github.com/akuity/kargo/pkg/gitprovider/github" // GitHub provider registration
+ _ "github.com/akuity/kargo/pkg/gitprovider/gitlab" // GitLab provider registration
)
const stepKindGitWaitForPR = "git-wait-for-pr"
diff --git a/ui/src/features/freight-timeline/open-container-initiative-utils.test.ts b/ui/src/features/freight-timeline/open-container-initiative-utils.test.ts
index b604968eb2..af2ceba472 100644
--- a/ui/src/features/freight-timeline/open-container-initiative-utils.test.ts
+++ b/ui/src/features/freight-timeline/open-container-initiative-utils.test.ts
@@ -56,17 +56,6 @@ describe('getGitCommitURL', () => {
url: 'git@bitbucket.org:akuity/kargo.git',
expected: 'https://bitbucket.org/akuity/kargo/commits/abc1234'
},
- // Bitbucket Data Center — self-hosted
- {
- name: 'bitbucket data center custom domain',
- url: 'https://bitbucket.internal.net/akuity/kargo.git',
- expected: 'https://bitbucket.internal.net/akuity/kargo/commits/abc1234'
- },
- {
- name: 'bitbucket data center SSH',
- url: 'git@bitbucket.internal.net:akuity/kargo.git',
- expected: 'https://bitbucket.internal.net/akuity/kargo/commits/abc1234'
- },
// Unknown provider — fall back to original url
{
name: 'unknown provider returns original url',