mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-06-02 08:20:50 +00:00
Refactor Gitlab Remote (#358)
- Replace custom client - Update Docs - Test if it works - Update Tests close #285
This commit is contained in:
parent
2f267e2a79
commit
169e7e5aa3
|
@ -398,11 +398,6 @@ var flags = []cli.Flag{
|
||||||
Name: "gitlab-private-mode",
|
Name: "gitlab-private-mode",
|
||||||
Usage: "gitlab is running in private mode",
|
Usage: "gitlab is running in private mode",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
|
||||||
EnvVar: "WOODPECKER_GITLAB_V3_API",
|
|
||||||
Name: "gitlab-v3-api",
|
|
||||||
Usage: "gitlab is running the v3 api",
|
|
||||||
},
|
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
EnvVar: "WOODPECKER_STASH",
|
EnvVar: "WOODPECKER_STASH",
|
||||||
Name: "stash",
|
Name: "stash",
|
||||||
|
|
|
@ -32,7 +32,6 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/remote/gitea"
|
"github.com/woodpecker-ci/woodpecker/server/remote/gitea"
|
||||||
"github.com/woodpecker-ci/woodpecker/server/remote/github"
|
"github.com/woodpecker-ci/woodpecker/server/remote/github"
|
||||||
"github.com/woodpecker-ci/woodpecker/server/remote/gitlab"
|
"github.com/woodpecker-ci/woodpecker/server/remote/gitlab"
|
||||||
"github.com/woodpecker-ci/woodpecker/server/remote/gitlab3"
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server/remote/gogs"
|
"github.com/woodpecker-ci/woodpecker/server/remote/gogs"
|
||||||
"github.com/woodpecker-ci/woodpecker/server/store"
|
"github.com/woodpecker-ci/woodpecker/server/store"
|
||||||
"github.com/woodpecker-ci/woodpecker/server/store/datastore"
|
"github.com/woodpecker-ci/woodpecker/server/store/datastore"
|
||||||
|
@ -149,25 +148,14 @@ func setupStash(c *cli.Context) (remote.Remote, error) {
|
||||||
|
|
||||||
// helper function to setup the Gitlab remote from the CLI arguments.
|
// helper function to setup the Gitlab remote from the CLI arguments.
|
||||||
func setupGitlab(c *cli.Context) (remote.Remote, error) {
|
func setupGitlab(c *cli.Context) (remote.Remote, error) {
|
||||||
if c.Bool("gitlab-v3-api") {
|
|
||||||
return gitlab3.New(gitlab3.Opts{
|
|
||||||
URL: c.String("gitlab-server"),
|
|
||||||
Client: c.String("gitlab-client"),
|
|
||||||
Secret: c.String("gitlab-secret"),
|
|
||||||
Username: c.String("gitlab-git-username"),
|
|
||||||
Password: c.String("gitlab-git-password"),
|
|
||||||
PrivateMode: c.Bool("gitlab-private-mode"),
|
|
||||||
SkipVerify: c.Bool("gitlab-skip-verify"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return gitlab.New(gitlab.Opts{
|
return gitlab.New(gitlab.Opts{
|
||||||
URL: c.String("gitlab-server"),
|
URL: c.String("gitlab-server"),
|
||||||
Client: c.String("gitlab-client"),
|
ClientID: c.String("gitlab-client"),
|
||||||
Secret: c.String("gitlab-secret"),
|
ClientSecret: c.String("gitlab-secret"),
|
||||||
Username: c.String("gitlab-git-username"),
|
Username: c.String("gitlab-git-username"),
|
||||||
Password: c.String("gitlab-git-password"),
|
Password: c.String("gitlab-git-password"),
|
||||||
PrivateMode: c.Bool("gitlab-private-mode"),
|
PrivateMode: c.Bool("gitlab-private-mode"),
|
||||||
SkipVerify: c.Bool("gitlab-skip-verify"),
|
SkipVerify: c.Bool("gitlab-skip-verify"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Multi pipelines
|
# Multi pipelines
|
||||||
|
|
||||||
> NOTE: This Feature is only available for GitHub & Gitea repositories. Follow [this](https://github.com/woodpecker-ci/woodpecker/issues/131) issue to support further development.
|
> NOTE: This Feature is only available for GitHub, Gitea & Gitlab repositories. Follow [this](https://github.com/woodpecker-ci/woodpecker/issues/131) issue to support further development.
|
||||||
|
|
||||||
By default, Woodpecker looks for the pipeline definition in `.woodpecker.yml` in the project root.
|
By default, Woodpecker looks for the pipeline definition in `.woodpecker.yml` in the project root.
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
|
|
||||||
| Feature | [GitHub](github/) | [Gitea](gitea/) | [Gitlab](gitlab/) | [Bitbucket](bitbucket/) | [Bitbucket Server](bitbucket_server/) | Gogs | Coding |
|
| Feature | [GitHub](github/) | [Gitea](gitea/) | [Gitlab](gitlab/) | [Bitbucket](bitbucket/) | [Bitbucket Server](bitbucket_server/) | Gogs | Coding |
|
||||||
| --- | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
| --- | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
||||||
| Event: Push | :white_check_mark: | :white_check_mark: |
|
| Event: Push | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||||
| Event: Tag | :white_check_mark: | :white_check_mark: |
|
| Event: Tag | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||||
| Event: Pull-Request | :white_check_mark: | :white_check_mark: |
|
| Event: Pull-Request | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||||
| Event: Deploy | :white_check_mark: | :white_check_mark: |
|
| Event: Deploy | :white_check_mark: | :white_check_mark: | :x: |
|
||||||
| OAuth | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
| OAuth | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||||
| [Multi pipeline](/docs/usage/multi-pipeline) | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: |
|
| [Multi pipeline](/docs/usage/multi-pipeline) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: |
|
||||||
| [when-path filter](/docs/usage/pipeline-syntax#path) | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: |
|
| [when-path filter](/docs/usage/pipeline-syntax#path) | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: |
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -51,6 +51,7 @@ require (
|
||||||
github.com/urfave/cli v1.22.4
|
github.com/urfave/cli v1.22.4
|
||||||
github.com/woodpecker-ci/expr v0.0.0-20210628233344-164b8b3d0915
|
github.com/woodpecker-ci/expr v0.0.0-20210628233344-164b8b3d0915
|
||||||
github.com/woodpecker-ci/togo v0.0.0-20180401185031-50a0e4726e74
|
github.com/woodpecker-ci/togo v0.0.0-20180401185031-50a0e4726e74
|
||||||
|
github.com/xanzy/go-gitlab v0.51.1
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0
|
github.com/xeipuuv/gojsonschema v1.2.0
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
|
||||||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a
|
golang.org/x/net v0.0.0-20210825183410-e898025ed96a
|
||||||
|
|
11
go.sum
11
go.sum
|
@ -379,6 +379,7 @@ github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-github/v39 v39.1.0 h1:1vf4gM0D1e+Df2HMxaYC3+o9+Huj3ywGTtWc3VVYaDA=
|
github.com/google/go-github/v39 v39.1.0 h1:1vf4gM0D1e+Df2HMxaYC3+o9+Huj3ywGTtWc3VVYaDA=
|
||||||
github.com/google/go-github/v39 v39.1.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE=
|
github.com/google/go-github/v39 v39.1.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE=
|
||||||
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
@ -414,8 +415,14 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||||
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
|
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
|
||||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.6.8 h1:92lWxgpa+fF3FozM4B3UZtHZMJX8T5XT+TFdCxsPyWs=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||||
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04x7iNw=
|
github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04x7iNw=
|
||||||
github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
|
@ -696,6 +703,8 @@ github.com/woodpecker-ci/expr v0.0.0-20210628233344-164b8b3d0915 h1:9zBOoKSR9CBe
|
||||||
github.com/woodpecker-ci/expr v0.0.0-20210628233344-164b8b3d0915/go.mod h1:PbzlZ93HrA1cf16OUP1vckAPq57gtF+ccnwZeDkmC9s=
|
github.com/woodpecker-ci/expr v0.0.0-20210628233344-164b8b3d0915/go.mod h1:PbzlZ93HrA1cf16OUP1vckAPq57gtF+ccnwZeDkmC9s=
|
||||||
github.com/woodpecker-ci/togo v0.0.0-20180401185031-50a0e4726e74 h1:q/tWgA3hMWrAQqsS4yfhc0+w4RevBGr9ghem/bFFDRY=
|
github.com/woodpecker-ci/togo v0.0.0-20180401185031-50a0e4726e74 h1:q/tWgA3hMWrAQqsS4yfhc0+w4RevBGr9ghem/bFFDRY=
|
||||||
github.com/woodpecker-ci/togo v0.0.0-20180401185031-50a0e4726e74/go.mod h1:lykh/ei/caPO6sv4NN+pqnDTo8kEKhZcnhafN8GhGNs=
|
github.com/woodpecker-ci/togo v0.0.0-20180401185031-50a0e4726e74/go.mod h1:lykh/ei/caPO6sv4NN+pqnDTo8kEKhZcnhafN8GhGNs=
|
||||||
|
github.com/xanzy/go-gitlab v0.51.1 h1:wWKLalwx4omxFoHh3PLs9zDgAD4GXDP/uoxwMRCSiWM=
|
||||||
|
github.com/xanzy/go-gitlab v0.51.1/go.mod h1:Q+hQhV508bDPoBijv7YjK/Lvlb4PhVhJdKqXVQrUoAE=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||||
|
@ -811,6 +820,7 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
|
||||||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a h1:bRuuGXV8wwSdGTB+CtJf+FjgO1APK1CoO39T4BN/XBw=
|
golang.org/x/net v0.0.0-20210825183410-e898025ed96a h1:bRuuGXV8wwSdGTB+CtJf+FjgO1APK1CoO39T4BN/XBw=
|
||||||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
@ -969,6 +979,7 @@ google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/
|
||||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
const (
|
|
||||||
droneServiceUrl = "/projects/:id/services/drone-ci"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Client) AddDroneService(id string, params QMap) error {
|
|
||||||
url, opaque := c.ResourceUrl(
|
|
||||||
droneServiceUrl,
|
|
||||||
QMap{":id": id},
|
|
||||||
params,
|
|
||||||
)
|
|
||||||
|
|
||||||
_, err := c.Do("PUT", url, opaque, nil)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) DeleteDroneService(id string) error {
|
|
||||||
url, opaque := c.ResourceUrl(
|
|
||||||
droneServiceUrl,
|
|
||||||
QMap{":id": id},
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
|
|
||||||
_, err := c.Do("DELETE", url, opaque, nil)
|
|
||||||
return err
|
|
||||||
}
|
|
|
@ -1,110 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Client struct {
|
|
||||||
BaseUrl string
|
|
||||||
ApiPath string
|
|
||||||
Token string
|
|
||||||
Client *http.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(baseUrl, apiPath, token string, skipVerify bool) *Client {
|
|
||||||
config := &tls.Config{InsecureSkipVerify: skipVerify}
|
|
||||||
tr := &http.Transport{
|
|
||||||
Proxy: http.ProxyFromEnvironment,
|
|
||||||
TLSClientConfig: config,
|
|
||||||
}
|
|
||||||
client := &http.Client{Transport: tr}
|
|
||||||
|
|
||||||
return &Client{
|
|
||||||
BaseUrl: baseUrl,
|
|
||||||
ApiPath: apiPath,
|
|
||||||
Token: token,
|
|
||||||
Client: client,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) ResourceUrl(u string, params, query QMap) (string, string) {
|
|
||||||
if params != nil {
|
|
||||||
for key, val := range params {
|
|
||||||
u = strings.Replace(u, key, encodeParameter(val), -1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
query_params := url.Values{}
|
|
||||||
|
|
||||||
if query != nil {
|
|
||||||
for key, val := range query {
|
|
||||||
query_params.Set(key, val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u = c.BaseUrl + c.ApiPath + u + "?" + query_params.Encode()
|
|
||||||
p, err := url.Parse(u)
|
|
||||||
if err != nil {
|
|
||||||
return u, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
opaque := "//" + p.Host + p.Path
|
|
||||||
return u, opaque
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) Do(method, url, opaque string, body []byte) ([]byte, error) {
|
|
||||||
var req *http.Request
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if body != nil {
|
|
||||||
reader := bytes.NewReader(body)
|
|
||||||
req, err = http.NewRequest(method, url, reader)
|
|
||||||
} else {
|
|
||||||
req, err = http.NewRequest(method, url, nil)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error while building gitlab request")
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.Token))
|
|
||||||
|
|
||||||
if len(opaque) > 0 {
|
|
||||||
req.URL.Opaque = opaque
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := c.Client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Client.Do error: %q", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
contents, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("%s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode >= 400 {
|
|
||||||
err = fmt.Errorf("*Gitlab.buildAndExecRequest failed: <%d> %s", resp.StatusCode, req.URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
return contents, err
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
groupsUrl = "/groups"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Get a list of all projects owned by the authenticated user.
|
|
||||||
func (g *Client) AllGroups() ([]*Namespace, error) {
|
|
||||||
var perPage = 100
|
|
||||||
var groups []*Namespace
|
|
||||||
|
|
||||||
for i := 1; true; i++ {
|
|
||||||
contents, err := g.Groups(i, perPage)
|
|
||||||
if err != nil {
|
|
||||||
return groups, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, value := range contents {
|
|
||||||
groups = append(groups, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(groups) == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(groups)/i < perPage {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return groups, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Client) Groups(page, perPage int) ([]*Namespace, error) {
|
|
||||||
url, opaque := g.ResourceUrl(groupsUrl, nil, QMap{
|
|
||||||
"page": strconv.Itoa(page),
|
|
||||||
"per_page": strconv.Itoa(perPage),
|
|
||||||
})
|
|
||||||
|
|
||||||
var groups []*Namespace
|
|
||||||
|
|
||||||
contents, err := g.Do("GET", url, opaque, nil)
|
|
||||||
if err == nil {
|
|
||||||
err = json.Unmarshal(contents, &groups)
|
|
||||||
}
|
|
||||||
|
|
||||||
return groups, err
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ParseHook parses hook payload from GitLab
|
|
||||||
func ParseHook(payload []byte) (*HookPayload, error) {
|
|
||||||
hp := HookPayload{}
|
|
||||||
if err := json.Unmarshal(payload, &hp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Basic sanity check
|
|
||||||
switch {
|
|
||||||
case len(hp.ObjectKind) == 0:
|
|
||||||
// Assume this is a post-receive within repository
|
|
||||||
if len(hp.After) == 0 {
|
|
||||||
return nil, fmt.Errorf("Invalid hook received, commit hash not found.")
|
|
||||||
}
|
|
||||||
case hp.ObjectKind == "push":
|
|
||||||
if hp.Repository == nil {
|
|
||||||
return nil, fmt.Errorf("Invalid push hook received, attributes not found")
|
|
||||||
}
|
|
||||||
case hp.ObjectKind == "tag_push":
|
|
||||||
if hp.Repository == nil {
|
|
||||||
return nil, fmt.Errorf("Invalid tag push hook received, attributes not found")
|
|
||||||
}
|
|
||||||
case hp.ObjectKind == "issue":
|
|
||||||
fallthrough
|
|
||||||
case hp.ObjectKind == "merge_request":
|
|
||||||
if hp.ObjectAttributes == nil {
|
|
||||||
return nil, fmt.Errorf("Invalid hook received, attributes not found.")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("Invalid hook received, payload format not recognized.")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &hp, nil
|
|
||||||
}
|
|
|
@ -1,168 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
projectsUrl = "/projects"
|
|
||||||
projectUrl = "/projects/:id"
|
|
||||||
repoUrlRawFileRef = "/projects/:id/repository/files/:filepath"
|
|
||||||
commitStatusUrl = "/projects/:id/statuses/:sha"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Get a list of all projects owned by the authenticated user.
|
|
||||||
func (g *Client) AllProjects(hide_archives bool) ([]*Project, error) {
|
|
||||||
var per_page = 100
|
|
||||||
var projects []*Project
|
|
||||||
|
|
||||||
for i := 1; true; i++ {
|
|
||||||
contents, err := g.Projects(i, per_page, hide_archives)
|
|
||||||
if err != nil {
|
|
||||||
return projects, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, value := range contents {
|
|
||||||
projects = append(projects, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(projects) == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(projects)/i < per_page {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return projects, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a list of projects owned by the authenticated user.
|
|
||||||
func (c *Client) Projects(page int, per_page int, hide_archives bool) ([]*Project, error) {
|
|
||||||
projectsOptions := QMap{
|
|
||||||
"page": strconv.Itoa(page),
|
|
||||||
"per_page": strconv.Itoa(per_page),
|
|
||||||
"membership": "true",
|
|
||||||
}
|
|
||||||
|
|
||||||
if hide_archives {
|
|
||||||
projectsOptions["archived"] = "false"
|
|
||||||
}
|
|
||||||
|
|
||||||
url, opaque := c.ResourceUrl(projectsUrl, nil, projectsOptions)
|
|
||||||
|
|
||||||
var projects []*Project
|
|
||||||
|
|
||||||
contents, err := c.Do("GET", url, opaque, nil)
|
|
||||||
if err == nil {
|
|
||||||
err = json.Unmarshal(contents, &projects)
|
|
||||||
}
|
|
||||||
|
|
||||||
return projects, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a project by id
|
|
||||||
func (c *Client) Project(id string) (*Project, error) {
|
|
||||||
url, opaque := c.ResourceUrl(projectUrl, QMap{":id": id}, nil)
|
|
||||||
|
|
||||||
var project *Project
|
|
||||||
|
|
||||||
contents, err := c.Do("GET", url, opaque, nil)
|
|
||||||
if err == nil {
|
|
||||||
err = json.Unmarshal(contents, &project)
|
|
||||||
}
|
|
||||||
|
|
||||||
return project, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) RepoRawFileRef(id, ref, filepath string) ([]byte, error) {
|
|
||||||
var fileRef FileRef
|
|
||||||
url, opaque := c.ResourceUrl(
|
|
||||||
repoUrlRawFileRef,
|
|
||||||
QMap{
|
|
||||||
":id": id,
|
|
||||||
":filepath": filepath,
|
|
||||||
},
|
|
||||||
QMap{
|
|
||||||
"ref": ref,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
contents, err := c.Do("GET", url, opaque, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(contents, &fileRef)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
fileRawContent, err := base64.StdEncoding.DecodeString(fileRef.Content)
|
|
||||||
return fileRawContent, err
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
func (c *Client) SetStatus(id, sha, state, desc, ref, link string) error {
|
|
||||||
url, opaque := c.ResourceUrl(
|
|
||||||
commitStatusUrl,
|
|
||||||
QMap{
|
|
||||||
":id": id,
|
|
||||||
":sha": sha,
|
|
||||||
},
|
|
||||||
QMap{
|
|
||||||
"state": state,
|
|
||||||
"ref": ref,
|
|
||||||
"target_url": link,
|
|
||||||
"description": desc,
|
|
||||||
"context": "ci/drone",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
_, err := c.Do("POST", url, opaque, nil)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a list of projects by query owned by the authenticated user.
|
|
||||||
func (c *Client) SearchProjectId(namespace string, name string) (id int, err error) {
|
|
||||||
|
|
||||||
url, opaque := c.ResourceUrl(projectsUrl, nil, QMap{
|
|
||||||
"query": strings.ToLower(name),
|
|
||||||
"membership": "true",
|
|
||||||
})
|
|
||||||
|
|
||||||
var projects []*Project
|
|
||||||
|
|
||||||
contents, err := c.Do("GET", url, opaque, nil)
|
|
||||||
if err == nil {
|
|
||||||
err = json.Unmarshal(contents, &projects)
|
|
||||||
} else {
|
|
||||||
return id, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, project := range projects {
|
|
||||||
if project.Namespace.Name == namespace && strings.ToLower(project.Name) == strings.ToLower(name) {
|
|
||||||
id = project.Id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return id, err
|
|
||||||
}
|
|
|
@ -1,164 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
type QMap map[string]string
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
Id int `json:"id,omitempty"`
|
|
||||||
Username string `json:"username,omitempty"`
|
|
||||||
Email string `json:"email,omitempty"`
|
|
||||||
AvatarUrl string `json:"avatar_url,omitempty"`
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProjectAccess struct {
|
|
||||||
AccessLevel int `json:"access_level,omitempty"`
|
|
||||||
NotificationLevel int `json:"notification_level,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type GroupAccess struct {
|
|
||||||
AccessLevel int `json:"access_level,omitempty"`
|
|
||||||
NotificationLevel int `json:"notification_level,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Permissions struct {
|
|
||||||
ProjectAccess *ProjectAccess `json:"project_access,omitempty"`
|
|
||||||
GroupAccess *GroupAccess `json:"group_access,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Member struct {
|
|
||||||
Id int
|
|
||||||
Username string
|
|
||||||
Email string
|
|
||||||
Name string
|
|
||||||
State string
|
|
||||||
CreatedAt string `json:"created_at,omitempty"`
|
|
||||||
// AccessLevel int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Project struct {
|
|
||||||
Id int `json:"id,omitempty"`
|
|
||||||
Owner *Member `json:"owner,omitempty"`
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
Description string `json:"description,omitempty"`
|
|
||||||
DefaultBranch string `json:"default_branch,omitempty"`
|
|
||||||
Public bool `json:"public,omitempty"`
|
|
||||||
Path string `json:"path,omitempty"`
|
|
||||||
PathWithNamespace string `json:"path_with_namespace,omitempty"`
|
|
||||||
Namespace *Namespace `json:"namespace,omitempty"`
|
|
||||||
SshRepoUrl string `json:"ssh_url_to_repo"`
|
|
||||||
HttpRepoUrl string `json:"http_url_to_repo"`
|
|
||||||
Url string `json:"web_url"`
|
|
||||||
AvatarUrl string `json:"avatar_url"`
|
|
||||||
Permissions *Permissions `json:"permissions,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Namespace struct {
|
|
||||||
Id int `json:"id,omitempty"`
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
Path string `json:"path,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Person struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type hProject struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
SshUrl string `json:"ssh_url"`
|
|
||||||
HttpUrl string `json:"http_url"`
|
|
||||||
GitSshUrl string `json:"git_ssh_url"`
|
|
||||||
GitHttpUrl string `json:"git_http_url"`
|
|
||||||
AvatarUrl string `json:"avatar_url"`
|
|
||||||
VisibilityLevel int `json:"visibility_level"`
|
|
||||||
WebUrl string `json:"web_url"`
|
|
||||||
PathWithNamespace string `json:"path_with_namespace"`
|
|
||||||
DefaultBranch string `json:"default_branch"`
|
|
||||||
Namespace string `json:"namespace"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type hRepository struct {
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
URL string `json:"url,omitempty"`
|
|
||||||
Description string `json:"description,omitempty"`
|
|
||||||
Homepage string `json:"homepage,omitempty"`
|
|
||||||
GitHttpUrl string `json:"git_http_url,omitempty"`
|
|
||||||
GitSshUrl string `json:"git_ssh_url,omitempty"`
|
|
||||||
VisibilityLevel int `json:"visibility_level,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type hCommit struct {
|
|
||||||
Id string `json:"id,omitempty"`
|
|
||||||
Message string `json:"message,omitempty"`
|
|
||||||
Timestamp string `json:"timestamp,omitempty"`
|
|
||||||
URL string `json:"url,omitempty"`
|
|
||||||
Author *Person `json:"author,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type HookObjAttr struct {
|
|
||||||
Id int `json:"id,omitempty"`
|
|
||||||
Title string `json:"title,omitempty"`
|
|
||||||
AssigneeId int `json:"assignee_id,omitempty"`
|
|
||||||
AuthorId int `json:"author_id,omitempty"`
|
|
||||||
ProjectId int `json:"project_id,omitempty"`
|
|
||||||
CreatedAt string `json:"created_at,omitempty"`
|
|
||||||
UpdatedAt string `json:"updated_at,omitempty"`
|
|
||||||
Position int `json:"position,omitempty"`
|
|
||||||
BranchName string `json:"branch_name,omitempty"`
|
|
||||||
Description string `json:"description,omitempty"`
|
|
||||||
MilestoneId int `json:"milestone_id,omitempty"`
|
|
||||||
State string `json:"state,omitempty"`
|
|
||||||
IId int `json:"iid,omitempty"`
|
|
||||||
TargetBranch string `json:"target_branch,omitempty"`
|
|
||||||
SourceBranch string `json:"source_branch,omitempty"`
|
|
||||||
SourceProjectId int `json:"source_project_id,omitempty"`
|
|
||||||
StCommits string `json:"st_commits,omitempty"`
|
|
||||||
StDiffs string `json:"st_diffs,omitempty"`
|
|
||||||
MergeStatus string `json:"merge_status,omitempty"`
|
|
||||||
TargetProjectId int `json:"target_project_id,omitempty"`
|
|
||||||
Url string `json:"url,omiyempty"`
|
|
||||||
Source *hProject `json:"source,omitempty"`
|
|
||||||
Target *hProject `json:"target,omitempty"`
|
|
||||||
LastCommit *hCommit `json:"last_commit,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type HookPayload struct {
|
|
||||||
Before string `json:"before,omitempty"`
|
|
||||||
After string `json:"after,omitempty"`
|
|
||||||
Ref string `json:"ref,omitempty"`
|
|
||||||
UserId int `json:"user_id,omitempty"`
|
|
||||||
UserName string `json:"user_name,omitempty"`
|
|
||||||
ProjectId int `json:"project_id,omitempty"`
|
|
||||||
Project *hProject `json:"project,omitempty"`
|
|
||||||
Repository *hRepository `json:"repository,omitempty"`
|
|
||||||
Commits []hCommit `json:"commits,omitempty"`
|
|
||||||
TotalCommitsCount int `json:"total_commits_count,omitempty"`
|
|
||||||
ObjectKind string `json:"object_kind,omitempty"`
|
|
||||||
ObjectAttributes *HookObjAttr `json:"object_attributes,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type FileRef struct {
|
|
||||||
FileName string `json:"file_name,omitempty"`
|
|
||||||
FilePath string `json:"file_path,omitempty"`
|
|
||||||
Size int `json:"size,omitempty"`
|
|
||||||
Encoding string `json:"encoding,omitempty"`
|
|
||||||
Content string `json:"content"`
|
|
||||||
Ref string `json:"ref,omitempty"`
|
|
||||||
BlobId string `json:"blob_id,omitempty"`
|
|
||||||
CommitId string `json:"commit_id,omitempty"`
|
|
||||||
LastCommitId string `json:"last_commit_id,omitempty"`
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
currentUserUrl = "/user"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Client) CurrentUser() (User, error) {
|
|
||||||
url, opaque := c.ResourceUrl(currentUserUrl, nil, nil)
|
|
||||||
var user User
|
|
||||||
|
|
||||||
contents, err := c.Do("GET", url, opaque, nil)
|
|
||||||
if err == nil {
|
|
||||||
err = json.Unmarshal(contents, &user)
|
|
||||||
}
|
|
||||||
|
|
||||||
return user, err
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var encodeMap = map[string]string{
|
|
||||||
".": "%252E",
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeParameter(value string) string {
|
|
||||||
value = url.QueryEscape(value)
|
|
||||||
|
|
||||||
for before, after := range encodeMap {
|
|
||||||
value = strings.Replace(value, before, after, -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tag returns current tag for push event hook payload
|
|
||||||
// This function returns empty string for any other events
|
|
||||||
func (h *HookPayload) Tag() string {
|
|
||||||
return strings.TrimPrefix(h.Ref, "refs/tags/")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Branch returns current branch for push event hook payload
|
|
||||||
// This function returns empty string for any other events
|
|
||||||
func (h *HookPayload) Branch() string {
|
|
||||||
return strings.TrimPrefix(h.Ref, "refs/heads/")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Head returns the latest changeset for push event hook payload
|
|
||||||
func (h *HookPayload) Head() hCommit {
|
|
||||||
c := hCommit{}
|
|
||||||
for _, cm := range h.Commits {
|
|
||||||
if h.After == cm.Id {
|
|
||||||
return cm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
|
243
server/remote/gitlab/convert.go
Normal file
243
server/remote/gitlab/convert.go
Normal file
|
@ -0,0 +1,243 @@
|
||||||
|
// Copyright 2021 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/woodpecker-ci/woodpecker/server/model"
|
||||||
|
|
||||||
|
"github.com/xanzy/go-gitlab"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (g *Gitlab) convertGitlabRepo(repo_ *gitlab.Project) (*model.Repo, error) {
|
||||||
|
parts := strings.Split(repo_.PathWithNamespace, "/")
|
||||||
|
// TODO: save repo id (support nested repos)
|
||||||
|
var owner = parts[0]
|
||||||
|
var name = parts[1]
|
||||||
|
repo := &model.Repo{
|
||||||
|
Owner: owner,
|
||||||
|
Name: name,
|
||||||
|
FullName: repo_.PathWithNamespace,
|
||||||
|
Avatar: repo_.AvatarURL,
|
||||||
|
Link: repo_.WebURL,
|
||||||
|
Clone: repo_.HTTPURLToRepo,
|
||||||
|
Branch: repo_.DefaultBranch,
|
||||||
|
Visibility: string(repo_.Visibility),
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(repo.Branch) == 0 { // TODO: do we need that?
|
||||||
|
repo.Branch = "master"
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(repo.Avatar) != 0 && !strings.HasPrefix(repo.Avatar, "http") {
|
||||||
|
repo.Avatar = fmt.Sprintf("%s/%s", g.URL, repo.Avatar)
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.PrivateMode {
|
||||||
|
repo.IsPrivate = true
|
||||||
|
} else {
|
||||||
|
repo.IsPrivate = !repo_.Public
|
||||||
|
}
|
||||||
|
|
||||||
|
return repo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertMergeRequestHock(hook *gitlab.MergeEvent, req *http.Request) (*model.Repo, *model.Build, error) {
|
||||||
|
repo := &model.Repo{}
|
||||||
|
build := &model.Build{}
|
||||||
|
|
||||||
|
target := hook.ObjectAttributes.Target
|
||||||
|
source := hook.ObjectAttributes.Source
|
||||||
|
obj := hook.ObjectAttributes
|
||||||
|
|
||||||
|
if target == nil && source == nil {
|
||||||
|
return nil, nil, fmt.Errorf("target and source keys expected in merge request hook")
|
||||||
|
} else if target == nil {
|
||||||
|
return nil, nil, fmt.Errorf("target key expected in merge request hook")
|
||||||
|
} else if source == nil {
|
||||||
|
return nil, nil, fmt.Errorf("source key exptected in merge request hook")
|
||||||
|
}
|
||||||
|
|
||||||
|
if target.PathWithNamespace != "" {
|
||||||
|
var err error
|
||||||
|
if repo.Owner, repo.Name, err = extractFromPath(target.PathWithNamespace); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
repo.FullName = target.PathWithNamespace
|
||||||
|
} else {
|
||||||
|
repo.Owner = req.FormValue("owner")
|
||||||
|
repo.Name = req.FormValue("name")
|
||||||
|
repo.FullName = fmt.Sprintf("%s/%s", repo.Owner, repo.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
repo.Link = target.WebURL
|
||||||
|
|
||||||
|
if target.GitHTTPURL != "" {
|
||||||
|
repo.Clone = target.GitHTTPURL
|
||||||
|
} else {
|
||||||
|
repo.Clone = target.HTTPURL
|
||||||
|
}
|
||||||
|
|
||||||
|
if target.DefaultBranch != "" {
|
||||||
|
repo.Branch = target.DefaultBranch
|
||||||
|
} else {
|
||||||
|
repo.Branch = "master"
|
||||||
|
}
|
||||||
|
|
||||||
|
if target.AvatarURL != "" {
|
||||||
|
repo.Avatar = target.AvatarURL
|
||||||
|
}
|
||||||
|
|
||||||
|
build.Event = model.EventPull
|
||||||
|
|
||||||
|
lastCommit := obj.LastCommit
|
||||||
|
|
||||||
|
build.Message = lastCommit.Message
|
||||||
|
build.Commit = lastCommit.ID
|
||||||
|
build.Remote = obj.Source.HTTPURL
|
||||||
|
|
||||||
|
build.Ref = fmt.Sprintf("refs/merge-requests/%d/head", obj.IID)
|
||||||
|
|
||||||
|
build.Branch = obj.SourceBranch
|
||||||
|
|
||||||
|
author := lastCommit.Author
|
||||||
|
|
||||||
|
build.Author = author.Name
|
||||||
|
build.Email = author.Email
|
||||||
|
|
||||||
|
if len(build.Email) != 0 {
|
||||||
|
build.Avatar = getUserAvatar(build.Email)
|
||||||
|
}
|
||||||
|
|
||||||
|
build.Title = obj.Title
|
||||||
|
build.Link = obj.URL
|
||||||
|
|
||||||
|
return repo, build, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertPushHock(hook *gitlab.PushEvent) (*model.Repo, *model.Build, error) {
|
||||||
|
repo := &model.Repo{}
|
||||||
|
build := &model.Build{}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if repo.Owner, repo.Name, err = extractFromPath(hook.Project.PathWithNamespace); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
repo.Avatar = hook.Project.AvatarURL
|
||||||
|
repo.Link = hook.Project.WebURL
|
||||||
|
repo.Clone = hook.Project.GitHTTPURL
|
||||||
|
repo.FullName = hook.Project.PathWithNamespace
|
||||||
|
repo.Branch = hook.Project.DefaultBranch
|
||||||
|
|
||||||
|
switch hook.Project.Visibility {
|
||||||
|
case gitlab.PrivateVisibility:
|
||||||
|
repo.IsPrivate = true
|
||||||
|
case gitlab.InternalVisibility:
|
||||||
|
repo.IsPrivate = true
|
||||||
|
case gitlab.PublicVisibility:
|
||||||
|
repo.IsPrivate = false
|
||||||
|
}
|
||||||
|
|
||||||
|
build.Event = model.EventPush
|
||||||
|
build.Commit = hook.After
|
||||||
|
build.Branch = strings.TrimPrefix(hook.Ref, "refs/heads/")
|
||||||
|
build.Ref = hook.Ref
|
||||||
|
|
||||||
|
for _, cm := range hook.Commits {
|
||||||
|
if hook.After == cm.ID {
|
||||||
|
build.Author = cm.Author.Name
|
||||||
|
build.Email = cm.Author.Email
|
||||||
|
build.Message = cm.Message
|
||||||
|
build.Timestamp = cm.Timestamp.Unix()
|
||||||
|
if len(build.Email) != 0 {
|
||||||
|
build.Avatar = getUserAvatar(build.Email)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return repo, build, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertTagHock(hook *gitlab.TagEvent) (*model.Repo, *model.Build, error) {
|
||||||
|
repo := &model.Repo{}
|
||||||
|
build := &model.Build{}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if repo.Owner, repo.Name, err = extractFromPath(hook.Project.PathWithNamespace); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
repo.Avatar = hook.Project.AvatarURL
|
||||||
|
repo.Link = hook.Project.WebURL
|
||||||
|
repo.Clone = hook.Project.GitHTTPURL
|
||||||
|
repo.FullName = hook.Project.PathWithNamespace
|
||||||
|
repo.Branch = hook.Project.DefaultBranch
|
||||||
|
|
||||||
|
switch hook.Project.Visibility {
|
||||||
|
case gitlab.PrivateVisibility:
|
||||||
|
repo.IsPrivate = true
|
||||||
|
case gitlab.InternalVisibility:
|
||||||
|
repo.IsPrivate = true
|
||||||
|
case gitlab.PublicVisibility:
|
||||||
|
repo.IsPrivate = false
|
||||||
|
}
|
||||||
|
|
||||||
|
build.Event = model.EventTag
|
||||||
|
build.Commit = hook.After
|
||||||
|
build.Branch = strings.TrimPrefix(hook.Ref, "refs/heads/")
|
||||||
|
build.Ref = hook.Ref
|
||||||
|
|
||||||
|
for _, cm := range hook.Commits {
|
||||||
|
if hook.After == cm.ID {
|
||||||
|
build.Author = cm.Author.Name
|
||||||
|
build.Email = cm.Author.Email
|
||||||
|
build.Message = cm.Message
|
||||||
|
build.Timestamp = cm.Timestamp.Unix()
|
||||||
|
if len(build.Email) != 0 {
|
||||||
|
build.Avatar = getUserAvatar(build.Email)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return repo, build, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUserAvatar(email string) string {
|
||||||
|
hasher := md5.New()
|
||||||
|
hasher.Write([]byte(email))
|
||||||
|
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"%s/%v.jpg?s=%s",
|
||||||
|
gravatarBase,
|
||||||
|
hex.EncodeToString(hasher.Sum(nil)),
|
||||||
|
"128",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractFromPath(str string) (string, string, error) {
|
||||||
|
s := strings.Split(str, "/")
|
||||||
|
if len(s) < 2 {
|
||||||
|
return "", "", fmt.Errorf("Minimum match not found")
|
||||||
|
}
|
||||||
|
return s[0], s[1], nil
|
||||||
|
}
|
|
@ -17,12 +17,12 @@ package gitlab
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server"
|
"github.com/woodpecker-ci/woodpecker/server"
|
||||||
|
@ -30,20 +30,38 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/remote"
|
"github.com/woodpecker-ci/woodpecker/server/remote"
|
||||||
"github.com/woodpecker-ci/woodpecker/shared/oauth2"
|
"github.com/woodpecker-ci/woodpecker/shared/oauth2"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server/remote/gitlab/client"
|
"github.com/xanzy/go-gitlab"
|
||||||
)
|
)
|
||||||
|
|
||||||
const DefaultScope = "api"
|
const (
|
||||||
|
defaultScope = "api"
|
||||||
|
perPage = 100
|
||||||
|
statusContext = "ci/drone"
|
||||||
|
)
|
||||||
|
|
||||||
// Opts defines configuration options.
|
// Opts defines configuration options.
|
||||||
type Opts struct {
|
type Opts struct {
|
||||||
URL string // Gogs server url.
|
URL string // Gitlab server url.
|
||||||
Client string // Oauth2 client id.
|
ClientID string // Oauth2 client id.
|
||||||
Secret string // Oauth2 client secret.
|
ClientSecret string // Oauth2 client secret.
|
||||||
Username string // Optional machine account username.
|
Username string // Optional machine account username.
|
||||||
Password string // Optional machine account password.
|
Password string // Optional machine account password.
|
||||||
PrivateMode bool // Gogs is running in private mode.
|
PrivateMode bool // Gogs is running in private mode.
|
||||||
SkipVerify bool // Skip ssl verification.
|
SkipVerify bool // Skip ssl verification.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gitlab implements "Remote" interface
|
||||||
|
type Gitlab struct {
|
||||||
|
URL string
|
||||||
|
ClientID string
|
||||||
|
ClientSecret string
|
||||||
|
Machine string
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
PrivateMode bool
|
||||||
|
SkipVerify bool
|
||||||
|
HideArchives bool
|
||||||
|
Search bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a Remote implementation that integrates with Gitlab, an open
|
// New returns a Remote implementation that integrates with Gitlab, an open
|
||||||
|
@ -58,78 +76,29 @@ func New(opts Opts) (remote.Remote, error) {
|
||||||
u.Host = host
|
u.Host = host
|
||||||
}
|
}
|
||||||
return &Gitlab{
|
return &Gitlab{
|
||||||
URL: opts.URL,
|
URL: opts.URL,
|
||||||
Client: opts.Client,
|
ClientID: opts.ClientID,
|
||||||
Secret: opts.Secret,
|
ClientSecret: opts.ClientSecret,
|
||||||
Machine: u.Host,
|
Machine: u.Host,
|
||||||
Username: opts.Username,
|
Username: opts.Username,
|
||||||
Password: opts.Password,
|
Password: opts.Password,
|
||||||
PrivateMode: opts.PrivateMode,
|
PrivateMode: opts.PrivateMode,
|
||||||
SkipVerify: opts.SkipVerify,
|
SkipVerify: opts.SkipVerify,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Gitlab struct {
|
|
||||||
URL string
|
|
||||||
Client string
|
|
||||||
Secret string
|
|
||||||
Machine string
|
|
||||||
Username string
|
|
||||||
Password string
|
|
||||||
PrivateMode bool
|
|
||||||
SkipVerify bool
|
|
||||||
HideArchives bool
|
|
||||||
Search bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func Load(config string) *Gitlab {
|
|
||||||
url_, err := url.Parse(config)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
params := url_.Query()
|
|
||||||
url_.RawQuery = ""
|
|
||||||
|
|
||||||
gitlab := Gitlab{}
|
|
||||||
gitlab.URL = url_.String()
|
|
||||||
gitlab.Client = params.Get("client_id")
|
|
||||||
gitlab.Secret = params.Get("client_secret")
|
|
||||||
// gitlab.AllowedOrgs = params["orgs"]
|
|
||||||
gitlab.SkipVerify, _ = strconv.ParseBool(params.Get("skip_verify"))
|
|
||||||
gitlab.HideArchives, _ = strconv.ParseBool(params.Get("hide_archives"))
|
|
||||||
// gitlab.Open, _ = strconv.ParseBool(params.Get("open"))
|
|
||||||
|
|
||||||
// switch params.Get("clone_mode") {
|
|
||||||
// case "oauth":
|
|
||||||
// gitlab.CloneMode = "oauth"
|
|
||||||
// default:
|
|
||||||
// gitlab.CloneMode = "token"
|
|
||||||
// }
|
|
||||||
|
|
||||||
// this is a temp workaround
|
|
||||||
gitlab.Search, _ = strconv.ParseBool(params.Get("search"))
|
|
||||||
|
|
||||||
return &gitlab
|
|
||||||
}
|
|
||||||
|
|
||||||
// Login authenticates the session and returns the
|
// Login authenticates the session and returns the
|
||||||
// remote user details.
|
// remote user details.
|
||||||
func (g *Gitlab) Login(ctx context.Context, res http.ResponseWriter, req *http.Request) (*model.User, error) {
|
func (g *Gitlab) Login(ctx context.Context, res http.ResponseWriter, req *http.Request) (*model.User, error) {
|
||||||
|
|
||||||
var config = &oauth2.Config{
|
var config = &oauth2.Config{
|
||||||
ClientId: g.Client,
|
ClientId: g.ClientID,
|
||||||
ClientSecret: g.Secret,
|
ClientSecret: g.ClientSecret,
|
||||||
Scope: DefaultScope,
|
Scope: defaultScope,
|
||||||
AuthURL: fmt.Sprintf("%s/oauth/authorize", g.URL),
|
AuthURL: fmt.Sprintf("%s/oauth/authorize", g.URL),
|
||||||
TokenURL: fmt.Sprintf("%s/oauth/token", g.URL),
|
TokenURL: fmt.Sprintf("%s/oauth/token", g.URL),
|
||||||
RedirectURL: fmt.Sprintf("%s/authorize", server.Config.Server.Host),
|
RedirectURL: fmt.Sprintf("%s/authorize", server.Config.Server.Host),
|
||||||
}
|
}
|
||||||
|
|
||||||
trans_ := &http.Transport{
|
|
||||||
Proxy: http.ProxyFromEnvironment,
|
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: g.SkipVerify},
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the OAuth errors
|
// get the OAuth errors
|
||||||
if err := req.FormValue("error"); err != "" {
|
if err := req.FormValue("error"); err != "" {
|
||||||
return nil, &remote.AuthError{
|
return nil, &remote.AuthError{
|
||||||
|
@ -146,248 +115,262 @@ func (g *Gitlab) Login(ctx context.Context, res http.ResponseWriter, req *http.R
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var trans = &oauth2.Transport{Config: config, Transport: trans_}
|
var trans = &oauth2.Transport{Config: config, Transport: &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: g.SkipVerify},
|
||||||
|
Proxy: http.ProxyFromEnvironment,
|
||||||
|
}}
|
||||||
var token_, err = trans.Exchange(code)
|
var token_, err = trans.Exchange(code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error exchanging token. %s", err)
|
return nil, fmt.Errorf("Error exchanging token. %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
client := NewClient(g.URL, token_.AccessToken, g.SkipVerify)
|
client, err := newClient(g.URL, token_.AccessToken, g.SkipVerify)
|
||||||
login, err := client.CurrentUser()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// if len(g.AllowedOrgs) != 0 {
|
login, _, err := client.Users.CurrentUser(gitlab.WithContext(ctx))
|
||||||
// groups, err := client.AllGroups()
|
if err != nil {
|
||||||
// if err != nil {
|
return nil, err
|
||||||
// return nil, fmt.Errorf("Could not check org membership. %s", err)
|
}
|
||||||
// }
|
|
||||||
//
|
|
||||||
// var member bool
|
|
||||||
// for _, group := range groups {
|
|
||||||
// for _, allowedOrg := range g.AllowedOrgs {
|
|
||||||
// if group.Path == allowedOrg {
|
|
||||||
// member = true
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if !member {
|
|
||||||
// return nil, false, fmt.Errorf("User does not belong to correct group. Must belong to %v", g.AllowedOrgs)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
user := &model.User{}
|
user := &model.User{
|
||||||
user.Login = login.Username
|
Login: login.Username,
|
||||||
user.Email = login.Email
|
Email: login.Email,
|
||||||
user.Token = token_.AccessToken
|
Avatar: login.AvatarURL,
|
||||||
user.Secret = token_.RefreshToken
|
Token: token_.AccessToken,
|
||||||
|
Secret: token_.RefreshToken,
|
||||||
if strings.HasPrefix(login.AvatarUrl, "http") {
|
}
|
||||||
user.Avatar = login.AvatarUrl
|
if !strings.HasPrefix(user.Avatar, "http") {
|
||||||
} else {
|
user.Avatar = g.URL + "/" + login.AvatarURL
|
||||||
user.Avatar = g.URL + "/" + login.AvatarUrl
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gitlab) Auth(ctx context.Context, token, secret string) (string, error) {
|
// Auth authenticates the session and returns the remote user login for the given token
|
||||||
client := NewClient(g.URL, token, g.SkipVerify)
|
func (g *Gitlab) Auth(ctx context.Context, token, _ string) (string, error) {
|
||||||
login, err := client.CurrentUser()
|
client, err := newClient(g.URL, token, g.SkipVerify)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
login, _, err := client.Users.CurrentUser(gitlab.WithContext(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return login.Username, nil
|
return login.Username, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gitlab) Teams(ctx context.Context, u *model.User) ([]*model.Team, error) {
|
// Teams fetches a list of team memberships from the remote system.
|
||||||
client := NewClient(g.URL, u.Token, g.SkipVerify)
|
func (g *Gitlab) Teams(ctx context.Context, user *model.User) ([]*model.Team, error) {
|
||||||
groups, err := client.AllGroups()
|
client, err := newClient(g.URL, user.Token, g.SkipVerify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var teams []*model.Team
|
|
||||||
for _, group := range groups {
|
teams := make([]*model.Team, 0, perPage)
|
||||||
teams = append(teams, &model.Team{
|
|
||||||
Login: group.Name,
|
for i := 1; true; i++ {
|
||||||
})
|
batch, _, err := client.Groups.ListGroups(&gitlab.ListGroupsOptions{
|
||||||
|
ListOptions: gitlab.ListOptions{Page: i, PerPage: perPage},
|
||||||
|
AllAvailable: gitlab.Bool(false),
|
||||||
|
MinAccessLevel: gitlab.AccessLevel(gitlab.DeveloperPermissions), // TODO: check whats best here
|
||||||
|
}, gitlab.WithContext(ctx))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range batch {
|
||||||
|
teams = append(teams, &model.Team{
|
||||||
|
Login: batch[i].Name,
|
||||||
|
Avatar: batch[i].AvatarURL,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(batch) < perPage {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return teams, nil
|
return teams, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getProject fetches the named repository from the remote system.
|
||||||
|
func (g *Gitlab) getProject(ctx context.Context, client *gitlab.Client, owner, name string) (*gitlab.Project, error) {
|
||||||
|
repo, _, err := client.Projects.GetProject(fmt.Sprintf("%s/%s", owner, name), nil, gitlab.WithContext(ctx))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return repo, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Repo fetches the named repository from the remote system.
|
// Repo fetches the named repository from the remote system.
|
||||||
func (g *Gitlab) Repo(ctx context.Context, u *model.User, owner, name string) (*model.Repo, error) {
|
func (g *Gitlab) Repo(ctx context.Context, user *model.User, owner, name string) (*model.Repo, error) {
|
||||||
client := NewClient(g.URL, u.Token, g.SkipVerify)
|
client, err := newClient(g.URL, user.Token, g.SkipVerify)
|
||||||
id, err := GetProjectId(g, client, owner, name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
repo_, err := client.Project(id)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
repo := &model.Repo{}
|
repo_, err := g.getProject(ctx, client, owner, name)
|
||||||
repo.Owner = owner
|
if err != nil {
|
||||||
repo.Name = name
|
return nil, err
|
||||||
repo.FullName = repo_.PathWithNamespace
|
|
||||||
repo.Link = repo_.Url
|
|
||||||
repo.Clone = repo_.HttpRepoUrl
|
|
||||||
repo.Branch = "master"
|
|
||||||
|
|
||||||
repo.Avatar = repo_.AvatarUrl
|
|
||||||
|
|
||||||
if len(repo.Avatar) != 0 && !strings.HasPrefix(repo.Avatar, "http") {
|
|
||||||
repo.Avatar = fmt.Sprintf("%s/%s", g.URL, repo.Avatar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if repo_.DefaultBranch != "" {
|
return g.convertGitlabRepo(repo_)
|
||||||
repo.Branch = repo_.DefaultBranch
|
|
||||||
}
|
|
||||||
|
|
||||||
if g.PrivateMode {
|
|
||||||
repo.IsPrivate = true
|
|
||||||
} else {
|
|
||||||
repo.IsPrivate = !repo_.Public
|
|
||||||
}
|
|
||||||
|
|
||||||
return repo, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repos fetches a list of repos from the remote system.
|
// Repos fetches a list of repos from the remote system.
|
||||||
func (g *Gitlab) Repos(ctx context.Context, u *model.User) ([]*model.Repo, error) {
|
func (g *Gitlab) Repos(ctx context.Context, user *model.User) ([]*model.Repo, error) {
|
||||||
client := NewClient(g.URL, u.Token, g.SkipVerify)
|
client, err := newClient(g.URL, user.Token, g.SkipVerify)
|
||||||
|
|
||||||
var repos = []*model.Repo{}
|
|
||||||
|
|
||||||
all, err := client.AllProjects(g.HideArchives)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return repos, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, repo_ := range all {
|
repos := make([]*model.Repo, 0, perPage)
|
||||||
var parts = strings.Split(repo_.PathWithNamespace, "/")
|
opts := &gitlab.ListProjectsOptions{
|
||||||
var owner = parts[0]
|
ListOptions: gitlab.ListOptions{PerPage: perPage},
|
||||||
var name = parts[1]
|
MinAccessLevel: gitlab.AccessLevel(gitlab.DeveloperPermissions), // TODO: check whats best here
|
||||||
|
}
|
||||||
|
if g.HideArchives {
|
||||||
|
opts.Archived = gitlab.Bool(false)
|
||||||
|
}
|
||||||
|
|
||||||
repo := &model.Repo{}
|
for i := 1; true; i++ {
|
||||||
repo.Owner = owner
|
opts.Page = i
|
||||||
repo.Name = name
|
batch, _, err := client.Projects.ListProjects(opts, gitlab.WithContext(ctx))
|
||||||
repo.FullName = repo_.PathWithNamespace
|
if err != nil {
|
||||||
repo.Link = repo_.Url
|
return nil, err
|
||||||
repo.Clone = repo_.HttpRepoUrl
|
|
||||||
repo.Branch = "master"
|
|
||||||
|
|
||||||
if repo_.DefaultBranch != "" {
|
|
||||||
repo.Branch = repo_.DefaultBranch
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.PrivateMode {
|
for i := range batch {
|
||||||
repo.IsPrivate = true
|
repo, err := g.convertGitlabRepo(batch[i])
|
||||||
} else {
|
if err != nil {
|
||||||
repo.IsPrivate = !repo_.Public
|
return nil, err
|
||||||
|
}
|
||||||
|
repos = append(repos, repo)
|
||||||
}
|
}
|
||||||
|
|
||||||
repos = append(repos, repo)
|
if len(batch) < perPage {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return repos, err
|
return repos, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perm fetches the named repository from the remote system.
|
// Perm fetches the named repository from the remote system.
|
||||||
func (g *Gitlab) Perm(ctx context.Context, u *model.User, owner, name string) (*model.Perm, error) {
|
func (g *Gitlab) Perm(ctx context.Context, user *model.User, owner, name string) (*model.Perm, error) {
|
||||||
|
client, err := newClient(g.URL, user.Token, g.SkipVerify)
|
||||||
client := NewClient(g.URL, u.Token, g.SkipVerify)
|
|
||||||
id, err := GetProjectId(g, client, owner, name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
repo, err := g.getProject(ctx, client, owner, name)
|
||||||
repo, err := client.Project(id)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// repo owner is granted full access
|
// repo owner is granted full access
|
||||||
if repo.Owner != nil && repo.Owner.Username == u.Login {
|
if repo.Owner != nil && repo.Owner.Username == user.Login {
|
||||||
return &model.Perm{Push: true, Pull: true, Admin: true}, nil
|
return &model.Perm{Push: true, Pull: true, Admin: true}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// check permission for current user
|
// return permission for current user
|
||||||
m := &model.Perm{}
|
return &model.Perm{
|
||||||
m.Admin = IsAdmin(repo)
|
Pull: isRead(repo),
|
||||||
m.Pull = IsRead(repo)
|
Push: isWrite(repo),
|
||||||
m.Push = IsWrite(repo)
|
Admin: isAdmin(repo),
|
||||||
return m, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// File fetches a file from the remote repository and returns in string format.
|
// File fetches a file from the remote repository and returns in string format.
|
||||||
func (g *Gitlab) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) {
|
func (g *Gitlab) File(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, fileName string) ([]byte, error) {
|
||||||
var client = NewClient(g.URL, u.Token, g.SkipVerify)
|
client, err := newClient(g.URL, user.Token, g.SkipVerify)
|
||||||
id, err := GetProjectId(g, client, r.Owner, r.Name)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
repo_, err := g.getProject(ctx, client, repo.Owner, repo.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
file, _, err := client.RepositoryFiles.GetRawFile(repo_.ID, fileName, &gitlab.GetRawFileOptions{Ref: &build.Commit}, gitlab.WithContext(ctx))
|
||||||
|
return file, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dir fetches a folder from the remote repository
|
||||||
|
func (g *Gitlab) Dir(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, path string) ([]*remote.FileMeta, error) {
|
||||||
|
client, err := newClient(g.URL, user.Token, g.SkipVerify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := client.RepoRawFileRef(id, b.Commit, f)
|
files := make([]*remote.FileMeta, 0, perPage)
|
||||||
|
repo_, err := g.getProject(ctx, client, repo.Owner, repo.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return out, err
|
opts := &gitlab.ListTreeOptions{
|
||||||
|
ListOptions: gitlab.ListOptions{PerPage: perPage},
|
||||||
|
Path: &path,
|
||||||
|
Ref: &build.Commit,
|
||||||
|
Recursive: gitlab.Bool(false),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 1; true; i++ {
|
||||||
|
opts.Page = 1
|
||||||
|
batch, _, err := client.Repositories.ListTree(repo_.ID, opts, gitlab.WithContext(ctx))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range batch {
|
||||||
|
if batch[i].Type != "blob" { // no file
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
data, err := g.File(ctx, user, repo, build, batch[i].Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
files = append(files, &remote.FileMeta{
|
||||||
|
Name: batch[i].Path,
|
||||||
|
Data: data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(batch) < perPage {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Gitlab) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]*remote.FileMeta, error) {
|
// Status sends the commit status back to gitlab.
|
||||||
return nil, fmt.Errorf("Not implemented")
|
func (g *Gitlab) Status(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, link string, proc *model.Proc) error {
|
||||||
|
client, err := newClient(g.URL, user.Token, g.SkipVerify)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
repo_, err := g.getProject(ctx, client, repo.Owner, repo.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err = client.Commits.SetCommitStatus(repo_.ID, build.Commit, &gitlab.SetCommitStatusOptions{
|
||||||
|
Ref: gitlab.String(strings.ReplaceAll(build.Ref, "refs/heads/", "")),
|
||||||
|
State: getStatus(build.Status),
|
||||||
|
Description: gitlab.String(getDesc(build.Status)),
|
||||||
|
TargetURL: &link,
|
||||||
|
Name: nil,
|
||||||
|
Context: gitlab.String(statusContext),
|
||||||
|
}, gitlab.WithContext(ctx))
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE Currently gitlab doesn't support status for commits and events,
|
|
||||||
// also if we want get MR status in gitlab we need implement a special plugin for gitlab,
|
|
||||||
// gitlab uses API to fetch build status on client side. But for now we skip this.
|
|
||||||
func (g *Gitlab) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error {
|
|
||||||
client := NewClient(g.URL, u.Token, g.SkipVerify)
|
|
||||||
|
|
||||||
status := getStatus(b.Status)
|
|
||||||
desc := getDesc(b.Status)
|
|
||||||
|
|
||||||
client.SetStatus(
|
|
||||||
ns(r.Owner, r.Name),
|
|
||||||
b.Commit,
|
|
||||||
status,
|
|
||||||
desc,
|
|
||||||
strings.Replace(b.Ref, "refs/heads/", "", -1),
|
|
||||||
link,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Gitlab statuses it's a new feature, just ignore error
|
|
||||||
// if gitlab version not support this
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Netrc returns a .netrc file that can be used to clone
|
|
||||||
// private repositories from a remote system.
|
|
||||||
// func (g *Gitlab) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) {
|
|
||||||
// url_, err := url.Parse(g.URL)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
// netrc := &model.Netrc{}
|
|
||||||
// netrc.Machine = url_.Host
|
|
||||||
//
|
|
||||||
// switch g.CloneMode {
|
|
||||||
// case "oauth":
|
|
||||||
// netrc.Login = "oauth2"
|
|
||||||
// netrc.Password = u.Token
|
|
||||||
// case "token":
|
|
||||||
// t := token.New(token.HookToken, r.FullName)
|
|
||||||
// netrc.Login = "drone-ci-token"
|
|
||||||
// netrc.Password, err = t.Sign(r.Hash)
|
|
||||||
// }
|
|
||||||
// return netrc, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Netrc returns a netrc file capable of authenticating Gitlab requests and
|
// Netrc returns a netrc file capable of authenticating Gitlab requests and
|
||||||
// cloning Gitlab repositories. The netrc will use the global machine account
|
// cloning Gitlab repositories. The netrc will use the global machine account
|
||||||
// when configured.
|
// when configured.
|
||||||
|
@ -408,296 +391,90 @@ func (g *Gitlab) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) {
|
||||||
|
|
||||||
// Activate activates a repository by adding a Post-commit hook and
|
// Activate activates a repository by adding a Post-commit hook and
|
||||||
// a Public Deploy key, if applicable.
|
// a Public Deploy key, if applicable.
|
||||||
func (g *Gitlab) Activate(ctx context.Context, u *model.User, r *model.Repo, link string) error {
|
func (g *Gitlab) Activate(ctx context.Context, user *model.User, repo *model.Repo, link string) error {
|
||||||
var client = NewClient(g.URL, u.Token, g.SkipVerify)
|
client, err := newClient(g.URL, user.Token, g.SkipVerify)
|
||||||
id, err := GetProjectId(g, client, r.Owner, r.Name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
uri, err := url.Parse(link)
|
uri, err := url.Parse(link)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
token := uri.Query().Get("access_token")
|
||||||
|
webUrl := fmt.Sprintf("%s://%s", uri.Scheme, uri.Host)
|
||||||
|
|
||||||
droneUrl := fmt.Sprintf("%s://%s", uri.Scheme, uri.Host)
|
repo_, err := g.getProject(ctx, client, repo.Owner, repo.Name)
|
||||||
droneToken := uri.Query().Get("access_token")
|
if err != nil {
|
||||||
ssl_verify := strconv.FormatBool(!g.SkipVerify)
|
return err
|
||||||
|
}
|
||||||
return client.AddDroneService(id, map[string]string{
|
// TODO: "WoodpeckerCIService"
|
||||||
"token": droneToken,
|
_, err = client.Services.SetDroneCIService(repo_.ID, &gitlab.SetDroneCIServiceOptions{
|
||||||
"drone_url": droneUrl,
|
Token: &token,
|
||||||
"enable_ssl_verification": ssl_verify,
|
DroneURL: &webUrl,
|
||||||
})
|
EnableSSLVerification: gitlab.Bool(!g.SkipVerify),
|
||||||
|
}, gitlab.WithContext(ctx))
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deactivate removes a repository by removing all the post-commit hooks
|
// Deactivate removes a repository by removing all the post-commit hooks
|
||||||
// which are equal to link and removing the SSH deploy key.
|
// which are equal to link and removing the SSH deploy key.
|
||||||
func (g *Gitlab) Deactivate(ctx context.Context, u *model.User, r *model.Repo, link string) error {
|
func (g *Gitlab) Deactivate(ctx context.Context, user *model.User, repo *model.Repo, link string) error {
|
||||||
var client = NewClient(g.URL, u.Token, g.SkipVerify)
|
client, err := newClient(g.URL, user.Token, g.SkipVerify)
|
||||||
id, err := GetProjectId(g, client, r.Owner, r.Name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return client.DeleteDroneService(id)
|
repo_, err := g.getProject(ctx, client, repo.Owner, repo.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// TODO: "WoodpeckerCIService"
|
||||||
|
_, err = client.Services.DeleteDroneCIService(repo_.ID, gitlab.WithContext(ctx))
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseHook parses the post-commit hook from the Request body
|
// Hook parses the post-commit hook from the Request body
|
||||||
// and returns the required data in a standard format.
|
// and returns the required data in a standard format.
|
||||||
func (g *Gitlab) Hook(req *http.Request) (*model.Repo, *model.Build, error) {
|
func (g *Gitlab) Hook(req *http.Request) (*model.Repo, *model.Build, error) {
|
||||||
defer req.Body.Close()
|
defer req.Body.Close()
|
||||||
var payload, _ = ioutil.ReadAll(req.Body)
|
payload, err := ioutil.ReadAll(req.Body)
|
||||||
var parsed, err = client.ParseHook(payload)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch parsed.ObjectKind {
|
eventType := gitlab.WebhookEventType(req)
|
||||||
case "merge_request":
|
// TODO: Fix Upstream: We get `Service Hook` - which the library do not understand
|
||||||
return mergeRequest(parsed, req)
|
if eventType == "Service Hook" {
|
||||||
case "tag_push", "push":
|
e := struct {
|
||||||
return push(parsed, req)
|
ObjectKind string `json:"object_kind"`
|
||||||
|
}{}
|
||||||
|
if err := json.Unmarshal(payload, &e); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
switch e.ObjectKind {
|
||||||
|
case "push":
|
||||||
|
eventType = gitlab.EventTypePush
|
||||||
|
case "tag_push":
|
||||||
|
eventType = gitlab.EventTypeTagPush
|
||||||
|
case "merge_request":
|
||||||
|
eventType = gitlab.EventTypeMergeRequest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed, err := gitlab.ParseWebhook(eventType, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch event := parsed.(type) {
|
||||||
|
case *gitlab.MergeEvent:
|
||||||
|
return convertMergeRequestHock(event, req)
|
||||||
|
case *gitlab.PushEvent:
|
||||||
|
return convertPushHock(event)
|
||||||
|
case *gitlab.TagEvent:
|
||||||
|
return convertTagHock(event)
|
||||||
default:
|
default:
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mergeRequest(parsed *client.HookPayload, req *http.Request) (*model.Repo, *model.Build, error) {
|
|
||||||
|
|
||||||
repo := &model.Repo{}
|
|
||||||
|
|
||||||
obj := parsed.ObjectAttributes
|
|
||||||
if obj == nil {
|
|
||||||
return nil, nil, fmt.Errorf("object_attributes key expected in merge request hook")
|
|
||||||
}
|
|
||||||
|
|
||||||
target := obj.Target
|
|
||||||
source := obj.Source
|
|
||||||
|
|
||||||
if target == nil && source == nil {
|
|
||||||
return nil, nil, fmt.Errorf("target and source keys expected in merge request hook")
|
|
||||||
} else if target == nil {
|
|
||||||
return nil, nil, fmt.Errorf("target key expected in merge request hook")
|
|
||||||
} else if source == nil {
|
|
||||||
return nil, nil, fmt.Errorf("source key exptected in merge request hook")
|
|
||||||
}
|
|
||||||
|
|
||||||
if target.PathWithNamespace != "" {
|
|
||||||
var err error
|
|
||||||
if repo.Owner, repo.Name, err = ExtractFromPath(target.PathWithNamespace); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
repo.FullName = target.PathWithNamespace
|
|
||||||
} else {
|
|
||||||
repo.Owner = req.FormValue("owner")
|
|
||||||
repo.Name = req.FormValue("name")
|
|
||||||
repo.FullName = fmt.Sprintf("%s/%s", repo.Owner, repo.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
repo.Link = target.WebUrl
|
|
||||||
|
|
||||||
if target.GitHttpUrl != "" {
|
|
||||||
repo.Clone = target.GitHttpUrl
|
|
||||||
} else {
|
|
||||||
repo.Clone = target.HttpUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
if target.DefaultBranch != "" {
|
|
||||||
repo.Branch = target.DefaultBranch
|
|
||||||
} else {
|
|
||||||
repo.Branch = "master"
|
|
||||||
}
|
|
||||||
|
|
||||||
if target.AvatarUrl != "" {
|
|
||||||
repo.Avatar = target.AvatarUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
build := &model.Build{}
|
|
||||||
build.Event = "pull_request"
|
|
||||||
|
|
||||||
lastCommit := obj.LastCommit
|
|
||||||
if lastCommit == nil {
|
|
||||||
return nil, nil, fmt.Errorf("last_commit key expected in merge request hook")
|
|
||||||
}
|
|
||||||
|
|
||||||
build.Message = lastCommit.Message
|
|
||||||
build.Commit = lastCommit.Id
|
|
||||||
//build.Remote = parsed.ObjectAttributes.Source.HttpUrl
|
|
||||||
|
|
||||||
build.Ref = fmt.Sprintf("refs/merge-requests/%d/head", obj.IId)
|
|
||||||
|
|
||||||
build.Branch = obj.SourceBranch
|
|
||||||
|
|
||||||
author := lastCommit.Author
|
|
||||||
if author == nil {
|
|
||||||
return nil, nil, fmt.Errorf("author key expected in merge request hook")
|
|
||||||
}
|
|
||||||
|
|
||||||
build.Author = author.Name
|
|
||||||
build.Email = author.Email
|
|
||||||
|
|
||||||
if len(build.Email) != 0 {
|
|
||||||
build.Avatar = GetUserAvatar(build.Email)
|
|
||||||
}
|
|
||||||
|
|
||||||
build.Title = obj.Title
|
|
||||||
build.Link = obj.Url
|
|
||||||
|
|
||||||
return repo, build, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func push(parsed *client.HookPayload, req *http.Request) (*model.Repo, *model.Build, error) {
|
|
||||||
repo := &model.Repo{}
|
|
||||||
|
|
||||||
// Since gitlab 8.5, used project instead repository key
|
|
||||||
// see https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/web_hooks/web_hooks.md#web-hooks
|
|
||||||
if project := parsed.Project; project != nil {
|
|
||||||
var err error
|
|
||||||
if repo.Owner, repo.Name, err = ExtractFromPath(project.PathWithNamespace); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
repo.Avatar = project.AvatarUrl
|
|
||||||
repo.Link = project.WebUrl
|
|
||||||
repo.Clone = project.GitHttpUrl
|
|
||||||
repo.FullName = project.PathWithNamespace
|
|
||||||
repo.Branch = project.DefaultBranch
|
|
||||||
|
|
||||||
switch project.VisibilityLevel {
|
|
||||||
case 0:
|
|
||||||
repo.IsPrivate = true
|
|
||||||
case 10:
|
|
||||||
repo.IsPrivate = true
|
|
||||||
case 20:
|
|
||||||
repo.IsPrivate = false
|
|
||||||
}
|
|
||||||
} else if repository := parsed.Repository; repository != nil {
|
|
||||||
repo.Owner = req.FormValue("owner")
|
|
||||||
repo.Name = req.FormValue("name")
|
|
||||||
repo.Link = repository.URL
|
|
||||||
repo.Clone = repository.GitHttpUrl
|
|
||||||
repo.Branch = "master"
|
|
||||||
repo.FullName = fmt.Sprintf("%s/%s", req.FormValue("owner"), req.FormValue("name"))
|
|
||||||
|
|
||||||
switch repository.VisibilityLevel {
|
|
||||||
case 0:
|
|
||||||
repo.IsPrivate = true
|
|
||||||
case 10:
|
|
||||||
repo.IsPrivate = true
|
|
||||||
case 20:
|
|
||||||
repo.IsPrivate = false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nil, nil, fmt.Errorf("No project/repository keys given")
|
|
||||||
}
|
|
||||||
|
|
||||||
build := &model.Build{}
|
|
||||||
build.Event = model.EventPush
|
|
||||||
build.Commit = parsed.After
|
|
||||||
build.Branch = parsed.Branch()
|
|
||||||
build.Ref = parsed.Ref
|
|
||||||
// hook.Commit.Remote = cloneUrl
|
|
||||||
|
|
||||||
var head = parsed.Head()
|
|
||||||
build.Message = head.Message
|
|
||||||
// build.Timestamp = head.Timestamp
|
|
||||||
|
|
||||||
// extracts the commit author (ideally email)
|
|
||||||
// from the post-commit hook
|
|
||||||
switch {
|
|
||||||
case head.Author != nil:
|
|
||||||
build.Email = head.Author.Email
|
|
||||||
build.Author = parsed.UserName
|
|
||||||
if len(build.Email) != 0 {
|
|
||||||
build.Avatar = GetUserAvatar(build.Email)
|
|
||||||
}
|
|
||||||
case head.Author == nil:
|
|
||||||
build.Author = parsed.UserName
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(build.Ref, "refs/tags/") {
|
|
||||||
build.Event = model.EventTag
|
|
||||||
}
|
|
||||||
|
|
||||||
return repo, build, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ¯\_(ツ)_/¯
|
|
||||||
func (g *Gitlab) Oauth2Transport(r *http.Request) *oauth2.Transport {
|
|
||||||
return &oauth2.Transport{
|
|
||||||
Config: &oauth2.Config{
|
|
||||||
ClientId: g.Client,
|
|
||||||
ClientSecret: g.Secret,
|
|
||||||
Scope: DefaultScope,
|
|
||||||
AuthURL: fmt.Sprintf("%s/oauth/authorize", g.URL),
|
|
||||||
TokenURL: fmt.Sprintf("%s/oauth/token", g.URL),
|
|
||||||
RedirectURL: fmt.Sprintf("%s/authorize", server.Config.Server.Host),
|
|
||||||
//settings.Server.Scheme, settings.Server.Hostname),
|
|
||||||
},
|
|
||||||
Transport: &http.Transport{
|
|
||||||
Proxy: http.ProxyFromEnvironment,
|
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: g.SkipVerify},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
StatusPending = "pending"
|
|
||||||
StatusRunning = "running"
|
|
||||||
StatusSuccess = "success"
|
|
||||||
StatusFailure = "failed"
|
|
||||||
StatusCanceled = "canceled"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
DescPending = "the build is pending"
|
|
||||||
DescRunning = "the buils is running"
|
|
||||||
DescSuccess = "the build was successful"
|
|
||||||
DescFailure = "the build failed"
|
|
||||||
DescCanceled = "the build canceled"
|
|
||||||
DescBlocked = "the build is pending approval"
|
|
||||||
DescDeclined = "the build was rejected"
|
|
||||||
)
|
|
||||||
|
|
||||||
// getStatus is a helper functin that converts a Drone
|
|
||||||
// status to a GitHub status.
|
|
||||||
func getStatus(status string) string {
|
|
||||||
switch status {
|
|
||||||
case model.StatusPending, model.StatusBlocked:
|
|
||||||
return StatusPending
|
|
||||||
case model.StatusRunning:
|
|
||||||
return StatusRunning
|
|
||||||
case model.StatusSuccess:
|
|
||||||
return StatusSuccess
|
|
||||||
case model.StatusFailure, model.StatusError:
|
|
||||||
return StatusFailure
|
|
||||||
case model.StatusKilled:
|
|
||||||
return StatusCanceled
|
|
||||||
default:
|
|
||||||
return StatusFailure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getDesc is a helper function that generates a description
|
|
||||||
// message for the build based on the status.
|
|
||||||
func getDesc(status string) string {
|
|
||||||
switch status {
|
|
||||||
case model.StatusPending:
|
|
||||||
return DescPending
|
|
||||||
case model.StatusRunning:
|
|
||||||
return DescRunning
|
|
||||||
case model.StatusSuccess:
|
|
||||||
return DescSuccess
|
|
||||||
case model.StatusFailure, model.StatusError:
|
|
||||||
return DescFailure
|
|
||||||
case model.StatusKilled:
|
|
||||||
return DescCanceled
|
|
||||||
case model.StatusBlocked:
|
|
||||||
return DescBlocked
|
|
||||||
case model.StatusDeclined:
|
|
||||||
return DescDeclined
|
|
||||||
default:
|
|
||||||
return DescFailure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -18,21 +18,46 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/franela/goblin"
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server/model"
|
"github.com/woodpecker-ci/woodpecker/server/model"
|
||||||
"github.com/woodpecker-ci/woodpecker/server/remote/gitlab/testdata"
|
"github.com/woodpecker-ci/woodpecker/server/remote/gitlab/testdata"
|
||||||
|
|
||||||
|
"github.com/franela/goblin"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func load(config string) *Gitlab {
|
||||||
|
url_, err := url.Parse(config)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
params := url_.Query()
|
||||||
|
url_.RawQuery = ""
|
||||||
|
|
||||||
|
gitlab := Gitlab{}
|
||||||
|
gitlab.URL = url_.String()
|
||||||
|
gitlab.ClientID = params.Get("client_id")
|
||||||
|
gitlab.ClientSecret = params.Get("client_secret")
|
||||||
|
gitlab.SkipVerify, _ = strconv.ParseBool(params.Get("skip_verify"))
|
||||||
|
gitlab.HideArchives, _ = strconv.ParseBool(params.Get("hide_archives"))
|
||||||
|
|
||||||
|
// this is a temp workaround
|
||||||
|
gitlab.Search, _ = strconv.ParseBool(params.Get("search"))
|
||||||
|
|
||||||
|
return &gitlab
|
||||||
|
}
|
||||||
|
|
||||||
func Test_Gitlab(t *testing.T) {
|
func Test_Gitlab(t *testing.T) {
|
||||||
// setup a dummy github server
|
// setup a dummy github server
|
||||||
var server = testdata.NewServer()
|
var server = testdata.NewServer(t)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
env := server.URL + "?client_id=test&client_secret=test"
|
env := server.URL + "?client_id=test&client_secret=test"
|
||||||
|
|
||||||
gitlab := Load(env)
|
client := load(env)
|
||||||
|
|
||||||
var user = model.User{
|
var user = model.User{
|
||||||
Login: "test_user",
|
Login: "test_user",
|
||||||
|
@ -50,16 +75,15 @@ func Test_Gitlab(t *testing.T) {
|
||||||
// Test projects method
|
// Test projects method
|
||||||
g.Describe("AllProjects", func() {
|
g.Describe("AllProjects", func() {
|
||||||
g.It("Should return only non-archived projects is hidden", func() {
|
g.It("Should return only non-archived projects is hidden", func() {
|
||||||
gitlab.HideArchives = true
|
client.HideArchives = true
|
||||||
_projects, err := gitlab.Repos(ctx, &user)
|
_projects, err := client.Repos(ctx, &user)
|
||||||
|
assert.NoError(t, err)
|
||||||
g.Assert(err == nil).IsTrue()
|
assert.Len(t, _projects, 1)
|
||||||
g.Assert(len(_projects)).Equal(1)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
g.It("Should return all the projects", func() {
|
g.It("Should return all the projects", func() {
|
||||||
gitlab.HideArchives = false
|
client.HideArchives = false
|
||||||
_projects, err := gitlab.Repos(ctx, &user)
|
_projects, err := client.Repos(ctx, &user)
|
||||||
|
|
||||||
g.Assert(err == nil).IsTrue()
|
g.Assert(err == nil).IsTrue()
|
||||||
g.Assert(len(_projects)).Equal(2)
|
g.Assert(len(_projects)).Equal(2)
|
||||||
|
@ -69,39 +93,37 @@ func Test_Gitlab(t *testing.T) {
|
||||||
// Test repository method
|
// Test repository method
|
||||||
g.Describe("Repo", func() {
|
g.Describe("Repo", func() {
|
||||||
g.It("Should return valid repo", func() {
|
g.It("Should return valid repo", func() {
|
||||||
_repo, err := gitlab.Repo(ctx, &user, "diaspora", "diaspora-client")
|
_repo, err := client.Repo(ctx, &user, "diaspora", "diaspora-client")
|
||||||
|
assert.NoError(t, err)
|
||||||
g.Assert(err == nil).IsTrue()
|
assert.Equal(t, "diaspora-client", _repo.Name)
|
||||||
g.Assert(_repo.Name).Equal("diaspora-client")
|
assert.Equal(t, "diaspora", _repo.Owner)
|
||||||
g.Assert(_repo.Owner).Equal("diaspora")
|
assert.True(t, _repo.IsPrivate)
|
||||||
g.Assert(_repo.IsPrivate).Equal(true)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
g.It("Should return error, when repo not exist", func() {
|
g.It("Should return error, when repo not exist", func() {
|
||||||
_, err := gitlab.Repo(ctx, &user, "not-existed", "not-existed")
|
_, err := client.Repo(ctx, &user, "not-existed", "not-existed")
|
||||||
|
assert.Error(t, err)
|
||||||
g.Assert(err != nil).IsTrue()
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test permissions method
|
// Test permissions method
|
||||||
g.Describe("Perm", func() {
|
g.Describe("Perm", func() {
|
||||||
g.It("Should return repo permissions", func() {
|
g.It("Should return repo permissions", func() {
|
||||||
perm, err := gitlab.Perm(ctx, &user, "diaspora", "diaspora-client")
|
perm, err := client.Perm(ctx, &user, "diaspora", "diaspora-client")
|
||||||
g.Assert(err == nil).IsTrue()
|
assert.NoError(t, err)
|
||||||
g.Assert(perm.Admin).Equal(true)
|
assert.True(t, perm.Admin)
|
||||||
g.Assert(perm.Pull).Equal(true)
|
assert.True(t, perm.Pull)
|
||||||
g.Assert(perm.Push).Equal(true)
|
assert.True(t, perm.Push)
|
||||||
})
|
})
|
||||||
g.It("Should return repo permissions when user is admin", func() {
|
g.It("Should return repo permissions when user is admin", func() {
|
||||||
perm, err := gitlab.Perm(ctx, &user, "brightbox", "puppet")
|
perm, err := client.Perm(ctx, &user, "brightbox", "puppet")
|
||||||
g.Assert(err == nil).IsTrue()
|
assert.NoError(t, err)
|
||||||
g.Assert(perm.Admin).Equal(true)
|
g.Assert(perm.Admin).Equal(true)
|
||||||
g.Assert(perm.Pull).Equal(true)
|
g.Assert(perm.Pull).Equal(true)
|
||||||
g.Assert(perm.Push).Equal(true)
|
g.Assert(perm.Push).Equal(true)
|
||||||
})
|
})
|
||||||
g.It("Should return error, when repo is not exist", func() {
|
g.It("Should return error, when repo is not exist", func() {
|
||||||
_, err := gitlab.Perm(ctx, &user, "not-existed", "not-existed")
|
_, err := client.Perm(ctx, &user, "not-existed", "not-existed")
|
||||||
|
|
||||||
g.Assert(err != nil).IsTrue()
|
g.Assert(err != nil).IsTrue()
|
||||||
})
|
})
|
||||||
|
@ -110,13 +132,12 @@ func Test_Gitlab(t *testing.T) {
|
||||||
// Test activate method
|
// Test activate method
|
||||||
g.Describe("Activate", func() {
|
g.Describe("Activate", func() {
|
||||||
g.It("Should be success", func() {
|
g.It("Should be success", func() {
|
||||||
err := gitlab.Activate(ctx, &user, &repo, "http://example.com/api/hook/test/test?access_token=token")
|
err := client.Activate(ctx, &user, &repo, "http://example.com/api/hook/test/test?access_token=token")
|
||||||
|
assert.NoError(t, err)
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
g.It("Should be failed, when token not given", func() {
|
g.It("Should be failed, when token not given", func() {
|
||||||
err := gitlab.Activate(ctx, &user, &repo, "http://example.com/api/hook/test/test")
|
err := client.Activate(ctx, &user, &repo, "http://example.com/api/hook/test/test")
|
||||||
|
|
||||||
g.Assert(err != nil).IsTrue()
|
g.Assert(err != nil).IsTrue()
|
||||||
})
|
})
|
||||||
|
@ -125,137 +146,75 @@ func Test_Gitlab(t *testing.T) {
|
||||||
// Test deactivate method
|
// Test deactivate method
|
||||||
g.Describe("Deactivate", func() {
|
g.Describe("Deactivate", func() {
|
||||||
g.It("Should be success", func() {
|
g.It("Should be success", func() {
|
||||||
err := gitlab.Deactivate(ctx, &user, &repo, "http://example.com/api/hook/test/test?access_token=token")
|
err := client.Deactivate(ctx, &user, &repo, "http://example.com/api/hook/test/test?access_token=token")
|
||||||
|
|
||||||
g.Assert(err == nil).IsTrue()
|
g.Assert(err == nil).IsTrue()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test login method
|
|
||||||
// g.Describe("Login", func() {
|
|
||||||
// g.It("Should return user", func() {
|
|
||||||
// user, err := gitlab.Login("valid_token", "")
|
|
||||||
|
|
||||||
// g.Assert(err == nil).IsTrue()
|
|
||||||
// g.Assert(user == nil).IsFalse()
|
|
||||||
// })
|
|
||||||
|
|
||||||
// g.It("Should return error, when token is invalid", func() {
|
|
||||||
// _, err := gitlab.Login("invalid_token", "")
|
|
||||||
|
|
||||||
// g.Assert(err != nil).IsTrue()
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
|
|
||||||
// Test hook method
|
// Test hook method
|
||||||
g.Describe("Hook", func() {
|
g.Describe("Hook", func() {
|
||||||
g.Describe("Push hook", func() {
|
g.Describe("Push hook", func() {
|
||||||
g.It("Should parse actual push hoook", func() {
|
g.It("Should parse actual push hoook", func() {
|
||||||
req, _ := http.NewRequest(
|
req, _ := http.NewRequest(
|
||||||
"POST",
|
testdata.ServiceHookMethod,
|
||||||
"http://example.com/api/hook?owner=diaspora&name=diaspora-client",
|
testdata.ServiceHookURL.String(),
|
||||||
bytes.NewReader(testdata.PushHook),
|
bytes.NewReader(testdata.ServiceHookPushBody),
|
||||||
)
|
)
|
||||||
|
req.Header = testdata.ServiceHookHeaders
|
||||||
|
|
||||||
repo, build, err := gitlab.Hook(req)
|
hookRepo, build, err := client.Hook(req)
|
||||||
|
assert.NoError(t, err)
|
||||||
g.Assert(err == nil).IsTrue()
|
if assert.NotNil(t, hookRepo) && assert.NotNil(t, build) {
|
||||||
g.Assert(repo.Owner).Equal("mike")
|
assert.Equal(t, build.Event, model.EventPush)
|
||||||
g.Assert(repo.Name).Equal("diaspora")
|
assert.Equal(t, "test", hookRepo.Owner)
|
||||||
g.Assert(repo.Avatar).Equal("http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg")
|
assert.Equal(t, "woodpecker", hookRepo.Name)
|
||||||
g.Assert(repo.Branch).Equal("develop")
|
assert.Equal(t, "http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg", hookRepo.Avatar)
|
||||||
g.Assert(build.Ref).Equal("refs/heads/master")
|
assert.Equal(t, "develop", hookRepo.Branch)
|
||||||
|
assert.Equal(t, "refs/heads/master", build.Ref)
|
||||||
})
|
}
|
||||||
|
|
||||||
g.It("Should parse legacy push hoook", func() {
|
|
||||||
req, _ := http.NewRequest(
|
|
||||||
"POST",
|
|
||||||
"http://example.com/api/hook?owner=diaspora&name=diaspora-client",
|
|
||||||
bytes.NewReader(testdata.LegacyPushHook),
|
|
||||||
)
|
|
||||||
|
|
||||||
repo, build, err := gitlab.Hook(req)
|
|
||||||
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(repo.Owner).Equal("diaspora")
|
|
||||||
g.Assert(repo.Name).Equal("diaspora-client")
|
|
||||||
g.Assert(repo.Avatar).Equal("")
|
|
||||||
g.Assert(repo.Branch).Equal("master")
|
|
||||||
g.Assert(build.Ref).Equal("refs/heads/master")
|
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
g.Describe("Tag push hook", func() {
|
g.Describe("Tag push hook", func() {
|
||||||
g.It("Should parse tag push hook", func() {
|
g.It("Should parse tag push hook", func() {
|
||||||
req, _ := http.NewRequest(
|
req, _ := http.NewRequest(
|
||||||
"POST",
|
testdata.ServiceHookMethod,
|
||||||
"http://example.com/api/hook?owner=diaspora&name=diaspora-client",
|
testdata.ServiceHookURL.String(),
|
||||||
bytes.NewReader(testdata.TagHook),
|
bytes.NewReader(testdata.ServiceHookTagPushBody),
|
||||||
)
|
)
|
||||||
|
req.Header = testdata.ServiceHookHeaders
|
||||||
|
|
||||||
repo, build, err := gitlab.Hook(req)
|
hookRepo, build, err := client.Hook(req)
|
||||||
|
assert.NoError(t, err)
|
||||||
g.Assert(err == nil).IsTrue()
|
if assert.NotNil(t, hookRepo) && assert.NotNil(t, build) {
|
||||||
g.Assert(repo.Owner).Equal("jsmith")
|
assert.Equal(t, "test", hookRepo.Owner)
|
||||||
g.Assert(repo.Name).Equal("example")
|
assert.Equal(t, "woodpecker", hookRepo.Name)
|
||||||
g.Assert(repo.Avatar).Equal("http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg")
|
assert.Equal(t, "http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg", hookRepo.Avatar)
|
||||||
g.Assert(repo.Branch).Equal("develop")
|
assert.Equal(t, "develop", hookRepo.Branch)
|
||||||
g.Assert(build.Ref).Equal("refs/tags/v1.0.0")
|
assert.Equal(t, "refs/tags/v22", build.Ref)
|
||||||
|
}
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should parse legacy tag push hook", func() {
|
|
||||||
req, _ := http.NewRequest(
|
|
||||||
"POST",
|
|
||||||
"http://example.com/api/hook?owner=diaspora&name=diaspora-client",
|
|
||||||
bytes.NewReader(testdata.LegacyTagHook),
|
|
||||||
)
|
|
||||||
|
|
||||||
repo, build, err := gitlab.Hook(req)
|
|
||||||
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(repo.Owner).Equal("diaspora")
|
|
||||||
g.Assert(repo.Name).Equal("diaspora-client")
|
|
||||||
g.Assert(build.Ref).Equal("refs/tags/v1.0.0")
|
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
g.Describe("Merge request hook", func() {
|
g.Describe("Merge request hook", func() {
|
||||||
g.It("Should parse merge request hook", func() {
|
g.It("Should parse merge request hook", func() {
|
||||||
req, _ := http.NewRequest(
|
req, _ := http.NewRequest(
|
||||||
"POST",
|
testdata.ServiceHookMethod,
|
||||||
"http://example.com/api/hook?owner=diaspora&name=diaspora-client",
|
testdata.ServiceHookURL.String(),
|
||||||
bytes.NewReader(testdata.MergeRequestHook),
|
bytes.NewReader(testdata.ServiceHookMergeRequestBody),
|
||||||
)
|
)
|
||||||
|
req.Header = testdata.ServiceHookHeaders
|
||||||
|
|
||||||
repo, build, err := gitlab.Hook(req)
|
hookRepo, build, err := client.Hook(req)
|
||||||
|
assert.NoError(t, err)
|
||||||
g.Assert(err == nil).IsTrue()
|
if assert.NotNil(t, hookRepo) && assert.NotNil(t, build) {
|
||||||
g.Assert(repo.Avatar).Equal("http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg")
|
assert.Equal(t, "http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg", hookRepo.Avatar)
|
||||||
g.Assert(repo.Branch).Equal("develop")
|
assert.Equal(t, "develop", hookRepo.Branch)
|
||||||
g.Assert(repo.Owner).Equal("awesome_space")
|
assert.Equal(t, "test", hookRepo.Owner)
|
||||||
g.Assert(repo.Name).Equal("awesome_project")
|
assert.Equal(t, "woodpecker", hookRepo.Name)
|
||||||
|
assert.Equal(t, "Update client.go 🎉", build.Title)
|
||||||
g.Assert(build.Title).Equal("MS-Viewport")
|
}
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should parse legacy merge request hook", func() {
|
|
||||||
req, _ := http.NewRequest(
|
|
||||||
"POST",
|
|
||||||
"http://example.com/api/hook?owner=diaspora&name=diaspora-client",
|
|
||||||
bytes.NewReader(testdata.LegacyMergeRequestHook),
|
|
||||||
)
|
|
||||||
|
|
||||||
repo, build, err := gitlab.Hook(req)
|
|
||||||
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(repo.Owner).Equal("diaspora")
|
|
||||||
g.Assert(repo.Name).Equal("diaspora-client")
|
|
||||||
|
|
||||||
g.Assert(build.Title).Equal("MS-Viewport")
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -15,30 +15,30 @@
|
||||||
package gitlab
|
package gitlab
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/md5"
|
"crypto/tls"
|
||||||
"encoding/hex"
|
"net/http"
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server/remote/gitlab/client"
|
"github.com/xanzy/go-gitlab"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
gravatarBase = "https://www.gravatar.com/avatar"
|
gravatarBase = "https://www.gravatar.com/avatar"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewClient is a helper function that returns a new GitHub
|
// newClient is a helper function that returns a new GitHub
|
||||||
// client using the provided OAuth token.
|
// client using the provided OAuth token.
|
||||||
func NewClient(url, accessToken string, skipVerify bool) *client.Client {
|
func newClient(url, accessToken string, skipVerify bool) (*gitlab.Client, error) {
|
||||||
client := client.New(url, "/api/v4", accessToken, skipVerify)
|
return gitlab.NewOAuthClient(accessToken, gitlab.WithBaseURL(url), gitlab.WithHTTPClient(&http.Client{
|
||||||
return client
|
Transport: &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: skipVerify},
|
||||||
|
Proxy: http.ProxyFromEnvironment,
|
||||||
|
},
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsRead is a helper function that returns true if the
|
// isRead is a helper function that returns true if the
|
||||||
// user has Read-only access to the repository.
|
// user has Read-only access to the repository.
|
||||||
func IsRead(proj *client.Project) bool {
|
func isRead(proj *gitlab.Project) bool {
|
||||||
var user = proj.Permissions.ProjectAccess
|
var user = proj.Permissions.ProjectAccess
|
||||||
var group = proj.Permissions.GroupAccess
|
var group = proj.Permissions.GroupAccess
|
||||||
|
|
||||||
|
@ -54,9 +54,9 @@ func IsRead(proj *client.Project) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsWrite is a helper function that returns true if the
|
// isWrite is a helper function that returns true if the
|
||||||
// user has Read-Write access to the repository.
|
// user has Read-Write access to the repository.
|
||||||
func IsWrite(proj *client.Project) bool {
|
func isWrite(proj *gitlab.Project) bool {
|
||||||
var user = proj.Permissions.ProjectAccess
|
var user = proj.Permissions.ProjectAccess
|
||||||
var group = proj.Permissions.GroupAccess
|
var group = proj.Permissions.GroupAccess
|
||||||
|
|
||||||
|
@ -70,9 +70,9 @@ func IsWrite(proj *client.Project) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsAdmin is a helper function that returns true if the
|
// isAdmin is a helper function that returns true if the
|
||||||
// user has Admin access to the repository.
|
// user has Admin access to the repository.
|
||||||
func IsAdmin(proj *client.Project) bool {
|
func isAdmin(proj *gitlab.Project) bool {
|
||||||
var user = proj.Permissions.ProjectAccess
|
var user = proj.Permissions.ProjectAccess
|
||||||
var group = proj.Permissions.GroupAccess
|
var group = proj.Permissions.GroupAccess
|
||||||
|
|
||||||
|
@ -85,55 +85,3 @@ func IsAdmin(proj *client.Project) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKeyTitle is a helper function that generates a title for the
|
|
||||||
// RSA public key based on the username and domain name.
|
|
||||||
func GetKeyTitle(rawurl string) (string, error) {
|
|
||||||
var uri, err = url.Parse(rawurl)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("drone@%s", uri.Host), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ns(owner, name string) string {
|
|
||||||
return fmt.Sprintf("%s%%2F%s", owner, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetUserAvatar(email string) string {
|
|
||||||
hasher := md5.New()
|
|
||||||
hasher.Write([]byte(email))
|
|
||||||
|
|
||||||
return fmt.Sprintf(
|
|
||||||
"%s/%v.jpg?s=%s",
|
|
||||||
gravatarBase,
|
|
||||||
hex.EncodeToString(hasher.Sum(nil)),
|
|
||||||
"128",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExtractFromPath(str string) (string, string, error) {
|
|
||||||
s := strings.Split(str, "/")
|
|
||||||
if len(s) < 2 {
|
|
||||||
return "", "", fmt.Errorf("Minimum match not found")
|
|
||||||
}
|
|
||||||
return s[0], s[1], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetUserEmail(c *client.Client, defaultURL string) (*client.Client, error) {
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetProjectId(r *Gitlab, c *client.Client, owner, name string) (projectId string, err error) {
|
|
||||||
if r.Search {
|
|
||||||
_projectId, err := c.SearchProjectId(owner, name)
|
|
||||||
if err != nil || _projectId == 0 {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
projectId := strconv.Itoa(_projectId)
|
|
||||||
return projectId, nil
|
|
||||||
} else {
|
|
||||||
projectId := ns(owner, name)
|
|
||||||
return projectId, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
72
server/remote/gitlab/status.go
Normal file
72
server/remote/gitlab/status.go
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
// Copyright 2021 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/woodpecker-ci/woodpecker/server/model"
|
||||||
|
|
||||||
|
"github.com/xanzy/go-gitlab"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DescPending = "the build is pending"
|
||||||
|
DescRunning = "the buils is running"
|
||||||
|
DescSuccess = "the build was successful"
|
||||||
|
DescFailure = "the build failed"
|
||||||
|
DescCanceled = "the build canceled"
|
||||||
|
DescBlocked = "the build is pending approval"
|
||||||
|
DescDeclined = "the build was rejected"
|
||||||
|
)
|
||||||
|
|
||||||
|
// getStatus is a helper that converts a Woodpecker status to a Gitlab status.
|
||||||
|
func getStatus(status string) gitlab.BuildStateValue {
|
||||||
|
switch status {
|
||||||
|
case model.StatusPending, model.StatusBlocked:
|
||||||
|
return gitlab.Pending
|
||||||
|
case model.StatusRunning:
|
||||||
|
return gitlab.Running
|
||||||
|
case model.StatusSuccess:
|
||||||
|
return gitlab.Success
|
||||||
|
case model.StatusFailure, model.StatusError:
|
||||||
|
return gitlab.Failed
|
||||||
|
case model.StatusKilled:
|
||||||
|
return gitlab.Canceled
|
||||||
|
default:
|
||||||
|
return gitlab.Failed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getDesc is a helper function that generates a description
|
||||||
|
// message for the build based on the status.
|
||||||
|
func getDesc(status string) string {
|
||||||
|
switch status {
|
||||||
|
case model.StatusPending:
|
||||||
|
return DescPending
|
||||||
|
case model.StatusRunning:
|
||||||
|
return DescRunning
|
||||||
|
case model.StatusSuccess:
|
||||||
|
return DescSuccess
|
||||||
|
case model.StatusFailure, model.StatusError:
|
||||||
|
return DescFailure
|
||||||
|
case model.StatusKilled:
|
||||||
|
return DescCanceled
|
||||||
|
case model.StatusBlocked:
|
||||||
|
return DescBlocked
|
||||||
|
case model.StatusDeclined:
|
||||||
|
return DescDeclined
|
||||||
|
default:
|
||||||
|
return DescFailure
|
||||||
|
}
|
||||||
|
}
|
567
server/remote/gitlab/testdata/hooks.go
vendored
567
server/remote/gitlab/testdata/hooks.go
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2021 Woodpecker Authors
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -14,335 +14,292 @@
|
||||||
|
|
||||||
package testdata
|
package testdata
|
||||||
|
|
||||||
var TagHook = []byte(`
|
import (
|
||||||
{
|
"net/http"
|
||||||
"object_kind": "tag_push",
|
"net/url"
|
||||||
"ref": "refs/tags/v1.0.0",
|
)
|
||||||
"before": "0000000000000000000000000000000000000000",
|
|
||||||
"after": "82b3d5ae55f7080f1e6022629cdb57bfae7cccc7",
|
|
||||||
"user_id": 1,
|
|
||||||
"user_name": "John Smith",
|
|
||||||
"user_avatar": "https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s=80",
|
|
||||||
"project_id": 1,
|
|
||||||
"project":{
|
|
||||||
"name":"Example",
|
|
||||||
"description":"",
|
|
||||||
"web_url":"http://example.com/jsmith/example",
|
|
||||||
"avatar_url":"http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg",
|
|
||||||
"git_ssh_url":"git@example.com:jsmith/example.git",
|
|
||||||
"git_http_url":"http://example.com/jsmith/example.git",
|
|
||||||
"namespace":"Jsmith",
|
|
||||||
"visibility_level":0,
|
|
||||||
"path_with_namespace":"jsmith/example",
|
|
||||||
"default_branch":"develop",
|
|
||||||
"homepage":"http://example.com/jsmith/example",
|
|
||||||
"url":"git@example.com:jsmith/example.git",
|
|
||||||
"ssh_url":"git@example.com:jsmith/example.git",
|
|
||||||
"http_url":"http://example.com/jsmith/example.git"
|
|
||||||
},
|
|
||||||
"repository":{
|
|
||||||
"name": "jsmith",
|
|
||||||
"url": "ssh://git@example.com/jsmith/example.git",
|
|
||||||
"description": "",
|
|
||||||
"homepage": "http://example.com/jsmith/example",
|
|
||||||
"git_http_url":"http://example.com/jsmith/example.git",
|
|
||||||
"git_ssh_url":"git@example.com:jsmith/example.git",
|
|
||||||
"visibility_level":0
|
|
||||||
},
|
|
||||||
"commits": [],
|
|
||||||
"total_commits_count": 0
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
||||||
var LegacyTagHook = []byte(`
|
var (
|
||||||
{
|
ServiceHookMethod = http.MethodPost
|
||||||
"object_kind": "tag_push",
|
ServiceHookURL, _ = url.Parse(
|
||||||
"ref": "refs/tags/v1.0.0",
|
"http://10.40.8.5:8000/hook?owner=test&name=woodpecker&access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9." +
|
||||||
"before": "0000000000000000000000000000000000000000",
|
"eyJ0ZXh0IjoidGVzdC93b29kcGVja2VyIiwidHlwZSI6Imhvb2sifQ.x3kPnmZtxZQ_9_eMhfQ1HSmj_SLhdT_Lu2hMczWjKh0")
|
||||||
"after": "82b3d5ae55f7080f1e6022629cdb57bfae7cccc7",
|
ServiceHookHeaders = http.Header{
|
||||||
"user_id": 1,
|
"Content-Type": []string{"application/json"},
|
||||||
"user_name": "John Smith",
|
"User-Agent": []string{"GitLab/14.3.0"},
|
||||||
"project_id": 1,
|
"X-Gitlab-Event": []string{"Service Hook"},
|
||||||
"repository": {
|
}
|
||||||
"name": "jsmith",
|
)
|
||||||
"url": "ssh://git@example.com/jsmith/example.git",
|
|
||||||
|
// ServiceHookPushBody is payload of ServiceHook: Push
|
||||||
|
var ServiceHookPushBody = []byte(`{
|
||||||
|
"object_kind": "push",
|
||||||
|
"event_name": "push",
|
||||||
|
"before": "ffe8eb4f91d1fe6bc49f1e610e50e4b5767f0104",
|
||||||
|
"after": "16862e368d8ab812e48833b741dad720d6e2cb7f",
|
||||||
|
"ref": "refs/heads/master",
|
||||||
|
"checkout_sha": "16862e368d8ab812e48833b741dad720d6e2cb7f",
|
||||||
|
"message": null,
|
||||||
|
"user_id": 2,
|
||||||
|
"user_name": "te st",
|
||||||
|
"user_username": "test",
|
||||||
|
"user_email": "",
|
||||||
|
"user_avatar": "https://www.gravatar.com/avatar/dd46a756faad4727fb679320751f6dea?s=80&d=identicon",
|
||||||
|
"project_id": 2,
|
||||||
|
"project": {
|
||||||
|
"id": 2,
|
||||||
|
"name": "Woodpecker",
|
||||||
"description": "",
|
"description": "",
|
||||||
"homepage": "http://example.com/jsmith/example",
|
"web_url": "http://10.40.8.5:3200/test/woodpecker",
|
||||||
"git_http_url":"http://example.com/jsmith/example.git",
|
"avatar_url": "http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg",
|
||||||
"git_ssh_url":"git@example.com:jsmith/example.git",
|
"git_ssh_url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
"visibility_level":0
|
"git_http_url": "http://10.40.8.5:3200/test/woodpecker.git",
|
||||||
|
"namespace": "te st",
|
||||||
|
"visibility_level": 20,
|
||||||
|
"path_with_namespace": "test/woodpecker",
|
||||||
|
"default_branch": "develop",
|
||||||
|
"ci_config_path": null,
|
||||||
|
"homepage": "http://10.40.8.5:3200/test/woodpecker",
|
||||||
|
"url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
|
"ssh_url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
|
"http_url": "http://10.40.8.5:3200/test/woodpecker.git"
|
||||||
},
|
},
|
||||||
"commits": [
|
"commits": [
|
||||||
{
|
{
|
||||||
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
"id": "16862e368d8ab812e48833b741dad720d6e2cb7f",
|
||||||
"message": "Update Catalan translation to e38cb41.",
|
"message": "Update main.go",
|
||||||
"timestamp": "2011-12-12T14:27:31+02:00",
|
"title": "Update main.go",
|
||||||
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
"timestamp": "2021-09-27T04:46:14+00:00",
|
||||||
|
"url": "http://10.40.8.5:3200/test/woodpecker/-/commit/16862e368d8ab812e48833b741dad720d6e2cb7f",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Jordi Mallach",
|
"name": "te st",
|
||||||
"email": "jordi@softcatala.org"
|
"email": "test@test.test"
|
||||||
}
|
},
|
||||||
},
|
"added": [
|
||||||
{
|
|
||||||
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
],
|
||||||
"message": "fixed readme",
|
"modified": [
|
||||||
"timestamp": "2012-01-03T23:36:29+02:00",
|
"cmd/cli/main.go"
|
||||||
"url": "http://example.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
],
|
||||||
"author": {
|
"removed": [
|
||||||
"name": "GitLab dev user",
|
|
||||||
"email": "gitlabdev@dv6700.(none)"
|
]
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"total_commits_count": 4
|
"total_commits_count": 1,
|
||||||
}
|
"push_options": {
|
||||||
`)
|
},
|
||||||
|
"repository": {
|
||||||
|
"name": "Woodpecker",
|
||||||
|
"url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
|
"description": "",
|
||||||
|
"homepage": "http://10.40.8.5:3200/test/woodpecker",
|
||||||
|
"git_http_url": "http://10.40.8.5:3200/test/woodpecker.git",
|
||||||
|
"git_ssh_url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
|
"visibility_level": 20
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
var MergeRequestHook = []byte(`
|
// ServiceHookTagPushBody is payload of ServiceHook: TagPush
|
||||||
{
|
var ServiceHookTagPushBody = []byte(`{
|
||||||
|
"object_kind": "tag_push",
|
||||||
|
"event_name": "tag_push",
|
||||||
|
"before": "0000000000000000000000000000000000000000",
|
||||||
|
"after": "fabed3d94cd03e6c2b7958afa9569c18a24d301f",
|
||||||
|
"ref": "refs/tags/v22",
|
||||||
|
"checkout_sha": "16862e368d8ab812e48833b741dad720d6e2cb7f",
|
||||||
|
"message": "hi",
|
||||||
|
"user_id": 2,
|
||||||
|
"user_name": "te st",
|
||||||
|
"user_username": "test",
|
||||||
|
"user_email": "",
|
||||||
|
"user_avatar": "https://www.gravatar.com/avatar/dd46a756faad4727fb679320751f6dea?s=80&d=identicon",
|
||||||
|
"project_id": 2,
|
||||||
|
"project": {
|
||||||
|
"id": 2,
|
||||||
|
"name": "Woodpecker",
|
||||||
|
"description": "",
|
||||||
|
"web_url": "http://10.40.8.5:3200/test/woodpecker",
|
||||||
|
"avatar_url": "http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg",
|
||||||
|
"git_ssh_url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
|
"git_http_url": "http://10.40.8.5:3200/test/woodpecker.git",
|
||||||
|
"namespace": "te st",
|
||||||
|
"visibility_level": 20,
|
||||||
|
"path_with_namespace": "test/woodpecker",
|
||||||
|
"default_branch": "develop",
|
||||||
|
"ci_config_path": null,
|
||||||
|
"homepage": "http://10.40.8.5:3200/test/woodpecker",
|
||||||
|
"url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
|
"ssh_url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
|
"http_url": "http://10.40.8.5:3200/test/woodpecker.git"
|
||||||
|
},
|
||||||
|
"commits": [
|
||||||
|
{
|
||||||
|
"id": "16862e368d8ab812e48833b741dad720d6e2cb7f",
|
||||||
|
"message": "Update main.go",
|
||||||
|
"title": "Update main.go",
|
||||||
|
"timestamp": "2021-09-27T04:46:14+00:00",
|
||||||
|
"url": "http://10.40.8.5:3200/test/woodpecker/-/commit/16862e368d8ab812e48833b741dad720d6e2cb7f",
|
||||||
|
"author": {
|
||||||
|
"name": "te st",
|
||||||
|
"email": "test@test.test"
|
||||||
|
},
|
||||||
|
"added": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"modified": [
|
||||||
|
"cmd/cli/main.go"
|
||||||
|
],
|
||||||
|
"removed": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total_commits_count": 1,
|
||||||
|
"push_options": {
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"name": "Woodpecker",
|
||||||
|
"url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
|
"description": "",
|
||||||
|
"homepage": "http://10.40.8.5:3200/test/woodpecker",
|
||||||
|
"git_http_url": "http://10.40.8.5:3200/test/woodpecker.git",
|
||||||
|
"git_ssh_url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
|
"visibility_level": 20
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
// ServiceHookMergeRequestBody is payload of ServiceHook: MergeRequest
|
||||||
|
var ServiceHookMergeRequestBody = []byte(`{
|
||||||
"object_kind": "merge_request",
|
"object_kind": "merge_request",
|
||||||
|
"event_type": "merge_request",
|
||||||
"user": {
|
"user": {
|
||||||
"name": "Administrator",
|
"id": 2,
|
||||||
"username": "root",
|
"name": "te st",
|
||||||
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
|
"username": "test",
|
||||||
|
"avatar_url": "https://www.gravatar.com/avatar/dd46a756faad4727fb679320751f6dea?s=80&d=identicon",
|
||||||
|
"email": "test@test.test"
|
||||||
|
},
|
||||||
|
"project": {
|
||||||
|
"id": 2,
|
||||||
|
"name": "Woodpecker",
|
||||||
|
"description": "",
|
||||||
|
"web_url": "http://10.40.8.5:3200/test/woodpecker",
|
||||||
|
"avatar_url": null,
|
||||||
|
"git_ssh_url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
|
"git_http_url": "http://10.40.8.5:3200/test/woodpecker.git",
|
||||||
|
"namespace": "te st",
|
||||||
|
"visibility_level": 20,
|
||||||
|
"path_with_namespace": "test/woodpecker",
|
||||||
|
"default_branch": "master",
|
||||||
|
"ci_config_path": null,
|
||||||
|
"homepage": "http://10.40.8.5:3200/test/woodpecker",
|
||||||
|
"url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
|
"ssh_url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
|
"http_url": "http://10.40.8.5:3200/test/woodpecker.git"
|
||||||
},
|
},
|
||||||
"object_attributes": {
|
"object_attributes": {
|
||||||
"id": 99,
|
"assignee_id": null,
|
||||||
"target_branch": "master",
|
"author_id": 2,
|
||||||
"source_branch": "ms-viewport",
|
"created_at": "2021-09-27 05:00:01 UTC",
|
||||||
"source_project_id": 14,
|
|
||||||
"author_id": 51,
|
|
||||||
"assignee_id": 6,
|
|
||||||
"title": "MS-Viewport",
|
|
||||||
"created_at": "2013-12-03T17:23:34Z",
|
|
||||||
"updated_at": "2013-12-03T17:23:34Z",
|
|
||||||
"st_commits": null,
|
|
||||||
"st_diffs": null,
|
|
||||||
"milestone_id": null,
|
|
||||||
"state": "opened",
|
|
||||||
"merge_status": "unchecked",
|
|
||||||
"target_project_id": 14,
|
|
||||||
"iid": 1,
|
|
||||||
"description": "",
|
"description": "",
|
||||||
"source":{
|
"head_pipeline_id": 5,
|
||||||
"name":"Awesome Project",
|
"id": 2,
|
||||||
"description":"Aut reprehenderit ut est.",
|
"iid": 2,
|
||||||
"web_url":"http://example.com/awesome_space/awesome_project",
|
"last_edited_at": null,
|
||||||
"avatar_url":"http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg",
|
"last_edited_by_id": null,
|
||||||
"git_ssh_url":"git@example.com:awesome_space/awesome_project.git",
|
"merge_commit_sha": null,
|
||||||
"git_http_url":"http://example.com/awesome_space/awesome_project.git",
|
"merge_error": null,
|
||||||
"namespace":"Awesome Space",
|
"merge_params": {
|
||||||
"visibility_level":20,
|
"force_remove_source_branch": "1"
|
||||||
"path_with_namespace":"awesome_space/awesome_project",
|
},
|
||||||
"default_branch":"master",
|
"merge_status": "unchecked",
|
||||||
"homepage":"http://example.com/awesome_space/awesome_project",
|
"merge_user_id": null,
|
||||||
"url":"http://example.com/awesome_space/awesome_project.git",
|
"merge_when_pipeline_succeeds": false,
|
||||||
"ssh_url":"git@example.com:awesome_space/awesome_project.git",
|
"milestone_id": null,
|
||||||
"http_url":"http://example.com/awesome_space/awesome_project.git"
|
"source_branch": "masterfdsafds",
|
||||||
|
"source_project_id": 2,
|
||||||
|
"state_id": 1,
|
||||||
|
"target_branch": "master",
|
||||||
|
"target_project_id": 2,
|
||||||
|
"time_estimate": 0,
|
||||||
|
"title": "Update client.go 🎉",
|
||||||
|
"updated_at": "2021-09-27 05:01:21 UTC",
|
||||||
|
"updated_by_id": null,
|
||||||
|
"url": "http://10.40.8.5:3200/test/woodpecker/-/merge_requests/2",
|
||||||
|
"source": {
|
||||||
|
"id": 2,
|
||||||
|
"name": "Woodpecker",
|
||||||
|
"description": "",
|
||||||
|
"web_url": "http://10.40.8.5:3200/test/woodpecker",
|
||||||
|
"avatar_url": "http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg",
|
||||||
|
"git_ssh_url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
|
"git_http_url": "http://10.40.8.5:3200/test/woodpecker.git",
|
||||||
|
"namespace": "te st",
|
||||||
|
"visibility_level": 20,
|
||||||
|
"path_with_namespace": "test/woodpecker",
|
||||||
|
"default_branch": "develop",
|
||||||
|
"ci_config_path": null,
|
||||||
|
"homepage": "http://10.40.8.5:3200/test/woodpecker",
|
||||||
|
"url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
|
"ssh_url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
|
"http_url": "http://10.40.8.5:3200/test/woodpecker.git"
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"name":"Awesome Project",
|
"id": 2,
|
||||||
"description":"Aut reprehenderit ut est.",
|
"name": "Woodpecker",
|
||||||
"web_url":"http://example.com/awesome_space/awesome_project",
|
"description": "",
|
||||||
"avatar_url":"http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg",
|
"web_url": "http://10.40.8.5:3200/test/woodpecker",
|
||||||
"git_ssh_url":"git@example.com:awesome_space/awesome_project.git",
|
"avatar_url": "http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg",
|
||||||
"git_http_url":"http://example.com/awesome_space/awesome_project.git",
|
"git_ssh_url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
"namespace":"Awesome Space",
|
"git_http_url": "http://10.40.8.5:3200/test/woodpecker.git",
|
||||||
"visibility_level":20,
|
"namespace": "te st",
|
||||||
"path_with_namespace":"awesome_space/awesome_project",
|
"visibility_level": 20,
|
||||||
"default_branch":"develop",
|
"path_with_namespace": "test/woodpecker",
|
||||||
"homepage":"http://example.com/awesome_space/awesome_project",
|
"default_branch": "develop",
|
||||||
"url":"http://example.com/awesome_space/awesome_project.git",
|
"ci_config_path": null,
|
||||||
"ssh_url":"git@example.com:awesome_space/awesome_project.git",
|
"homepage": "http://10.40.8.5:3200/test/woodpecker",
|
||||||
"http_url":"http://example.com/awesome_space/awesome_project.git"
|
"url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
|
"ssh_url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
|
"http_url": "http://10.40.8.5:3200/test/woodpecker.git"
|
||||||
},
|
},
|
||||||
"last_commit": {
|
"last_commit": {
|
||||||
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
"id": "0ab96a10266b95b4b533dcfd98738015fbe70889",
|
||||||
"message": "fixed readme",
|
"message": "Update state.go",
|
||||||
"timestamp": "2012-01-03T23:36:29+02:00",
|
"title": "Update state.go",
|
||||||
"url": "http://example.com/awesome_space/awesome_project/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
"timestamp": "2021-09-27T05:01:20+00:00",
|
||||||
|
"url": "http://10.40.8.5:3200/test/woodpecker/-/commit/0ab96a10266b95b4b533dcfd98738015fbe70889",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "GitLab dev user",
|
"name": "te st",
|
||||||
"email": "gitlabdev@dv6700.(none)"
|
"email": "test@test.test"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"work_in_progress": false,
|
"work_in_progress": false,
|
||||||
"url": "http://example.com/diaspora/merge_requests/1",
|
"total_time_spent": 0,
|
||||||
"action": "open",
|
"time_change": 0,
|
||||||
"assignee": {
|
"human_total_time_spent": null,
|
||||||
"name": "User1",
|
"human_time_change": null,
|
||||||
"username": "user1",
|
"human_time_estimate": null,
|
||||||
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
|
"assignee_ids": [
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
||||||
var LegacyMergeRequestHook = []byte(`
|
],
|
||||||
{
|
|
||||||
"object_kind": "merge_request",
|
|
||||||
"user": {
|
|
||||||
"name": "Administrator",
|
|
||||||
"username": "root",
|
|
||||||
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
|
|
||||||
},
|
|
||||||
"object_attributes": {
|
|
||||||
"id": 99,
|
|
||||||
"target_branch": "master",
|
|
||||||
"source_branch": "ms-viewport",
|
|
||||||
"source_project_id": 14,
|
|
||||||
"author_id": 51,
|
|
||||||
"assignee_id": 6,
|
|
||||||
"title": "MS-Viewport",
|
|
||||||
"created_at": "2013-12-03T17:23:34Z",
|
|
||||||
"updated_at": "2013-12-03T17:23:34Z",
|
|
||||||
"st_commits": null,
|
|
||||||
"st_diffs": null,
|
|
||||||
"milestone_id": null,
|
|
||||||
"state": "opened",
|
"state": "opened",
|
||||||
"merge_status": "unchecked",
|
"action": "update",
|
||||||
"target_project_id": 14,
|
"oldrev": "6ef047571374c96a2bf13c361efd1fb008b0063e"
|
||||||
"iid": 1,
|
},
|
||||||
"description": "",
|
"labels": [
|
||||||
"source": {
|
|
||||||
"name": "awesome_project",
|
|
||||||
"ssh_url": "ssh://git@example.com/awesome_space/awesome_project.git",
|
|
||||||
"http_url": "http://example.com/awesome_space/awesome_project.git",
|
|
||||||
"visibility_level": 20,
|
|
||||||
"namespace": "awesome_space"
|
|
||||||
},
|
|
||||||
"target": {
|
|
||||||
"name": "awesome_project",
|
|
||||||
"ssh_url": "ssh://git@example.com/awesome_space/awesome_project.git",
|
|
||||||
"http_url": "http://example.com/awesome_space/awesome_project.git",
|
|
||||||
"visibility_level": 20,
|
|
||||||
"namespace": "awesome_space"
|
|
||||||
},
|
|
||||||
"last_commit": {
|
|
||||||
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"message": "fixed readme",
|
|
||||||
"timestamp": "2012-01-03T23:36:29+02:00",
|
|
||||||
"url": "http://example.com/awesome_space/awesome_project/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"author": {
|
|
||||||
"name": "GitLab dev user",
|
|
||||||
"email": "gitlabdev@dv6700.(none)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"url": "http://example.com/diaspora/merge_requests/1",
|
|
||||||
"action": "open"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
||||||
var PushHook = []byte(`
|
|
||||||
{
|
|
||||||
"object_kind": "push",
|
|
||||||
"before": "95790bf891e76fee5e1747ab589903a6a1f80f22",
|
|
||||||
"after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"ref": "refs/heads/master",
|
|
||||||
"user_id": 4,
|
|
||||||
"user_name": "John Smith",
|
|
||||||
"user_email": "john@example.com",
|
|
||||||
"user_avatar": "https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80",
|
|
||||||
"project_id": 15,
|
|
||||||
"project":{
|
|
||||||
"name":"Diaspora",
|
|
||||||
"description":"",
|
|
||||||
"web_url":"http://example.com/mike/diaspora",
|
|
||||||
"avatar_url":"http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg",
|
|
||||||
"git_ssh_url":"git@example.com:mike/diaspora.git",
|
|
||||||
"git_http_url":"http://example.com/mike/diaspora.git",
|
|
||||||
"namespace":"Mike",
|
|
||||||
"visibility_level":0,
|
|
||||||
"path_with_namespace":"mike/diaspora",
|
|
||||||
"default_branch":"develop",
|
|
||||||
"homepage":"http://example.com/mike/diaspora",
|
|
||||||
"url":"git@example.com:mike/diasporadiaspora.git",
|
|
||||||
"ssh_url":"git@example.com:mike/diaspora.git",
|
|
||||||
"http_url":"http://example.com/mike/diaspora.git"
|
|
||||||
},
|
|
||||||
"repository":{
|
|
||||||
"name": "Diaspora",
|
|
||||||
"url": "git@example.com:mike/diasporadiaspora.git",
|
|
||||||
"description": "",
|
|
||||||
"homepage": "http://example.com/mike/diaspora",
|
|
||||||
"git_http_url":"http://example.com/mike/diaspora.git",
|
|
||||||
"git_ssh_url":"git@example.com:mike/diaspora.git",
|
|
||||||
"visibility_level":0
|
|
||||||
},
|
|
||||||
"commits": [
|
|
||||||
{
|
|
||||||
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
|
||||||
"message": "Update Catalan translation to e38cb41.",
|
|
||||||
"timestamp": "2011-12-12T14:27:31+02:00",
|
|
||||||
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
|
||||||
"author": {
|
|
||||||
"name": "Jordi Mallach",
|
|
||||||
"email": "jordi@softcatala.org"
|
|
||||||
},
|
|
||||||
"added": ["CHANGELOG"],
|
|
||||||
"modified": ["app/controller/application.rb"],
|
|
||||||
"removed": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"message": "fixed readme",
|
|
||||||
"timestamp": "2012-01-03T23:36:29+02:00",
|
|
||||||
"url": "http://example.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"author": {
|
|
||||||
"name": "GitLab dev user",
|
|
||||||
"email": "gitlabdev@dv6700.(none)"
|
|
||||||
},
|
|
||||||
"added": ["CHANGELOG"],
|
|
||||||
"modified": ["app/controller/application.rb"],
|
|
||||||
"removed": []
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
"total_commits_count": 4
|
"changes": {
|
||||||
}
|
"updated_at": {
|
||||||
`)
|
"previous": "2021-09-27 05:00:01 UTC",
|
||||||
|
"current": "2021-09-27 05:01:21 UTC"
|
||||||
var LegacyPushHook = []byte(`
|
}
|
||||||
{
|
},
|
||||||
"object_kind": "push",
|
|
||||||
"before": "95790bf891e76fee5e1747ab589903a6a1f80f22",
|
|
||||||
"after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"ref": "refs/heads/master",
|
|
||||||
"user_id": 4,
|
|
||||||
"user_name": "John Smith",
|
|
||||||
"user_email": "john@example.com",
|
|
||||||
"project_id": 15,
|
|
||||||
"repository": {
|
"repository": {
|
||||||
"name": "Diaspora",
|
"name": "Woodpecker",
|
||||||
"url": "git@example.com:mike/diasporadiaspora.git",
|
"url": "git@10.40.8.5:test/woodpecker.git",
|
||||||
"description": "",
|
"description": "",
|
||||||
"homepage": "http://example.com/mike/diaspora",
|
"homepage": "http://10.40.8.5:3200/test/woodpecker"
|
||||||
"git_http_url":"http://example.com/mike/diaspora.git",
|
}
|
||||||
"git_ssh_url":"git@example.com:mike/diaspora.git",
|
}`)
|
||||||
"visibility_level":0
|
|
||||||
},
|
|
||||||
"commits": [
|
|
||||||
{
|
|
||||||
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
|
||||||
"message": "Update Catalan translation to e38cb41.",
|
|
||||||
"timestamp": "2011-12-12T14:27:31+02:00",
|
|
||||||
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
|
||||||
"author": {
|
|
||||||
"name": "Jordi Mallach",
|
|
||||||
"email": "jordi@softcatala.org"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"message": "fixed readme",
|
|
||||||
"timestamp": "2012-01-03T23:36:29+02:00",
|
|
||||||
"url": "http://example.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"author": {
|
|
||||||
"name": "GitLab dev user",
|
|
||||||
"email": "gitlabdev@dv6700.(none)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"total_commits_count": 4
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
30
server/remote/gitlab/testdata/projects.go
vendored
30
server/remote/gitlab/testdata/projects.go
vendored
|
@ -30,7 +30,7 @@ var allProjectsPayload = []byte(`
|
||||||
"id": 3,
|
"id": 3,
|
||||||
"name": "Diaspora",
|
"name": "Diaspora",
|
||||||
"username": "some_user",
|
"username": "some_user",
|
||||||
"created_at": "2013-09-30T13: 46: 02Z"
|
"created_at": "2013-09-30T13:46:02Z"
|
||||||
},
|
},
|
||||||
"name": "Diaspora Client",
|
"name": "Diaspora Client",
|
||||||
"name_with_namespace": "Diaspora / Diaspora Client",
|
"name_with_namespace": "Diaspora / Diaspora Client",
|
||||||
|
@ -40,16 +40,16 @@ var allProjectsPayload = []byte(`
|
||||||
"merge_requests_enabled": true,
|
"merge_requests_enabled": true,
|
||||||
"wiki_enabled": true,
|
"wiki_enabled": true,
|
||||||
"snippets_enabled": false,
|
"snippets_enabled": false,
|
||||||
"created_at": "2013-09-30T13: 46: 02Z",
|
"created_at": "2013-09-30T13:46:02Z",
|
||||||
"last_activity_at": "2013-09-30T13: 46: 02Z",
|
"last_activity_at": "2013-09-30T13:46:02Z",
|
||||||
"namespace": {
|
"namespace": {
|
||||||
"created_at": "2013-09-30T13: 46: 02Z",
|
"created_at": "2013-09-30T13:46:02Z",
|
||||||
"description": "",
|
"description": "",
|
||||||
"id": 3,
|
"id": 3,
|
||||||
"name": "Diaspora",
|
"name": "Diaspora",
|
||||||
"owner_id": 1,
|
"owner_id": 1,
|
||||||
"path": "diaspora",
|
"path": "diaspora",
|
||||||
"updated_at": "2013-09-30T13: 46: 02Z"
|
"updated_at": "2013-09-30T13:46:02Z"
|
||||||
},
|
},
|
||||||
"archived": false
|
"archived": false
|
||||||
},
|
},
|
||||||
|
@ -107,7 +107,7 @@ var notArchivedProjectsPayload = []byte(`
|
||||||
"id": 3,
|
"id": 3,
|
||||||
"name": "Diaspora",
|
"name": "Diaspora",
|
||||||
"username": "some_user",
|
"username": "some_user",
|
||||||
"created_at": "2013-09-30T13: 46: 02Z"
|
"created_at": "2013-09-30T13:46:02Z"
|
||||||
},
|
},
|
||||||
"name": "Diaspora Client",
|
"name": "Diaspora Client",
|
||||||
"name_with_namespace": "Diaspora / Diaspora Client",
|
"name_with_namespace": "Diaspora / Diaspora Client",
|
||||||
|
@ -117,16 +117,16 @@ var notArchivedProjectsPayload = []byte(`
|
||||||
"merge_requests_enabled": true,
|
"merge_requests_enabled": true,
|
||||||
"wiki_enabled": true,
|
"wiki_enabled": true,
|
||||||
"snippets_enabled": false,
|
"snippets_enabled": false,
|
||||||
"created_at": "2013-09-30T13: 46: 02Z",
|
"created_at": "2013-09-30T13:46:02Z",
|
||||||
"last_activity_at": "2013-09-30T13: 46: 02Z",
|
"last_activity_at": "2013-09-30T13:46:02Z",
|
||||||
"namespace": {
|
"namespace": {
|
||||||
"created_at": "2013-09-30T13: 46: 02Z",
|
"created_at": "2013-09-30T13:46:02Z",
|
||||||
"description": "",
|
"description": "",
|
||||||
"id": 3,
|
"id": 3,
|
||||||
"name": "Diaspora",
|
"name": "Diaspora",
|
||||||
"owner_id": 1,
|
"owner_id": 1,
|
||||||
"path": "diaspora",
|
"path": "diaspora",
|
||||||
"updated_at": "2013-09-30T13: 46: 02Z"
|
"updated_at": "2013-09-30T13:46:02Z"
|
||||||
},
|
},
|
||||||
"archived": false
|
"archived": false
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ var project4Paylod = []byte(`
|
||||||
"id": 3,
|
"id": 3,
|
||||||
"name": "Diaspora",
|
"name": "Diaspora",
|
||||||
"username": "some_user",
|
"username": "some_user",
|
||||||
"created_at": "2013-09-30T13: 46: 02Z"
|
"created_at": "2013-09-30T13:46:02Z"
|
||||||
},
|
},
|
||||||
"name": "Diaspora Client",
|
"name": "Diaspora Client",
|
||||||
"name_with_namespace": "Diaspora / Diaspora Client",
|
"name_with_namespace": "Diaspora / Diaspora Client",
|
||||||
|
@ -157,16 +157,16 @@ var project4Paylod = []byte(`
|
||||||
"merge_requests_enabled": true,
|
"merge_requests_enabled": true,
|
||||||
"wiki_enabled": true,
|
"wiki_enabled": true,
|
||||||
"snippets_enabled": false,
|
"snippets_enabled": false,
|
||||||
"created_at": "2013-09-30T13: 46: 02Z",
|
"created_at": "2013-09-30T13:46:02Z",
|
||||||
"last_activity_at": "2013-09-30T13: 46: 02Z",
|
"last_activity_at": "2013-09-30T13:46:02Z",
|
||||||
"namespace": {
|
"namespace": {
|
||||||
"created_at": "2013-09-30T13: 46: 02Z",
|
"created_at": "2013-09-30T13:46:02Z",
|
||||||
"description": "",
|
"description": "",
|
||||||
"id": 3,
|
"id": 3,
|
||||||
"name": "Diaspora",
|
"name": "Diaspora",
|
||||||
"owner_id": 1,
|
"owner_id": 1,
|
||||||
"path": "diaspora",
|
"path": "diaspora",
|
||||||
"updated_at": "2013-09-30T13: 46: 02Z"
|
"updated_at": "2013-09-30T13:46:02Z"
|
||||||
},
|
},
|
||||||
"archived": false,
|
"archived": false,
|
||||||
"permissions": {
|
"permissions": {
|
||||||
|
|
26
server/remote/gitlab/testdata/testdata.go
vendored
26
server/remote/gitlab/testdata/testdata.go
vendored
|
@ -15,22 +15,31 @@
|
||||||
package testdata
|
package testdata
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
// setup a mock server for testing purposes.
|
// NewServer setup a mock server for testing purposes.
|
||||||
func NewServer() *httptest.Server {
|
func NewServer(t *testing.T) *httptest.Server {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
server := httptest.NewServer(mux)
|
server := httptest.NewServer(mux)
|
||||||
|
|
||||||
// handle requests and serve mock data
|
// handle requests and serve mock data
|
||||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
//println(r.URL.Path + " " + r.Method)
|
t.Logf("gitlab remote mock server: [%s] %s", r.Method, r.URL.Path)
|
||||||
// evaluate the path to serve a dummy data file
|
// evaluate the path to serve a dummy data file
|
||||||
|
|
||||||
|
// TODO: find source of "/api/v4/" requests
|
||||||
|
// assert.EqualValues(t, "go-gitlab", r.Header.Get("user-agent"), "on request: "+r.URL.Path)
|
||||||
|
|
||||||
switch r.URL.Path {
|
switch r.URL.Path {
|
||||||
case "/api/v4/projects":
|
case "/api/v4/projects":
|
||||||
if r.URL.Query().Get("archived") == "false" {
|
if r.FormValue("archived") == "false" {
|
||||||
w.Write(notArchivedProjectsPayload)
|
w.Write(notArchivedProjectsPayload)
|
||||||
} else {
|
} else {
|
||||||
w.Write(allProjectsPayload)
|
w.Write(allProjectsPayload)
|
||||||
|
@ -43,10 +52,15 @@ func NewServer() *httptest.Server {
|
||||||
case "/api/v4/projects/brightbox/puppet":
|
case "/api/v4/projects/brightbox/puppet":
|
||||||
w.Write(project6Paylod)
|
w.Write(project6Paylod)
|
||||||
return
|
return
|
||||||
case "/api/v4/projects/diaspora/diaspora-client/services/drone-ci":
|
case "/api/v4/projects/4/services/drone-ci":
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case "PUT":
|
case "PUT":
|
||||||
if r.FormValue("token") == "" {
|
body, _ := io.ReadAll(r.Body)
|
||||||
|
opts := make(map[string]interface{})
|
||||||
|
assert.NoError(t, json.Unmarshal(body, &opts))
|
||||||
|
token, ok := opts["token"].(string)
|
||||||
|
assert.True(t, ok)
|
||||||
|
if token == "" {
|
||||||
w.WriteHeader(404)
|
w.WriteHeader(404)
|
||||||
} else {
|
} else {
|
||||||
w.WriteHeader(201)
|
w.WriteHeader(201)
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
const (
|
|
||||||
droneServiceUrl = "/projects/:id/services/drone-ci"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Client) AddDroneService(id string, params QMap) error {
|
|
||||||
url, opaque := c.ResourceUrl(
|
|
||||||
droneServiceUrl,
|
|
||||||
QMap{":id": id},
|
|
||||||
params,
|
|
||||||
)
|
|
||||||
|
|
||||||
_, err := c.Do("PUT", url, opaque, nil)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) DeleteDroneService(id string) error {
|
|
||||||
url, opaque := c.ResourceUrl(
|
|
||||||
droneServiceUrl,
|
|
||||||
QMap{":id": id},
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
|
|
||||||
_, err := c.Do("DELETE", url, opaque, nil)
|
|
||||||
return err
|
|
||||||
}
|
|
|
@ -1,110 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Client struct {
|
|
||||||
BaseUrl string
|
|
||||||
ApiPath string
|
|
||||||
Token string
|
|
||||||
Client *http.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(baseUrl, apiPath, token string, skipVerify bool) *Client {
|
|
||||||
config := &tls.Config{InsecureSkipVerify: skipVerify}
|
|
||||||
tr := &http.Transport{
|
|
||||||
Proxy: http.ProxyFromEnvironment,
|
|
||||||
TLSClientConfig: config,
|
|
||||||
}
|
|
||||||
client := &http.Client{Transport: tr}
|
|
||||||
|
|
||||||
return &Client{
|
|
||||||
BaseUrl: baseUrl,
|
|
||||||
ApiPath: apiPath,
|
|
||||||
Token: token,
|
|
||||||
Client: client,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) ResourceUrl(u string, params, query QMap) (string, string) {
|
|
||||||
if params != nil {
|
|
||||||
for key, val := range params {
|
|
||||||
u = strings.Replace(u, key, encodeParameter(val), -1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
query_params := url.Values{}
|
|
||||||
|
|
||||||
if query != nil {
|
|
||||||
for key, val := range query {
|
|
||||||
query_params.Set(key, val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u = c.BaseUrl + c.ApiPath + u + "?" + query_params.Encode()
|
|
||||||
p, err := url.Parse(u)
|
|
||||||
if err != nil {
|
|
||||||
return u, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
opaque := "//" + p.Host + p.Path
|
|
||||||
return u, opaque
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) Do(method, url, opaque string, body []byte) ([]byte, error) {
|
|
||||||
var req *http.Request
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if body != nil {
|
|
||||||
reader := bytes.NewReader(body)
|
|
||||||
req, err = http.NewRequest(method, url, reader)
|
|
||||||
} else {
|
|
||||||
req, err = http.NewRequest(method, url, nil)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error while building gitlab request")
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.Token))
|
|
||||||
|
|
||||||
if len(opaque) > 0 {
|
|
||||||
req.URL.Opaque = opaque
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := c.Client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Client.Do error: %q", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
contents, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("%s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode >= 400 {
|
|
||||||
err = fmt.Errorf("*Gitlab.buildAndExecRequest failed: <%d> %s", resp.StatusCode, req.URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
return contents, err
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
groupsUrl = "/groups"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Get a list of all projects owned by the authenticated user.
|
|
||||||
func (g *Client) AllGroups() ([]*Namespace, error) {
|
|
||||||
var perPage = 100
|
|
||||||
var groups []*Namespace
|
|
||||||
|
|
||||||
for i := 1; true; i++ {
|
|
||||||
contents, err := g.Groups(i, perPage)
|
|
||||||
if err != nil {
|
|
||||||
return groups, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, value := range contents {
|
|
||||||
groups = append(groups, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(groups) == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(groups)/i < perPage {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return groups, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Client) Groups(page, perPage int) ([]*Namespace, error) {
|
|
||||||
url, opaque := g.ResourceUrl(groupsUrl, nil, QMap{
|
|
||||||
"page": strconv.Itoa(page),
|
|
||||||
"per_page": strconv.Itoa(perPage),
|
|
||||||
})
|
|
||||||
|
|
||||||
var groups []*Namespace
|
|
||||||
|
|
||||||
contents, err := g.Do("GET", url, opaque, nil)
|
|
||||||
if err == nil {
|
|
||||||
err = json.Unmarshal(contents, &groups)
|
|
||||||
}
|
|
||||||
|
|
||||||
return groups, err
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ParseHook parses hook payload from GitLab
|
|
||||||
func ParseHook(payload []byte) (*HookPayload, error) {
|
|
||||||
hp := HookPayload{}
|
|
||||||
if err := json.Unmarshal(payload, &hp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Basic sanity check
|
|
||||||
switch {
|
|
||||||
case len(hp.ObjectKind) == 0:
|
|
||||||
// Assume this is a post-receive within repository
|
|
||||||
if len(hp.After) == 0 {
|
|
||||||
return nil, fmt.Errorf("Invalid hook received, commit hash not found.")
|
|
||||||
}
|
|
||||||
case hp.ObjectKind == "push":
|
|
||||||
if hp.Repository == nil {
|
|
||||||
return nil, fmt.Errorf("Invalid push hook received, attributes not found")
|
|
||||||
}
|
|
||||||
case hp.ObjectKind == "tag_push":
|
|
||||||
if hp.Repository == nil {
|
|
||||||
return nil, fmt.Errorf("Invalid tag push hook received, attributes not found")
|
|
||||||
}
|
|
||||||
case hp.ObjectKind == "issue":
|
|
||||||
fallthrough
|
|
||||||
case hp.ObjectKind == "merge_request":
|
|
||||||
if hp.ObjectAttributes == nil {
|
|
||||||
return nil, fmt.Errorf("Invalid hook received, attributes not found.")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("Invalid hook received, payload format not recognized.")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &hp, nil
|
|
||||||
}
|
|
|
@ -1,175 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
searchUrl = "/projects/search/:query"
|
|
||||||
projectsUrl = "/projects"
|
|
||||||
projectUrl = "/projects/:id"
|
|
||||||
repoUrlRawFile = "/projects/:id/repository/blobs/:sha"
|
|
||||||
repoUrlRawFileRef = "/projects/:id/repository/files"
|
|
||||||
commitStatusUrl = "/projects/:id/statuses/:sha"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Get a list of all projects owned by the authenticated user.
|
|
||||||
func (g *Client) AllProjects(hide_archives bool) ([]*Project, error) {
|
|
||||||
var per_page = 100
|
|
||||||
var projects []*Project
|
|
||||||
|
|
||||||
for i := 1; true; i++ {
|
|
||||||
contents, err := g.Projects(i, per_page, hide_archives)
|
|
||||||
if err != nil {
|
|
||||||
return projects, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, value := range contents {
|
|
||||||
projects = append(projects, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(projects) == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(projects)/i < per_page {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return projects, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a list of projects owned by the authenticated user.
|
|
||||||
func (c *Client) Projects(page int, per_page int, hide_archives bool) ([]*Project, error) {
|
|
||||||
projectsOptions := QMap{
|
|
||||||
"page": strconv.Itoa(page),
|
|
||||||
"per_page": strconv.Itoa(per_page),
|
|
||||||
}
|
|
||||||
|
|
||||||
if hide_archives {
|
|
||||||
projectsOptions["archived"] = "false"
|
|
||||||
}
|
|
||||||
|
|
||||||
url, opaque := c.ResourceUrl(projectsUrl, nil, projectsOptions)
|
|
||||||
|
|
||||||
var projects []*Project
|
|
||||||
|
|
||||||
contents, err := c.Do("GET", url, opaque, nil)
|
|
||||||
if err == nil {
|
|
||||||
err = json.Unmarshal(contents, &projects)
|
|
||||||
}
|
|
||||||
|
|
||||||
return projects, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a project by id
|
|
||||||
func (c *Client) Project(id string) (*Project, error) {
|
|
||||||
url, opaque := c.ResourceUrl(projectUrl, QMap{":id": id}, nil)
|
|
||||||
|
|
||||||
var project *Project
|
|
||||||
|
|
||||||
contents, err := c.Do("GET", url, opaque, nil)
|
|
||||||
if err == nil {
|
|
||||||
err = json.Unmarshal(contents, &project)
|
|
||||||
}
|
|
||||||
|
|
||||||
return project, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Raw file content
|
|
||||||
func (c *Client) RepoRawFile(id, sha, filepath string) ([]byte, error) {
|
|
||||||
url, opaque := c.ResourceUrl(
|
|
||||||
repoUrlRawFile,
|
|
||||||
QMap{
|
|
||||||
":id": id,
|
|
||||||
":sha": sha,
|
|
||||||
},
|
|
||||||
QMap{
|
|
||||||
"filepath": filepath,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
contents, err := c.Do("GET", url, opaque, nil)
|
|
||||||
|
|
||||||
return contents, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) RepoRawFileRef(id, ref, filepath string) ([]byte, error) {
|
|
||||||
url, opaque := c.ResourceUrl(
|
|
||||||
repoUrlRawFileRef,
|
|
||||||
QMap{
|
|
||||||
":id": id,
|
|
||||||
},
|
|
||||||
QMap{
|
|
||||||
"filepath": filepath,
|
|
||||||
"ref": ref,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
contents, err := c.Do("GET", url, opaque, nil)
|
|
||||||
|
|
||||||
return contents, err
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
func (c *Client) SetStatus(id, sha, state, desc, ref, link string) error {
|
|
||||||
url, opaque := c.ResourceUrl(
|
|
||||||
commitStatusUrl,
|
|
||||||
QMap{
|
|
||||||
":id": id,
|
|
||||||
":sha": sha,
|
|
||||||
},
|
|
||||||
QMap{
|
|
||||||
"state": state,
|
|
||||||
"ref": ref,
|
|
||||||
"target_url": link,
|
|
||||||
"description": desc,
|
|
||||||
"context": "ci/drone",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
_, err := c.Do("POST", url, opaque, nil)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a list of projects by query owned by the authenticated user.
|
|
||||||
func (c *Client) SearchProjectId(namespace string, name string) (id int, err error) {
|
|
||||||
|
|
||||||
url, opaque := c.ResourceUrl(searchUrl, nil, QMap{
|
|
||||||
":query": strings.ToLower(name),
|
|
||||||
})
|
|
||||||
|
|
||||||
var projects []*Project
|
|
||||||
|
|
||||||
contents, err := c.Do("GET", url, opaque, nil)
|
|
||||||
if err == nil {
|
|
||||||
err = json.Unmarshal(contents, &projects)
|
|
||||||
} else {
|
|
||||||
return id, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, project := range projects {
|
|
||||||
if project.Namespace.Name == namespace && strings.ToLower(project.Name) == strings.ToLower(name) {
|
|
||||||
id = project.Id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return id, err
|
|
||||||
}
|
|
|
@ -1,152 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
type QMap map[string]string
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
Id int `json:"id,omitempty"`
|
|
||||||
Username string `json:"username,omitempty"`
|
|
||||||
Email string `json:"email,omitempty"`
|
|
||||||
AvatarUrl string `json:"avatar_url,omitempty"`
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProjectAccess struct {
|
|
||||||
AccessLevel int `json:"access_level,omitempty"`
|
|
||||||
NotificationLevel int `json:"notification_level,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type GroupAccess struct {
|
|
||||||
AccessLevel int `json:"access_level,omitempty"`
|
|
||||||
NotificationLevel int `json:"notification_level,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Permissions struct {
|
|
||||||
ProjectAccess *ProjectAccess `json:"project_access,omitempty"`
|
|
||||||
GroupAccess *GroupAccess `json:"group_access,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Member struct {
|
|
||||||
Id int
|
|
||||||
Username string
|
|
||||||
Email string
|
|
||||||
Name string
|
|
||||||
State string
|
|
||||||
CreatedAt string `json:"created_at,omitempty"`
|
|
||||||
// AccessLevel int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Project struct {
|
|
||||||
Id int `json:"id,omitempty"`
|
|
||||||
Owner *Member `json:"owner,omitempty"`
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
Description string `json:"description,omitempty"`
|
|
||||||
DefaultBranch string `json:"default_branch,omitempty"`
|
|
||||||
Public bool `json:"public,omitempty"`
|
|
||||||
Path string `json:"path,omitempty"`
|
|
||||||
PathWithNamespace string `json:"path_with_namespace,omitempty"`
|
|
||||||
Namespace *Namespace `json:"namespace,omitempty"`
|
|
||||||
SshRepoUrl string `json:"ssh_url_to_repo"`
|
|
||||||
HttpRepoUrl string `json:"http_url_to_repo"`
|
|
||||||
Url string `json:"web_url"`
|
|
||||||
AvatarUrl string `json:"avatar_url"`
|
|
||||||
Permissions *Permissions `json:"permissions,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Namespace struct {
|
|
||||||
Id int `json:"id,omitempty"`
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
Path string `json:"path,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Person struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type hProject struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
SshUrl string `json:"ssh_url"`
|
|
||||||
HttpUrl string `json:"http_url"`
|
|
||||||
GitSshUrl string `json:"git_ssh_url"`
|
|
||||||
GitHttpUrl string `json:"git_http_url"`
|
|
||||||
AvatarUrl string `json:"avatar_url"`
|
|
||||||
VisibilityLevel int `json:"visibility_level"`
|
|
||||||
WebUrl string `json:"web_url"`
|
|
||||||
PathWithNamespace string `json:"path_with_namespace"`
|
|
||||||
DefaultBranch string `json:"default_branch"`
|
|
||||||
Namespace string `json:"namespace"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type hRepository struct {
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
URL string `json:"url,omitempty"`
|
|
||||||
Description string `json:"description,omitempty"`
|
|
||||||
Homepage string `json:"homepage,omitempty"`
|
|
||||||
GitHttpUrl string `json:"git_http_url,omitempty"`
|
|
||||||
GitSshUrl string `json:"git_ssh_url,omitempty"`
|
|
||||||
VisibilityLevel int `json:"visibility_level,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type hCommit struct {
|
|
||||||
Id string `json:"id,omitempty"`
|
|
||||||
Message string `json:"message,omitempty"`
|
|
||||||
Timestamp string `json:"timestamp,omitempty"`
|
|
||||||
URL string `json:"url,omitempty"`
|
|
||||||
Author *Person `json:"author,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type HookObjAttr struct {
|
|
||||||
Id int `json:"id,omitempty"`
|
|
||||||
Title string `json:"title,omitempty"`
|
|
||||||
AssigneeId int `json:"assignee_id,omitempty"`
|
|
||||||
AuthorId int `json:"author_id,omitempty"`
|
|
||||||
ProjectId int `json:"project_id,omitempty"`
|
|
||||||
CreatedAt string `json:"created_at,omitempty"`
|
|
||||||
UpdatedAt string `json:"updated_at,omitempty"`
|
|
||||||
Position int `json:"position,omitempty"`
|
|
||||||
BranchName string `json:"branch_name,omitempty"`
|
|
||||||
Description string `json:"description,omitempty"`
|
|
||||||
MilestoneId int `json:"milestone_id,omitempty"`
|
|
||||||
State string `json:"state,omitempty"`
|
|
||||||
IId int `json:"iid,omitempty"`
|
|
||||||
TargetBranch string `json:"target_branch,omitempty"`
|
|
||||||
SourceBranch string `json:"source_branch,omitempty"`
|
|
||||||
SourceProjectId int `json:"source_project_id,omitempty"`
|
|
||||||
StCommits string `json:"st_commits,omitempty"`
|
|
||||||
StDiffs string `json:"st_diffs,omitempty"`
|
|
||||||
MergeStatus string `json:"merge_status,omitempty"`
|
|
||||||
TargetProjectId int `json:"target_project_id,omitempty"`
|
|
||||||
Url string `json:"url,omiyempty"`
|
|
||||||
Source *hProject `json:"source,omitempty"`
|
|
||||||
Target *hProject `json:"target,omitempty"`
|
|
||||||
LastCommit *hCommit `json:"last_commit,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type HookPayload struct {
|
|
||||||
Before string `json:"before,omitempty"`
|
|
||||||
After string `json:"after,omitempty"`
|
|
||||||
Ref string `json:"ref,omitempty"`
|
|
||||||
UserId int `json:"user_id,omitempty"`
|
|
||||||
UserName string `json:"user_name,omitempty"`
|
|
||||||
ProjectId int `json:"project_id,omitempty"`
|
|
||||||
Project *hProject `json:"project,omitempty"`
|
|
||||||
Repository *hRepository `json:"repository,omitempty"`
|
|
||||||
Commits []hCommit `json:"commits,omitempty"`
|
|
||||||
TotalCommitsCount int `json:"total_commits_count,omitempty"`
|
|
||||||
ObjectKind string `json:"object_kind,omitempty"`
|
|
||||||
ObjectAttributes *HookObjAttr `json:"object_attributes,omitempty"`
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
currentUserUrl = "/user"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Client) CurrentUser() (User, error) {
|
|
||||||
url, opaque := c.ResourceUrl(currentUserUrl, nil, nil)
|
|
||||||
var user User
|
|
||||||
|
|
||||||
contents, err := c.Do("GET", url, opaque, nil)
|
|
||||||
if err == nil {
|
|
||||||
err = json.Unmarshal(contents, &user)
|
|
||||||
}
|
|
||||||
|
|
||||||
return user, err
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var encodeMap = map[string]string{
|
|
||||||
".": "%252E",
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeParameter(value string) string {
|
|
||||||
value = url.QueryEscape(value)
|
|
||||||
|
|
||||||
for before, after := range encodeMap {
|
|
||||||
value = strings.Replace(value, before, after, -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tag returns current tag for push event hook payload
|
|
||||||
// This function returns empty string for any other events
|
|
||||||
func (h *HookPayload) Tag() string {
|
|
||||||
return strings.TrimPrefix(h.Ref, "refs/tags/")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Branch returns current branch for push event hook payload
|
|
||||||
// This function returns empty string for any other events
|
|
||||||
func (h *HookPayload) Branch() string {
|
|
||||||
return strings.TrimPrefix(h.Ref, "refs/heads/")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Head returns the latest changeset for push event hook payload
|
|
||||||
func (h *HookPayload) Head() hCommit {
|
|
||||||
c := hCommit{}
|
|
||||||
for _, cm := range h.Commits {
|
|
||||||
if h.After == cm.Id {
|
|
||||||
return cm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
|
|
@ -1,703 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package gitlab3
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server"
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server/model"
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server/remote"
|
|
||||||
"github.com/woodpecker-ci/woodpecker/shared/oauth2"
|
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server/remote/gitlab3/client"
|
|
||||||
)
|
|
||||||
|
|
||||||
const DefaultScope = "api"
|
|
||||||
|
|
||||||
// Opts defines configuration options.
|
|
||||||
type Opts struct {
|
|
||||||
URL string // Gogs server url.
|
|
||||||
Client string // Oauth2 client id.
|
|
||||||
Secret string // Oauth2 client secret.
|
|
||||||
Username string // Optional machine account username.
|
|
||||||
Password string // Optional machine account password.
|
|
||||||
PrivateMode bool // Gogs is running in private mode.
|
|
||||||
SkipVerify bool // Skip ssl verification.
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns a Remote implementation that integrates with Gitlab, an open
|
|
||||||
// source Git service. See https://gitlab.com
|
|
||||||
func New(opts Opts) (remote.Remote, error) {
|
|
||||||
u, err := url.Parse(opts.URL)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
host, _, err := net.SplitHostPort(u.Host)
|
|
||||||
if err == nil {
|
|
||||||
u.Host = host
|
|
||||||
}
|
|
||||||
return &Gitlab{
|
|
||||||
URL: opts.URL,
|
|
||||||
Client: opts.Client,
|
|
||||||
Secret: opts.Secret,
|
|
||||||
Machine: u.Host,
|
|
||||||
Username: opts.Username,
|
|
||||||
Password: opts.Password,
|
|
||||||
PrivateMode: opts.PrivateMode,
|
|
||||||
SkipVerify: opts.SkipVerify,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Gitlab struct {
|
|
||||||
URL string
|
|
||||||
Client string
|
|
||||||
Secret string
|
|
||||||
Machine string
|
|
||||||
Username string
|
|
||||||
Password string
|
|
||||||
PrivateMode bool
|
|
||||||
SkipVerify bool
|
|
||||||
HideArchives bool
|
|
||||||
Search bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func Load(config string) *Gitlab {
|
|
||||||
url_, err := url.Parse(config)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
params := url_.Query()
|
|
||||||
url_.RawQuery = ""
|
|
||||||
|
|
||||||
gitlab := Gitlab{}
|
|
||||||
gitlab.URL = url_.String()
|
|
||||||
gitlab.Client = params.Get("client_id")
|
|
||||||
gitlab.Secret = params.Get("client_secret")
|
|
||||||
// gitlab.AllowedOrgs = params["orgs"]
|
|
||||||
gitlab.SkipVerify, _ = strconv.ParseBool(params.Get("skip_verify"))
|
|
||||||
gitlab.HideArchives, _ = strconv.ParseBool(params.Get("hide_archives"))
|
|
||||||
// gitlab.Open, _ = strconv.ParseBool(params.Get("open"))
|
|
||||||
|
|
||||||
// switch params.Get("clone_mode") {
|
|
||||||
// case "oauth":
|
|
||||||
// gitlab.CloneMode = "oauth"
|
|
||||||
// default:
|
|
||||||
// gitlab.CloneMode = "token"
|
|
||||||
// }
|
|
||||||
|
|
||||||
// this is a temp workaround
|
|
||||||
gitlab.Search, _ = strconv.ParseBool(params.Get("search"))
|
|
||||||
|
|
||||||
return &gitlab
|
|
||||||
}
|
|
||||||
|
|
||||||
// Login authenticates the session and returns the
|
|
||||||
// remote user details.
|
|
||||||
func (g *Gitlab) Login(ctx context.Context, res http.ResponseWriter, req *http.Request) (*model.User, error) {
|
|
||||||
|
|
||||||
var config = &oauth2.Config{
|
|
||||||
ClientId: g.Client,
|
|
||||||
ClientSecret: g.Secret,
|
|
||||||
Scope: DefaultScope,
|
|
||||||
AuthURL: fmt.Sprintf("%s/oauth/authorize", g.URL),
|
|
||||||
TokenURL: fmt.Sprintf("%s/oauth/token", g.URL),
|
|
||||||
RedirectURL: fmt.Sprintf("%s/authorize", server.Config.Server.Host),
|
|
||||||
}
|
|
||||||
|
|
||||||
trans_ := &http.Transport{
|
|
||||||
Proxy: http.ProxyFromEnvironment,
|
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: g.SkipVerify},
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the OAuth errors
|
|
||||||
if err := req.FormValue("error"); err != "" {
|
|
||||||
return nil, &remote.AuthError{
|
|
||||||
Err: err,
|
|
||||||
Description: req.FormValue("error_description"),
|
|
||||||
URI: req.FormValue("error_uri"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the OAuth code
|
|
||||||
var code = req.FormValue("code")
|
|
||||||
if len(code) == 0 {
|
|
||||||
http.Redirect(res, req, config.AuthCodeURL("drone"), http.StatusSeeOther)
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var trans = &oauth2.Transport{Config: config, Transport: trans_}
|
|
||||||
var token_, err = trans.Exchange(code)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error exchanging token. %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
client := NewClient(g.URL, token_.AccessToken, g.SkipVerify)
|
|
||||||
login, err := client.CurrentUser()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// if len(g.AllowedOrgs) != 0 {
|
|
||||||
// groups, err := client.AllGroups()
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, fmt.Errorf("Could not check org membership. %s", err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// var member bool
|
|
||||||
// for _, group := range groups {
|
|
||||||
// for _, allowedOrg := range g.AllowedOrgs {
|
|
||||||
// if group.Path == allowedOrg {
|
|
||||||
// member = true
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if !member {
|
|
||||||
// return nil, false, fmt.Errorf("User does not belong to correct group. Must belong to %v", g.AllowedOrgs)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
user := &model.User{}
|
|
||||||
user.Login = login.Username
|
|
||||||
user.Email = login.Email
|
|
||||||
user.Token = token_.AccessToken
|
|
||||||
user.Secret = token_.RefreshToken
|
|
||||||
|
|
||||||
if strings.HasPrefix(login.AvatarUrl, "http") {
|
|
||||||
user.Avatar = login.AvatarUrl
|
|
||||||
} else {
|
|
||||||
user.Avatar = g.URL + "/" + login.AvatarUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
return user, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Gitlab) Auth(ctx context.Context, token, secret string) (string, error) {
|
|
||||||
client := NewClient(g.URL, token, g.SkipVerify)
|
|
||||||
login, err := client.CurrentUser()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return login.Username, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Gitlab) Teams(ctx context.Context, u *model.User) ([]*model.Team, error) {
|
|
||||||
client := NewClient(g.URL, u.Token, g.SkipVerify)
|
|
||||||
groups, err := client.AllGroups()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var teams []*model.Team
|
|
||||||
for _, group := range groups {
|
|
||||||
teams = append(teams, &model.Team{
|
|
||||||
Login: group.Name,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return teams, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Repo fetches the named repository from the remote system.
|
|
||||||
func (g *Gitlab) Repo(ctx context.Context, u *model.User, owner, name string) (*model.Repo, error) {
|
|
||||||
client := NewClient(g.URL, u.Token, g.SkipVerify)
|
|
||||||
id, err := GetProjectId(g, client, owner, name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
repo_, err := client.Project(id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
repo := &model.Repo{}
|
|
||||||
repo.Owner = owner
|
|
||||||
repo.Name = name
|
|
||||||
repo.FullName = repo_.PathWithNamespace
|
|
||||||
repo.Link = repo_.Url
|
|
||||||
repo.Clone = repo_.HttpRepoUrl
|
|
||||||
repo.Branch = "master"
|
|
||||||
|
|
||||||
repo.Avatar = repo_.AvatarUrl
|
|
||||||
|
|
||||||
if len(repo.Avatar) != 0 && !strings.HasPrefix(repo.Avatar, "http") {
|
|
||||||
repo.Avatar = fmt.Sprintf("%s/%s", g.URL, repo.Avatar)
|
|
||||||
}
|
|
||||||
|
|
||||||
if repo_.DefaultBranch != "" {
|
|
||||||
repo.Branch = repo_.DefaultBranch
|
|
||||||
}
|
|
||||||
|
|
||||||
if g.PrivateMode {
|
|
||||||
repo.IsPrivate = true
|
|
||||||
} else {
|
|
||||||
repo.IsPrivate = !repo_.Public
|
|
||||||
}
|
|
||||||
|
|
||||||
return repo, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Repos fetches a list of repos from the remote system.
|
|
||||||
func (g *Gitlab) Repos(ctx context.Context, u *model.User) ([]*model.Repo, error) {
|
|
||||||
client := NewClient(g.URL, u.Token, g.SkipVerify)
|
|
||||||
|
|
||||||
var repos = []*model.Repo{}
|
|
||||||
|
|
||||||
all, err := client.AllProjects(g.HideArchives)
|
|
||||||
if err != nil {
|
|
||||||
return repos, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, repo_ := range all {
|
|
||||||
var parts = strings.Split(repo_.PathWithNamespace, "/")
|
|
||||||
var owner = parts[0]
|
|
||||||
var name = parts[1]
|
|
||||||
|
|
||||||
repo := &model.Repo{}
|
|
||||||
repo.Owner = owner
|
|
||||||
repo.Name = name
|
|
||||||
repo.FullName = repo_.PathWithNamespace
|
|
||||||
repo.Link = repo_.Url
|
|
||||||
repo.Clone = repo_.HttpRepoUrl
|
|
||||||
repo.Branch = "master"
|
|
||||||
|
|
||||||
if repo_.DefaultBranch != "" {
|
|
||||||
repo.Branch = repo_.DefaultBranch
|
|
||||||
}
|
|
||||||
|
|
||||||
if g.PrivateMode {
|
|
||||||
repo.IsPrivate = true
|
|
||||||
} else {
|
|
||||||
repo.IsPrivate = !repo_.Public
|
|
||||||
}
|
|
||||||
|
|
||||||
repos = append(repos, repo)
|
|
||||||
}
|
|
||||||
|
|
||||||
return repos, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perm fetches the named repository from the remote system.
|
|
||||||
func (g *Gitlab) Perm(ctx context.Context, u *model.User, owner, name string) (*model.Perm, error) {
|
|
||||||
|
|
||||||
client := NewClient(g.URL, u.Token, g.SkipVerify)
|
|
||||||
id, err := GetProjectId(g, client, owner, name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
repo, err := client.Project(id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// repo owner is granted full access
|
|
||||||
if repo.Owner != nil && repo.Owner.Username == u.Login {
|
|
||||||
return &model.Perm{Push: true, Pull: true, Admin: true}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// check permission for current user
|
|
||||||
m := &model.Perm{}
|
|
||||||
m.Admin = IsAdmin(repo)
|
|
||||||
m.Pull = IsRead(repo)
|
|
||||||
m.Push = IsWrite(repo)
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// File fetches a file from the remote repository and returns in string format.
|
|
||||||
func (g *Gitlab) File(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, f string) ([]byte, error) {
|
|
||||||
var client = NewClient(g.URL, user.Token, g.SkipVerify)
|
|
||||||
id, err := GetProjectId(g, client, repo.Owner, repo.Name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
out, err := client.RepoRawFile(id, build.Commit, f)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Gitlab) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]*remote.FileMeta, error) {
|
|
||||||
return nil, fmt.Errorf("Not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE Currently gitlab doesn't support status for commits and events,
|
|
||||||
// also if we want get MR status in gitlab we need implement a special plugin for gitlab,
|
|
||||||
// gitlab uses API to fetch build status on client side. But for now we skip this.
|
|
||||||
func (g *Gitlab) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error {
|
|
||||||
client := NewClient(g.URL, u.Token, g.SkipVerify)
|
|
||||||
|
|
||||||
status := getStatus(b.Status)
|
|
||||||
desc := getDesc(b.Status)
|
|
||||||
|
|
||||||
client.SetStatus(
|
|
||||||
ns(r.Owner, r.Name),
|
|
||||||
b.Commit,
|
|
||||||
status,
|
|
||||||
desc,
|
|
||||||
strings.Replace(b.Ref, "refs/heads/", "", -1),
|
|
||||||
link,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Gitlab statuses it's a new feature, just ignore error
|
|
||||||
// if gitlab version not support this
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Netrc returns a .netrc file that can be used to clone
|
|
||||||
// private repositories from a remote system.
|
|
||||||
// func (g *Gitlab) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) {
|
|
||||||
// url_, err := url.Parse(g.URL)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
// netrc := &model.Netrc{}
|
|
||||||
// netrc.Machine = url_.Host
|
|
||||||
//
|
|
||||||
// switch g.CloneMode {
|
|
||||||
// case "oauth":
|
|
||||||
// netrc.Login = "oauth2"
|
|
||||||
// netrc.Password = u.Token
|
|
||||||
// case "token":
|
|
||||||
// t := token.New(token.HookToken, r.FullName)
|
|
||||||
// netrc.Login = "drone-ci-token"
|
|
||||||
// netrc.Password, err = t.Sign(r.Hash)
|
|
||||||
// }
|
|
||||||
// return netrc, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Netrc returns a netrc file capable of authenticating Gitlab requests and
|
|
||||||
// cloning Gitlab repositories. The netrc will use the global machine account
|
|
||||||
// when configured.
|
|
||||||
func (g *Gitlab) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) {
|
|
||||||
if g.Password != "" {
|
|
||||||
return &model.Netrc{
|
|
||||||
Login: g.Username,
|
|
||||||
Password: g.Password,
|
|
||||||
Machine: g.Machine,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
return &model.Netrc{
|
|
||||||
Login: "oauth2",
|
|
||||||
Password: u.Token,
|
|
||||||
Machine: g.Machine,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Activate activates a repository by adding a Post-commit hook and
|
|
||||||
// a Public Deploy key, if applicable.
|
|
||||||
func (g *Gitlab) Activate(ctx context.Context, u *model.User, r *model.Repo, link string) error {
|
|
||||||
var client = NewClient(g.URL, u.Token, g.SkipVerify)
|
|
||||||
id, err := GetProjectId(g, client, r.Owner, r.Name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
uri, err := url.Parse(link)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
droneUrl := fmt.Sprintf("%s://%s", uri.Scheme, uri.Host)
|
|
||||||
droneToken := uri.Query().Get("access_token")
|
|
||||||
ssl_verify := strconv.FormatBool(!g.SkipVerify)
|
|
||||||
|
|
||||||
return client.AddDroneService(id, map[string]string{
|
|
||||||
"token": droneToken,
|
|
||||||
"drone_url": droneUrl,
|
|
||||||
"enable_ssl_verification": ssl_verify,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deactivate removes a repository by removing all the post-commit hooks
|
|
||||||
// which are equal to link and removing the SSH deploy key.
|
|
||||||
func (g *Gitlab) Deactivate(ctx context.Context, u *model.User, r *model.Repo, link string) error {
|
|
||||||
var client = NewClient(g.URL, u.Token, g.SkipVerify)
|
|
||||||
id, err := GetProjectId(g, client, r.Owner, r.Name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return client.DeleteDroneService(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseHook parses the post-commit hook from the Request body
|
|
||||||
// and returns the required data in a standard format.
|
|
||||||
func (g *Gitlab) Hook(req *http.Request) (*model.Repo, *model.Build, error) {
|
|
||||||
defer req.Body.Close()
|
|
||||||
var payload, _ = ioutil.ReadAll(req.Body)
|
|
||||||
var parsed, err = client.ParseHook(payload)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch parsed.ObjectKind {
|
|
||||||
case "merge_request":
|
|
||||||
return mergeRequest(parsed, req)
|
|
||||||
case "tag_push", "push":
|
|
||||||
return push(parsed, req)
|
|
||||||
default:
|
|
||||||
return nil, nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mergeRequest(parsed *client.HookPayload, req *http.Request) (*model.Repo, *model.Build, error) {
|
|
||||||
|
|
||||||
repo := &model.Repo{}
|
|
||||||
|
|
||||||
obj := parsed.ObjectAttributes
|
|
||||||
if obj == nil {
|
|
||||||
return nil, nil, fmt.Errorf("object_attributes key expected in merge request hook")
|
|
||||||
}
|
|
||||||
|
|
||||||
target := obj.Target
|
|
||||||
source := obj.Source
|
|
||||||
|
|
||||||
if target == nil && source == nil {
|
|
||||||
return nil, nil, fmt.Errorf("target and source keys expected in merge request hook")
|
|
||||||
} else if target == nil {
|
|
||||||
return nil, nil, fmt.Errorf("target key expected in merge request hook")
|
|
||||||
} else if source == nil {
|
|
||||||
return nil, nil, fmt.Errorf("source key exptected in merge request hook")
|
|
||||||
}
|
|
||||||
|
|
||||||
if target.PathWithNamespace != "" {
|
|
||||||
var err error
|
|
||||||
if repo.Owner, repo.Name, err = ExtractFromPath(target.PathWithNamespace); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
repo.FullName = target.PathWithNamespace
|
|
||||||
} else {
|
|
||||||
repo.Owner = req.FormValue("owner")
|
|
||||||
repo.Name = req.FormValue("name")
|
|
||||||
repo.FullName = fmt.Sprintf("%s/%s", repo.Owner, repo.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
repo.Link = target.WebUrl
|
|
||||||
|
|
||||||
if target.GitHttpUrl != "" {
|
|
||||||
repo.Clone = target.GitHttpUrl
|
|
||||||
} else {
|
|
||||||
repo.Clone = target.HttpUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
if target.DefaultBranch != "" {
|
|
||||||
repo.Branch = target.DefaultBranch
|
|
||||||
} else {
|
|
||||||
repo.Branch = "master"
|
|
||||||
}
|
|
||||||
|
|
||||||
if target.AvatarUrl != "" {
|
|
||||||
repo.Avatar = target.AvatarUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
build := &model.Build{}
|
|
||||||
build.Event = "pull_request"
|
|
||||||
|
|
||||||
lastCommit := obj.LastCommit
|
|
||||||
if lastCommit == nil {
|
|
||||||
return nil, nil, fmt.Errorf("last_commit key expected in merge request hook")
|
|
||||||
}
|
|
||||||
|
|
||||||
build.Message = lastCommit.Message
|
|
||||||
build.Commit = lastCommit.Id
|
|
||||||
//build.Remote = parsed.ObjectAttributes.Source.HttpUrl
|
|
||||||
|
|
||||||
build.Ref = fmt.Sprintf("refs/merge-requests/%d/head", obj.IId)
|
|
||||||
|
|
||||||
build.Branch = obj.SourceBranch
|
|
||||||
|
|
||||||
author := lastCommit.Author
|
|
||||||
if author == nil {
|
|
||||||
return nil, nil, fmt.Errorf("author key expected in merge request hook")
|
|
||||||
}
|
|
||||||
|
|
||||||
build.Author = author.Name
|
|
||||||
build.Email = author.Email
|
|
||||||
|
|
||||||
if len(build.Email) != 0 {
|
|
||||||
build.Avatar = GetUserAvatar(build.Email)
|
|
||||||
}
|
|
||||||
|
|
||||||
build.Title = obj.Title
|
|
||||||
build.Link = obj.Url
|
|
||||||
|
|
||||||
return repo, build, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func push(parsed *client.HookPayload, req *http.Request) (*model.Repo, *model.Build, error) {
|
|
||||||
repo := &model.Repo{}
|
|
||||||
|
|
||||||
// Since gitlab 8.5, used project instead repository key
|
|
||||||
// see https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/web_hooks/web_hooks.md#web-hooks
|
|
||||||
if project := parsed.Project; project != nil {
|
|
||||||
var err error
|
|
||||||
if repo.Owner, repo.Name, err = ExtractFromPath(project.PathWithNamespace); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
repo.Avatar = project.AvatarUrl
|
|
||||||
repo.Link = project.WebUrl
|
|
||||||
repo.Clone = project.GitHttpUrl
|
|
||||||
repo.FullName = project.PathWithNamespace
|
|
||||||
repo.Branch = project.DefaultBranch
|
|
||||||
|
|
||||||
switch project.VisibilityLevel {
|
|
||||||
case 0:
|
|
||||||
repo.IsPrivate = true
|
|
||||||
case 10:
|
|
||||||
repo.IsPrivate = true
|
|
||||||
case 20:
|
|
||||||
repo.IsPrivate = false
|
|
||||||
}
|
|
||||||
} else if repository := parsed.Repository; repository != nil {
|
|
||||||
repo.Owner = req.FormValue("owner")
|
|
||||||
repo.Name = req.FormValue("name")
|
|
||||||
repo.Link = repository.URL
|
|
||||||
repo.Clone = repository.GitHttpUrl
|
|
||||||
repo.Branch = "master"
|
|
||||||
repo.FullName = fmt.Sprintf("%s/%s", req.FormValue("owner"), req.FormValue("name"))
|
|
||||||
|
|
||||||
switch repository.VisibilityLevel {
|
|
||||||
case 0:
|
|
||||||
repo.IsPrivate = true
|
|
||||||
case 10:
|
|
||||||
repo.IsPrivate = true
|
|
||||||
case 20:
|
|
||||||
repo.IsPrivate = false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nil, nil, fmt.Errorf("No project/repository keys given")
|
|
||||||
}
|
|
||||||
|
|
||||||
build := &model.Build{}
|
|
||||||
build.Event = model.EventPush
|
|
||||||
build.Commit = parsed.After
|
|
||||||
build.Branch = parsed.Branch()
|
|
||||||
build.Ref = parsed.Ref
|
|
||||||
// hook.Commit.Remote = cloneUrl
|
|
||||||
|
|
||||||
var head = parsed.Head()
|
|
||||||
build.Message = head.Message
|
|
||||||
// build.Timestamp = head.Timestamp
|
|
||||||
|
|
||||||
// extracts the commit author (ideally email)
|
|
||||||
// from the post-commit hook
|
|
||||||
switch {
|
|
||||||
case head.Author != nil:
|
|
||||||
build.Email = head.Author.Email
|
|
||||||
build.Author = parsed.UserName
|
|
||||||
if len(build.Email) != 0 {
|
|
||||||
build.Avatar = GetUserAvatar(build.Email)
|
|
||||||
}
|
|
||||||
case head.Author == nil:
|
|
||||||
build.Author = parsed.UserName
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(build.Ref, "refs/tags/") {
|
|
||||||
build.Event = model.EventTag
|
|
||||||
}
|
|
||||||
|
|
||||||
return repo, build, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ¯\_(ツ)_/¯
|
|
||||||
func (g *Gitlab) Oauth2Transport(r *http.Request) *oauth2.Transport {
|
|
||||||
return &oauth2.Transport{
|
|
||||||
Config: &oauth2.Config{
|
|
||||||
ClientId: g.Client,
|
|
||||||
ClientSecret: g.Secret,
|
|
||||||
Scope: DefaultScope,
|
|
||||||
AuthURL: fmt.Sprintf("%s/oauth/authorize", g.URL),
|
|
||||||
TokenURL: fmt.Sprintf("%s/oauth/token", g.URL),
|
|
||||||
RedirectURL: fmt.Sprintf("%s/authorize", server.Config.Server.Host),
|
|
||||||
//settings.Server.Scheme, settings.Server.Hostname),
|
|
||||||
},
|
|
||||||
Transport: &http.Transport{
|
|
||||||
Proxy: http.ProxyFromEnvironment,
|
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: g.SkipVerify},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
StatusPending = "pending"
|
|
||||||
StatusRunning = "running"
|
|
||||||
StatusSuccess = "success"
|
|
||||||
StatusFailure = "failed"
|
|
||||||
StatusCanceled = "canceled"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
DescPending = "the build is pending"
|
|
||||||
DescRunning = "the buils is running"
|
|
||||||
DescSuccess = "the build was successful"
|
|
||||||
DescFailure = "the build failed"
|
|
||||||
DescCanceled = "the build canceled"
|
|
||||||
DescBlocked = "the build is pending approval"
|
|
||||||
DescDeclined = "the build was rejected"
|
|
||||||
)
|
|
||||||
|
|
||||||
// getStatus is a helper functin that converts a Drone
|
|
||||||
// status to a GitHub status.
|
|
||||||
func getStatus(status string) string {
|
|
||||||
switch status {
|
|
||||||
case model.StatusPending, model.StatusBlocked:
|
|
||||||
return StatusPending
|
|
||||||
case model.StatusRunning:
|
|
||||||
return StatusRunning
|
|
||||||
case model.StatusSuccess:
|
|
||||||
return StatusSuccess
|
|
||||||
case model.StatusFailure, model.StatusError:
|
|
||||||
return StatusFailure
|
|
||||||
case model.StatusKilled:
|
|
||||||
return StatusCanceled
|
|
||||||
default:
|
|
||||||
return StatusFailure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getDesc is a helper function that generates a description
|
|
||||||
// message for the build based on the status.
|
|
||||||
func getDesc(status string) string {
|
|
||||||
switch status {
|
|
||||||
case model.StatusPending:
|
|
||||||
return DescPending
|
|
||||||
case model.StatusRunning:
|
|
||||||
return DescRunning
|
|
||||||
case model.StatusSuccess:
|
|
||||||
return DescSuccess
|
|
||||||
case model.StatusFailure, model.StatusError:
|
|
||||||
return DescFailure
|
|
||||||
case model.StatusKilled:
|
|
||||||
return DescCanceled
|
|
||||||
case model.StatusBlocked:
|
|
||||||
return DescBlocked
|
|
||||||
case model.StatusDeclined:
|
|
||||||
return DescDeclined
|
|
||||||
default:
|
|
||||||
return DescFailure
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,261 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package gitlab3
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/franela/goblin"
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server/model"
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server/remote/gitlab3/testdata"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_Gitlab(t *testing.T) {
|
|
||||||
// setup a dummy github server
|
|
||||||
var server = testdata.NewServer()
|
|
||||||
defer server.Close()
|
|
||||||
|
|
||||||
env := server.URL + "?client_id=test&client_secret=test"
|
|
||||||
|
|
||||||
gitlab := Load(env)
|
|
||||||
|
|
||||||
var user = model.User{
|
|
||||||
Login: "test_user",
|
|
||||||
Token: "e3b0c44298fc1c149afbf4c8996fb",
|
|
||||||
}
|
|
||||||
|
|
||||||
var repo = model.Repo{
|
|
||||||
Name: "diaspora-client",
|
|
||||||
Owner: "diaspora",
|
|
||||||
}
|
|
||||||
|
|
||||||
g := goblin.Goblin(t)
|
|
||||||
g.Describe("Gitlab Plugin", func() {
|
|
||||||
// Test projects method
|
|
||||||
g.Describe("AllProjects", func() {
|
|
||||||
g.It("Should return only non-archived projects is hidden", func() {
|
|
||||||
gitlab.HideArchives = true
|
|
||||||
_projects, err := gitlab.Repos(nil, &user)
|
|
||||||
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(len(_projects)).Equal(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should return all the projects", func() {
|
|
||||||
gitlab.HideArchives = false
|
|
||||||
_projects, err := gitlab.Repos(nil, &user)
|
|
||||||
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(len(_projects)).Equal(2)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// Test repository method
|
|
||||||
g.Describe("Repo", func() {
|
|
||||||
g.It("Should return valid repo", func() {
|
|
||||||
_repo, err := gitlab.Repo(nil, &user, "diaspora", "diaspora-client")
|
|
||||||
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(_repo.Name).Equal("diaspora-client")
|
|
||||||
g.Assert(_repo.Owner).Equal("diaspora")
|
|
||||||
g.Assert(_repo.IsPrivate).Equal(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should return error, when repo not exist", func() {
|
|
||||||
_, err := gitlab.Repo(nil, &user, "not-existed", "not-existed")
|
|
||||||
|
|
||||||
g.Assert(err != nil).IsTrue()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// Test permissions method
|
|
||||||
g.Describe("Perm", func() {
|
|
||||||
g.It("Should return repo permissions", func() {
|
|
||||||
perm, err := gitlab.Perm(nil, &user, "diaspora", "diaspora-client")
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(perm.Admin).Equal(true)
|
|
||||||
g.Assert(perm.Pull).Equal(true)
|
|
||||||
g.Assert(perm.Push).Equal(true)
|
|
||||||
})
|
|
||||||
g.It("Should return repo permissions when user is admin", func() {
|
|
||||||
perm, err := gitlab.Perm(nil, &user, "brightbox", "puppet")
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(perm.Admin).Equal(true)
|
|
||||||
g.Assert(perm.Pull).Equal(true)
|
|
||||||
g.Assert(perm.Push).Equal(true)
|
|
||||||
})
|
|
||||||
g.It("Should return error, when repo is not exist", func() {
|
|
||||||
_, err := gitlab.Perm(nil, &user, "not-existed", "not-existed")
|
|
||||||
|
|
||||||
g.Assert(err != nil).IsTrue()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// Test activate method
|
|
||||||
g.Describe("Activate", func() {
|
|
||||||
g.It("Should be success", func() {
|
|
||||||
err := gitlab.Activate(nil, &user, &repo, "http://example.com/api/hook/test/test?access_token=token")
|
|
||||||
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should be failed, when token not given", func() {
|
|
||||||
err := gitlab.Activate(nil, &user, &repo, "http://example.com/api/hook/test/test")
|
|
||||||
|
|
||||||
g.Assert(err != nil).IsTrue()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// Test deactivate method
|
|
||||||
g.Describe("Deactivate", func() {
|
|
||||||
g.It("Should be success", func() {
|
|
||||||
err := gitlab.Deactivate(nil, &user, &repo, "http://example.com/api/hook/test/test?access_token=token")
|
|
||||||
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// Test login method
|
|
||||||
// g.Describe("Login", func() {
|
|
||||||
// g.It("Should return user", func() {
|
|
||||||
// user, err := gitlab.Login("valid_token", "")
|
|
||||||
|
|
||||||
// g.Assert(err == nil).IsTrue()
|
|
||||||
// g.Assert(user == nil).IsFalse()
|
|
||||||
// })
|
|
||||||
|
|
||||||
// g.It("Should return error, when token is invalid", func() {
|
|
||||||
// _, err := gitlab.Login("invalid_token", "")
|
|
||||||
|
|
||||||
// g.Assert(err != nil).IsTrue()
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
|
|
||||||
// Test hook method
|
|
||||||
g.Describe("Hook", func() {
|
|
||||||
g.Describe("Push hook", func() {
|
|
||||||
g.It("Should parse actual push hoook", func() {
|
|
||||||
req, _ := http.NewRequest(
|
|
||||||
"POST",
|
|
||||||
"http://example.com/api/hook?owner=diaspora&name=diaspora-client",
|
|
||||||
bytes.NewReader(testdata.PushHook),
|
|
||||||
)
|
|
||||||
|
|
||||||
repo, build, err := gitlab.Hook(req)
|
|
||||||
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(repo.Owner).Equal("mike")
|
|
||||||
g.Assert(repo.Name).Equal("diaspora")
|
|
||||||
g.Assert(repo.Avatar).Equal("http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg")
|
|
||||||
g.Assert(repo.Branch).Equal("develop")
|
|
||||||
g.Assert(build.Ref).Equal("refs/heads/master")
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should parse legacy push hoook", func() {
|
|
||||||
req, _ := http.NewRequest(
|
|
||||||
"POST",
|
|
||||||
"http://example.com/api/hook?owner=diaspora&name=diaspora-client",
|
|
||||||
bytes.NewReader(testdata.LegacyPushHook),
|
|
||||||
)
|
|
||||||
|
|
||||||
repo, build, err := gitlab.Hook(req)
|
|
||||||
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(repo.Owner).Equal("diaspora")
|
|
||||||
g.Assert(repo.Name).Equal("diaspora-client")
|
|
||||||
g.Assert(repo.Avatar).Equal("")
|
|
||||||
g.Assert(repo.Branch).Equal("master")
|
|
||||||
g.Assert(build.Ref).Equal("refs/heads/master")
|
|
||||||
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
g.Describe("Tag push hook", func() {
|
|
||||||
g.It("Should parse tag push hook", func() {
|
|
||||||
req, _ := http.NewRequest(
|
|
||||||
"POST",
|
|
||||||
"http://example.com/api/hook?owner=diaspora&name=diaspora-client",
|
|
||||||
bytes.NewReader(testdata.TagHook),
|
|
||||||
)
|
|
||||||
|
|
||||||
repo, build, err := gitlab.Hook(req)
|
|
||||||
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(repo.Owner).Equal("jsmith")
|
|
||||||
g.Assert(repo.Name).Equal("example")
|
|
||||||
g.Assert(repo.Avatar).Equal("http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg")
|
|
||||||
g.Assert(repo.Branch).Equal("develop")
|
|
||||||
g.Assert(build.Ref).Equal("refs/tags/v1.0.0")
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should parse legacy tag push hook", func() {
|
|
||||||
req, _ := http.NewRequest(
|
|
||||||
"POST",
|
|
||||||
"http://example.com/api/hook?owner=diaspora&name=diaspora-client",
|
|
||||||
bytes.NewReader(testdata.LegacyTagHook),
|
|
||||||
)
|
|
||||||
|
|
||||||
repo, build, err := gitlab.Hook(req)
|
|
||||||
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(repo.Owner).Equal("diaspora")
|
|
||||||
g.Assert(repo.Name).Equal("diaspora-client")
|
|
||||||
g.Assert(build.Ref).Equal("refs/tags/v1.0.0")
|
|
||||||
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
g.Describe("Merge request hook", func() {
|
|
||||||
g.It("Should parse merge request hook", func() {
|
|
||||||
req, _ := http.NewRequest(
|
|
||||||
"POST",
|
|
||||||
"http://example.com/api/hook?owner=diaspora&name=diaspora-client",
|
|
||||||
bytes.NewReader(testdata.MergeRequestHook),
|
|
||||||
)
|
|
||||||
|
|
||||||
repo, build, err := gitlab.Hook(req)
|
|
||||||
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(repo.Avatar).Equal("http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg")
|
|
||||||
g.Assert(repo.Branch).Equal("develop")
|
|
||||||
g.Assert(repo.Owner).Equal("awesome_space")
|
|
||||||
g.Assert(repo.Name).Equal("awesome_project")
|
|
||||||
|
|
||||||
g.Assert(build.Title).Equal("MS-Viewport")
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should parse legacy merge request hook", func() {
|
|
||||||
req, _ := http.NewRequest(
|
|
||||||
"POST",
|
|
||||||
"http://example.com/api/hook?owner=diaspora&name=diaspora-client",
|
|
||||||
bytes.NewReader(testdata.LegacyMergeRequestHook),
|
|
||||||
)
|
|
||||||
|
|
||||||
repo, build, err := gitlab.Hook(req)
|
|
||||||
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(repo.Owner).Equal("diaspora")
|
|
||||||
g.Assert(repo.Name).Equal("diaspora-client")
|
|
||||||
|
|
||||||
g.Assert(build.Title).Equal("MS-Viewport")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,139 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package gitlab3
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/md5"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server/remote/gitlab3/client"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
gravatarBase = "https://www.gravatar.com/avatar"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewClient is a helper function that returns a new GitHub
|
|
||||||
// client using the provided OAuth token.
|
|
||||||
func NewClient(url, accessToken string, skipVerify bool) *client.Client {
|
|
||||||
client := client.New(url, "/api/v3", accessToken, skipVerify)
|
|
||||||
return client
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsRead is a helper function that returns true if the
|
|
||||||
// user has Read-only access to the repository.
|
|
||||||
func IsRead(proj *client.Project) bool {
|
|
||||||
var user = proj.Permissions.ProjectAccess
|
|
||||||
var group = proj.Permissions.GroupAccess
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case proj.Public:
|
|
||||||
return true
|
|
||||||
case user != nil && user.AccessLevel >= 20:
|
|
||||||
return true
|
|
||||||
case group != nil && group.AccessLevel >= 20:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsWrite is a helper function that returns true if the
|
|
||||||
// user has Read-Write access to the repository.
|
|
||||||
func IsWrite(proj *client.Project) bool {
|
|
||||||
var user = proj.Permissions.ProjectAccess
|
|
||||||
var group = proj.Permissions.GroupAccess
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case user != nil && user.AccessLevel >= 30:
|
|
||||||
return true
|
|
||||||
case group != nil && group.AccessLevel >= 30:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAdmin is a helper function that returns true if the
|
|
||||||
// user has Admin access to the repository.
|
|
||||||
func IsAdmin(proj *client.Project) bool {
|
|
||||||
var user = proj.Permissions.ProjectAccess
|
|
||||||
var group = proj.Permissions.GroupAccess
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case user != nil && user.AccessLevel >= 40:
|
|
||||||
return true
|
|
||||||
case group != nil && group.AccessLevel >= 40:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetKeyTitle is a helper function that generates a title for the
|
|
||||||
// RSA public key based on the username and domain name.
|
|
||||||
func GetKeyTitle(rawurl string) (string, error) {
|
|
||||||
var uri, err = url.Parse(rawurl)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("drone@%s", uri.Host), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ns(owner, name string) string {
|
|
||||||
return fmt.Sprintf("%s%%2F%s", owner, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetUserAvatar(email string) string {
|
|
||||||
hasher := md5.New()
|
|
||||||
hasher.Write([]byte(email))
|
|
||||||
|
|
||||||
return fmt.Sprintf(
|
|
||||||
"%s/%v.jpg?s=%s",
|
|
||||||
gravatarBase,
|
|
||||||
hex.EncodeToString(hasher.Sum(nil)),
|
|
||||||
"128",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExtractFromPath(str string) (string, string, error) {
|
|
||||||
s := strings.Split(str, "/")
|
|
||||||
if len(s) < 2 {
|
|
||||||
return "", "", fmt.Errorf("Minimum match not found")
|
|
||||||
}
|
|
||||||
return s[0], s[1], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetUserEmail(c *client.Client, defaultURL string) (*client.Client, error) {
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetProjectId(r *Gitlab, c *client.Client, owner, name string) (projectId string, err error) {
|
|
||||||
if r.Search {
|
|
||||||
_projectId, err := c.SearchProjectId(owner, name)
|
|
||||||
if err != nil || _projectId == 0 {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
projectId := strconv.Itoa(_projectId)
|
|
||||||
return projectId, nil
|
|
||||||
} else {
|
|
||||||
projectId := ns(owner, name)
|
|
||||||
return projectId, nil
|
|
||||||
}
|
|
||||||
}
|
|
348
server/remote/gitlab3/testdata/hooks.go
vendored
348
server/remote/gitlab3/testdata/hooks.go
vendored
|
@ -1,348 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package testdata
|
|
||||||
|
|
||||||
var TagHook = []byte(`
|
|
||||||
{
|
|
||||||
"object_kind": "tag_push",
|
|
||||||
"ref": "refs/tags/v1.0.0",
|
|
||||||
"before": "0000000000000000000000000000000000000000",
|
|
||||||
"after": "82b3d5ae55f7080f1e6022629cdb57bfae7cccc7",
|
|
||||||
"user_id": 1,
|
|
||||||
"user_name": "John Smith",
|
|
||||||
"user_avatar": "https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s=80",
|
|
||||||
"project_id": 1,
|
|
||||||
"project":{
|
|
||||||
"name":"Example",
|
|
||||||
"description":"",
|
|
||||||
"web_url":"http://example.com/jsmith/example",
|
|
||||||
"avatar_url":"http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg",
|
|
||||||
"git_ssh_url":"git@example.com:jsmith/example.git",
|
|
||||||
"git_http_url":"http://example.com/jsmith/example.git",
|
|
||||||
"namespace":"Jsmith",
|
|
||||||
"visibility_level":0,
|
|
||||||
"path_with_namespace":"jsmith/example",
|
|
||||||
"default_branch":"develop",
|
|
||||||
"homepage":"http://example.com/jsmith/example",
|
|
||||||
"url":"git@example.com:jsmith/example.git",
|
|
||||||
"ssh_url":"git@example.com:jsmith/example.git",
|
|
||||||
"http_url":"http://example.com/jsmith/example.git"
|
|
||||||
},
|
|
||||||
"repository":{
|
|
||||||
"name": "jsmith",
|
|
||||||
"url": "ssh://git@example.com/jsmith/example.git",
|
|
||||||
"description": "",
|
|
||||||
"homepage": "http://example.com/jsmith/example",
|
|
||||||
"git_http_url":"http://example.com/jsmith/example.git",
|
|
||||||
"git_ssh_url":"git@example.com:jsmith/example.git",
|
|
||||||
"visibility_level":0
|
|
||||||
},
|
|
||||||
"commits": [],
|
|
||||||
"total_commits_count": 0
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
||||||
var LegacyTagHook = []byte(`
|
|
||||||
{
|
|
||||||
"object_kind": "tag_push",
|
|
||||||
"ref": "refs/tags/v1.0.0",
|
|
||||||
"before": "0000000000000000000000000000000000000000",
|
|
||||||
"after": "82b3d5ae55f7080f1e6022629cdb57bfae7cccc7",
|
|
||||||
"user_id": 1,
|
|
||||||
"user_name": "John Smith",
|
|
||||||
"project_id": 1,
|
|
||||||
"repository": {
|
|
||||||
"name": "jsmith",
|
|
||||||
"url": "ssh://git@example.com/jsmith/example.git",
|
|
||||||
"description": "",
|
|
||||||
"homepage": "http://example.com/jsmith/example",
|
|
||||||
"git_http_url":"http://example.com/jsmith/example.git",
|
|
||||||
"git_ssh_url":"git@example.com:jsmith/example.git",
|
|
||||||
"visibility_level":0
|
|
||||||
},
|
|
||||||
"commits": [
|
|
||||||
{
|
|
||||||
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
|
||||||
"message": "Update Catalan translation to e38cb41.",
|
|
||||||
"timestamp": "2011-12-12T14:27:31+02:00",
|
|
||||||
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
|
||||||
"author": {
|
|
||||||
"name": "Jordi Mallach",
|
|
||||||
"email": "jordi@softcatala.org"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"message": "fixed readme",
|
|
||||||
"timestamp": "2012-01-03T23:36:29+02:00",
|
|
||||||
"url": "http://example.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"author": {
|
|
||||||
"name": "GitLab dev user",
|
|
||||||
"email": "gitlabdev@dv6700.(none)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"total_commits_count": 4
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
||||||
var MergeRequestHook = []byte(`
|
|
||||||
{
|
|
||||||
"object_kind": "merge_request",
|
|
||||||
"user": {
|
|
||||||
"name": "Administrator",
|
|
||||||
"username": "root",
|
|
||||||
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
|
|
||||||
},
|
|
||||||
"object_attributes": {
|
|
||||||
"id": 99,
|
|
||||||
"target_branch": "master",
|
|
||||||
"source_branch": "ms-viewport",
|
|
||||||
"source_project_id": 14,
|
|
||||||
"author_id": 51,
|
|
||||||
"assignee_id": 6,
|
|
||||||
"title": "MS-Viewport",
|
|
||||||
"created_at": "2013-12-03T17:23:34Z",
|
|
||||||
"updated_at": "2013-12-03T17:23:34Z",
|
|
||||||
"st_commits": null,
|
|
||||||
"st_diffs": null,
|
|
||||||
"milestone_id": null,
|
|
||||||
"state": "opened",
|
|
||||||
"merge_status": "unchecked",
|
|
||||||
"target_project_id": 14,
|
|
||||||
"iid": 1,
|
|
||||||
"description": "",
|
|
||||||
"source":{
|
|
||||||
"name":"Awesome Project",
|
|
||||||
"description":"Aut reprehenderit ut est.",
|
|
||||||
"web_url":"http://example.com/awesome_space/awesome_project",
|
|
||||||
"avatar_url":"http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg",
|
|
||||||
"git_ssh_url":"git@example.com:awesome_space/awesome_project.git",
|
|
||||||
"git_http_url":"http://example.com/awesome_space/awesome_project.git",
|
|
||||||
"namespace":"Awesome Space",
|
|
||||||
"visibility_level":20,
|
|
||||||
"path_with_namespace":"awesome_space/awesome_project",
|
|
||||||
"default_branch":"master",
|
|
||||||
"homepage":"http://example.com/awesome_space/awesome_project",
|
|
||||||
"url":"http://example.com/awesome_space/awesome_project.git",
|
|
||||||
"ssh_url":"git@example.com:awesome_space/awesome_project.git",
|
|
||||||
"http_url":"http://example.com/awesome_space/awesome_project.git"
|
|
||||||
},
|
|
||||||
"target": {
|
|
||||||
"name":"Awesome Project",
|
|
||||||
"description":"Aut reprehenderit ut est.",
|
|
||||||
"web_url":"http://example.com/awesome_space/awesome_project",
|
|
||||||
"avatar_url":"http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg",
|
|
||||||
"git_ssh_url":"git@example.com:awesome_space/awesome_project.git",
|
|
||||||
"git_http_url":"http://example.com/awesome_space/awesome_project.git",
|
|
||||||
"namespace":"Awesome Space",
|
|
||||||
"visibility_level":20,
|
|
||||||
"path_with_namespace":"awesome_space/awesome_project",
|
|
||||||
"default_branch":"develop",
|
|
||||||
"homepage":"http://example.com/awesome_space/awesome_project",
|
|
||||||
"url":"http://example.com/awesome_space/awesome_project.git",
|
|
||||||
"ssh_url":"git@example.com:awesome_space/awesome_project.git",
|
|
||||||
"http_url":"http://example.com/awesome_space/awesome_project.git"
|
|
||||||
},
|
|
||||||
"last_commit": {
|
|
||||||
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"message": "fixed readme",
|
|
||||||
"timestamp": "2012-01-03T23:36:29+02:00",
|
|
||||||
"url": "http://example.com/awesome_space/awesome_project/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"author": {
|
|
||||||
"name": "GitLab dev user",
|
|
||||||
"email": "gitlabdev@dv6700.(none)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"work_in_progress": false,
|
|
||||||
"url": "http://example.com/diaspora/merge_requests/1",
|
|
||||||
"action": "open",
|
|
||||||
"assignee": {
|
|
||||||
"name": "User1",
|
|
||||||
"username": "user1",
|
|
||||||
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
||||||
var LegacyMergeRequestHook = []byte(`
|
|
||||||
{
|
|
||||||
"object_kind": "merge_request",
|
|
||||||
"user": {
|
|
||||||
"name": "Administrator",
|
|
||||||
"username": "root",
|
|
||||||
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
|
|
||||||
},
|
|
||||||
"object_attributes": {
|
|
||||||
"id": 99,
|
|
||||||
"target_branch": "master",
|
|
||||||
"source_branch": "ms-viewport",
|
|
||||||
"source_project_id": 14,
|
|
||||||
"author_id": 51,
|
|
||||||
"assignee_id": 6,
|
|
||||||
"title": "MS-Viewport",
|
|
||||||
"created_at": "2013-12-03T17:23:34Z",
|
|
||||||
"updated_at": "2013-12-03T17:23:34Z",
|
|
||||||
"st_commits": null,
|
|
||||||
"st_diffs": null,
|
|
||||||
"milestone_id": null,
|
|
||||||
"state": "opened",
|
|
||||||
"merge_status": "unchecked",
|
|
||||||
"target_project_id": 14,
|
|
||||||
"iid": 1,
|
|
||||||
"description": "",
|
|
||||||
"source": {
|
|
||||||
"name": "awesome_project",
|
|
||||||
"ssh_url": "ssh://git@example.com/awesome_space/awesome_project.git",
|
|
||||||
"http_url": "http://example.com/awesome_space/awesome_project.git",
|
|
||||||
"visibility_level": 20,
|
|
||||||
"namespace": "awesome_space"
|
|
||||||
},
|
|
||||||
"target": {
|
|
||||||
"name": "awesome_project",
|
|
||||||
"ssh_url": "ssh://git@example.com/awesome_space/awesome_project.git",
|
|
||||||
"http_url": "http://example.com/awesome_space/awesome_project.git",
|
|
||||||
"visibility_level": 20,
|
|
||||||
"namespace": "awesome_space"
|
|
||||||
},
|
|
||||||
"last_commit": {
|
|
||||||
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"message": "fixed readme",
|
|
||||||
"timestamp": "2012-01-03T23:36:29+02:00",
|
|
||||||
"url": "http://example.com/awesome_space/awesome_project/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"author": {
|
|
||||||
"name": "GitLab dev user",
|
|
||||||
"email": "gitlabdev@dv6700.(none)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"url": "http://example.com/diaspora/merge_requests/1",
|
|
||||||
"action": "open"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
||||||
var PushHook = []byte(`
|
|
||||||
{
|
|
||||||
"object_kind": "push",
|
|
||||||
"before": "95790bf891e76fee5e1747ab589903a6a1f80f22",
|
|
||||||
"after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"ref": "refs/heads/master",
|
|
||||||
"user_id": 4,
|
|
||||||
"user_name": "John Smith",
|
|
||||||
"user_email": "john@example.com",
|
|
||||||
"user_avatar": "https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80",
|
|
||||||
"project_id": 15,
|
|
||||||
"project":{
|
|
||||||
"name":"Diaspora",
|
|
||||||
"description":"",
|
|
||||||
"web_url":"http://example.com/mike/diaspora",
|
|
||||||
"avatar_url":"http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg",
|
|
||||||
"git_ssh_url":"git@example.com:mike/diaspora.git",
|
|
||||||
"git_http_url":"http://example.com/mike/diaspora.git",
|
|
||||||
"namespace":"Mike",
|
|
||||||
"visibility_level":0,
|
|
||||||
"path_with_namespace":"mike/diaspora",
|
|
||||||
"default_branch":"develop",
|
|
||||||
"homepage":"http://example.com/mike/diaspora",
|
|
||||||
"url":"git@example.com:mike/diasporadiaspora.git",
|
|
||||||
"ssh_url":"git@example.com:mike/diaspora.git",
|
|
||||||
"http_url":"http://example.com/mike/diaspora.git"
|
|
||||||
},
|
|
||||||
"repository":{
|
|
||||||
"name": "Diaspora",
|
|
||||||
"url": "git@example.com:mike/diasporadiaspora.git",
|
|
||||||
"description": "",
|
|
||||||
"homepage": "http://example.com/mike/diaspora",
|
|
||||||
"git_http_url":"http://example.com/mike/diaspora.git",
|
|
||||||
"git_ssh_url":"git@example.com:mike/diaspora.git",
|
|
||||||
"visibility_level":0
|
|
||||||
},
|
|
||||||
"commits": [
|
|
||||||
{
|
|
||||||
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
|
||||||
"message": "Update Catalan translation to e38cb41.",
|
|
||||||
"timestamp": "2011-12-12T14:27:31+02:00",
|
|
||||||
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
|
||||||
"author": {
|
|
||||||
"name": "Jordi Mallach",
|
|
||||||
"email": "jordi@softcatala.org"
|
|
||||||
},
|
|
||||||
"added": ["CHANGELOG"],
|
|
||||||
"modified": ["app/controller/application.rb"],
|
|
||||||
"removed": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"message": "fixed readme",
|
|
||||||
"timestamp": "2012-01-03T23:36:29+02:00",
|
|
||||||
"url": "http://example.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"author": {
|
|
||||||
"name": "GitLab dev user",
|
|
||||||
"email": "gitlabdev@dv6700.(none)"
|
|
||||||
},
|
|
||||||
"added": ["CHANGELOG"],
|
|
||||||
"modified": ["app/controller/application.rb"],
|
|
||||||
"removed": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"total_commits_count": 4
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
||||||
var LegacyPushHook = []byte(`
|
|
||||||
{
|
|
||||||
"object_kind": "push",
|
|
||||||
"before": "95790bf891e76fee5e1747ab589903a6a1f80f22",
|
|
||||||
"after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"ref": "refs/heads/master",
|
|
||||||
"user_id": 4,
|
|
||||||
"user_name": "John Smith",
|
|
||||||
"user_email": "john@example.com",
|
|
||||||
"project_id": 15,
|
|
||||||
"repository": {
|
|
||||||
"name": "Diaspora",
|
|
||||||
"url": "git@example.com:mike/diasporadiaspora.git",
|
|
||||||
"description": "",
|
|
||||||
"homepage": "http://example.com/mike/diaspora",
|
|
||||||
"git_http_url":"http://example.com/mike/diaspora.git",
|
|
||||||
"git_ssh_url":"git@example.com:mike/diaspora.git",
|
|
||||||
"visibility_level":0
|
|
||||||
},
|
|
||||||
"commits": [
|
|
||||||
{
|
|
||||||
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
|
||||||
"message": "Update Catalan translation to e38cb41.",
|
|
||||||
"timestamp": "2011-12-12T14:27:31+02:00",
|
|
||||||
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
|
||||||
"author": {
|
|
||||||
"name": "Jordi Mallach",
|
|
||||||
"email": "jordi@softcatala.org"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"message": "fixed readme",
|
|
||||||
"timestamp": "2012-01-03T23:36:29+02:00",
|
|
||||||
"url": "http://example.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
|
||||||
"author": {
|
|
||||||
"name": "GitLab dev user",
|
|
||||||
"email": "gitlabdev@dv6700.(none)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"total_commits_count": 4
|
|
||||||
}
|
|
||||||
`)
|
|
17
server/remote/gitlab3/testdata/oauth.go
vendored
17
server/remote/gitlab3/testdata/oauth.go
vendored
|
@ -1,17 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package testdata
|
|
||||||
|
|
||||||
var accessTokenPayload = []byte(`access_token=sekret&scope=api&token_type=bearer`)
|
|
226
server/remote/gitlab3/testdata/projects.go
vendored
226
server/remote/gitlab3/testdata/projects.go
vendored
|
@ -1,226 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package testdata
|
|
||||||
|
|
||||||
// sample repository list
|
|
||||||
var allProjectsPayload = []byte(`
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"id": 4,
|
|
||||||
"description": null,
|
|
||||||
"default_branch": "master",
|
|
||||||
"public": false,
|
|
||||||
"visibility_level": 0,
|
|
||||||
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",
|
|
||||||
"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",
|
|
||||||
"web_url": "http://example.com/diaspora/diaspora-client",
|
|
||||||
"owner": {
|
|
||||||
"id": 3,
|
|
||||||
"name": "Diaspora",
|
|
||||||
"username": "some_user",
|
|
||||||
"created_at": "2013-09-30T13: 46: 02Z"
|
|
||||||
},
|
|
||||||
"name": "Diaspora Client",
|
|
||||||
"name_with_namespace": "Diaspora / Diaspora Client",
|
|
||||||
"path": "diaspora-client",
|
|
||||||
"path_with_namespace": "diaspora/diaspora-client",
|
|
||||||
"issues_enabled": true,
|
|
||||||
"merge_requests_enabled": true,
|
|
||||||
"wiki_enabled": true,
|
|
||||||
"snippets_enabled": false,
|
|
||||||
"created_at": "2013-09-30T13: 46: 02Z",
|
|
||||||
"last_activity_at": "2013-09-30T13: 46: 02Z",
|
|
||||||
"namespace": {
|
|
||||||
"created_at": "2013-09-30T13: 46: 02Z",
|
|
||||||
"description": "",
|
|
||||||
"id": 3,
|
|
||||||
"name": "Diaspora",
|
|
||||||
"owner_id": 1,
|
|
||||||
"path": "diaspora",
|
|
||||||
"updated_at": "2013-09-30T13: 46: 02Z"
|
|
||||||
},
|
|
||||||
"archived": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 6,
|
|
||||||
"description": null,
|
|
||||||
"default_branch": "master",
|
|
||||||
"public": false,
|
|
||||||
"visibility_level": 0,
|
|
||||||
"ssh_url_to_repo": "git@example.com:brightbox/puppet.git",
|
|
||||||
"http_url_to_repo": "http://example.com/brightbox/puppet.git",
|
|
||||||
"web_url": "http://example.com/brightbox/puppet",
|
|
||||||
"owner": {
|
|
||||||
"id": 1,
|
|
||||||
"name": "Brightbox",
|
|
||||||
"username": "test_user",
|
|
||||||
"created_at": "2013-09-30T13:46:02Z"
|
|
||||||
},
|
|
||||||
"name": "Puppet",
|
|
||||||
"name_with_namespace": "Brightbox / Puppet",
|
|
||||||
"path": "puppet",
|
|
||||||
"path_with_namespace": "brightbox/puppet",
|
|
||||||
"issues_enabled": true,
|
|
||||||
"merge_requests_enabled": true,
|
|
||||||
"wiki_enabled": true,
|
|
||||||
"snippets_enabled": false,
|
|
||||||
"created_at": "2013-09-30T13:46:02Z",
|
|
||||||
"last_activity_at": "2013-09-30T13:46:02Z",
|
|
||||||
"namespace": {
|
|
||||||
"created_at": "2013-09-30T13:46:02Z",
|
|
||||||
"description": "",
|
|
||||||
"id": 4,
|
|
||||||
"name": "Brightbox",
|
|
||||||
"owner_id": 1,
|
|
||||||
"path": "brightbox",
|
|
||||||
"updated_at": "2013-09-30T13:46:02Z"
|
|
||||||
},
|
|
||||||
"archived": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
`)
|
|
||||||
|
|
||||||
var notArchivedProjectsPayload = []byte(`
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"id": 4,
|
|
||||||
"description": null,
|
|
||||||
"default_branch": "master",
|
|
||||||
"public": false,
|
|
||||||
"visibility_level": 0,
|
|
||||||
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",
|
|
||||||
"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",
|
|
||||||
"web_url": "http://example.com/diaspora/diaspora-client",
|
|
||||||
"owner": {
|
|
||||||
"id": 3,
|
|
||||||
"name": "Diaspora",
|
|
||||||
"username": "some_user",
|
|
||||||
"created_at": "2013-09-30T13: 46: 02Z"
|
|
||||||
},
|
|
||||||
"name": "Diaspora Client",
|
|
||||||
"name_with_namespace": "Diaspora / Diaspora Client",
|
|
||||||
"path": "diaspora-client",
|
|
||||||
"path_with_namespace": "diaspora/diaspora-client",
|
|
||||||
"issues_enabled": true,
|
|
||||||
"merge_requests_enabled": true,
|
|
||||||
"wiki_enabled": true,
|
|
||||||
"snippets_enabled": false,
|
|
||||||
"created_at": "2013-09-30T13: 46: 02Z",
|
|
||||||
"last_activity_at": "2013-09-30T13: 46: 02Z",
|
|
||||||
"namespace": {
|
|
||||||
"created_at": "2013-09-30T13: 46: 02Z",
|
|
||||||
"description": "",
|
|
||||||
"id": 3,
|
|
||||||
"name": "Diaspora",
|
|
||||||
"owner_id": 1,
|
|
||||||
"path": "diaspora",
|
|
||||||
"updated_at": "2013-09-30T13: 46: 02Z"
|
|
||||||
},
|
|
||||||
"archived": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
`)
|
|
||||||
|
|
||||||
var project4Paylod = []byte(`
|
|
||||||
{
|
|
||||||
"id": 4,
|
|
||||||
"description": null,
|
|
||||||
"default_branch": "master",
|
|
||||||
"public": false,
|
|
||||||
"visibility_level": 0,
|
|
||||||
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",
|
|
||||||
"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",
|
|
||||||
"web_url": "http://example.com/diaspora/diaspora-client",
|
|
||||||
"owner": {
|
|
||||||
"id": 3,
|
|
||||||
"name": "Diaspora",
|
|
||||||
"username": "some_user",
|
|
||||||
"created_at": "2013-09-30T13: 46: 02Z"
|
|
||||||
},
|
|
||||||
"name": "Diaspora Client",
|
|
||||||
"name_with_namespace": "Diaspora / Diaspora Client",
|
|
||||||
"path": "diaspora-client",
|
|
||||||
"path_with_namespace": "diaspora/diaspora-client",
|
|
||||||
"issues_enabled": true,
|
|
||||||
"merge_requests_enabled": true,
|
|
||||||
"wiki_enabled": true,
|
|
||||||
"snippets_enabled": false,
|
|
||||||
"created_at": "2013-09-30T13: 46: 02Z",
|
|
||||||
"last_activity_at": "2013-09-30T13: 46: 02Z",
|
|
||||||
"namespace": {
|
|
||||||
"created_at": "2013-09-30T13: 46: 02Z",
|
|
||||||
"description": "",
|
|
||||||
"id": 3,
|
|
||||||
"name": "Diaspora",
|
|
||||||
"owner_id": 1,
|
|
||||||
"path": "diaspora",
|
|
||||||
"updated_at": "2013-09-30T13: 46: 02Z"
|
|
||||||
},
|
|
||||||
"archived": false,
|
|
||||||
"permissions": {
|
|
||||||
"project_access": {
|
|
||||||
"access_level": 10,
|
|
||||||
"notification_level": 3
|
|
||||||
},
|
|
||||||
"group_access": {
|
|
||||||
"access_level": 50,
|
|
||||||
"notification_level": 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
||||||
var project6Paylod = []byte(`
|
|
||||||
{
|
|
||||||
"id": 6,
|
|
||||||
"description": null,
|
|
||||||
"default_branch": "master",
|
|
||||||
"public": false,
|
|
||||||
"visibility_level": 0,
|
|
||||||
"ssh_url_to_repo": "git@example.com:brightbox/puppet.git",
|
|
||||||
"http_url_to_repo": "http://example.com/brightbox/puppet.git",
|
|
||||||
"web_url": "http://example.com/brightbox/puppet",
|
|
||||||
"owner": {
|
|
||||||
"id": 1,
|
|
||||||
"name": "Brightbox",
|
|
||||||
"username": "test_user",
|
|
||||||
"created_at": "2013-09-30T13:46:02Z"
|
|
||||||
},
|
|
||||||
"name": "Puppet",
|
|
||||||
"name_with_namespace": "Brightbox / Puppet",
|
|
||||||
"path": "puppet",
|
|
||||||
"path_with_namespace": "brightbox/puppet",
|
|
||||||
"issues_enabled": true,
|
|
||||||
"merge_requests_enabled": true,
|
|
||||||
"wiki_enabled": true,
|
|
||||||
"snippets_enabled": false,
|
|
||||||
"created_at": "2013-09-30T13:46:02Z",
|
|
||||||
"last_activity_at": "2013-09-30T13:46:02Z",
|
|
||||||
"namespace": {
|
|
||||||
"created_at": "2013-09-30T13:46:02Z",
|
|
||||||
"description": "",
|
|
||||||
"id": 4,
|
|
||||||
"name": "Brightbox",
|
|
||||||
"owner_id": 1,
|
|
||||||
"path": "brightbox",
|
|
||||||
"updated_at": "2013-09-30T13:46:02Z"
|
|
||||||
},
|
|
||||||
"archived": false,
|
|
||||||
"permissions": {
|
|
||||||
"project_access": null,
|
|
||||||
"group_access": null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`)
|
|
74
server/remote/gitlab3/testdata/testdata.go
vendored
74
server/remote/gitlab3/testdata/testdata.go
vendored
|
@ -1,74 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package testdata
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
)
|
|
||||||
|
|
||||||
// setup a mock server for testing purposes.
|
|
||||||
func NewServer() *httptest.Server {
|
|
||||||
mux := http.NewServeMux()
|
|
||||||
server := httptest.NewServer(mux)
|
|
||||||
|
|
||||||
// handle requests and serve mock data
|
|
||||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
//println(r.URL.Path + " " + r.Method)
|
|
||||||
// evaluate the path to serve a dummy data file
|
|
||||||
switch r.URL.Path {
|
|
||||||
case "/api/v3/projects":
|
|
||||||
if r.URL.Query().Get("archived") == "false" {
|
|
||||||
w.Write(notArchivedProjectsPayload)
|
|
||||||
} else {
|
|
||||||
w.Write(allProjectsPayload)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
case "/api/v3/projects/diaspora/diaspora-client":
|
|
||||||
w.Write(project4Paylod)
|
|
||||||
return
|
|
||||||
case "/api/v3/projects/brightbox/puppet":
|
|
||||||
w.Write(project6Paylod)
|
|
||||||
return
|
|
||||||
case "/api/v3/projects/diaspora/diaspora-client/services/drone-ci":
|
|
||||||
switch r.Method {
|
|
||||||
case "PUT":
|
|
||||||
if r.FormValue("token") == "" {
|
|
||||||
w.WriteHeader(404)
|
|
||||||
} else {
|
|
||||||
w.WriteHeader(201)
|
|
||||||
}
|
|
||||||
case "DELETE":
|
|
||||||
w.WriteHeader(201)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
case "/oauth/token":
|
|
||||||
w.Write(accessTokenPayload)
|
|
||||||
return
|
|
||||||
case "/api/v3/user":
|
|
||||||
w.Write(currentUserPayload)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// else return a 404
|
|
||||||
http.NotFound(w, r)
|
|
||||||
})
|
|
||||||
|
|
||||||
// return the server to the client which
|
|
||||||
// will need to know the base URL path
|
|
||||||
return server
|
|
||||||
}
|
|
38
server/remote/gitlab3/testdata/users.go
vendored
38
server/remote/gitlab3/testdata/users.go
vendored
|
@ -1,38 +0,0 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package testdata
|
|
||||||
|
|
||||||
var currentUserPayload = []byte(`
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"username": "john_smith",
|
|
||||||
"email": "john@example.com",
|
|
||||||
"name": "John Smith",
|
|
||||||
"private_token": "dd34asd13as",
|
|
||||||
"state": "active",
|
|
||||||
"created_at": "2012-05-23T08:00:58Z",
|
|
||||||
"bio": null,
|
|
||||||
"skype": "",
|
|
||||||
"linkedin": "",
|
|
||||||
"twitter": "",
|
|
||||||
"website_url": "",
|
|
||||||
"theme_id": 1,
|
|
||||||
"color_scheme_id": 2,
|
|
||||||
"is_admin": false,
|
|
||||||
"can_create_group": true,
|
|
||||||
"can_create_project": true,
|
|
||||||
"projects_limit": 100
|
|
||||||
}
|
|
||||||
`)
|
|
363
vendor/github.com/hashicorp/go-cleanhttp/LICENSE
generated
vendored
Normal file
363
vendor/github.com/hashicorp/go-cleanhttp/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
Mozilla Public License, version 2.0
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
|
||||||
|
1.1. "Contributor"
|
||||||
|
|
||||||
|
means each individual or legal entity that creates, contributes to the
|
||||||
|
creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. "Contributor Version"
|
||||||
|
|
||||||
|
means the combination of the Contributions of others (if any) used by a
|
||||||
|
Contributor and that particular Contributor's Contribution.
|
||||||
|
|
||||||
|
1.3. "Contribution"
|
||||||
|
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. "Covered Software"
|
||||||
|
|
||||||
|
means Source Code Form to which the initial Contributor has attached the
|
||||||
|
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||||
|
Modifications of such Source Code Form, in each case including portions
|
||||||
|
thereof.
|
||||||
|
|
||||||
|
1.5. "Incompatible With Secondary Licenses"
|
||||||
|
means
|
||||||
|
|
||||||
|
a. that the initial Contributor has attached the notice described in
|
||||||
|
Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
b. that the Covered Software was made available under the terms of
|
||||||
|
version 1.1 or earlier of the License, but not also under the terms of
|
||||||
|
a Secondary License.
|
||||||
|
|
||||||
|
1.6. "Executable Form"
|
||||||
|
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. "Larger Work"
|
||||||
|
|
||||||
|
means a work that combines Covered Software with other material, in a
|
||||||
|
separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. "License"
|
||||||
|
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. "Licensable"
|
||||||
|
|
||||||
|
means having the right to grant, to the maximum extent possible, whether
|
||||||
|
at the time of the initial grant or subsequently, any and all of the
|
||||||
|
rights conveyed by this License.
|
||||||
|
|
||||||
|
1.10. "Modifications"
|
||||||
|
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
a. any file in Source Code Form that results from an addition to,
|
||||||
|
deletion from, or modification of the contents of Covered Software; or
|
||||||
|
|
||||||
|
b. any new file in Source Code Form that contains any Covered Software.
|
||||||
|
|
||||||
|
1.11. "Patent Claims" of a Contributor
|
||||||
|
|
||||||
|
means any patent claim(s), including without limitation, method,
|
||||||
|
process, and apparatus claims, in any patent Licensable by such
|
||||||
|
Contributor that would be infringed, but for the grant of the License,
|
||||||
|
by the making, using, selling, offering for sale, having made, import,
|
||||||
|
or transfer of either its Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
1.12. "Secondary License"
|
||||||
|
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||||
|
General Public License, Version 2.1, the GNU Affero General Public
|
||||||
|
License, Version 3.0, or any later versions of those licenses.
|
||||||
|
|
||||||
|
1.13. "Source Code Form"
|
||||||
|
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. "You" (or "Your")
|
||||||
|
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, "You" includes any entity that controls, is
|
||||||
|
controlled by, or is under common control with You. For purposes of this
|
||||||
|
definition, "control" means (a) the power, direct or indirect, to cause
|
||||||
|
the direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||||
|
outstanding shares or beneficial ownership of such entity.
|
||||||
|
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
a. under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||||
|
sale, have made, import, and otherwise transfer either its
|
||||||
|
Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution
|
||||||
|
become effective for each Contribution on the date the Contributor first
|
||||||
|
distributes such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under
|
||||||
|
this License. No additional rights or licenses will be implied from the
|
||||||
|
distribution or licensing of Covered Software under this License.
|
||||||
|
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
a. for any code that a Contributor has removed from Covered Software; or
|
||||||
|
|
||||||
|
b. for infringements caused by: (i) Your and any other third party's
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
c. under Patent Claims infringed by Covered Software in the absence of
|
||||||
|
its Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks,
|
||||||
|
or logos of any Contributor (except as may be necessary to comply with
|
||||||
|
the notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this
|
||||||
|
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||||
|
permitted under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its
|
||||||
|
Contributions are its original creation(s) or it has sufficient rights to
|
||||||
|
grant the rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under
|
||||||
|
applicable copyright doctrines of fair use, fair dealing, or other
|
||||||
|
equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||||
|
Section 2.1.
|
||||||
|
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under
|
||||||
|
the terms of this License. You must inform recipients that the Source
|
||||||
|
Code Form of the Covered Software is governed by the terms of this
|
||||||
|
License, and how they can obtain a copy of this License. You may not
|
||||||
|
attempt to alter or restrict the recipients' rights in the Source Code
|
||||||
|
Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
a. such Covered Software must also be made available in Source Code Form,
|
||||||
|
as described in Section 3.1, and You must inform recipients of the
|
||||||
|
Executable Form how they can obtain a copy of such Source Code Form by
|
||||||
|
reasonable means in a timely manner, at a charge no more than the cost
|
||||||
|
of distribution to the recipient; and
|
||||||
|
|
||||||
|
b. You may distribute such Executable Form under the terms of this
|
||||||
|
License, or sublicense it under different terms, provided that the
|
||||||
|
license for the Executable Form does not attempt to limit or alter the
|
||||||
|
recipients' rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for
|
||||||
|
the Covered Software. If the Larger Work is a combination of Covered
|
||||||
|
Software with a work governed by one or more Secondary Licenses, and the
|
||||||
|
Covered Software is not Incompatible With Secondary Licenses, this
|
||||||
|
License permits You to additionally distribute such Covered Software
|
||||||
|
under the terms of such Secondary License(s), so that the recipient of
|
||||||
|
the Larger Work may, at their option, further distribute the Covered
|
||||||
|
Software under the terms of either this License or such Secondary
|
||||||
|
License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices
|
||||||
|
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||||
|
limitations of liability) contained within the Source Code Form of the
|
||||||
|
Covered Software, except that You may alter any license notices to the
|
||||||
|
extent required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on
|
||||||
|
behalf of any Contributor. You must make it absolutely clear that any
|
||||||
|
such warranty, support, indemnity, or liability obligation is offered by
|
||||||
|
You alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this License
|
||||||
|
with respect to some or all of the Covered Software due to statute,
|
||||||
|
judicial order, or regulation then You must: (a) comply with the terms of
|
||||||
|
this License to the maximum extent possible; and (b) describe the
|
||||||
|
limitations and the code they affect. Such description must be placed in a
|
||||||
|
text file included with all distributions of the Covered Software under
|
||||||
|
this License. Except to the extent prohibited by statute or regulation,
|
||||||
|
such description must be sufficiently detailed for a recipient of ordinary
|
||||||
|
skill to be able to understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically if You
|
||||||
|
fail to comply with any of its terms. However, if You become compliant,
|
||||||
|
then the rights granted under this License from a particular Contributor
|
||||||
|
are reinstated (a) provisionally, unless and until such Contributor
|
||||||
|
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||||
|
basis, if such Contributor fails to notify You of the non-compliance by
|
||||||
|
some reasonable means prior to 60 days after You have come back into
|
||||||
|
compliance. Moreover, Your grants from a particular Contributor are
|
||||||
|
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||||
|
non-compliance by some reasonable means, this is the first time You have
|
||||||
|
received notice of non-compliance with this License from such
|
||||||
|
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||||
|
of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions,
|
||||||
|
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||||
|
directly or indirectly infringes any patent, then the rights granted to
|
||||||
|
You by any and all Contributors for the Covered Software under Section
|
||||||
|
2.1 of this License shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||||
|
license agreements (excluding distributors and resellers) which have been
|
||||||
|
validly granted by You or Your distributors under this License prior to
|
||||||
|
termination shall survive termination.
|
||||||
|
|
||||||
|
6. Disclaimer of Warranty
|
||||||
|
|
||||||
|
Covered Software is provided under this License on an "as is" basis,
|
||||||
|
without warranty of any kind, either expressed, implied, or statutory,
|
||||||
|
including, without limitation, warranties that the Covered Software is free
|
||||||
|
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||||
|
The entire risk as to the quality and performance of the Covered Software
|
||||||
|
is with You. Should any Covered Software prove defective in any respect,
|
||||||
|
You (not any Contributor) assume the cost of any necessary servicing,
|
||||||
|
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||||
|
part of this License. No use of any Covered Software is authorized under
|
||||||
|
this License except under this disclaimer.
|
||||||
|
|
||||||
|
7. Limitation of Liability
|
||||||
|
|
||||||
|
Under no circumstances and under no legal theory, whether tort (including
|
||||||
|
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||||
|
distributes Covered Software as permitted above, be liable to You for any
|
||||||
|
direct, indirect, special, incidental, or consequential damages of any
|
||||||
|
character including, without limitation, damages for lost profits, loss of
|
||||||
|
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses, even if such party shall have been
|
||||||
|
informed of the possibility of such damages. This limitation of liability
|
||||||
|
shall not apply to liability for death or personal injury resulting from
|
||||||
|
such party's negligence to the extent applicable law prohibits such
|
||||||
|
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||||
|
incidental or consequential damages, so this exclusion and limitation may
|
||||||
|
not apply to You.
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the courts
|
||||||
|
of a jurisdiction where the defendant maintains its principal place of
|
||||||
|
business and such litigation shall be governed by laws of that
|
||||||
|
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||||
|
in this Section shall prevent a party's ability to bring cross-claims or
|
||||||
|
counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. Any law or regulation which provides that
|
||||||
|
the language of a contract shall be construed against the drafter shall not
|
||||||
|
be used to construe this License against a Contributor.
|
||||||
|
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version
|
||||||
|
of the License under which You originally received the Covered Software,
|
||||||
|
or under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a
|
||||||
|
modified version of this License if you rename the license and remove
|
||||||
|
any references to the name of the license steward (except to note that
|
||||||
|
such modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||||
|
Licenses If You choose to distribute Source Code Form that is
|
||||||
|
Incompatible With Secondary Licenses under the terms of this version of
|
||||||
|
the License, the notice described in Exhibit B of this License must be
|
||||||
|
attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular file,
|
||||||
|
then You may include the notice in a location (such as a LICENSE file in a
|
||||||
|
relevant directory) where a recipient would be likely to look for such a
|
||||||
|
notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||||
|
|
||||||
|
This Source Code Form is "Incompatible
|
||||||
|
With Secondary Licenses", as defined by
|
||||||
|
the Mozilla Public License, v. 2.0.
|
||||||
|
|
30
vendor/github.com/hashicorp/go-cleanhttp/README.md
generated
vendored
Normal file
30
vendor/github.com/hashicorp/go-cleanhttp/README.md
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# cleanhttp
|
||||||
|
|
||||||
|
Functions for accessing "clean" Go http.Client values
|
||||||
|
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The Go standard library contains a default `http.Client` called
|
||||||
|
`http.DefaultClient`. It is a common idiom in Go code to start with
|
||||||
|
`http.DefaultClient` and tweak it as necessary, and in fact, this is
|
||||||
|
encouraged; from the `http` package documentation:
|
||||||
|
|
||||||
|
> The Client's Transport typically has internal state (cached TCP connections),
|
||||||
|
so Clients should be reused instead of created as needed. Clients are safe for
|
||||||
|
concurrent use by multiple goroutines.
|
||||||
|
|
||||||
|
Unfortunately, this is a shared value, and it is not uncommon for libraries to
|
||||||
|
assume that they are free to modify it at will. With enough dependencies, it
|
||||||
|
can be very easy to encounter strange problems and race conditions due to
|
||||||
|
manipulation of this shared value across libraries and goroutines (clients are
|
||||||
|
safe for concurrent use, but writing values to the client struct itself is not
|
||||||
|
protected).
|
||||||
|
|
||||||
|
Making things worse is the fact that a bare `http.Client` will use a default
|
||||||
|
`http.Transport` called `http.DefaultTransport`, which is another global value
|
||||||
|
that behaves the same way. So it is not simply enough to replace
|
||||||
|
`http.DefaultClient` with `&http.Client{}`.
|
||||||
|
|
||||||
|
This repository provides some simple functions to get a "clean" `http.Client`
|
||||||
|
-- one that uses the same default values as the Go standard library, but
|
||||||
|
returns a client that does not share any state with other clients.
|
57
vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go
generated
vendored
Normal file
57
vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package cleanhttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultTransport returns a new http.Transport with similar default values to
|
||||||
|
// http.DefaultTransport, but with idle connections and keepalives disabled.
|
||||||
|
func DefaultTransport() *http.Transport {
|
||||||
|
transport := DefaultPooledTransport()
|
||||||
|
transport.DisableKeepAlives = true
|
||||||
|
transport.MaxIdleConnsPerHost = -1
|
||||||
|
return transport
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultPooledTransport returns a new http.Transport with similar default
|
||||||
|
// values to http.DefaultTransport. Do not use this for transient transports as
|
||||||
|
// it can leak file descriptors over time. Only use this for transports that
|
||||||
|
// will be re-used for the same host(s).
|
||||||
|
func DefaultPooledTransport() *http.Transport {
|
||||||
|
transport := &http.Transport{
|
||||||
|
Proxy: http.ProxyFromEnvironment,
|
||||||
|
DialContext: (&net.Dialer{
|
||||||
|
Timeout: 30 * time.Second,
|
||||||
|
KeepAlive: 30 * time.Second,
|
||||||
|
DualStack: true,
|
||||||
|
}).DialContext,
|
||||||
|
MaxIdleConns: 100,
|
||||||
|
IdleConnTimeout: 90 * time.Second,
|
||||||
|
TLSHandshakeTimeout: 10 * time.Second,
|
||||||
|
ExpectContinueTimeout: 1 * time.Second,
|
||||||
|
MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1,
|
||||||
|
}
|
||||||
|
return transport
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultClient returns a new http.Client with similar default values to
|
||||||
|
// http.Client, but with a non-shared Transport, idle connections disabled, and
|
||||||
|
// keepalives disabled.
|
||||||
|
func DefaultClient() *http.Client {
|
||||||
|
return &http.Client{
|
||||||
|
Transport: DefaultTransport(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultPooledClient returns a new http.Client with similar default values to
|
||||||
|
// http.Client, but with a shared Transport. Do not use this function for
|
||||||
|
// transient clients as it can leak file descriptors over time. Only use this
|
||||||
|
// for clients that will be re-used for the same host(s).
|
||||||
|
func DefaultPooledClient() *http.Client {
|
||||||
|
return &http.Client{
|
||||||
|
Transport: DefaultPooledTransport(),
|
||||||
|
}
|
||||||
|
}
|
20
vendor/github.com/hashicorp/go-cleanhttp/doc.go
generated
vendored
Normal file
20
vendor/github.com/hashicorp/go-cleanhttp/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Package cleanhttp offers convenience utilities for acquiring "clean"
|
||||||
|
// http.Transport and http.Client structs.
|
||||||
|
//
|
||||||
|
// Values set on http.DefaultClient and http.DefaultTransport affect all
|
||||||
|
// callers. This can have detrimental effects, esepcially in TLS contexts,
|
||||||
|
// where client or root certificates set to talk to multiple endpoints can end
|
||||||
|
// up displacing each other, leading to hard-to-debug issues. This package
|
||||||
|
// provides non-shared http.Client and http.Transport structs to ensure that
|
||||||
|
// the configuration will not be overwritten by other parts of the application
|
||||||
|
// or dependencies.
|
||||||
|
//
|
||||||
|
// The DefaultClient and DefaultTransport functions disable idle connections
|
||||||
|
// and keepalives. Without ensuring that idle connections are closed before
|
||||||
|
// garbage collection, short-term clients/transports can leak file descriptors,
|
||||||
|
// eventually leading to "too many open files" errors. If you will be
|
||||||
|
// connecting to the same hosts repeatedly from the same client, you can use
|
||||||
|
// DefaultPooledClient to receive a client that has connection pooling
|
||||||
|
// semantics similar to http.DefaultClient.
|
||||||
|
//
|
||||||
|
package cleanhttp
|
1
vendor/github.com/hashicorp/go-cleanhttp/go.mod
generated
vendored
Normal file
1
vendor/github.com/hashicorp/go-cleanhttp/go.mod
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
module github.com/hashicorp/go-cleanhttp
|
48
vendor/github.com/hashicorp/go-cleanhttp/handlers.go
generated
vendored
Normal file
48
vendor/github.com/hashicorp/go-cleanhttp/handlers.go
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
package cleanhttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandlerInput provides input options to cleanhttp's handlers
|
||||||
|
type HandlerInput struct {
|
||||||
|
ErrStatus int
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintablePathCheckHandler is a middleware that ensures the request path
|
||||||
|
// contains only printable runes.
|
||||||
|
func PrintablePathCheckHandler(next http.Handler, input *HandlerInput) http.Handler {
|
||||||
|
// Nil-check on input to make it optional
|
||||||
|
if input == nil {
|
||||||
|
input = &HandlerInput{
|
||||||
|
ErrStatus: http.StatusBadRequest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default to http.StatusBadRequest on error
|
||||||
|
if input.ErrStatus == 0 {
|
||||||
|
input.ErrStatus = http.StatusBadRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r != nil {
|
||||||
|
// Check URL path for non-printable characters
|
||||||
|
idx := strings.IndexFunc(r.URL.Path, func(c rune) bool {
|
||||||
|
return !unicode.IsPrint(c)
|
||||||
|
})
|
||||||
|
|
||||||
|
if idx != -1 {
|
||||||
|
w.WriteHeader(input.ErrStatus)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if next != nil {
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
})
|
||||||
|
}
|
4
vendor/github.com/hashicorp/go-retryablehttp/.gitignore
generated
vendored
Normal file
4
vendor/github.com/hashicorp/go-retryablehttp/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
*.test
|
||||||
|
.vscode/
|
363
vendor/github.com/hashicorp/go-retryablehttp/LICENSE
generated
vendored
Normal file
363
vendor/github.com/hashicorp/go-retryablehttp/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
Mozilla Public License, version 2.0
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
|
||||||
|
1.1. "Contributor"
|
||||||
|
|
||||||
|
means each individual or legal entity that creates, contributes to the
|
||||||
|
creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. "Contributor Version"
|
||||||
|
|
||||||
|
means the combination of the Contributions of others (if any) used by a
|
||||||
|
Contributor and that particular Contributor's Contribution.
|
||||||
|
|
||||||
|
1.3. "Contribution"
|
||||||
|
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. "Covered Software"
|
||||||
|
|
||||||
|
means Source Code Form to which the initial Contributor has attached the
|
||||||
|
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||||
|
Modifications of such Source Code Form, in each case including portions
|
||||||
|
thereof.
|
||||||
|
|
||||||
|
1.5. "Incompatible With Secondary Licenses"
|
||||||
|
means
|
||||||
|
|
||||||
|
a. that the initial Contributor has attached the notice described in
|
||||||
|
Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
b. that the Covered Software was made available under the terms of
|
||||||
|
version 1.1 or earlier of the License, but not also under the terms of
|
||||||
|
a Secondary License.
|
||||||
|
|
||||||
|
1.6. "Executable Form"
|
||||||
|
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. "Larger Work"
|
||||||
|
|
||||||
|
means a work that combines Covered Software with other material, in a
|
||||||
|
separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. "License"
|
||||||
|
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. "Licensable"
|
||||||
|
|
||||||
|
means having the right to grant, to the maximum extent possible, whether
|
||||||
|
at the time of the initial grant or subsequently, any and all of the
|
||||||
|
rights conveyed by this License.
|
||||||
|
|
||||||
|
1.10. "Modifications"
|
||||||
|
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
a. any file in Source Code Form that results from an addition to,
|
||||||
|
deletion from, or modification of the contents of Covered Software; or
|
||||||
|
|
||||||
|
b. any new file in Source Code Form that contains any Covered Software.
|
||||||
|
|
||||||
|
1.11. "Patent Claims" of a Contributor
|
||||||
|
|
||||||
|
means any patent claim(s), including without limitation, method,
|
||||||
|
process, and apparatus claims, in any patent Licensable by such
|
||||||
|
Contributor that would be infringed, but for the grant of the License,
|
||||||
|
by the making, using, selling, offering for sale, having made, import,
|
||||||
|
or transfer of either its Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
1.12. "Secondary License"
|
||||||
|
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||||
|
General Public License, Version 2.1, the GNU Affero General Public
|
||||||
|
License, Version 3.0, or any later versions of those licenses.
|
||||||
|
|
||||||
|
1.13. "Source Code Form"
|
||||||
|
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. "You" (or "Your")
|
||||||
|
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, "You" includes any entity that controls, is
|
||||||
|
controlled by, or is under common control with You. For purposes of this
|
||||||
|
definition, "control" means (a) the power, direct or indirect, to cause
|
||||||
|
the direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||||
|
outstanding shares or beneficial ownership of such entity.
|
||||||
|
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
a. under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||||
|
sale, have made, import, and otherwise transfer either its
|
||||||
|
Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution
|
||||||
|
become effective for each Contribution on the date the Contributor first
|
||||||
|
distributes such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under
|
||||||
|
this License. No additional rights or licenses will be implied from the
|
||||||
|
distribution or licensing of Covered Software under this License.
|
||||||
|
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
a. for any code that a Contributor has removed from Covered Software; or
|
||||||
|
|
||||||
|
b. for infringements caused by: (i) Your and any other third party's
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
c. under Patent Claims infringed by Covered Software in the absence of
|
||||||
|
its Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks,
|
||||||
|
or logos of any Contributor (except as may be necessary to comply with
|
||||||
|
the notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this
|
||||||
|
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||||
|
permitted under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its
|
||||||
|
Contributions are its original creation(s) or it has sufficient rights to
|
||||||
|
grant the rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under
|
||||||
|
applicable copyright doctrines of fair use, fair dealing, or other
|
||||||
|
equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||||
|
Section 2.1.
|
||||||
|
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under
|
||||||
|
the terms of this License. You must inform recipients that the Source
|
||||||
|
Code Form of the Covered Software is governed by the terms of this
|
||||||
|
License, and how they can obtain a copy of this License. You may not
|
||||||
|
attempt to alter or restrict the recipients' rights in the Source Code
|
||||||
|
Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
a. such Covered Software must also be made available in Source Code Form,
|
||||||
|
as described in Section 3.1, and You must inform recipients of the
|
||||||
|
Executable Form how they can obtain a copy of such Source Code Form by
|
||||||
|
reasonable means in a timely manner, at a charge no more than the cost
|
||||||
|
of distribution to the recipient; and
|
||||||
|
|
||||||
|
b. You may distribute such Executable Form under the terms of this
|
||||||
|
License, or sublicense it under different terms, provided that the
|
||||||
|
license for the Executable Form does not attempt to limit or alter the
|
||||||
|
recipients' rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for
|
||||||
|
the Covered Software. If the Larger Work is a combination of Covered
|
||||||
|
Software with a work governed by one or more Secondary Licenses, and the
|
||||||
|
Covered Software is not Incompatible With Secondary Licenses, this
|
||||||
|
License permits You to additionally distribute such Covered Software
|
||||||
|
under the terms of such Secondary License(s), so that the recipient of
|
||||||
|
the Larger Work may, at their option, further distribute the Covered
|
||||||
|
Software under the terms of either this License or such Secondary
|
||||||
|
License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices
|
||||||
|
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||||
|
limitations of liability) contained within the Source Code Form of the
|
||||||
|
Covered Software, except that You may alter any license notices to the
|
||||||
|
extent required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on
|
||||||
|
behalf of any Contributor. You must make it absolutely clear that any
|
||||||
|
such warranty, support, indemnity, or liability obligation is offered by
|
||||||
|
You alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this License
|
||||||
|
with respect to some or all of the Covered Software due to statute,
|
||||||
|
judicial order, or regulation then You must: (a) comply with the terms of
|
||||||
|
this License to the maximum extent possible; and (b) describe the
|
||||||
|
limitations and the code they affect. Such description must be placed in a
|
||||||
|
text file included with all distributions of the Covered Software under
|
||||||
|
this License. Except to the extent prohibited by statute or regulation,
|
||||||
|
such description must be sufficiently detailed for a recipient of ordinary
|
||||||
|
skill to be able to understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically if You
|
||||||
|
fail to comply with any of its terms. However, if You become compliant,
|
||||||
|
then the rights granted under this License from a particular Contributor
|
||||||
|
are reinstated (a) provisionally, unless and until such Contributor
|
||||||
|
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||||
|
basis, if such Contributor fails to notify You of the non-compliance by
|
||||||
|
some reasonable means prior to 60 days after You have come back into
|
||||||
|
compliance. Moreover, Your grants from a particular Contributor are
|
||||||
|
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||||
|
non-compliance by some reasonable means, this is the first time You have
|
||||||
|
received notice of non-compliance with this License from such
|
||||||
|
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||||
|
of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions,
|
||||||
|
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||||
|
directly or indirectly infringes any patent, then the rights granted to
|
||||||
|
You by any and all Contributors for the Covered Software under Section
|
||||||
|
2.1 of this License shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||||
|
license agreements (excluding distributors and resellers) which have been
|
||||||
|
validly granted by You or Your distributors under this License prior to
|
||||||
|
termination shall survive termination.
|
||||||
|
|
||||||
|
6. Disclaimer of Warranty
|
||||||
|
|
||||||
|
Covered Software is provided under this License on an "as is" basis,
|
||||||
|
without warranty of any kind, either expressed, implied, or statutory,
|
||||||
|
including, without limitation, warranties that the Covered Software is free
|
||||||
|
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||||
|
The entire risk as to the quality and performance of the Covered Software
|
||||||
|
is with You. Should any Covered Software prove defective in any respect,
|
||||||
|
You (not any Contributor) assume the cost of any necessary servicing,
|
||||||
|
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||||
|
part of this License. No use of any Covered Software is authorized under
|
||||||
|
this License except under this disclaimer.
|
||||||
|
|
||||||
|
7. Limitation of Liability
|
||||||
|
|
||||||
|
Under no circumstances and under no legal theory, whether tort (including
|
||||||
|
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||||
|
distributes Covered Software as permitted above, be liable to You for any
|
||||||
|
direct, indirect, special, incidental, or consequential damages of any
|
||||||
|
character including, without limitation, damages for lost profits, loss of
|
||||||
|
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses, even if such party shall have been
|
||||||
|
informed of the possibility of such damages. This limitation of liability
|
||||||
|
shall not apply to liability for death or personal injury resulting from
|
||||||
|
such party's negligence to the extent applicable law prohibits such
|
||||||
|
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||||
|
incidental or consequential damages, so this exclusion and limitation may
|
||||||
|
not apply to You.
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the courts
|
||||||
|
of a jurisdiction where the defendant maintains its principal place of
|
||||||
|
business and such litigation shall be governed by laws of that
|
||||||
|
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||||
|
in this Section shall prevent a party's ability to bring cross-claims or
|
||||||
|
counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. Any law or regulation which provides that
|
||||||
|
the language of a contract shall be construed against the drafter shall not
|
||||||
|
be used to construe this License against a Contributor.
|
||||||
|
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version
|
||||||
|
of the License under which You originally received the Covered Software,
|
||||||
|
or under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a
|
||||||
|
modified version of this License if you rename the license and remove
|
||||||
|
any references to the name of the license steward (except to note that
|
||||||
|
such modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||||
|
Licenses If You choose to distribute Source Code Form that is
|
||||||
|
Incompatible With Secondary Licenses under the terms of this version of
|
||||||
|
the License, the notice described in Exhibit B of this License must be
|
||||||
|
attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular file,
|
||||||
|
then You may include the notice in a location (such as a LICENSE file in a
|
||||||
|
relevant directory) where a recipient would be likely to look for such a
|
||||||
|
notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||||
|
|
||||||
|
This Source Code Form is "Incompatible
|
||||||
|
With Secondary Licenses", as defined by
|
||||||
|
the Mozilla Public License, v. 2.0.
|
||||||
|
|
11
vendor/github.com/hashicorp/go-retryablehttp/Makefile
generated
vendored
Normal file
11
vendor/github.com/hashicorp/go-retryablehttp/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
default: test
|
||||||
|
|
||||||
|
test:
|
||||||
|
go vet ./...
|
||||||
|
go test -race ./...
|
||||||
|
|
||||||
|
updatedeps:
|
||||||
|
go get -f -t -u ./...
|
||||||
|
go get -f -u ./...
|
||||||
|
|
||||||
|
.PHONY: default test updatedeps
|
62
vendor/github.com/hashicorp/go-retryablehttp/README.md
generated
vendored
Normal file
62
vendor/github.com/hashicorp/go-retryablehttp/README.md
generated
vendored
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
go-retryablehttp
|
||||||
|
================
|
||||||
|
|
||||||
|
[![Build Status](http://img.shields.io/travis/hashicorp/go-retryablehttp.svg?style=flat-square)][travis]
|
||||||
|
[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs]
|
||||||
|
|
||||||
|
[travis]: http://travis-ci.org/hashicorp/go-retryablehttp
|
||||||
|
[godocs]: http://godoc.org/github.com/hashicorp/go-retryablehttp
|
||||||
|
|
||||||
|
The `retryablehttp` package provides a familiar HTTP client interface with
|
||||||
|
automatic retries and exponential backoff. It is a thin wrapper over the
|
||||||
|
standard `net/http` client library and exposes nearly the same public API. This
|
||||||
|
makes `retryablehttp` very easy to drop into existing programs.
|
||||||
|
|
||||||
|
`retryablehttp` performs automatic retries under certain conditions. Mainly, if
|
||||||
|
an error is returned by the client (connection errors, etc.), or if a 500-range
|
||||||
|
response code is received (except 501), then a retry is invoked after a wait
|
||||||
|
period. Otherwise, the response is returned and left to the caller to
|
||||||
|
interpret.
|
||||||
|
|
||||||
|
The main difference from `net/http` is that requests which take a request body
|
||||||
|
(POST/PUT et. al) can have the body provided in a number of ways (some more or
|
||||||
|
less efficient) that allow "rewinding" the request body if the initial request
|
||||||
|
fails so that the full request can be attempted again. See the
|
||||||
|
[godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp) for more
|
||||||
|
details.
|
||||||
|
|
||||||
|
Version 0.6.0 and before are compatible with Go prior to 1.12. From 0.6.1 onward, Go 1.12+ is required.
|
||||||
|
From 0.6.7 onward, Go 1.13+ is required.
|
||||||
|
|
||||||
|
Example Use
|
||||||
|
===========
|
||||||
|
|
||||||
|
Using this library should look almost identical to what you would do with
|
||||||
|
`net/http`. The most simple example of a GET request is shown below:
|
||||||
|
|
||||||
|
```go
|
||||||
|
resp, err := retryablehttp.Get("/foo")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The returned response object is an `*http.Response`, the same thing you would
|
||||||
|
usually get from `net/http`. Had the request failed one or more times, the above
|
||||||
|
call would block and retry with exponential backoff.
|
||||||
|
|
||||||
|
## Getting a stdlib `*http.Client` with retries
|
||||||
|
|
||||||
|
It's possible to convert a `*retryablehttp.Client` directly to a `*http.Client`.
|
||||||
|
This makes use of retryablehttp broadly applicable with minimal effort. Simply
|
||||||
|
configure a `*retryablehttp.Client` as you wish, and then call `StandardClient()`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
retryClient := retryablehttp.NewClient()
|
||||||
|
retryClient.RetryMax = 10
|
||||||
|
|
||||||
|
standardClient := retryClient.StandardClient() // *http.Client
|
||||||
|
```
|
||||||
|
|
||||||
|
For more usage and examples see the
|
||||||
|
[godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp).
|
774
vendor/github.com/hashicorp/go-retryablehttp/client.go
generated
vendored
Normal file
774
vendor/github.com/hashicorp/go-retryablehttp/client.go
generated
vendored
Normal file
|
@ -0,0 +1,774 @@
|
||||||
|
// Package retryablehttp provides a familiar HTTP client interface with
|
||||||
|
// automatic retries and exponential backoff. It is a thin wrapper over the
|
||||||
|
// standard net/http client library and exposes nearly the same public API.
|
||||||
|
// This makes retryablehttp very easy to drop into existing programs.
|
||||||
|
//
|
||||||
|
// retryablehttp performs automatic retries under certain conditions. Mainly, if
|
||||||
|
// an error is returned by the client (connection errors etc), or if a 500-range
|
||||||
|
// response is received, then a retry is invoked. Otherwise, the response is
|
||||||
|
// returned and left to the caller to interpret.
|
||||||
|
//
|
||||||
|
// Requests which take a request body should provide a non-nil function
|
||||||
|
// parameter. The best choice is to provide either a function satisfying
|
||||||
|
// ReaderFunc which provides multiple io.Readers in an efficient manner, a
|
||||||
|
// *bytes.Buffer (the underlying raw byte slice will be used) or a raw byte
|
||||||
|
// slice. As it is a reference type, and we will wrap it as needed by readers,
|
||||||
|
// we can efficiently re-use the request body without needing to copy it. If an
|
||||||
|
// io.Reader (such as a *bytes.Reader) is provided, the full body will be read
|
||||||
|
// prior to the first request, and will be efficiently re-used for any retries.
|
||||||
|
// ReadSeeker can be used, but some users have observed occasional data races
|
||||||
|
// between the net/http library and the Seek functionality of some
|
||||||
|
// implementations of ReadSeeker, so should be avoided if possible.
|
||||||
|
package retryablehttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"crypto/x509"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"math"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
cleanhttp "github.com/hashicorp/go-cleanhttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Default retry configuration
|
||||||
|
defaultRetryWaitMin = 1 * time.Second
|
||||||
|
defaultRetryWaitMax = 30 * time.Second
|
||||||
|
defaultRetryMax = 4
|
||||||
|
|
||||||
|
// defaultLogger is the logger provided with defaultClient
|
||||||
|
defaultLogger = log.New(os.Stderr, "", log.LstdFlags)
|
||||||
|
|
||||||
|
// defaultClient is used for performing requests without explicitly making
|
||||||
|
// a new client. It is purposely private to avoid modifications.
|
||||||
|
defaultClient = NewClient()
|
||||||
|
|
||||||
|
// We need to consume response bodies to maintain http connections, but
|
||||||
|
// limit the size we consume to respReadLimit.
|
||||||
|
respReadLimit = int64(4096)
|
||||||
|
|
||||||
|
// A regular expression to match the error returned by net/http when the
|
||||||
|
// configured number of redirects is exhausted. This error isn't typed
|
||||||
|
// specifically so we resort to matching on the error string.
|
||||||
|
redirectsErrorRe = regexp.MustCompile(`stopped after \d+ redirects\z`)
|
||||||
|
|
||||||
|
// A regular expression to match the error returned by net/http when the
|
||||||
|
// scheme specified in the URL is invalid. This error isn't typed
|
||||||
|
// specifically so we resort to matching on the error string.
|
||||||
|
schemeErrorRe = regexp.MustCompile(`unsupported protocol scheme`)
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReaderFunc is the type of function that can be given natively to NewRequest
|
||||||
|
type ReaderFunc func() (io.Reader, error)
|
||||||
|
|
||||||
|
// LenReader is an interface implemented by many in-memory io.Reader's. Used
|
||||||
|
// for automatically sending the right Content-Length header when possible.
|
||||||
|
type LenReader interface {
|
||||||
|
Len() int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request wraps the metadata needed to create HTTP requests.
|
||||||
|
type Request struct {
|
||||||
|
// body is a seekable reader over the request body payload. This is
|
||||||
|
// used to rewind the request data in between retries.
|
||||||
|
body ReaderFunc
|
||||||
|
|
||||||
|
// Embed an HTTP request directly. This makes a *Request act exactly
|
||||||
|
// like an *http.Request so that all meta methods are supported.
|
||||||
|
*http.Request
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithContext returns wrapped Request with a shallow copy of underlying *http.Request
|
||||||
|
// with its context changed to ctx. The provided ctx must be non-nil.
|
||||||
|
func (r *Request) WithContext(ctx context.Context) *Request {
|
||||||
|
r.Request = r.Request.WithContext(ctx)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyBytes allows accessing the request body. It is an analogue to
|
||||||
|
// http.Request's Body variable, but it returns a copy of the underlying data
|
||||||
|
// rather than consuming it.
|
||||||
|
//
|
||||||
|
// This function is not thread-safe; do not call it at the same time as another
|
||||||
|
// call, or at the same time this request is being used with Client.Do.
|
||||||
|
func (r *Request) BodyBytes() ([]byte, error) {
|
||||||
|
if r.body == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
body, err := r.body()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
_, err = buf.ReadFrom(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBody allows setting the request body.
|
||||||
|
//
|
||||||
|
// It is useful if a new body needs to be set without constructing a new Request.
|
||||||
|
func (r *Request) SetBody(rawBody interface{}) error {
|
||||||
|
bodyReader, contentLength, err := getBodyReaderAndContentLength(rawBody)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.body = bodyReader
|
||||||
|
r.ContentLength = contentLength
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteTo allows copying the request body into a writer.
|
||||||
|
//
|
||||||
|
// It writes data to w until there's no more data to write or
|
||||||
|
// when an error occurs. The return int64 value is the number of bytes
|
||||||
|
// written. Any error encountered during the write is also returned.
|
||||||
|
// The signature matches io.WriterTo interface.
|
||||||
|
func (r *Request) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
body, err := r.body()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c, ok := body.(io.Closer); ok {
|
||||||
|
defer c.Close()
|
||||||
|
}
|
||||||
|
return io.Copy(w, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBodyReaderAndContentLength(rawBody interface{}) (ReaderFunc, int64, error) {
|
||||||
|
var bodyReader ReaderFunc
|
||||||
|
var contentLength int64
|
||||||
|
|
||||||
|
switch body := rawBody.(type) {
|
||||||
|
// If they gave us a function already, great! Use it.
|
||||||
|
case ReaderFunc:
|
||||||
|
bodyReader = body
|
||||||
|
tmp, err := body()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if lr, ok := tmp.(LenReader); ok {
|
||||||
|
contentLength = int64(lr.Len())
|
||||||
|
}
|
||||||
|
if c, ok := tmp.(io.Closer); ok {
|
||||||
|
c.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
case func() (io.Reader, error):
|
||||||
|
bodyReader = body
|
||||||
|
tmp, err := body()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if lr, ok := tmp.(LenReader); ok {
|
||||||
|
contentLength = int64(lr.Len())
|
||||||
|
}
|
||||||
|
if c, ok := tmp.(io.Closer); ok {
|
||||||
|
c.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a regular byte slice, we can read it over and over via new
|
||||||
|
// readers
|
||||||
|
case []byte:
|
||||||
|
buf := body
|
||||||
|
bodyReader = func() (io.Reader, error) {
|
||||||
|
return bytes.NewReader(buf), nil
|
||||||
|
}
|
||||||
|
contentLength = int64(len(buf))
|
||||||
|
|
||||||
|
// If a bytes.Buffer we can read the underlying byte slice over and
|
||||||
|
// over
|
||||||
|
case *bytes.Buffer:
|
||||||
|
buf := body
|
||||||
|
bodyReader = func() (io.Reader, error) {
|
||||||
|
return bytes.NewReader(buf.Bytes()), nil
|
||||||
|
}
|
||||||
|
contentLength = int64(buf.Len())
|
||||||
|
|
||||||
|
// We prioritize *bytes.Reader here because we don't really want to
|
||||||
|
// deal with it seeking so want it to match here instead of the
|
||||||
|
// io.ReadSeeker case.
|
||||||
|
case *bytes.Reader:
|
||||||
|
buf, err := ioutil.ReadAll(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
bodyReader = func() (io.Reader, error) {
|
||||||
|
return bytes.NewReader(buf), nil
|
||||||
|
}
|
||||||
|
contentLength = int64(len(buf))
|
||||||
|
|
||||||
|
// Compat case
|
||||||
|
case io.ReadSeeker:
|
||||||
|
raw := body
|
||||||
|
bodyReader = func() (io.Reader, error) {
|
||||||
|
_, err := raw.Seek(0, 0)
|
||||||
|
return ioutil.NopCloser(raw), err
|
||||||
|
}
|
||||||
|
if lr, ok := raw.(LenReader); ok {
|
||||||
|
contentLength = int64(lr.Len())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read all in so we can reset
|
||||||
|
case io.Reader:
|
||||||
|
buf, err := ioutil.ReadAll(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
bodyReader = func() (io.Reader, error) {
|
||||||
|
return bytes.NewReader(buf), nil
|
||||||
|
}
|
||||||
|
contentLength = int64(len(buf))
|
||||||
|
|
||||||
|
// No body provided, nothing to do
|
||||||
|
case nil:
|
||||||
|
|
||||||
|
// Unrecognized type
|
||||||
|
default:
|
||||||
|
return nil, 0, fmt.Errorf("cannot handle type %T", rawBody)
|
||||||
|
}
|
||||||
|
return bodyReader, contentLength, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromRequest wraps an http.Request in a retryablehttp.Request
|
||||||
|
func FromRequest(r *http.Request) (*Request, error) {
|
||||||
|
bodyReader, _, err := getBodyReaderAndContentLength(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Could assert contentLength == r.ContentLength
|
||||||
|
return &Request{bodyReader, r}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRequest creates a new wrapped request.
|
||||||
|
func NewRequest(method, url string, rawBody interface{}) (*Request, error) {
|
||||||
|
bodyReader, contentLength, err := getBodyReaderAndContentLength(rawBody)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
httpReq, err := http.NewRequest(method, url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
httpReq.ContentLength = contentLength
|
||||||
|
|
||||||
|
return &Request{bodyReader, httpReq}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logger interface allows to use other loggers than
|
||||||
|
// standard log.Logger.
|
||||||
|
type Logger interface {
|
||||||
|
Printf(string, ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// LeveledLogger is an interface that can be implemented by any logger or a
|
||||||
|
// logger wrapper to provide leveled logging. The methods accept a message
|
||||||
|
// string and a variadic number of key-value pairs. For log.Printf style
|
||||||
|
// formatting where message string contains a format specifier, use Logger
|
||||||
|
// interface.
|
||||||
|
type LeveledLogger interface {
|
||||||
|
Error(msg string, keysAndValues ...interface{})
|
||||||
|
Info(msg string, keysAndValues ...interface{})
|
||||||
|
Debug(msg string, keysAndValues ...interface{})
|
||||||
|
Warn(msg string, keysAndValues ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// hookLogger adapts an LeveledLogger to Logger for use by the existing hook functions
|
||||||
|
// without changing the API.
|
||||||
|
type hookLogger struct {
|
||||||
|
LeveledLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h hookLogger) Printf(s string, args ...interface{}) {
|
||||||
|
h.Info(fmt.Sprintf(s, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestLogHook allows a function to run before each retry. The HTTP
|
||||||
|
// request which will be made, and the retry number (0 for the initial
|
||||||
|
// request) are available to users. The internal logger is exposed to
|
||||||
|
// consumers.
|
||||||
|
type RequestLogHook func(Logger, *http.Request, int)
|
||||||
|
|
||||||
|
// ResponseLogHook is like RequestLogHook, but allows running a function
|
||||||
|
// on each HTTP response. This function will be invoked at the end of
|
||||||
|
// every HTTP request executed, regardless of whether a subsequent retry
|
||||||
|
// needs to be performed or not. If the response body is read or closed
|
||||||
|
// from this method, this will affect the response returned from Do().
|
||||||
|
type ResponseLogHook func(Logger, *http.Response)
|
||||||
|
|
||||||
|
// CheckRetry specifies a policy for handling retries. It is called
|
||||||
|
// following each request with the response and error values returned by
|
||||||
|
// the http.Client. If CheckRetry returns false, the Client stops retrying
|
||||||
|
// and returns the response to the caller. If CheckRetry returns an error,
|
||||||
|
// that error value is returned in lieu of the error from the request. The
|
||||||
|
// Client will close any response body when retrying, but if the retry is
|
||||||
|
// aborted it is up to the CheckRetry callback to properly close any
|
||||||
|
// response body before returning.
|
||||||
|
type CheckRetry func(ctx context.Context, resp *http.Response, err error) (bool, error)
|
||||||
|
|
||||||
|
// Backoff specifies a policy for how long to wait between retries.
|
||||||
|
// It is called after a failing request to determine the amount of time
|
||||||
|
// that should pass before trying again.
|
||||||
|
type Backoff func(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration
|
||||||
|
|
||||||
|
// ErrorHandler is called if retries are expired, containing the last status
|
||||||
|
// from the http library. If not specified, default behavior for the library is
|
||||||
|
// to close the body and return an error indicating how many tries were
|
||||||
|
// attempted. If overriding this, be sure to close the body if needed.
|
||||||
|
type ErrorHandler func(resp *http.Response, err error, numTries int) (*http.Response, error)
|
||||||
|
|
||||||
|
// Client is used to make HTTP requests. It adds additional functionality
|
||||||
|
// like automatic retries to tolerate minor outages.
|
||||||
|
type Client struct {
|
||||||
|
HTTPClient *http.Client // Internal HTTP client.
|
||||||
|
Logger interface{} // Customer logger instance. Can be either Logger or LeveledLogger
|
||||||
|
|
||||||
|
RetryWaitMin time.Duration // Minimum time to wait
|
||||||
|
RetryWaitMax time.Duration // Maximum time to wait
|
||||||
|
RetryMax int // Maximum number of retries
|
||||||
|
|
||||||
|
// RequestLogHook allows a user-supplied function to be called
|
||||||
|
// before each retry.
|
||||||
|
RequestLogHook RequestLogHook
|
||||||
|
|
||||||
|
// ResponseLogHook allows a user-supplied function to be called
|
||||||
|
// with the response from each HTTP request executed.
|
||||||
|
ResponseLogHook ResponseLogHook
|
||||||
|
|
||||||
|
// CheckRetry specifies the policy for handling retries, and is called
|
||||||
|
// after each request. The default policy is DefaultRetryPolicy.
|
||||||
|
CheckRetry CheckRetry
|
||||||
|
|
||||||
|
// Backoff specifies the policy for how long to wait between retries
|
||||||
|
Backoff Backoff
|
||||||
|
|
||||||
|
// ErrorHandler specifies the custom error handler to use, if any
|
||||||
|
ErrorHandler ErrorHandler
|
||||||
|
|
||||||
|
loggerInit sync.Once
|
||||||
|
clientInit sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient creates a new Client with default settings.
|
||||||
|
func NewClient() *Client {
|
||||||
|
return &Client{
|
||||||
|
HTTPClient: cleanhttp.DefaultPooledClient(),
|
||||||
|
Logger: defaultLogger,
|
||||||
|
RetryWaitMin: defaultRetryWaitMin,
|
||||||
|
RetryWaitMax: defaultRetryWaitMax,
|
||||||
|
RetryMax: defaultRetryMax,
|
||||||
|
CheckRetry: DefaultRetryPolicy,
|
||||||
|
Backoff: DefaultBackoff,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) logger() interface{} {
|
||||||
|
c.loggerInit.Do(func() {
|
||||||
|
if c.Logger == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch c.Logger.(type) {
|
||||||
|
case Logger, LeveledLogger:
|
||||||
|
// ok
|
||||||
|
default:
|
||||||
|
// This should happen in dev when they are setting Logger and work on code, not in prod.
|
||||||
|
panic(fmt.Sprintf("invalid logger type passed, must be Logger or LeveledLogger, was %T", c.Logger))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return c.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultRetryPolicy provides a default callback for Client.CheckRetry, which
|
||||||
|
// will retry on connection errors and server errors.
|
||||||
|
func DefaultRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) {
|
||||||
|
// do not retry on context.Canceled or context.DeadlineExceeded
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return false, ctx.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't propagate other errors
|
||||||
|
shouldRetry, _ := baseRetryPolicy(resp, err)
|
||||||
|
return shouldRetry, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorPropagatedRetryPolicy is the same as DefaultRetryPolicy, except it
|
||||||
|
// propagates errors back instead of returning nil. This allows you to inspect
|
||||||
|
// why it decided to retry or not.
|
||||||
|
func ErrorPropagatedRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) {
|
||||||
|
// do not retry on context.Canceled or context.DeadlineExceeded
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return false, ctx.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseRetryPolicy(resp, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func baseRetryPolicy(resp *http.Response, err error) (bool, error) {
|
||||||
|
if err != nil {
|
||||||
|
if v, ok := err.(*url.Error); ok {
|
||||||
|
// Don't retry if the error was due to too many redirects.
|
||||||
|
if redirectsErrorRe.MatchString(v.Error()) {
|
||||||
|
return false, v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't retry if the error was due to an invalid protocol scheme.
|
||||||
|
if schemeErrorRe.MatchString(v.Error()) {
|
||||||
|
return false, v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't retry if the error was due to TLS cert verification failure.
|
||||||
|
if _, ok := v.Err.(x509.UnknownAuthorityError); ok {
|
||||||
|
return false, v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The error is likely recoverable so retry.
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 429 Too Many Requests is recoverable. Sometimes the server puts
|
||||||
|
// a Retry-After response header to indicate when the server is
|
||||||
|
// available to start processing request from client.
|
||||||
|
if resp.StatusCode == http.StatusTooManyRequests {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the response code. We retry on 500-range responses to allow
|
||||||
|
// the server time to recover, as 500's are typically not permanent
|
||||||
|
// errors and may relate to outages on the server side. This will catch
|
||||||
|
// invalid response codes as well, like 0 and 999.
|
||||||
|
if resp.StatusCode == 0 || (resp.StatusCode >= 500 && resp.StatusCode != 501) {
|
||||||
|
return true, fmt.Errorf("unexpected HTTP status %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultBackoff provides a default callback for Client.Backoff which
|
||||||
|
// will perform exponential backoff based on the attempt number and limited
|
||||||
|
// by the provided minimum and maximum durations.
|
||||||
|
//
|
||||||
|
// It also tries to parse Retry-After response header when a http.StatusTooManyRequests
|
||||||
|
// (HTTP Code 429) is found in the resp parameter. Hence it will return the number of
|
||||||
|
// seconds the server states it may be ready to process more requests from this client.
|
||||||
|
func DefaultBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration {
|
||||||
|
if resp != nil {
|
||||||
|
if resp.StatusCode == http.StatusTooManyRequests {
|
||||||
|
if s, ok := resp.Header["Retry-After"]; ok {
|
||||||
|
if sleep, err := strconv.ParseInt(s[0], 10, 64); err == nil {
|
||||||
|
return time.Second * time.Duration(sleep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mult := math.Pow(2, float64(attemptNum)) * float64(min)
|
||||||
|
sleep := time.Duration(mult)
|
||||||
|
if float64(sleep) != mult || sleep > max {
|
||||||
|
sleep = max
|
||||||
|
}
|
||||||
|
return sleep
|
||||||
|
}
|
||||||
|
|
||||||
|
// LinearJitterBackoff provides a callback for Client.Backoff which will
|
||||||
|
// perform linear backoff based on the attempt number and with jitter to
|
||||||
|
// prevent a thundering herd.
|
||||||
|
//
|
||||||
|
// min and max here are *not* absolute values. The number to be multiplied by
|
||||||
|
// the attempt number will be chosen at random from between them, thus they are
|
||||||
|
// bounding the jitter.
|
||||||
|
//
|
||||||
|
// For instance:
|
||||||
|
// * To get strictly linear backoff of one second increasing each retry, set
|
||||||
|
// both to one second (1s, 2s, 3s, 4s, ...)
|
||||||
|
// * To get a small amount of jitter centered around one second increasing each
|
||||||
|
// retry, set to around one second, such as a min of 800ms and max of 1200ms
|
||||||
|
// (892ms, 2102ms, 2945ms, 4312ms, ...)
|
||||||
|
// * To get extreme jitter, set to a very wide spread, such as a min of 100ms
|
||||||
|
// and a max of 20s (15382ms, 292ms, 51321ms, 35234ms, ...)
|
||||||
|
func LinearJitterBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration {
|
||||||
|
// attemptNum always starts at zero but we want to start at 1 for multiplication
|
||||||
|
attemptNum++
|
||||||
|
|
||||||
|
if max <= min {
|
||||||
|
// Unclear what to do here, or they are the same, so return min *
|
||||||
|
// attemptNum
|
||||||
|
return min * time.Duration(attemptNum)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seed rand; doing this every time is fine
|
||||||
|
rand := rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
|
||||||
|
|
||||||
|
// Pick a random number that lies somewhere between the min and max and
|
||||||
|
// multiply by the attemptNum. attemptNum starts at zero so we always
|
||||||
|
// increment here. We first get a random percentage, then apply that to the
|
||||||
|
// difference between min and max, and add to min.
|
||||||
|
jitter := rand.Float64() * float64(max-min)
|
||||||
|
jitterMin := int64(jitter) + int64(min)
|
||||||
|
return time.Duration(jitterMin * int64(attemptNum))
|
||||||
|
}
|
||||||
|
|
||||||
|
// PassthroughErrorHandler is an ErrorHandler that directly passes through the
|
||||||
|
// values from the net/http library for the final request. The body is not
|
||||||
|
// closed.
|
||||||
|
func PassthroughErrorHandler(resp *http.Response, err error, _ int) (*http.Response, error) {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do wraps calling an HTTP method with retries.
|
||||||
|
func (c *Client) Do(req *Request) (*http.Response, error) {
|
||||||
|
c.clientInit.Do(func() {
|
||||||
|
if c.HTTPClient == nil {
|
||||||
|
c.HTTPClient = cleanhttp.DefaultPooledClient()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
logger := c.logger()
|
||||||
|
|
||||||
|
if logger != nil {
|
||||||
|
switch v := logger.(type) {
|
||||||
|
case LeveledLogger:
|
||||||
|
v.Debug("performing request", "method", req.Method, "url", req.URL)
|
||||||
|
case Logger:
|
||||||
|
v.Printf("[DEBUG] %s %s", req.Method, req.URL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp *http.Response
|
||||||
|
var attempt int
|
||||||
|
var shouldRetry bool
|
||||||
|
var doErr, checkErr error
|
||||||
|
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
attempt++
|
||||||
|
|
||||||
|
var code int // HTTP response code
|
||||||
|
|
||||||
|
// Always rewind the request body when non-nil.
|
||||||
|
if req.body != nil {
|
||||||
|
body, err := req.body()
|
||||||
|
if err != nil {
|
||||||
|
c.HTTPClient.CloseIdleConnections()
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
if c, ok := body.(io.ReadCloser); ok {
|
||||||
|
req.Body = c
|
||||||
|
} else {
|
||||||
|
req.Body = ioutil.NopCloser(body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.RequestLogHook != nil {
|
||||||
|
switch v := logger.(type) {
|
||||||
|
case LeveledLogger:
|
||||||
|
c.RequestLogHook(hookLogger{v}, req.Request, i)
|
||||||
|
case Logger:
|
||||||
|
c.RequestLogHook(v, req.Request, i)
|
||||||
|
default:
|
||||||
|
c.RequestLogHook(nil, req.Request, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt the request
|
||||||
|
resp, doErr = c.HTTPClient.Do(req.Request)
|
||||||
|
if resp != nil {
|
||||||
|
code = resp.StatusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we should continue with retries.
|
||||||
|
shouldRetry, checkErr = c.CheckRetry(req.Context(), resp, doErr)
|
||||||
|
|
||||||
|
if doErr != nil {
|
||||||
|
switch v := logger.(type) {
|
||||||
|
case LeveledLogger:
|
||||||
|
v.Error("request failed", "error", doErr, "method", req.Method, "url", req.URL)
|
||||||
|
case Logger:
|
||||||
|
v.Printf("[ERR] %s %s request failed: %v", req.Method, req.URL, doErr)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Call this here to maintain the behavior of logging all requests,
|
||||||
|
// even if CheckRetry signals to stop.
|
||||||
|
if c.ResponseLogHook != nil {
|
||||||
|
// Call the response logger function if provided.
|
||||||
|
switch v := logger.(type) {
|
||||||
|
case LeveledLogger:
|
||||||
|
c.ResponseLogHook(hookLogger{v}, resp)
|
||||||
|
case Logger:
|
||||||
|
c.ResponseLogHook(v, resp)
|
||||||
|
default:
|
||||||
|
c.ResponseLogHook(nil, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !shouldRetry {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// We do this before drainBody because there's no need for the I/O if
|
||||||
|
// we're breaking out
|
||||||
|
remain := c.RetryMax - i
|
||||||
|
if remain <= 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're going to retry, consume any response to reuse the connection.
|
||||||
|
if doErr == nil {
|
||||||
|
c.drainBody(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
wait := c.Backoff(c.RetryWaitMin, c.RetryWaitMax, i, resp)
|
||||||
|
desc := fmt.Sprintf("%s %s", req.Method, req.URL)
|
||||||
|
if code > 0 {
|
||||||
|
desc = fmt.Sprintf("%s (status: %d)", desc, code)
|
||||||
|
}
|
||||||
|
if logger != nil {
|
||||||
|
switch v := logger.(type) {
|
||||||
|
case LeveledLogger:
|
||||||
|
v.Debug("retrying request", "request", desc, "timeout", wait, "remaining", remain)
|
||||||
|
case Logger:
|
||||||
|
v.Printf("[DEBUG] %s: retrying in %s (%d left)", desc, wait, remain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-req.Context().Done():
|
||||||
|
c.HTTPClient.CloseIdleConnections()
|
||||||
|
return nil, req.Context().Err()
|
||||||
|
case <-time.After(wait):
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make shallow copy of http Request so that we can modify its body
|
||||||
|
// without racing against the closeBody call in persistConn.writeLoop.
|
||||||
|
httpreq := *req.Request
|
||||||
|
req.Request = &httpreq
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is the closest we have to success criteria
|
||||||
|
if doErr == nil && checkErr == nil && !shouldRetry {
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
defer c.HTTPClient.CloseIdleConnections()
|
||||||
|
|
||||||
|
err := doErr
|
||||||
|
if checkErr != nil {
|
||||||
|
err = checkErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.ErrorHandler != nil {
|
||||||
|
return c.ErrorHandler(resp, err, attempt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// By default, we close the response body and return an error without
|
||||||
|
// returning the response
|
||||||
|
if resp != nil {
|
||||||
|
c.drainBody(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// this means CheckRetry thought the request was a failure, but didn't
|
||||||
|
// communicate why
|
||||||
|
if err == nil {
|
||||||
|
return nil, fmt.Errorf("%s %s giving up after %d attempt(s)",
|
||||||
|
req.Method, req.URL, attempt)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("%s %s giving up after %d attempt(s): %w",
|
||||||
|
req.Method, req.URL, attempt, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the response body so we can reuse this connection.
|
||||||
|
func (c *Client) drainBody(body io.ReadCloser) {
|
||||||
|
defer body.Close()
|
||||||
|
_, err := io.Copy(ioutil.Discard, io.LimitReader(body, respReadLimit))
|
||||||
|
if err != nil {
|
||||||
|
if c.logger() != nil {
|
||||||
|
switch v := c.logger().(type) {
|
||||||
|
case LeveledLogger:
|
||||||
|
v.Error("error reading response body", "error", err)
|
||||||
|
case Logger:
|
||||||
|
v.Printf("[ERR] error reading response body: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get is a shortcut for doing a GET request without making a new client.
|
||||||
|
func Get(url string) (*http.Response, error) {
|
||||||
|
return defaultClient.Get(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get is a convenience helper for doing simple GET requests.
|
||||||
|
func (c *Client) Get(url string) (*http.Response, error) {
|
||||||
|
req, err := NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.Do(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Head is a shortcut for doing a HEAD request without making a new client.
|
||||||
|
func Head(url string) (*http.Response, error) {
|
||||||
|
return defaultClient.Head(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Head is a convenience method for doing simple HEAD requests.
|
||||||
|
func (c *Client) Head(url string) (*http.Response, error) {
|
||||||
|
req, err := NewRequest("HEAD", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.Do(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post is a shortcut for doing a POST request without making a new client.
|
||||||
|
func Post(url, bodyType string, body interface{}) (*http.Response, error) {
|
||||||
|
return defaultClient.Post(url, bodyType, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post is a convenience method for doing simple POST requests.
|
||||||
|
func (c *Client) Post(url, bodyType string, body interface{}) (*http.Response, error) {
|
||||||
|
req, err := NewRequest("POST", url, body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", bodyType)
|
||||||
|
return c.Do(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostForm is a shortcut to perform a POST with form data without creating
|
||||||
|
// a new client.
|
||||||
|
func PostForm(url string, data url.Values) (*http.Response, error) {
|
||||||
|
return defaultClient.PostForm(url, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostForm is a convenience method for doing simple POST operations using
|
||||||
|
// pre-filled url.Values form data.
|
||||||
|
func (c *Client) PostForm(url string, data url.Values) (*http.Response, error) {
|
||||||
|
return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// StandardClient returns a stdlib *http.Client with a custom Transport, which
|
||||||
|
// shims in a *retryablehttp.Client for added retries.
|
||||||
|
func (c *Client) StandardClient() *http.Client {
|
||||||
|
return &http.Client{
|
||||||
|
Transport: &RoundTripper{Client: c},
|
||||||
|
}
|
||||||
|
}
|
8
vendor/github.com/hashicorp/go-retryablehttp/go.mod
generated
vendored
Normal file
8
vendor/github.com/hashicorp/go-retryablehttp/go.mod
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
module github.com/hashicorp/go-retryablehttp
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2
|
||||||
|
)
|
||||||
|
|
||||||
|
go 1.13
|
10
vendor/github.com/hashicorp/go-retryablehttp/go.sum
generated
vendored
Normal file
10
vendor/github.com/hashicorp/go-retryablehttp/go.sum
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
52
vendor/github.com/hashicorp/go-retryablehttp/roundtripper.go
generated
vendored
Normal file
52
vendor/github.com/hashicorp/go-retryablehttp/roundtripper.go
generated
vendored
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package retryablehttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RoundTripper implements the http.RoundTripper interface, using a retrying
|
||||||
|
// HTTP client to execute requests.
|
||||||
|
//
|
||||||
|
// It is important to note that retryablehttp doesn't always act exactly as a
|
||||||
|
// RoundTripper should. This is highly dependent on the retryable client's
|
||||||
|
// configuration.
|
||||||
|
type RoundTripper struct {
|
||||||
|
// The client to use during requests. If nil, the default retryablehttp
|
||||||
|
// client and settings will be used.
|
||||||
|
Client *Client
|
||||||
|
|
||||||
|
// once ensures that the logic to initialize the default client runs at
|
||||||
|
// most once, in a single thread.
|
||||||
|
once sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
// init initializes the underlying retryable client.
|
||||||
|
func (rt *RoundTripper) init() {
|
||||||
|
if rt.Client == nil {
|
||||||
|
rt.Client = NewClient()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoundTrip satisfies the http.RoundTripper interface.
|
||||||
|
func (rt *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
rt.once.Do(rt.init)
|
||||||
|
|
||||||
|
// Convert the request to be retryable.
|
||||||
|
retryableReq, err := FromRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the request.
|
||||||
|
resp, err := rt.Client.Do(retryableReq)
|
||||||
|
// If we got an error returned by standard library's `Do` method, unwrap it
|
||||||
|
// otherwise we will wind up erroneously re-nesting the error.
|
||||||
|
if _, ok := err.(*url.Error); ok {
|
||||||
|
return resp, errors.Unwrap(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, err
|
||||||
|
}
|
28
vendor/github.com/xanzy/go-gitlab/.gitignore
generated
vendored
Normal file
28
vendor/github.com/xanzy/go-gitlab/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Folders
|
||||||
|
_obj
|
||||||
|
_test
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
|
*.cgo1.go
|
||||||
|
*.cgo2.c
|
||||||
|
_cgo_defun.c
|
||||||
|
_cgo_gotypes.go
|
||||||
|
_cgo_export.*
|
||||||
|
|
||||||
|
_testmain.go
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.test
|
||||||
|
*.prof
|
||||||
|
|
||||||
|
# IDE specific files and folders
|
||||||
|
.idea
|
||||||
|
*.iml
|
59
vendor/github.com/xanzy/go-gitlab/.golangci.yml
generated
vendored
Normal file
59
vendor/github.com/xanzy/go-gitlab/.golangci.yml
generated
vendored
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
# This file contains all available configuration options
|
||||||
|
# with their default values.
|
||||||
|
|
||||||
|
# Options for analysis running
|
||||||
|
run:
|
||||||
|
concurrency: 4
|
||||||
|
timeout: 10m
|
||||||
|
issues-exit-code: 1
|
||||||
|
# Include test files or not, default is true
|
||||||
|
tests: true
|
||||||
|
|
||||||
|
# Output configuration options
|
||||||
|
output:
|
||||||
|
format: line-number
|
||||||
|
|
||||||
|
# All available settings of specific linters
|
||||||
|
linters-settings:
|
||||||
|
misspell:
|
||||||
|
locale: US
|
||||||
|
ignore-words:
|
||||||
|
- noteable
|
||||||
|
unused:
|
||||||
|
# Treat code as a program (not a library) and report unused exported identifiers
|
||||||
|
check-exported: false
|
||||||
|
|
||||||
|
linters:
|
||||||
|
enable:
|
||||||
|
- asciicheck
|
||||||
|
- deadcode
|
||||||
|
- dogsled
|
||||||
|
- errorlint
|
||||||
|
- exportloopref
|
||||||
|
- goconst
|
||||||
|
- golint
|
||||||
|
- gosimple
|
||||||
|
- govet
|
||||||
|
- ineffassign
|
||||||
|
- megacheck
|
||||||
|
- misspell
|
||||||
|
- nakedret
|
||||||
|
- nolintlint
|
||||||
|
- staticcheck
|
||||||
|
- structcheck
|
||||||
|
- typecheck
|
||||||
|
- unconvert
|
||||||
|
- unused
|
||||||
|
- varcheck
|
||||||
|
- whitespace
|
||||||
|
disable:
|
||||||
|
- errcheck
|
||||||
|
disable-all: false
|
||||||
|
fast: false
|
||||||
|
|
||||||
|
issues:
|
||||||
|
# Maximum issues count per one linter (set to 0 to disable)
|
||||||
|
max-issues-per-linter: 0
|
||||||
|
|
||||||
|
# Maximum count of issues with the same text (set to 0 to disable)
|
||||||
|
max-same-issues: 0
|
201
vendor/github.com/xanzy/go-gitlab/LICENSE
generated
vendored
Normal file
201
vendor/github.com/xanzy/go-gitlab/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
194
vendor/github.com/xanzy/go-gitlab/README.md
generated
vendored
Normal file
194
vendor/github.com/xanzy/go-gitlab/README.md
generated
vendored
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
# go-gitlab
|
||||||
|
|
||||||
|
A GitLab API client enabling Go programs to interact with GitLab in a simple and uniform way
|
||||||
|
|
||||||
|
[![Build Status](https://github.com/xanzy/go-gitlab/workflows/Lint%20and%20Test/badge.svg)](https://github.com/xanzy/go-gitlab/actions?workflow=Lint%20and%20Test)
|
||||||
|
[![Sourcegraph](https://sourcegraph.com/github.com/xanzy/go-gitlab/-/badge.svg)](https://sourcegraph.com/github.com/xanzy/go-gitlab?badge)
|
||||||
|
[![GoDoc](https://godoc.org/github.com/xanzy/go-gitlab?status.svg)](https://godoc.org/github.com/xanzy/go-gitlab)
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/github.com/xanzy/go-gitlab)](https://goreportcard.com/report/github.com/xanzy/go-gitlab)
|
||||||
|
|
||||||
|
## NOTE
|
||||||
|
|
||||||
|
Release v0.6.0 (released on 25-08-2017) no longer supports the older V3 Gitlab API. If
|
||||||
|
you need V3 support, please use the `f-api-v3` branch. This release contains some backwards
|
||||||
|
incompatible changes that were needed to fully support the V4 Gitlab API.
|
||||||
|
|
||||||
|
## Coverage
|
||||||
|
|
||||||
|
This API client package covers most of the existing Gitlab API calls and is updated regularly
|
||||||
|
to add new and/or missing endpoints. Currently the following services are supported:
|
||||||
|
|
||||||
|
- [x] Applications
|
||||||
|
- [x] Award Emojis
|
||||||
|
- [x] Branches
|
||||||
|
- [x] Broadcast Messages
|
||||||
|
- [x] Commits
|
||||||
|
- [x] Container Registry
|
||||||
|
- [x] Custom Attributes
|
||||||
|
- [x] Deploy Keys
|
||||||
|
- [x] Deployments
|
||||||
|
- [ ] Discussions (threaded comments)
|
||||||
|
- [x] Environments
|
||||||
|
- [ ] Epic Issues
|
||||||
|
- [ ] Epics
|
||||||
|
- [x] Events
|
||||||
|
- [x] Feature Flags
|
||||||
|
- [ ] Geo Nodes
|
||||||
|
- [x] GitLab CI Config Templates
|
||||||
|
- [x] Gitignores Templates
|
||||||
|
- [x] Group Access Requests
|
||||||
|
- [x] Group Issue Boards
|
||||||
|
- [x] Group Members
|
||||||
|
- [x] Group Milestones
|
||||||
|
- [x] Group Wikis
|
||||||
|
- [x] Group-Level Variables
|
||||||
|
- [x] Groups
|
||||||
|
- [x] Instance Clusters
|
||||||
|
- [x] Invites
|
||||||
|
- [x] Issue Boards
|
||||||
|
- [x] Issues
|
||||||
|
- [x] Jobs
|
||||||
|
- [x] Keys
|
||||||
|
- [x] Labels
|
||||||
|
- [x] License
|
||||||
|
- [x] Merge Request Approvals
|
||||||
|
- [x] Merge Requests
|
||||||
|
- [x] Namespaces
|
||||||
|
- [x] Notes (comments)
|
||||||
|
- [x] Notification Settings
|
||||||
|
- [x] Open Source License Templates
|
||||||
|
- [x] Pages
|
||||||
|
- [x] Pages Domains
|
||||||
|
- [x] Personal Access Tokens
|
||||||
|
- [x] Pipeline Schedules
|
||||||
|
- [x] Pipeline Triggers
|
||||||
|
- [x] Pipelines
|
||||||
|
- [x] Project Access Requests
|
||||||
|
- [x] Project Badges
|
||||||
|
- [x] Project Clusters
|
||||||
|
- [x] Project Import/export
|
||||||
|
- [x] Project Members
|
||||||
|
- [x] Project Milestones
|
||||||
|
- [x] Project Snippets
|
||||||
|
- [x] Project-Level Variables
|
||||||
|
- [x] Projects (including setting Webhooks)
|
||||||
|
- [x] Protected Branches
|
||||||
|
- [x] Protected Environments
|
||||||
|
- [x] Protected Tags
|
||||||
|
- [x] Repositories
|
||||||
|
- [x] Repository Files
|
||||||
|
- [x] Runners
|
||||||
|
- [x] Search
|
||||||
|
- [x] Services
|
||||||
|
- [x] Settings
|
||||||
|
- [x] Sidekiq Metrics
|
||||||
|
- [x] System Hooks
|
||||||
|
- [x] Tags
|
||||||
|
- [x] Todos
|
||||||
|
- [x] Users
|
||||||
|
- [x] Validate CI Configuration
|
||||||
|
- [x] Version
|
||||||
|
- [x] Wikis
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/xanzy/go-gitlab"
|
||||||
|
```
|
||||||
|
|
||||||
|
Construct a new GitLab client, then use the various services on the client to
|
||||||
|
access different parts of the GitLab API. For example, to list all
|
||||||
|
users:
|
||||||
|
|
||||||
|
```go
|
||||||
|
git, err := gitlab.NewClient("yourtokengoeshere")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to create client: %v", err)
|
||||||
|
}
|
||||||
|
users, _, err := git.Users.ListUsers(&gitlab.ListUsersOptions{})
|
||||||
|
```
|
||||||
|
|
||||||
|
There are a few `With...` option functions that can be used to customize
|
||||||
|
the API client. For example, to set a custom base URL:
|
||||||
|
|
||||||
|
```go
|
||||||
|
git, err := gitlab.NewClient("yourtokengoeshere", gitlab.WithBaseURL("https://git.mydomain.com/api/v4"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to create client: %v", err)
|
||||||
|
}
|
||||||
|
users, _, err := git.Users.ListUsers(&gitlab.ListUsersOptions{})
|
||||||
|
```
|
||||||
|
|
||||||
|
Some API methods have optional parameters that can be passed. For example,
|
||||||
|
to list all projects for user "svanharmelen":
|
||||||
|
|
||||||
|
```go
|
||||||
|
git := gitlab.NewClient("yourtokengoeshere")
|
||||||
|
opt := &ListProjectsOptions{Search: gitlab.String("svanharmelen")}
|
||||||
|
projects, _, err := git.Projects.ListProjects(opt)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
The [examples](https://github.com/xanzy/go-gitlab/tree/master/examples) directory
|
||||||
|
contains a couple for clear examples, of which one is partially listed here as well:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/xanzy/go-gitlab"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
git, err := gitlab.NewClient("yourtokengoeshere")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to create client: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new project
|
||||||
|
p := &gitlab.CreateProjectOptions{
|
||||||
|
Name: gitlab.String("My Project"),
|
||||||
|
Description: gitlab.String("Just a test project to play with"),
|
||||||
|
MergeRequestsEnabled: gitlab.Bool(true),
|
||||||
|
SnippetsEnabled: gitlab.Bool(true),
|
||||||
|
Visibility: gitlab.Visibility(gitlab.PublicVisibility),
|
||||||
|
}
|
||||||
|
project, _, err := git.Projects.CreateProject(p)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new snippet
|
||||||
|
s := &gitlab.CreateProjectSnippetOptions{
|
||||||
|
Title: gitlab.String("Dummy Snippet"),
|
||||||
|
FileName: gitlab.String("snippet.go"),
|
||||||
|
Content: gitlab.String("package main...."),
|
||||||
|
Visibility: gitlab.Visibility(gitlab.PublicVisibility),
|
||||||
|
}
|
||||||
|
_, _, err = git.ProjectSnippets.CreateSnippet(project.ID, s)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For complete usage of go-gitlab, see the full [package docs](https://godoc.org/github.com/xanzy/go-gitlab).
|
||||||
|
|
||||||
|
## ToDo
|
||||||
|
|
||||||
|
- The biggest thing this package still needs is tests :disappointed:
|
||||||
|
|
||||||
|
## Issues
|
||||||
|
|
||||||
|
- If you have an issue: report it on the [issue tracker](https://github.com/xanzy/go-gitlab/issues)
|
||||||
|
|
||||||
|
## Author
|
||||||
|
|
||||||
|
Sander van Harmelen (<sander@vanharmelen.nl>)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>
|
253
vendor/github.com/xanzy/go-gitlab/access_requests.go
generated
vendored
Normal file
253
vendor/github.com/xanzy/go-gitlab/access_requests.go
generated
vendored
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AccessRequest represents a access request for a group or project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html
|
||||||
|
type AccessRequest struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
State string `json:"state"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
RequestedAt *time.Time `json:"requested_at"`
|
||||||
|
AccessLevel AccessLevelValue `json:"access_level"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccessRequestsService handles communication with the project/group
|
||||||
|
// access requests related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/access_requests.html
|
||||||
|
type AccessRequestsService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAccessRequestsOptions represents the available
|
||||||
|
// ListProjectAccessRequests() or ListGroupAccessRequests() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#list-access-requests-for-a-group-or-project
|
||||||
|
type ListAccessRequestsOptions ListOptions
|
||||||
|
|
||||||
|
// ListProjectAccessRequests gets a list of access requests
|
||||||
|
// viewable by the authenticated user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#list-access-requests-for-a-group-or-project
|
||||||
|
func (s *AccessRequestsService) ListProjectAccessRequests(pid interface{}, opt *ListAccessRequestsOptions, options ...RequestOptionFunc) ([]*AccessRequest, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/access_requests", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ars []*AccessRequest
|
||||||
|
resp, err := s.client.Do(req, &ars)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ars, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupAccessRequests gets a list of access requests
|
||||||
|
// viewable by the authenticated user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#list-access-requests-for-a-group-or-project
|
||||||
|
func (s *AccessRequestsService) ListGroupAccessRequests(gid interface{}, opt *ListAccessRequestsOptions, options ...RequestOptionFunc) ([]*AccessRequest, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/access_requests", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ars []*AccessRequest
|
||||||
|
resp, err := s.client.Do(req, &ars)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ars, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestProjectAccess requests access for the authenticated user
|
||||||
|
// to a group or project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#request-access-to-a-group-or-project
|
||||||
|
func (s *AccessRequestsService) RequestProjectAccess(pid interface{}, options ...RequestOptionFunc) (*AccessRequest, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/access_requests", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ar := new(AccessRequest)
|
||||||
|
resp, err := s.client.Do(req, ar)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ar, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestGroupAccess requests access for the authenticated user
|
||||||
|
// to a group or project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#request-access-to-a-group-or-project
|
||||||
|
func (s *AccessRequestsService) RequestGroupAccess(gid interface{}, options ...RequestOptionFunc) (*AccessRequest, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/access_requests", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ar := new(AccessRequest)
|
||||||
|
resp, err := s.client.Do(req, ar)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ar, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApproveAccessRequestOptions represents the available
|
||||||
|
// ApproveProjectAccessRequest() and ApproveGroupAccessRequest() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#approve-an-access-request
|
||||||
|
type ApproveAccessRequestOptions struct {
|
||||||
|
AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApproveProjectAccessRequest approves an access request for the given user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#approve-an-access-request
|
||||||
|
func (s *AccessRequestsService) ApproveProjectAccessRequest(pid interface{}, user int, opt *ApproveAccessRequestOptions, options ...RequestOptionFunc) (*AccessRequest, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/access_requests/%d/approve", pathEscape(project), user)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ar := new(AccessRequest)
|
||||||
|
resp, err := s.client.Do(req, ar)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ar, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApproveGroupAccessRequest approves an access request for the given user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#approve-an-access-request
|
||||||
|
func (s *AccessRequestsService) ApproveGroupAccessRequest(gid interface{}, user int, opt *ApproveAccessRequestOptions, options ...RequestOptionFunc) (*AccessRequest, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/access_requests/%d/approve", pathEscape(group), user)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ar := new(AccessRequest)
|
||||||
|
resp, err := s.client.Do(req, ar)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ar, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DenyProjectAccessRequest denies an access request for the given user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#deny-an-access-request
|
||||||
|
func (s *AccessRequestsService) DenyProjectAccessRequest(pid interface{}, user int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/access_requests/%d", pathEscape(project), user)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DenyGroupAccessRequest denies an access request for the given user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#deny-an-access-request
|
||||||
|
func (s *AccessRequestsService) DenyGroupAccessRequest(gid interface{}, user int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/access_requests/%d", pathEscape(group), user)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
106
vendor/github.com/xanzy/go-gitlab/applications.go
generated
vendored
Normal file
106
vendor/github.com/xanzy/go-gitlab/applications.go
generated
vendored
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ApplicationsService handles communication with administrables applications
|
||||||
|
// of the Gitlab API.
|
||||||
|
//
|
||||||
|
// Gitlab API docs : https://docs.gitlab.com/ee/api/applications.html
|
||||||
|
type ApplicationsService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Application represents a GitLab application
|
||||||
|
type Application struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
ApplicationID string `json:"application_id"`
|
||||||
|
ApplicationName string `json:"application_name"`
|
||||||
|
Secret string `json:"secret"`
|
||||||
|
CallbackURL string `json:"callback_url"`
|
||||||
|
Confidential bool `json:"confidential"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateApplicationOptions represents the available CreateApplication() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/applications.html#create-an-application
|
||||||
|
type CreateApplicationOptions struct {
|
||||||
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
|
RedirectURI *string `url:"redirect_uri,omitempty" json:"redirect_uri,omitempty"`
|
||||||
|
Scopes *string `url:"scopes,omitempty" json:"scopes,omitempty"`
|
||||||
|
Confidential *bool `url:"confidential,omitempty" json:"confidential,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateApplication creates a new application owned by the authenticated user.
|
||||||
|
//
|
||||||
|
// Gitlab API docs : https://docs.gitlab.com/ce/api/applications.html#create-an-application
|
||||||
|
func (s *ApplicationsService) CreateApplication(opt *CreateApplicationOptions, options ...RequestOptionFunc) (*Application, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, "applications", opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
a := new(Application)
|
||||||
|
resp, err := s.client.Do(req, a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListApplicationsOptions represents the available
|
||||||
|
// ListApplications() options.
|
||||||
|
type ListApplicationsOptions ListOptions
|
||||||
|
|
||||||
|
// ListApplications get a list of administrables applications by the authenticated user
|
||||||
|
//
|
||||||
|
// Gitlab API docs : https://docs.gitlab.com/ce/api/applications.html#list-all-applications
|
||||||
|
func (s *ApplicationsService) ListApplications(opt *ListApplicationsOptions, options ...RequestOptionFunc) ([]*Application, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, "applications", opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var as []*Application
|
||||||
|
resp, err := s.client.Do(req, &as)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return as, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteApplication removes a specific application.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/applications.html#delete-an-application
|
||||||
|
func (s *ApplicationsService) DeleteApplication(application int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
u := fmt.Sprintf("applications/%d", application)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
199
vendor/github.com/xanzy/go-gitlab/audit_events.go
generated
vendored
Normal file
199
vendor/github.com/xanzy/go-gitlab/audit_events.go
generated
vendored
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AuditEvent represents an audit event for a group, a project or the instance.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/audit_events.html
|
||||||
|
type AuditEvent struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
AuthorID int `json:"author_id"`
|
||||||
|
EntityID int `json:"entity_id"`
|
||||||
|
EntityType string `json:"entity_type"`
|
||||||
|
Details AuditEventDetails `json:"details"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuditEventDetails represents the details portion of an audit event for
|
||||||
|
// a group, a project or the instance. The exact fields that are returned
|
||||||
|
// for an audit event depend on the action being recorded.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/audit_events.html
|
||||||
|
type AuditEventDetails struct {
|
||||||
|
With string `json:"with"`
|
||||||
|
Add string `json:"add"`
|
||||||
|
As string `json:"as"`
|
||||||
|
Change string `json:"change"`
|
||||||
|
From string `json:"from"`
|
||||||
|
To string `json:"to"`
|
||||||
|
Remove string `json:"remove"`
|
||||||
|
CustomMessage string `json:"custom_message"`
|
||||||
|
AuthorName string `json:"author_name"`
|
||||||
|
TargetID interface{} `json:"target_id"`
|
||||||
|
TargetType string `json:"target_type"`
|
||||||
|
TargetDetails string `json:"target_details"`
|
||||||
|
IPAddress string `json:"ip_address"`
|
||||||
|
EntityPath string `json:"entity_path"`
|
||||||
|
FailedLogin string `json:"failed_login"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuditEventsService handles communication with the project/group/instance
|
||||||
|
// audit event related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/audit_events.html
|
||||||
|
type AuditEventsService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAuditEventsOptions represents the available ListProjectAuditEvents(),
|
||||||
|
// ListGroupAuditEvents() or ListInstanceAuditEvents() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/audit_events.html
|
||||||
|
type ListAuditEventsOptions struct {
|
||||||
|
ListOptions
|
||||||
|
CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
|
||||||
|
CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListInstanceAuditEvents gets a list of audit events for instance.
|
||||||
|
// Authentication as Administrator is required.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/audit_events.html
|
||||||
|
func (s *AuditEventsService) ListInstanceAuditEvents(opt *ListAuditEventsOptions, options ...RequestOptionFunc) ([]*AuditEvent, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, "audit_events", opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var aes []*AuditEvent
|
||||||
|
resp, err := s.client.Do(req, &aes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return aes, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInstanceAuditEvent gets a specific instance audit event.
|
||||||
|
// Authentication as Administrator is required.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/audit_events.html
|
||||||
|
func (s *AuditEventsService) GetInstanceAuditEvent(event int, options ...RequestOptionFunc) (*AuditEvent, *Response, error) {
|
||||||
|
u := fmt.Sprintf("audit_events/%d", event)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ae := new(AuditEvent)
|
||||||
|
resp, err := s.client.Do(req, ae)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ae, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupAuditEvents gets a list of audit events for the specified group
|
||||||
|
// viewable by the authenticated user.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/audit_events.html
|
||||||
|
func (s *AuditEventsService) ListGroupAuditEvents(gid interface{}, opt *ListAuditEventsOptions, options ...RequestOptionFunc) ([]*AuditEvent, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/audit_events", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var aes []*AuditEvent
|
||||||
|
resp, err := s.client.Do(req, &aes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return aes, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupAuditEvent gets a specific group audit event.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/audit_events.html
|
||||||
|
func (s *AuditEventsService) GetGroupAuditEvent(gid interface{}, event int, options ...RequestOptionFunc) (*AuditEvent, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/audit_events/%d", pathEscape(group), event)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ae := new(AuditEvent)
|
||||||
|
resp, err := s.client.Do(req, ae)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ae, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListProjectAuditEvents gets a list of audit events for the specified project
|
||||||
|
// viewable by the authenticated user.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/audit_events.html
|
||||||
|
func (s *AuditEventsService) ListProjectAuditEvents(pid interface{}, opt *ListAuditEventsOptions, options ...RequestOptionFunc) ([]*AuditEvent, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/audit_events", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var aes []*AuditEvent
|
||||||
|
resp, err := s.client.Do(req, &aes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return aes, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProjectAuditEvent gets a specific project audit event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/audit_events.html
|
||||||
|
func (s *AuditEventsService) GetProjectAuditEvent(pid interface{}, event int, options ...RequestOptionFunc) (*AuditEvent, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/audit_events/%d", pathEscape(project), event)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ae := new(AuditEvent)
|
||||||
|
resp, err := s.client.Do(req, ae)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ae, resp, err
|
||||||
|
}
|
64
vendor/github.com/xanzy/go-gitlab/avatar.go
generated
vendored
Normal file
64
vendor/github.com/xanzy/go-gitlab/avatar.go
generated
vendored
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Pavel Kostohrys
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AvatarRequestsService handles communication with the avatar related methods
|
||||||
|
// of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/avatar.html
|
||||||
|
type AvatarRequestsService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avatar represents a GitLab avatar.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/avatar.html
|
||||||
|
type Avatar struct {
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAvatarOptions represents the available GetAvatar() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/avatar.html#get-a-single-avatar-url
|
||||||
|
type GetAvatarOptions struct {
|
||||||
|
Email *string `url:"email,omitempty" json:"email,omitempty"`
|
||||||
|
Size *int `url:"size,omitempty" json:"size,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAvatar gets the avatar URL for a user with the given email address.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/avatar.html#get-a-single-avatar-url
|
||||||
|
func (s *AvatarRequestsService) GetAvatar(opt *GetAvatarOptions, options ...RequestOptionFunc) (*Avatar, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, "avatar", opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
avatar := new(Avatar)
|
||||||
|
response, err := s.client.Do(req, avatar)
|
||||||
|
if err != nil {
|
||||||
|
return nil, response, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return avatar, response, nil
|
||||||
|
}
|
468
vendor/github.com/xanzy/go-gitlab/award_emojis.go
generated
vendored
Normal file
468
vendor/github.com/xanzy/go-gitlab/award_emojis.go
generated
vendored
Normal file
|
@ -0,0 +1,468 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Arkbriar
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AwardEmojiService handles communication with the emoji awards related methods
|
||||||
|
// of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/award_emoji.html
|
||||||
|
type AwardEmojiService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// AwardEmoji represents a GitLab Award Emoji.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/award_emoji.html
|
||||||
|
type AwardEmoji struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
User struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
ID int `json:"id"`
|
||||||
|
State string `json:"state"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
} `json:"user"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
UpdatedAt *time.Time `json:"updated_at"`
|
||||||
|
AwardableID int `json:"awardable_id"`
|
||||||
|
AwardableType string `json:"awardable_type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
awardMergeRequest = "merge_requests"
|
||||||
|
awardIssue = "issues"
|
||||||
|
awardSnippets = "snippets"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListAwardEmojiOptions represents the available options for listing emoji
|
||||||
|
// for each resources
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html
|
||||||
|
type ListAwardEmojiOptions ListOptions
|
||||||
|
|
||||||
|
// ListMergeRequestAwardEmoji gets a list of all award emoji on the merge request.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji
|
||||||
|
func (s *AwardEmojiService) ListMergeRequestAwardEmoji(pid interface{}, mergeRequestIID int, opt *ListAwardEmojiOptions, options ...RequestOptionFunc) ([]*AwardEmoji, *Response, error) {
|
||||||
|
return s.listAwardEmoji(pid, awardMergeRequest, mergeRequestIID, opt, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListIssueAwardEmoji gets a list of all award emoji on the issue.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji
|
||||||
|
func (s *AwardEmojiService) ListIssueAwardEmoji(pid interface{}, issueIID int, opt *ListAwardEmojiOptions, options ...RequestOptionFunc) ([]*AwardEmoji, *Response, error) {
|
||||||
|
return s.listAwardEmoji(pid, awardIssue, issueIID, opt, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListSnippetAwardEmoji gets a list of all award emoji on the snippet.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji
|
||||||
|
func (s *AwardEmojiService) ListSnippetAwardEmoji(pid interface{}, snippetID int, opt *ListAwardEmojiOptions, options ...RequestOptionFunc) ([]*AwardEmoji, *Response, error) {
|
||||||
|
return s.listAwardEmoji(pid, awardSnippets, snippetID, opt, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AwardEmojiService) listAwardEmoji(pid interface{}, resource string, resourceID int, opt *ListAwardEmojiOptions, options ...RequestOptionFunc) ([]*AwardEmoji, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/%s/%d/award_emoji",
|
||||||
|
pathEscape(project),
|
||||||
|
resource,
|
||||||
|
resourceID,
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var as []*AwardEmoji
|
||||||
|
resp, err := s.client.Do(req, &as)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return as, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMergeRequestAwardEmoji get an award emoji from merge request.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji
|
||||||
|
func (s *AwardEmojiService) GetMergeRequestAwardEmoji(pid interface{}, mergeRequestIID, awardID int, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) {
|
||||||
|
return s.getAwardEmoji(pid, awardMergeRequest, mergeRequestIID, awardID, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIssueAwardEmoji get an award emoji from issue.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji
|
||||||
|
func (s *AwardEmojiService) GetIssueAwardEmoji(pid interface{}, issueIID, awardID int, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) {
|
||||||
|
return s.getAwardEmoji(pid, awardIssue, issueIID, awardID, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSnippetAwardEmoji get an award emoji from snippet.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji
|
||||||
|
func (s *AwardEmojiService) GetSnippetAwardEmoji(pid interface{}, snippetID, awardID int, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) {
|
||||||
|
return s.getAwardEmoji(pid, awardSnippets, snippetID, awardID, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AwardEmojiService) getAwardEmoji(pid interface{}, resource string, resourceID, awardID int, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/%s/%d/award_emoji/%d",
|
||||||
|
pathEscape(project),
|
||||||
|
resource,
|
||||||
|
resourceID,
|
||||||
|
awardID,
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
a := new(AwardEmoji)
|
||||||
|
resp, err := s.client.Do(req, &a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateAwardEmojiOptions represents the available options for awarding emoji
|
||||||
|
// for a resource
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji
|
||||||
|
type CreateAwardEmojiOptions struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateMergeRequestAwardEmoji get an award emoji from merge request.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji
|
||||||
|
func (s *AwardEmojiService) CreateMergeRequestAwardEmoji(pid interface{}, mergeRequestIID int, opt *CreateAwardEmojiOptions, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) {
|
||||||
|
return s.createAwardEmoji(pid, awardMergeRequest, mergeRequestIID, opt, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateIssueAwardEmoji get an award emoji from issue.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji
|
||||||
|
func (s *AwardEmojiService) CreateIssueAwardEmoji(pid interface{}, issueIID int, opt *CreateAwardEmojiOptions, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) {
|
||||||
|
return s.createAwardEmoji(pid, awardIssue, issueIID, opt, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateSnippetAwardEmoji get an award emoji from snippet.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji
|
||||||
|
func (s *AwardEmojiService) CreateSnippetAwardEmoji(pid interface{}, snippetID int, opt *CreateAwardEmojiOptions, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) {
|
||||||
|
return s.createAwardEmoji(pid, awardSnippets, snippetID, opt, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AwardEmojiService) createAwardEmoji(pid interface{}, resource string, resourceID int, opt *CreateAwardEmojiOptions, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/%s/%d/award_emoji",
|
||||||
|
pathEscape(project),
|
||||||
|
resource,
|
||||||
|
resourceID,
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
a := new(AwardEmoji)
|
||||||
|
resp, err := s.client.Do(req, &a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteIssueAwardEmoji delete award emoji on an issue.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji-on-a-note
|
||||||
|
func (s *AwardEmojiService) DeleteIssueAwardEmoji(pid interface{}, issueIID, awardID int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
return s.deleteAwardEmoji(pid, awardMergeRequest, issueIID, awardID, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMergeRequestAwardEmoji delete award emoji on a merge request.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji-on-a-note
|
||||||
|
func (s *AwardEmojiService) DeleteMergeRequestAwardEmoji(pid interface{}, mergeRequestIID, awardID int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
return s.deleteAwardEmoji(pid, awardMergeRequest, mergeRequestIID, awardID, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteSnippetAwardEmoji delete award emoji on a snippet.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji-on-a-note
|
||||||
|
func (s *AwardEmojiService) DeleteSnippetAwardEmoji(pid interface{}, snippetID, awardID int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
return s.deleteAwardEmoji(pid, awardMergeRequest, snippetID, awardID, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAwardEmoji Delete an award emoji on the specified resource.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#delete-an-award-emoji
|
||||||
|
func (s *AwardEmojiService) deleteAwardEmoji(pid interface{}, resource string, resourceID, awardID int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/%s/%d/award_emoji/%d", pathEscape(project), resource,
|
||||||
|
resourceID, awardID)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListIssuesAwardEmojiOnNote gets a list of all award emoji on a note from the
|
||||||
|
// issue.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes
|
||||||
|
func (s *AwardEmojiService) ListIssuesAwardEmojiOnNote(pid interface{}, issueID, noteID int, opt *ListAwardEmojiOptions, options ...RequestOptionFunc) ([]*AwardEmoji, *Response, error) {
|
||||||
|
return s.listAwardEmojiOnNote(pid, awardIssue, issueID, noteID, opt, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListMergeRequestAwardEmojiOnNote gets a list of all award emoji on a note
|
||||||
|
// from the merge request.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes
|
||||||
|
func (s *AwardEmojiService) ListMergeRequestAwardEmojiOnNote(pid interface{}, mergeRequestIID, noteID int, opt *ListAwardEmojiOptions, options ...RequestOptionFunc) ([]*AwardEmoji, *Response, error) {
|
||||||
|
return s.listAwardEmojiOnNote(pid, awardMergeRequest, mergeRequestIID, noteID, opt, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListSnippetAwardEmojiOnNote gets a list of all award emoji on a note from the
|
||||||
|
// snippet.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes
|
||||||
|
func (s *AwardEmojiService) ListSnippetAwardEmojiOnNote(pid interface{}, snippetIID, noteID int, opt *ListAwardEmojiOptions, options ...RequestOptionFunc) ([]*AwardEmoji, *Response, error) {
|
||||||
|
return s.listAwardEmojiOnNote(pid, awardSnippets, snippetIID, noteID, opt, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AwardEmojiService) listAwardEmojiOnNote(pid interface{}, resources string, ressourceID, noteID int, opt *ListAwardEmojiOptions, options ...RequestOptionFunc) ([]*AwardEmoji, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/%s/%d/notes/%d/award_emoji", pathEscape(project), resources,
|
||||||
|
ressourceID, noteID)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var as []*AwardEmoji
|
||||||
|
resp, err := s.client.Do(req, &as)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return as, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIssuesAwardEmojiOnNote gets an award emoji on a note from an issue.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes
|
||||||
|
func (s *AwardEmojiService) GetIssuesAwardEmojiOnNote(pid interface{}, issueID, noteID, awardID int, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) {
|
||||||
|
return s.getSingleNoteAwardEmoji(pid, awardIssue, issueID, noteID, awardID, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMergeRequestAwardEmojiOnNote gets an award emoji on a note from a
|
||||||
|
// merge request.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes
|
||||||
|
func (s *AwardEmojiService) GetMergeRequestAwardEmojiOnNote(pid interface{}, mergeRequestIID, noteID, awardID int, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) {
|
||||||
|
return s.getSingleNoteAwardEmoji(pid, awardMergeRequest, mergeRequestIID, noteID, awardID,
|
||||||
|
options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSnippetAwardEmojiOnNote gets an award emoji on a note from a snippet.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes
|
||||||
|
func (s *AwardEmojiService) GetSnippetAwardEmojiOnNote(pid interface{}, snippetIID, noteID, awardID int, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) {
|
||||||
|
return s.getSingleNoteAwardEmoji(pid, awardSnippets, snippetIID, noteID, awardID, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AwardEmojiService) getSingleNoteAwardEmoji(pid interface{}, ressource string, resourceID, noteID, awardID int, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/%s/%d/notes/%d/award_emoji/%d",
|
||||||
|
pathEscape(project),
|
||||||
|
ressource,
|
||||||
|
resourceID,
|
||||||
|
noteID,
|
||||||
|
awardID,
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
a := new(AwardEmoji)
|
||||||
|
resp, err := s.client.Do(req, &a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateIssuesAwardEmojiOnNote gets an award emoji on a note from an issue.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes
|
||||||
|
func (s *AwardEmojiService) CreateIssuesAwardEmojiOnNote(pid interface{}, issueID, noteID int, opt *CreateAwardEmojiOptions, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) {
|
||||||
|
return s.createAwardEmojiOnNote(pid, awardIssue, issueID, noteID, opt, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateMergeRequestAwardEmojiOnNote gets an award emoji on a note from a
|
||||||
|
// merge request.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes
|
||||||
|
func (s *AwardEmojiService) CreateMergeRequestAwardEmojiOnNote(pid interface{}, mergeRequestIID, noteID int, opt *CreateAwardEmojiOptions, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) {
|
||||||
|
return s.createAwardEmojiOnNote(pid, awardMergeRequest, mergeRequestIID, noteID, opt, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateSnippetAwardEmojiOnNote gets an award emoji on a note from a snippet.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes
|
||||||
|
func (s *AwardEmojiService) CreateSnippetAwardEmojiOnNote(pid interface{}, snippetIID, noteID int, opt *CreateAwardEmojiOptions, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) {
|
||||||
|
return s.createAwardEmojiOnNote(pid, awardSnippets, snippetIID, noteID, opt, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateAwardEmojiOnNote award emoji on a note.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji-on-a-note
|
||||||
|
func (s *AwardEmojiService) createAwardEmojiOnNote(pid interface{}, resource string, resourceID, noteID int, opt *CreateAwardEmojiOptions, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/%s/%d/notes/%d/award_emoji",
|
||||||
|
pathEscape(project),
|
||||||
|
resource,
|
||||||
|
resourceID,
|
||||||
|
noteID,
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
a := new(AwardEmoji)
|
||||||
|
resp, err := s.client.Do(req, &a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteIssuesAwardEmojiOnNote deletes an award emoji on a note from an issue.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes
|
||||||
|
func (s *AwardEmojiService) DeleteIssuesAwardEmojiOnNote(pid interface{}, issueID, noteID, awardID int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
return s.deleteAwardEmojiOnNote(pid, awardIssue, issueID, noteID, awardID, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMergeRequestAwardEmojiOnNote deletes an award emoji on a note from a
|
||||||
|
// merge request.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes
|
||||||
|
func (s *AwardEmojiService) DeleteMergeRequestAwardEmojiOnNote(pid interface{}, mergeRequestIID, noteID, awardID int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
return s.deleteAwardEmojiOnNote(pid, awardMergeRequest, mergeRequestIID, noteID, awardID,
|
||||||
|
options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteSnippetAwardEmojiOnNote deletes an award emoji on a note from a snippet.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes
|
||||||
|
func (s *AwardEmojiService) DeleteSnippetAwardEmojiOnNote(pid interface{}, snippetIID, noteID, awardID int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
return s.deleteAwardEmojiOnNote(pid, awardSnippets, snippetIID, noteID, awardID, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AwardEmojiService) deleteAwardEmojiOnNote(pid interface{}, resource string, resourceID, noteID, awardID int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/%s/%d/notes/%d/award_emoji/%d",
|
||||||
|
pathEscape(project),
|
||||||
|
resource,
|
||||||
|
resourceID,
|
||||||
|
noteID,
|
||||||
|
awardID,
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
345
vendor/github.com/xanzy/go-gitlab/boards.go
generated
vendored
Normal file
345
vendor/github.com/xanzy/go-gitlab/boards.go
generated
vendored
Normal file
|
@ -0,0 +1,345 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IssueBoardsService handles communication with the issue board related
|
||||||
|
// methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html
|
||||||
|
type IssueBoardsService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// IssueBoard represents a GitLab issue board.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html
|
||||||
|
type IssueBoard struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Project *Project `json:"project"`
|
||||||
|
Milestone *Milestone `json:"milestone"`
|
||||||
|
Lists []*BoardList `json:"lists"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b IssueBoard) String() string {
|
||||||
|
return Stringify(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoardList represents a GitLab board list.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html
|
||||||
|
type BoardList struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Label *Label `json:"label"`
|
||||||
|
Position int `json:"position"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b BoardList) String() string {
|
||||||
|
return Stringify(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateIssueBoardOptions represents the available CreateIssueBoard() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/boards.html#create-a-board-starter
|
||||||
|
type CreateIssueBoardOptions struct {
|
||||||
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateIssueBoard creates a new issue board.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/boards.html#create-a-board-starter
|
||||||
|
func (s *IssueBoardsService) CreateIssueBoard(pid interface{}, opt *CreateIssueBoardOptions, options ...RequestOptionFunc) (*IssueBoard, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/boards", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
board := new(IssueBoard)
|
||||||
|
resp, err := s.client.Do(req, board)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return board, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateIssueBoardOptions represents the available UpdateIssueBoard() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/boards.html#update-a-board-starter
|
||||||
|
type UpdateIssueBoardOptions struct {
|
||||||
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
|
AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
|
||||||
|
MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"`
|
||||||
|
Labels Labels `url:"labels,omitempty" json:"labels,omitempty"`
|
||||||
|
Weight *int `url:"weight,omitempty" json:"weight,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateIssueBoard update an issue board.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/boards.html#create-a-board-starter
|
||||||
|
func (s *IssueBoardsService) UpdateIssueBoard(pid interface{}, board int, opt *UpdateIssueBoardOptions, options ...RequestOptionFunc) (*IssueBoard, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/boards/%d", pathEscape(project), board)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
is := new(IssueBoard)
|
||||||
|
resp, err := s.client.Do(req, is)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return is, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteIssueBoard deletes an issue board.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/boards.html#delete-a-board-starter
|
||||||
|
func (s *IssueBoardsService) DeleteIssueBoard(pid interface{}, board int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/boards/%d", pathEscape(project), board)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListIssueBoardsOptions represents the available ListIssueBoards() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#project-board
|
||||||
|
type ListIssueBoardsOptions ListOptions
|
||||||
|
|
||||||
|
// ListIssueBoards gets a list of all issue boards in a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#project-board
|
||||||
|
func (s *IssueBoardsService) ListIssueBoards(pid interface{}, opt *ListIssueBoardsOptions, options ...RequestOptionFunc) ([]*IssueBoard, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/boards", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var is []*IssueBoard
|
||||||
|
resp, err := s.client.Do(req, &is)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return is, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIssueBoard gets a single issue board of a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#single-board
|
||||||
|
func (s *IssueBoardsService) GetIssueBoard(pid interface{}, board int, options ...RequestOptionFunc) (*IssueBoard, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/boards/%d", pathEscape(project), board)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ib := new(IssueBoard)
|
||||||
|
resp, err := s.client.Do(req, ib)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ib, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIssueBoardListsOptions represents the available GetIssueBoardLists() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#list-board-lists
|
||||||
|
type GetIssueBoardListsOptions ListOptions
|
||||||
|
|
||||||
|
// GetIssueBoardLists gets a list of the issue board's lists. Does not include
|
||||||
|
// backlog and closed lists.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#list-board-lists
|
||||||
|
func (s *IssueBoardsService) GetIssueBoardLists(pid interface{}, board int, opt *GetIssueBoardListsOptions, options ...RequestOptionFunc) ([]*BoardList, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/boards/%d/lists", pathEscape(project), board)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var bl []*BoardList
|
||||||
|
resp, err := s.client.Do(req, &bl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bl, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIssueBoardList gets a single issue board list.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#single-board-list
|
||||||
|
func (s *IssueBoardsService) GetIssueBoardList(pid interface{}, board, list int, options ...RequestOptionFunc) (*BoardList, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/boards/%d/lists/%d",
|
||||||
|
pathEscape(project),
|
||||||
|
board,
|
||||||
|
list,
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bl := new(BoardList)
|
||||||
|
resp, err := s.client.Do(req, bl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bl, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateIssueBoardListOptions represents the available CreateIssueBoardList()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#new-board-list
|
||||||
|
type CreateIssueBoardListOptions struct {
|
||||||
|
LabelID *int `url:"label_id" json:"label_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateIssueBoardList creates a new issue board list.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#new-board-list
|
||||||
|
func (s *IssueBoardsService) CreateIssueBoardList(pid interface{}, board int, opt *CreateIssueBoardListOptions, options ...RequestOptionFunc) (*BoardList, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/boards/%d/lists", pathEscape(project), board)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bl := new(BoardList)
|
||||||
|
resp, err := s.client.Do(req, bl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bl, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateIssueBoardListOptions represents the available UpdateIssueBoardList()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#edit-board-list
|
||||||
|
type UpdateIssueBoardListOptions struct {
|
||||||
|
Position *int `url:"position" json:"position"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateIssueBoardList updates the position of an existing issue board list.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#edit-board-list
|
||||||
|
func (s *IssueBoardsService) UpdateIssueBoardList(pid interface{}, board, list int, opt *UpdateIssueBoardListOptions, options ...RequestOptionFunc) (*BoardList, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/boards/%d/lists/%d",
|
||||||
|
pathEscape(project),
|
||||||
|
board,
|
||||||
|
list,
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bl := new(BoardList)
|
||||||
|
resp, err := s.client.Do(req, bl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bl, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteIssueBoardList soft deletes an issue board list. Only for admins and
|
||||||
|
// project owners.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/boards.html#delete-a-board-list
|
||||||
|
func (s *IssueBoardsService) DeleteIssueBoardList(pid interface{}, board, list int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/boards/%d/lists/%d",
|
||||||
|
pathEscape(project),
|
||||||
|
board,
|
||||||
|
list,
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
245
vendor/github.com/xanzy/go-gitlab/branches.go
generated
vendored
Normal file
245
vendor/github.com/xanzy/go-gitlab/branches.go
generated
vendored
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BranchesService handles communication with the branch related methods
|
||||||
|
// of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/branches.html
|
||||||
|
type BranchesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Branch represents a GitLab branch.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/branches.html
|
||||||
|
type Branch struct {
|
||||||
|
Commit *Commit `json:"commit"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Protected bool `json:"protected"`
|
||||||
|
Merged bool `json:"merged"`
|
||||||
|
Default bool `json:"default"`
|
||||||
|
CanPush bool `json:"can_push"`
|
||||||
|
DevelopersCanPush bool `json:"developers_can_push"`
|
||||||
|
DevelopersCanMerge bool `json:"developers_can_merge"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Branch) String() string {
|
||||||
|
return Stringify(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListBranchesOptions represents the available ListBranches() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/branches.html#list-repository-branches
|
||||||
|
type ListBranchesOptions struct {
|
||||||
|
ListOptions
|
||||||
|
Search *string `url:"search,omitempty" json:"search,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListBranches gets a list of repository branches from a project, sorted by
|
||||||
|
// name alphabetically.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/branches.html#list-repository-branches
|
||||||
|
func (s *BranchesService) ListBranches(pid interface{}, opts *ListBranchesOptions, options ...RequestOptionFunc) ([]*Branch, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/branches", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opts, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var b []*Branch
|
||||||
|
resp, err := s.client.Do(req, &b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBranch gets a single project repository branch.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/branches.html#get-single-repository-branch
|
||||||
|
func (s *BranchesService) GetBranch(pid interface{}, branch string, options ...RequestOptionFunc) (*Branch, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/branches/%s", pathEscape(project), url.PathEscape(branch))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b := new(Branch)
|
||||||
|
resp, err := s.client.Do(req, b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProtectBranchOptions represents the available ProtectBranch() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/branches.html#protect-repository-branch
|
||||||
|
type ProtectBranchOptions struct {
|
||||||
|
DevelopersCanPush *bool `url:"developers_can_push,omitempty" json:"developers_can_push,omitempty"`
|
||||||
|
DevelopersCanMerge *bool `url:"developers_can_merge,omitempty" json:"developers_can_merge,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProtectBranch protects a single project repository branch. This is an
|
||||||
|
// idempotent function, protecting an already protected repository branch
|
||||||
|
// still returns a 200 OK status code.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/branches.html#protect-repository-branch
|
||||||
|
func (s *BranchesService) ProtectBranch(pid interface{}, branch string, opts *ProtectBranchOptions, options ...RequestOptionFunc) (*Branch, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/branches/%s/protect", pathEscape(project), url.PathEscape(branch))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opts, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b := new(Branch)
|
||||||
|
resp, err := s.client.Do(req, b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnprotectBranch unprotects a single project repository branch. This is an
|
||||||
|
// idempotent function, unprotecting an already unprotected repository branch
|
||||||
|
// still returns a 200 OK status code.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/branches.html#unprotect-repository-branch
|
||||||
|
func (s *BranchesService) UnprotectBranch(pid interface{}, branch string, options ...RequestOptionFunc) (*Branch, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/branches/%s/unprotect", pathEscape(project), url.PathEscape(branch))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b := new(Branch)
|
||||||
|
resp, err := s.client.Do(req, b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateBranchOptions represents the available CreateBranch() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/branches.html#create-repository-branch
|
||||||
|
type CreateBranchOptions struct {
|
||||||
|
Branch *string `url:"branch,omitempty" json:"branch,omitempty"`
|
||||||
|
Ref *string `url:"ref,omitempty" json:"ref,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateBranch creates branch from commit SHA or existing branch.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/branches.html#create-repository-branch
|
||||||
|
func (s *BranchesService) CreateBranch(pid interface{}, opt *CreateBranchOptions, options ...RequestOptionFunc) (*Branch, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/branches", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b := new(Branch)
|
||||||
|
resp, err := s.client.Do(req, b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBranch deletes an existing branch.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/branches.html#delete-repository-branch
|
||||||
|
func (s *BranchesService) DeleteBranch(pid interface{}, branch string, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/branches/%s", pathEscape(project), url.PathEscape(branch))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMergedBranches deletes all branches that are merged into the project's default branch.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/branches.html#delete-merged-branches
|
||||||
|
func (s *BranchesService) DeleteMergedBranches(pid interface{}, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/merged_branches", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
173
vendor/github.com/xanzy/go-gitlab/broadcast_messages.go
generated
vendored
Normal file
173
vendor/github.com/xanzy/go-gitlab/broadcast_messages.go
generated
vendored
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BroadcastMessagesService handles communication with the broadcast
|
||||||
|
// messages methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/broadcast_messages.html
|
||||||
|
type BroadcastMessagesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// BroadcastMessage represents a GitLab issue board.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/broadcast_messages.html#get-all-broadcast-messages
|
||||||
|
type BroadcastMessage struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
StartsAt *time.Time `json:"starts_at"`
|
||||||
|
EndsAt *time.Time `json:"ends_at"`
|
||||||
|
Color string `json:"color"`
|
||||||
|
Font string `json:"font"`
|
||||||
|
ID int `json:"id"`
|
||||||
|
Active bool `json:"active"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListBroadcastMessagesOptions represents the available ListBroadcastMessages()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/broadcast_messages.html#get-all-broadcast-messages
|
||||||
|
type ListBroadcastMessagesOptions ListOptions
|
||||||
|
|
||||||
|
// ListBroadcastMessages gets a list of all broadcasted messages.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/broadcast_messages.html#get-all-broadcast-messages
|
||||||
|
func (s *BroadcastMessagesService) ListBroadcastMessages(opt *ListBroadcastMessagesOptions, options ...RequestOptionFunc) ([]*BroadcastMessage, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, "broadcast_messages", opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var bs []*BroadcastMessage
|
||||||
|
resp, err := s.client.Do(req, &bs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bs, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBroadcastMessage gets a single broadcast message.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/broadcast_messages.html#get-a-specific-broadcast-message
|
||||||
|
func (s *BroadcastMessagesService) GetBroadcastMessage(broadcast int, options ...RequestOptionFunc) (*BroadcastMessage, *Response, error) {
|
||||||
|
u := fmt.Sprintf("broadcast_messages/%d", broadcast)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b := new(BroadcastMessage)
|
||||||
|
resp, err := s.client.Do(req, &b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateBroadcastMessageOptions represents the available CreateBroadcastMessage()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/broadcast_messages.html#create-a-broadcast-message
|
||||||
|
type CreateBroadcastMessageOptions struct {
|
||||||
|
Message *string `url:"message" json:"message"`
|
||||||
|
StartsAt *time.Time `url:"starts_at,omitempty" json:"starts_at,omitempty"`
|
||||||
|
EndsAt *time.Time `url:"ends_at,omitempty" json:"ends_at,omitempty"`
|
||||||
|
Color *string `url:"color,omitempty" json:"color,omitempty"`
|
||||||
|
Font *string `url:"font,omitempty" json:"font,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateBroadcastMessage creates a message to broadcast.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/broadcast_messages.html#create-a-broadcast-message
|
||||||
|
func (s *BroadcastMessagesService) CreateBroadcastMessage(opt *CreateBroadcastMessageOptions, options ...RequestOptionFunc) (*BroadcastMessage, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, "broadcast_messages", opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b := new(BroadcastMessage)
|
||||||
|
resp, err := s.client.Do(req, &b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateBroadcastMessageOptions represents the available CreateBroadcastMessage()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/broadcast_messages.html#update-a-broadcast-message
|
||||||
|
type UpdateBroadcastMessageOptions struct {
|
||||||
|
Message *string `url:"message,omitempty" json:"message,omitempty"`
|
||||||
|
StartsAt *time.Time `url:"starts_at,omitempty" json:"starts_at,omitempty"`
|
||||||
|
EndsAt *time.Time `url:"ends_at,omitempty" json:"ends_at,omitempty"`
|
||||||
|
Color *string `url:"color,omitempty" json:"color,omitempty"`
|
||||||
|
Font *string `url:"font,omitempty" json:"font,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateBroadcastMessage update a broadcasted message.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/broadcast_messages.html#update-a-broadcast-message
|
||||||
|
func (s *BroadcastMessagesService) UpdateBroadcastMessage(broadcast int, opt *UpdateBroadcastMessageOptions, options ...RequestOptionFunc) (*BroadcastMessage, *Response, error) {
|
||||||
|
u := fmt.Sprintf("broadcast_messages/%d", broadcast)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b := new(BroadcastMessage)
|
||||||
|
resp, err := s.client.Do(req, &b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBroadcastMessage deletes a broadcasted message.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/broadcast_messages.html#delete-a-broadcast-message
|
||||||
|
func (s *BroadcastMessagesService) DeleteBroadcastMessage(broadcast int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
u := fmt.Sprintf("broadcast_messages/%d", broadcast)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
86
vendor/github.com/xanzy/go-gitlab/ci_yml_templates.go
generated
vendored
Normal file
86
vendor/github.com/xanzy/go-gitlab/ci_yml_templates.go
generated
vendored
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CIYMLTemplatesService handles communication with the gitlab
|
||||||
|
// CI YML templates related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/gitlab_ci_ymls.html
|
||||||
|
type CIYMLTemplatesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// CIYMLTemplate represents a GitLab CI YML template.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/gitlab_ci_ymls.html
|
||||||
|
type CIYMLTemplate struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListCIYMLTemplatesOptions represents the available ListAllTemplates() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/gitignores.html#list-gitignore-templates
|
||||||
|
type ListCIYMLTemplatesOptions ListOptions
|
||||||
|
|
||||||
|
// ListAllTemplates get all GitLab CI YML templates.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/gitlab_ci_ymls.html#list-gitlab-ci-yml-templates
|
||||||
|
func (s *CIYMLTemplatesService) ListAllTemplates(opt *ListCIYMLTemplatesOptions, options ...RequestOptionFunc) ([]*CIYMLTemplate, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, "templates/gitlab_ci_ymls", opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var cts []*CIYMLTemplate
|
||||||
|
resp, err := s.client.Do(req, &cts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cts, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTemplate get a single GitLab CI YML template.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/gitlab_ci_ymls.html#single-gitlab-ci-yml-template
|
||||||
|
func (s *CIYMLTemplatesService) GetTemplate(key string, options ...RequestOptionFunc) (*CIYMLTemplate, *Response, error) {
|
||||||
|
u := fmt.Sprintf("templates/gitlab_ci_ymls/%s", pathEscape(key))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ct := new(CIYMLTemplate)
|
||||||
|
resp, err := s.client.Do(req, ct)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ct, resp, err
|
||||||
|
}
|
92
vendor/github.com/xanzy/go-gitlab/client_options.go
generated
vendored
Normal file
92
vendor/github.com/xanzy/go-gitlab/client_options.go
generated
vendored
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
retryablehttp "github.com/hashicorp/go-retryablehttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ClientOptionFunc can be used to customize a new GitLab API client.
|
||||||
|
type ClientOptionFunc func(*Client) error
|
||||||
|
|
||||||
|
// WithBaseURL sets the base URL for API requests to a custom endpoint.
|
||||||
|
func WithBaseURL(urlStr string) ClientOptionFunc {
|
||||||
|
return func(c *Client) error {
|
||||||
|
return c.setBaseURL(urlStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCustomBackoff can be used to configure a custom backoff policy.
|
||||||
|
func WithCustomBackoff(backoff retryablehttp.Backoff) ClientOptionFunc {
|
||||||
|
return func(c *Client) error {
|
||||||
|
c.client.Backoff = backoff
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCustomLeveledLogger can be used to configure a custom retryablehttp
|
||||||
|
// leveled logger.
|
||||||
|
func WithCustomLeveledLogger(leveledLogger retryablehttp.LeveledLogger) ClientOptionFunc {
|
||||||
|
return func(c *Client) error {
|
||||||
|
c.client.Logger = leveledLogger
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCustomLimiter injects a custom rate limiter to the client.
|
||||||
|
func WithCustomLimiter(limiter RateLimiter) ClientOptionFunc {
|
||||||
|
return func(c *Client) error {
|
||||||
|
c.configureLimiterOnce.Do(func() {
|
||||||
|
c.limiter = limiter
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCustomLogger can be used to configure a custom retryablehttp logger.
|
||||||
|
func WithCustomLogger(logger retryablehttp.Logger) ClientOptionFunc {
|
||||||
|
return func(c *Client) error {
|
||||||
|
c.client.Logger = logger
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCustomRetry can be used to configure a custom retry policy.
|
||||||
|
func WithCustomRetry(checkRetry retryablehttp.CheckRetry) ClientOptionFunc {
|
||||||
|
return func(c *Client) error {
|
||||||
|
c.client.CheckRetry = checkRetry
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithHTTPClient can be used to configure a custom HTTP client.
|
||||||
|
func WithHTTPClient(httpClient *http.Client) ClientOptionFunc {
|
||||||
|
return func(c *Client) error {
|
||||||
|
c.client.HTTPClient = httpClient
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithoutRetries disables the default retry logic.
|
||||||
|
func WithoutRetries() ClientOptionFunc {
|
||||||
|
return func(c *Client) error {
|
||||||
|
c.disableRetries = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
593
vendor/github.com/xanzy/go-gitlab/commits.go
generated
vendored
Normal file
593
vendor/github.com/xanzy/go-gitlab/commits.go
generated
vendored
Normal file
|
@ -0,0 +1,593 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CommitsService handles communication with the commit related methods
|
||||||
|
// of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html
|
||||||
|
type CommitsService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit represents a GitLab commit.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html
|
||||||
|
type Commit struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
ShortID string `json:"short_id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
AuthorName string `json:"author_name"`
|
||||||
|
AuthorEmail string `json:"author_email"`
|
||||||
|
AuthoredDate *time.Time `json:"authored_date"`
|
||||||
|
CommitterName string `json:"committer_name"`
|
||||||
|
CommitterEmail string `json:"committer_email"`
|
||||||
|
CommittedDate *time.Time `json:"committed_date"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
ParentIDs []string `json:"parent_ids"`
|
||||||
|
Stats *CommitStats `json:"stats"`
|
||||||
|
Status *BuildStateValue `json:"status"`
|
||||||
|
LastPipeline *PipelineInfo `json:"last_pipeline"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitStats represents the number of added and deleted files in a commit.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html
|
||||||
|
type CommitStats struct {
|
||||||
|
Additions int `json:"additions"`
|
||||||
|
Deletions int `json:"deletions"`
|
||||||
|
Total int `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Commit) String() string {
|
||||||
|
return Stringify(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListCommitsOptions represents the available ListCommits() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#list-repository-commits
|
||||||
|
type ListCommitsOptions struct {
|
||||||
|
ListOptions
|
||||||
|
RefName *string `url:"ref_name,omitempty" json:"ref_name,omitempty"`
|
||||||
|
Since *time.Time `url:"since,omitempty" json:"since,omitempty"`
|
||||||
|
Until *time.Time `url:"until,omitempty" json:"until,omitempty"`
|
||||||
|
Path *string `url:"path,omitempty" json:"path,omitempty"`
|
||||||
|
All *bool `url:"all,omitempty" json:"all,omitempty"`
|
||||||
|
WithStats *bool `url:"with_stats,omitempty" json:"with_stats,omitempty"`
|
||||||
|
FirstParent *bool `url:"first_parent,omitempty" json:"first_parent,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListCommits gets a list of repository commits in a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#list-commits
|
||||||
|
func (s *CommitsService) ListCommits(pid interface{}, opt *ListCommitsOptions, options ...RequestOptionFunc) ([]*Commit, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/commits", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var c []*Commit
|
||||||
|
resp, err := s.client.Do(req, &c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitRef represents the reference of branches/tags in a commit.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/commits.html#get-references-a-commit-is-pushed-to
|
||||||
|
type CommitRef struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCommitRefsOptions represents the available GetCommitRefs() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/commits.html#get-references-a-commit-is-pushed-to
|
||||||
|
type GetCommitRefsOptions struct {
|
||||||
|
ListOptions
|
||||||
|
Type *string `url:"type,omitempty" json:"type,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCommitRefs gets all references (from branches or tags) a commit is pushed to
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/commits.html#get-references-a-commit-is-pushed-to
|
||||||
|
func (s *CommitsService) GetCommitRefs(pid interface{}, sha string, opt *GetCommitRefsOptions, options ...RequestOptionFunc) ([]*CommitRef, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/commits/%s/refs", pathEscape(project), url.PathEscape(sha))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var cs []*CommitRef
|
||||||
|
resp, err := s.client.Do(req, &cs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cs, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCommit gets a specific commit identified by the commit hash or name of a
|
||||||
|
// branch or tag.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-a-single-commit
|
||||||
|
func (s *CommitsService) GetCommit(pid interface{}, sha string, options ...RequestOptionFunc) (*Commit, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if sha == "" {
|
||||||
|
return nil, nil, fmt.Errorf("SHA must be a non-empty string")
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/commits/%s", pathEscape(project), url.PathEscape(sha))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c := new(Commit)
|
||||||
|
resp, err := s.client.Do(req, c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateCommitOptions represents the available options for a new commit.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions
|
||||||
|
type CreateCommitOptions struct {
|
||||||
|
Branch *string `url:"branch,omitempty" json:"branch,omitempty"`
|
||||||
|
CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"`
|
||||||
|
StartBranch *string `url:"start_branch,omitempty" json:"start_branch,omitempty"`
|
||||||
|
StartSHA *string `url:"start_sha,omitempty" json:"start_sha,omitempty"`
|
||||||
|
StartProject *string `url:"start_project,omitempty" json:"start_project,omitempty"`
|
||||||
|
Actions []*CommitActionOptions `url:"actions" json:"actions"`
|
||||||
|
AuthorEmail *string `url:"author_email,omitempty" json:"author_email,omitempty"`
|
||||||
|
AuthorName *string `url:"author_name,omitempty" json:"author_name,omitempty"`
|
||||||
|
Stats *bool `url:"stats,omitempty" json:"stats,omitempty"`
|
||||||
|
Force *bool `url:"force,omitempty" json:"force,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitActionOptions represents the available options for a new single
|
||||||
|
// file action.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions
|
||||||
|
type CommitActionOptions struct {
|
||||||
|
Action *FileActionValue `url:"action,omitempty" json:"action,omitempty"`
|
||||||
|
FilePath *string `url:"file_path,omitempty" json:"file_path,omitempty"`
|
||||||
|
PreviousPath *string `url:"previous_path,omitempty" json:"previous_path,omitempty"`
|
||||||
|
Content *string `url:"content,omitempty" json:"content,omitempty"`
|
||||||
|
Encoding *string `url:"encoding,omitempty" json:"encoding,omitempty"`
|
||||||
|
LastCommitID *string `url:"last_commit_id,omitempty" json:"last_commit_id,omitempty"`
|
||||||
|
ExecuteFilemode *bool `url:"execute_filemode,omitempty" json:"execute_filemode,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateCommit creates a commit with multiple files and actions.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions
|
||||||
|
func (s *CommitsService) CreateCommit(pid interface{}, opt *CreateCommitOptions, options ...RequestOptionFunc) (*Commit, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/commits", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c := new(Commit)
|
||||||
|
resp, err := s.client.Do(req, &c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diff represents a GitLab diff.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html
|
||||||
|
type Diff struct {
|
||||||
|
Diff string `json:"diff"`
|
||||||
|
NewPath string `json:"new_path"`
|
||||||
|
OldPath string `json:"old_path"`
|
||||||
|
AMode string `json:"a_mode"`
|
||||||
|
BMode string `json:"b_mode"`
|
||||||
|
NewFile bool `json:"new_file"`
|
||||||
|
RenamedFile bool `json:"renamed_file"`
|
||||||
|
DeletedFile bool `json:"deleted_file"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d Diff) String() string {
|
||||||
|
return Stringify(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCommitDiffOptions represents the available GetCommitDiff() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/commits.html#get-the-diff-of-a-commit
|
||||||
|
type GetCommitDiffOptions ListOptions
|
||||||
|
|
||||||
|
// GetCommitDiff gets the diff of a commit in a project..
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/commits.html#get-the-diff-of-a-commit
|
||||||
|
func (s *CommitsService) GetCommitDiff(pid interface{}, sha string, opt *GetCommitDiffOptions, options ...RequestOptionFunc) ([]*Diff, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/commits/%s/diff", pathEscape(project), url.PathEscape(sha))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var d []*Diff
|
||||||
|
resp, err := s.client.Do(req, &d)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return d, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitComment represents a GitLab commit comment.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html
|
||||||
|
type CommitComment struct {
|
||||||
|
Note string `json:"note"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
Line int `json:"line"`
|
||||||
|
LineType string `json:"line_type"`
|
||||||
|
Author Author `json:"author"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Author represents a GitLab commit author
|
||||||
|
type Author struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
State string `json:"state"`
|
||||||
|
Blocked bool `json:"blocked"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c CommitComment) String() string {
|
||||||
|
return Stringify(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCommitCommentsOptions represents the available GetCommitComments() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/commits.html#get-the-comments-of-a-commit
|
||||||
|
type GetCommitCommentsOptions ListOptions
|
||||||
|
|
||||||
|
// GetCommitComments gets the comments of a commit in a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/commits.html#get-the-comments-of-a-commit
|
||||||
|
func (s *CommitsService) GetCommitComments(pid interface{}, sha string, opt *GetCommitCommentsOptions, options ...RequestOptionFunc) ([]*CommitComment, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/commits/%s/comments", pathEscape(project), url.PathEscape(sha))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var c []*CommitComment
|
||||||
|
resp, err := s.client.Do(req, &c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostCommitCommentOptions represents the available PostCommitComment()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/commits.html#post-comment-to-commit
|
||||||
|
type PostCommitCommentOptions struct {
|
||||||
|
Note *string `url:"note,omitempty" json:"note,omitempty"`
|
||||||
|
Path *string `url:"path" json:"path"`
|
||||||
|
Line *int `url:"line" json:"line"`
|
||||||
|
LineType *string `url:"line_type" json:"line_type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostCommitComment adds a comment to a commit. Optionally you can post
|
||||||
|
// comments on a specific line of a commit. Therefor both path, line_new and
|
||||||
|
// line_old are required.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/commits.html#post-comment-to-commit
|
||||||
|
func (s *CommitsService) PostCommitComment(pid interface{}, sha string, opt *PostCommitCommentOptions, options ...RequestOptionFunc) (*CommitComment, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/commits/%s/comments", pathEscape(project), url.PathEscape(sha))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c := new(CommitComment)
|
||||||
|
resp, err := s.client.Do(req, c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCommitStatusesOptions represents the available GetCommitStatuses() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-the-status-of-a-commit
|
||||||
|
type GetCommitStatusesOptions struct {
|
||||||
|
ListOptions
|
||||||
|
Ref *string `url:"ref,omitempty" json:"ref,omitempty"`
|
||||||
|
Stage *string `url:"stage,omitempty" json:"stage,omitempty"`
|
||||||
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
|
All *bool `url:"all,omitempty" json:"all,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitStatus represents a GitLab commit status.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-the-status-of-a-commit
|
||||||
|
type CommitStatus struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
SHA string `json:"sha"`
|
||||||
|
Ref string `json:"ref"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
StartedAt *time.Time `json:"started_at"`
|
||||||
|
FinishedAt *time.Time `json:"finished_at"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
AllowFailure bool `json:"allow_failure"`
|
||||||
|
Author Author `json:"author"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
TargetURL string `json:"target_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCommitStatuses gets the statuses of a commit in a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-the-status-of-a-commit
|
||||||
|
func (s *CommitsService) GetCommitStatuses(pid interface{}, sha string, opt *GetCommitStatusesOptions, options ...RequestOptionFunc) ([]*CommitStatus, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/commits/%s/statuses", pathEscape(project), url.PathEscape(sha))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var cs []*CommitStatus
|
||||||
|
resp, err := s.client.Do(req, &cs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cs, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCommitStatusOptions represents the available SetCommitStatus() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#post-the-status-to-commit
|
||||||
|
type SetCommitStatusOptions struct {
|
||||||
|
State BuildStateValue `url:"state" json:"state"`
|
||||||
|
Ref *string `url:"ref,omitempty" json:"ref,omitempty"`
|
||||||
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
|
Context *string `url:"context,omitempty" json:"context,omitempty"`
|
||||||
|
TargetURL *string `url:"target_url,omitempty" json:"target_url,omitempty"`
|
||||||
|
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||||
|
Coverage *float64 `url:"coverage,omitempty" json:"coverage,omitempty"`
|
||||||
|
PipelineID *int `url:"pipeline_id,omitempty" json:"pipeline_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCommitStatus sets the status of a commit in a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#post-the-status-to-commit
|
||||||
|
func (s *CommitsService) SetCommitStatus(pid interface{}, sha string, opt *SetCommitStatusOptions, options ...RequestOptionFunc) (*CommitStatus, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/statuses/%s", pathEscape(project), url.PathEscape(sha))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cs := new(CommitStatus)
|
||||||
|
resp, err := s.client.Do(req, &cs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cs, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMergeRequestsByCommit gets merge request associated with a commit.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/commits.html#list-merge-requests-associated-with-a-commit
|
||||||
|
func (s *CommitsService) GetMergeRequestsByCommit(pid interface{}, sha string, options ...RequestOptionFunc) ([]*MergeRequest, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/commits/%s/merge_requests", pathEscape(project), url.PathEscape(sha))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var mrs []*MergeRequest
|
||||||
|
resp, err := s.client.Do(req, &mrs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return mrs, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CherryPickCommitOptions represents the available CherryPickCommit() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#cherry-pick-a-commit
|
||||||
|
type CherryPickCommitOptions struct {
|
||||||
|
Branch *string `url:"branch,omitempty" json:"branch,omitempty"`
|
||||||
|
DryRun *bool `url:"dry_run,omitempty" json:"dry_run,omitempty"`
|
||||||
|
Message *string `url:"message,omitempty" json:"message,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CherryPickCommit cherry picks a commit to a given branch.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#cherry-pick-a-commit
|
||||||
|
func (s *CommitsService) CherryPickCommit(pid interface{}, sha string, opt *CherryPickCommitOptions, options ...RequestOptionFunc) (*Commit, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/commits/%s/cherry_pick", pathEscape(project), url.PathEscape(sha))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c := new(Commit)
|
||||||
|
resp, err := s.client.Do(req, &c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevertCommitOptions represents the available RevertCommit() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/commits.html#revert-a-commit
|
||||||
|
type RevertCommitOptions struct {
|
||||||
|
Branch *string `url:"branch,omitempty" json:"branch,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevertCommit reverts a commit in a given branch.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/commits.html#revert-a-commit
|
||||||
|
func (s *CommitsService) RevertCommit(pid interface{}, sha string, opt *RevertCommitOptions, options ...RequestOptionFunc) (*Commit, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/commits/%s/revert", pathEscape(project), url.PathEscape(sha))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c := new(Commit)
|
||||||
|
resp, err := s.client.Do(req, &c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GPGSignature represents a Gitlab commit's GPG Signature.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/commits.html#get-gpg-signature-of-a-commit
|
||||||
|
type GPGSignature struct {
|
||||||
|
KeyID int `json:"gpg_key_id"`
|
||||||
|
KeyPrimaryKeyID string `json:"gpg_key_primary_keyid"`
|
||||||
|
KeyUserName string `json:"gpg_key_user_name"`
|
||||||
|
KeyUserEmail string `json:"gpg_key_user_email"`
|
||||||
|
VerificationStatus string `json:"verification_status"`
|
||||||
|
KeySubkeyID int `json:"gpg_key_subkey_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGPGSiganature gets a GPG signature of a commit.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/commits.html#get-gpg-signature-of-a-commit
|
||||||
|
func (s *CommitsService) GetGPGSiganature(pid interface{}, sha string, options ...RequestOptionFunc) (*GPGSignature, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/repository/commits/%s/signature", pathEscape(project), url.PathEscape(sha))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sig := new(GPGSignature)
|
||||||
|
resp, err := s.client.Do(req, &sig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sig, resp, err
|
||||||
|
}
|
247
vendor/github.com/xanzy/go-gitlab/container_registry.go
generated
vendored
Normal file
247
vendor/github.com/xanzy/go-gitlab/container_registry.go
generated
vendored
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ContainerRegistryService handles communication with the container registry
|
||||||
|
// related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/container_registry.html
|
||||||
|
type ContainerRegistryService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryRepository represents a GitLab content registry repository.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/container_registry.html
|
||||||
|
type RegistryRepository struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
Location string `json:"location"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
CleanupPolicyStartedAt *time.Time `json:"cleanup_policy_started_at"`
|
||||||
|
TagsCount int `json:"tags_count"`
|
||||||
|
Tags []*RegistryRepositoryTag `json:"tags"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s RegistryRepository) String() string {
|
||||||
|
return Stringify(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryRepositoryTag represents a GitLab registry image tag.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/container_registry.html
|
||||||
|
type RegistryRepositoryTag struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
Location string `json:"location"`
|
||||||
|
Revision string `json:"revision"`
|
||||||
|
ShortRevision string `json:"short_revision"`
|
||||||
|
Digest string `json:"digest"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
TotalSize int `json:"total_size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s RegistryRepositoryTag) String() string {
|
||||||
|
return Stringify(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListRegistryRepositoriesOptions represents the available
|
||||||
|
// ListRegistryRepositories() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/container_registry.html#list-registry-repositories
|
||||||
|
type ListRegistryRepositoriesOptions struct {
|
||||||
|
ListOptions
|
||||||
|
Tags *bool `url:"tags,omitempty" json:"tags,omitempty"`
|
||||||
|
TagsCount *bool `url:"tags_count,omitempty" json:"tags_count,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListRegistryRepositories gets a list of registry repositories in a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/container_registry.html#list-registry-repositories
|
||||||
|
func (s *ContainerRegistryService) ListRegistryRepositories(pid interface{}, opt *ListRegistryRepositoriesOptions, options ...RequestOptionFunc) ([]*RegistryRepository, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/registry/repositories", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var repos []*RegistryRepository
|
||||||
|
resp, err := s.client.Do(req, &repos)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return repos, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRegistryRepository deletes a repository in a registry.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/container_registry.html#delete-registry-repository
|
||||||
|
func (s *ContainerRegistryService) DeleteRegistryRepository(pid interface{}, repository int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/registry/repositories/%d", pathEscape(project), repository)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListRegistryRepositoryTagsOptions represents the available
|
||||||
|
// ListRegistryRepositoryTags() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/container_registry.html#list-registry-repository-tags
|
||||||
|
type ListRegistryRepositoryTagsOptions ListOptions
|
||||||
|
|
||||||
|
// ListRegistryRepositoryTags gets a list of tags for given registry repository.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/container_registry.html#list-registry-repository-tags
|
||||||
|
func (s *ContainerRegistryService) ListRegistryRepositoryTags(pid interface{}, repository int, opt *ListRegistryRepositoryTagsOptions, options ...RequestOptionFunc) ([]*RegistryRepositoryTag, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/registry/repositories/%d/tags",
|
||||||
|
pathEscape(project),
|
||||||
|
repository,
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var tags []*RegistryRepositoryTag
|
||||||
|
resp, err := s.client.Do(req, &tags)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tags, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRegistryRepositoryTagDetail get details of a registry repository tag
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/container_registry.html#get-details-of-a-registry-repository-tag
|
||||||
|
func (s *ContainerRegistryService) GetRegistryRepositoryTagDetail(pid interface{}, repository int, tagName string, options ...RequestOptionFunc) (*RegistryRepositoryTag, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/registry/repositories/%d/tags/%s",
|
||||||
|
pathEscape(project),
|
||||||
|
repository,
|
||||||
|
tagName,
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tag := new(RegistryRepositoryTag)
|
||||||
|
resp, err := s.client.Do(req, &tag)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRegistryRepositoryTag deletes a registry repository tag.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/container_registry.html#delete-a-registry-repository-tag
|
||||||
|
func (s *ContainerRegistryService) DeleteRegistryRepositoryTag(pid interface{}, repository int, tagName string, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/registry/repositories/%d/tags/%s",
|
||||||
|
pathEscape(project),
|
||||||
|
repository,
|
||||||
|
tagName,
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRegistryRepositoryTagsOptions represents the available
|
||||||
|
// DeleteRegistryRepositoryTags() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/container_registry.html#delete-repository-tags-in-bulk
|
||||||
|
type DeleteRegistryRepositoryTagsOptions struct {
|
||||||
|
NameRegexpDelete *string `url:"name_regex_delete,omitempty" json:"name_regex_delete,omitempty"`
|
||||||
|
NameRegexpKeep *string `url:"name_regex_keep,omitempty" json:"name_regex_keep,omitempty"`
|
||||||
|
KeepN *int `url:"keep_n,omitempty" json:"keep_n,omitempty"`
|
||||||
|
OlderThan *string `url:"older_than,omitempty" json:"older_than,omitempty"`
|
||||||
|
|
||||||
|
// Deprecated members
|
||||||
|
NameRegexp *string `url:"name_regex,omitempty" json:"name_regex,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRegistryRepositoryTags deletes repository tags in bulk based on
|
||||||
|
// given criteria.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/container_registry.html#delete-repository-tags-in-bulk
|
||||||
|
func (s *ContainerRegistryService) DeleteRegistryRepositoryTags(pid interface{}, repository int, opt *DeleteRegistryRepositoryTagsOptions, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/registry/repositories/%d/tags",
|
||||||
|
pathEscape(project),
|
||||||
|
repository,
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
188
vendor/github.com/xanzy/go-gitlab/custom_attributes.go
generated
vendored
Normal file
188
vendor/github.com/xanzy/go-gitlab/custom_attributes.go
generated
vendored
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CustomAttributesService handles communication with the group, project and
|
||||||
|
// user custom attributes related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/custom_attributes.html
|
||||||
|
type CustomAttributesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// CustomAttribute struct is used to unmarshal response to api calls.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/custom_attributes.html
|
||||||
|
type CustomAttribute struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListCustomUserAttributes lists the custom attributes of the specified user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#list-custom-attributes
|
||||||
|
func (s *CustomAttributesService) ListCustomUserAttributes(user int, options ...RequestOptionFunc) ([]*CustomAttribute, *Response, error) {
|
||||||
|
return s.listCustomAttributes("users", user, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListCustomGroupAttributes lists the custom attributes of the specified group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#list-custom-attributes
|
||||||
|
func (s *CustomAttributesService) ListCustomGroupAttributes(group int, options ...RequestOptionFunc) ([]*CustomAttribute, *Response, error) {
|
||||||
|
return s.listCustomAttributes("groups", group, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListCustomProjectAttributes lists the custom attributes of the specified project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#list-custom-attributes
|
||||||
|
func (s *CustomAttributesService) ListCustomProjectAttributes(project int, options ...RequestOptionFunc) ([]*CustomAttribute, *Response, error) {
|
||||||
|
return s.listCustomAttributes("projects", project, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CustomAttributesService) listCustomAttributes(resource string, id int, options ...RequestOptionFunc) ([]*CustomAttribute, *Response, error) {
|
||||||
|
u := fmt.Sprintf("%s/%d/custom_attributes", resource, id)
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var cas []*CustomAttribute
|
||||||
|
resp, err := s.client.Do(req, &cas)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
return cas, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCustomUserAttribute returns the user attribute with a speciifc key.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#single-custom-attribute
|
||||||
|
func (s *CustomAttributesService) GetCustomUserAttribute(user int, key string, options ...RequestOptionFunc) (*CustomAttribute, *Response, error) {
|
||||||
|
return s.getCustomAttribute("users", user, key, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCustomGroupAttribute returns the group attribute with a speciifc key.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#single-custom-attribute
|
||||||
|
func (s *CustomAttributesService) GetCustomGroupAttribute(group int, key string, options ...RequestOptionFunc) (*CustomAttribute, *Response, error) {
|
||||||
|
return s.getCustomAttribute("groups", group, key, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCustomProjectAttribute returns the project attribute with a speciifc key.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#single-custom-attribute
|
||||||
|
func (s *CustomAttributesService) GetCustomProjectAttribute(project int, key string, options ...RequestOptionFunc) (*CustomAttribute, *Response, error) {
|
||||||
|
return s.getCustomAttribute("projects", project, key, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CustomAttributesService) getCustomAttribute(resource string, id int, key string, options ...RequestOptionFunc) (*CustomAttribute, *Response, error) {
|
||||||
|
u := fmt.Sprintf("%s/%d/custom_attributes/%s", resource, id, key)
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ca *CustomAttribute
|
||||||
|
resp, err := s.client.Do(req, &ca)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
return ca, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCustomUserAttribute sets the custom attributes of the specified user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#set-custom-attribute
|
||||||
|
func (s *CustomAttributesService) SetCustomUserAttribute(user int, c CustomAttribute, options ...RequestOptionFunc) (*CustomAttribute, *Response, error) {
|
||||||
|
return s.setCustomAttribute("users", user, c, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCustomGroupAttribute sets the custom attributes of the specified group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#set-custom-attribute
|
||||||
|
func (s *CustomAttributesService) SetCustomGroupAttribute(group int, c CustomAttribute, options ...RequestOptionFunc) (*CustomAttribute, *Response, error) {
|
||||||
|
return s.setCustomAttribute("groups", group, c, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCustomProjectAttribute sets the custom attributes of the specified project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#set-custom-attribute
|
||||||
|
func (s *CustomAttributesService) SetCustomProjectAttribute(project int, c CustomAttribute, options ...RequestOptionFunc) (*CustomAttribute, *Response, error) {
|
||||||
|
return s.setCustomAttribute("projects", project, c, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CustomAttributesService) setCustomAttribute(resource string, id int, c CustomAttribute, options ...RequestOptionFunc) (*CustomAttribute, *Response, error) {
|
||||||
|
u := fmt.Sprintf("%s/%d/custom_attributes/%s", resource, id, c.Key)
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, c, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ca := new(CustomAttribute)
|
||||||
|
resp, err := s.client.Do(req, ca)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
return ca, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteCustomUserAttribute removes the custom attribute of the specified user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#delete-custom-attribute
|
||||||
|
func (s *CustomAttributesService) DeleteCustomUserAttribute(user int, key string, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
return s.deleteCustomAttribute("users", user, key, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteCustomGroupAttribute removes the custom attribute of the specified group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#delete-custom-attribute
|
||||||
|
func (s *CustomAttributesService) DeleteCustomGroupAttribute(group int, key string, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
return s.deleteCustomAttribute("groups", group, key, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteCustomProjectAttribute removes the custom attribute of the specified project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#delete-custom-attribute
|
||||||
|
func (s *CustomAttributesService) DeleteCustomProjectAttribute(project int, key string, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
return s.deleteCustomAttribute("projects", project, key, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CustomAttributesService) deleteCustomAttribute(resource string, id int, key string, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
u := fmt.Sprintf("%s/%d/custom_attributes/%s", resource, id, key)
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
235
vendor/github.com/xanzy/go-gitlab/deploy_keys.go
generated
vendored
Normal file
235
vendor/github.com/xanzy/go-gitlab/deploy_keys.go
generated
vendored
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeployKeysService handles communication with the keys related methods
|
||||||
|
// of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/deploy_keys.html
|
||||||
|
type DeployKeysService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeployKey represents a GitLab deploy key.
|
||||||
|
type DeployKey struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Key string `json:"key"`
|
||||||
|
CanPush *bool `json:"can_push"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k DeployKey) String() string {
|
||||||
|
return Stringify(k)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAllDeployKeys gets a list of all deploy keys
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_keys.html#list-all-deploy-keys
|
||||||
|
func (s *DeployKeysService) ListAllDeployKeys(options ...RequestOptionFunc) ([]*DeployKey, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, "deploy_keys", nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ks []*DeployKey
|
||||||
|
resp, err := s.client.Do(req, &ks)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ks, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListProjectDeployKeysOptions represents the available ListProjectDeployKeys()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_keys.html#list-project-deploy-keys
|
||||||
|
type ListProjectDeployKeysOptions ListOptions
|
||||||
|
|
||||||
|
// ListProjectDeployKeys gets a list of a project's deploy keys
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_keys.html#list-project-deploy-keys
|
||||||
|
func (s *DeployKeysService) ListProjectDeployKeys(pid interface{}, opt *ListProjectDeployKeysOptions, options ...RequestOptionFunc) ([]*DeployKey, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/deploy_keys", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ks []*DeployKey
|
||||||
|
resp, err := s.client.Do(req, &ks)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ks, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDeployKey gets a single deploy key.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_keys.html#single-deploy-key
|
||||||
|
func (s *DeployKeysService) GetDeployKey(pid interface{}, deployKey int, options ...RequestOptionFunc) (*DeployKey, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/deploy_keys/%d", pathEscape(project), deployKey)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
k := new(DeployKey)
|
||||||
|
resp, err := s.client.Do(req, k)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return k, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddDeployKeyOptions represents the available ADDDeployKey() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_keys.html#add-deploy-key
|
||||||
|
type AddDeployKeyOptions struct {
|
||||||
|
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
||||||
|
Key *string `url:"key,omitempty" json:"key,omitempty"`
|
||||||
|
CanPush *bool `url:"can_push,omitempty" json:"can_push,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddDeployKey creates a new deploy key for a project. If deploy key already
|
||||||
|
// exists in another project - it will be joined to project but only if
|
||||||
|
// original one was is accessible by same user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_keys.html#add-deploy-key
|
||||||
|
func (s *DeployKeysService) AddDeployKey(pid interface{}, opt *AddDeployKeyOptions, options ...RequestOptionFunc) (*DeployKey, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/deploy_keys", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
k := new(DeployKey)
|
||||||
|
resp, err := s.client.Do(req, k)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return k, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteDeployKey deletes a deploy key from a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_keys.html#delete-deploy-key
|
||||||
|
func (s *DeployKeysService) DeleteDeployKey(pid interface{}, deployKey int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/deploy_keys/%d", pathEscape(project), deployKey)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableDeployKey enables a deploy key.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_keys.html#enable-a-deploy-key
|
||||||
|
func (s *DeployKeysService) EnableDeployKey(pid interface{}, deployKey int, options ...RequestOptionFunc) (*DeployKey, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/deploy_keys/%d/enable", pathEscape(project), deployKey)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
k := new(DeployKey)
|
||||||
|
resp, err := s.client.Do(req, k)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return k, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateDeployKeyOptions represents the available UpdateDeployKey() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_keys.html#update-deploy-key
|
||||||
|
type UpdateDeployKeyOptions struct {
|
||||||
|
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
||||||
|
CanPush *bool `url:"can_push,omitempty" json:"can_push,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateDeployKey updates a deploy key for a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_keys.html#update-deploy-key
|
||||||
|
func (s *DeployKeysService) UpdateDeployKey(pid interface{}, deployKey int, opt *UpdateDeployKeyOptions, options ...RequestOptionFunc) (*DeployKey, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/deploy_keys/%d", pathEscape(project), deployKey)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
k := new(DeployKey)
|
||||||
|
resp, err := s.client.Do(req, k)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return k, resp, err
|
||||||
|
}
|
238
vendor/github.com/xanzy/go-gitlab/deploy_tokens.go
generated
vendored
Normal file
238
vendor/github.com/xanzy/go-gitlab/deploy_tokens.go
generated
vendored
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeployTokensService handles communication with the deploy tokens related methods
|
||||||
|
// of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/deploy_tokens.html
|
||||||
|
type DeployTokensService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeployToken represents a GitLab deploy token.
|
||||||
|
type DeployToken struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
ExpiresAt *time.Time `json:"expires_at"`
|
||||||
|
Token string `json:"token,omitempty"`
|
||||||
|
Scopes []string `json:"scopes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k DeployToken) String() string {
|
||||||
|
return Stringify(k)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAllDeployTokens gets a list of all deploy tokens.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_tokens.html#list-all-deploy-tokens
|
||||||
|
func (s *DeployTokensService) ListAllDeployTokens(options ...RequestOptionFunc) ([]*DeployToken, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, "deploy_tokens", nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ts []*DeployToken
|
||||||
|
resp, err := s.client.Do(req, &ts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ts, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListProjectDeployTokensOptions represents the available ListProjectDeployTokens()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_tokens.html#list-project-deploy-tokens
|
||||||
|
type ListProjectDeployTokensOptions ListOptions
|
||||||
|
|
||||||
|
// ListProjectDeployTokens gets a list of a project's deploy tokens.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_tokens.html#list-project-deploy-tokens
|
||||||
|
func (s *DeployTokensService) ListProjectDeployTokens(pid interface{}, opt *ListProjectDeployTokensOptions, options ...RequestOptionFunc) ([]*DeployToken, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/deploy_tokens", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ts []*DeployToken
|
||||||
|
resp, err := s.client.Do(req, &ts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ts, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateProjectDeployTokenOptions represents the available CreateProjectDeployToken() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_tokens.html#create-a-project-deploy-token
|
||||||
|
type CreateProjectDeployTokenOptions struct {
|
||||||
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
|
ExpiresAt *time.Time `url:"expires_at,omitempty" json:"expires_at,omitempty"`
|
||||||
|
Username *string `url:"username,omitempty" json:"username,omitempty"`
|
||||||
|
Scopes []string `url:"scopes,omitempty" json:"scopes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateProjectDeployToken creates a new deploy token for a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_tokens.html#create-a-project-deploy-token
|
||||||
|
func (s *DeployTokensService) CreateProjectDeployToken(pid interface{}, opt *CreateProjectDeployTokenOptions, options ...RequestOptionFunc) (*DeployToken, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/deploy_tokens", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
t := new(DeployToken)
|
||||||
|
resp, err := s.client.Do(req, t)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return t, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteProjectDeployToken removes a deploy token from the project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_tokens.html#delete-a-project-deploy-token
|
||||||
|
func (s *DeployTokensService) DeleteProjectDeployToken(pid interface{}, deployToken int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/deploy_tokens/%d", pathEscape(project), deployToken)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupDeployTokensOptions represents the available ListGroupDeployTokens()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_tokens.html#list-group-deploy-deploy-tokens
|
||||||
|
type ListGroupDeployTokensOptions ListOptions
|
||||||
|
|
||||||
|
// ListGroupDeployTokens gets a list of a group’s deploy tokens.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_tokens.html#list-project-deploy-tokens
|
||||||
|
func (s *DeployTokensService) ListGroupDeployTokens(gid interface{}, opt *ListGroupDeployTokensOptions, options ...RequestOptionFunc) ([]*DeployToken, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/deploy_tokens", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ts []*DeployToken
|
||||||
|
resp, err := s.client.Do(req, &ts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ts, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateGroupDeployTokenOptions represents the available CreateGroupDeployToken() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_tokens.html#create-a-group-deploy-token
|
||||||
|
type CreateGroupDeployTokenOptions struct {
|
||||||
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
|
ExpiresAt *time.Time `url:"expires_at,omitempty" json:"expires_at,omitempty"`
|
||||||
|
Username *string `url:"username,omitempty" json:"username,omitempty"`
|
||||||
|
Scopes []string `url:"scopes,omitempty" json:"scopes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateGroupDeployToken creates a new deploy token for a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_tokens.html#create-a-group-deploy-token
|
||||||
|
func (s *DeployTokensService) CreateGroupDeployToken(gid interface{}, opt *CreateGroupDeployTokenOptions, options ...RequestOptionFunc) (*DeployToken, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/deploy_tokens", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
t := new(DeployToken)
|
||||||
|
resp, err := s.client.Do(req, t)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return t, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteGroupDeployToken removes a deploy token from the group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deploy_tokens.html#delete-a-group-deploy-token
|
||||||
|
func (s *DeployTokensService) DeleteGroupDeployToken(gid interface{}, deployToken int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/deploy_tokens/%d", pathEscape(group), deployToken)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
203
vendor/github.com/xanzy/go-gitlab/deployments.go
generated
vendored
Normal file
203
vendor/github.com/xanzy/go-gitlab/deployments.go
generated
vendored
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeploymentsService handles communication with the deployment related methods
|
||||||
|
// of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/deployments.html
|
||||||
|
type DeploymentsService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deployment represents the Gitlab deployment
|
||||||
|
type Deployment struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
IID int `json:"iid"`
|
||||||
|
Ref string `json:"ref"`
|
||||||
|
SHA string `json:"sha"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
UpdatedAt *time.Time `json:"updated_at"`
|
||||||
|
User *ProjectUser `json:"user"`
|
||||||
|
Environment *Environment `json:"environment"`
|
||||||
|
Deployable struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Stage string `json:"stage"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Ref string `json:"ref"`
|
||||||
|
Tag bool `json:"tag"`
|
||||||
|
Coverage float64 `json:"coverage"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
StartedAt *time.Time `json:"started_at"`
|
||||||
|
FinishedAt *time.Time `json:"finished_at"`
|
||||||
|
Duration float64 `json:"duration"`
|
||||||
|
User *User `json:"user"`
|
||||||
|
Commit *Commit `json:"commit"`
|
||||||
|
Pipeline struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
SHA string `json:"sha"`
|
||||||
|
Ref string `json:"ref"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
UpdatedAt *time.Time `json:"updated_at"`
|
||||||
|
} `json:"pipeline"`
|
||||||
|
Runner *Runner `json:"runner"`
|
||||||
|
} `json:"deployable"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListProjectDeploymentsOptions represents the available ListProjectDeployments() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/deployments.html#list-project-deployments
|
||||||
|
type ListProjectDeploymentsOptions struct {
|
||||||
|
ListOptions
|
||||||
|
OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
|
||||||
|
Sort *string `url:"sort,omitempty" json:"sort,omitempty"`
|
||||||
|
Environment *string `url:"environment,omitempty" json:"environment,omitempty"`
|
||||||
|
Status *string `url:"status,omitempty" json:"status,omitempty"`
|
||||||
|
|
||||||
|
// Only for Gitlab versions less than 14
|
||||||
|
UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
|
||||||
|
UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
|
||||||
|
|
||||||
|
// Only for Gitlab 14 or higher
|
||||||
|
FinishedAfter *time.Time `url:"finished_after,omitempty" json:"finished_after,omitempty"`
|
||||||
|
FinishedBefore *time.Time `url:"finished_before,omitempty" json:"finished_before,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListProjectDeployments gets a list of deployments in a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/deployments.html#list-project-deployments
|
||||||
|
func (s *DeploymentsService) ListProjectDeployments(pid interface{}, opts *ListProjectDeploymentsOptions, options ...RequestOptionFunc) ([]*Deployment, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/deployments", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opts, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ds []*Deployment
|
||||||
|
resp, err := s.client.Do(req, &ds)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ds, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProjectDeployment get a deployment for a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/deployments.html#get-a-specific-deployment
|
||||||
|
func (s *DeploymentsService) GetProjectDeployment(pid interface{}, deployment int, options ...RequestOptionFunc) (*Deployment, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/deployments/%d", pathEscape(project), deployment)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
d := new(Deployment)
|
||||||
|
resp, err := s.client.Do(req, d)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return d, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateProjectDeploymentOptions represents the available
|
||||||
|
// CreateProjectDeployment() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/deployments.html#create-a-deployment
|
||||||
|
type CreateProjectDeploymentOptions struct {
|
||||||
|
Environment *string `url:"environment,omitempty" json:"environment,omitempty"`
|
||||||
|
Ref *string `url:"ref,omitempty" json:"ref,omitempty"`
|
||||||
|
SHA *string `url:"sha,omitempty" json:"sha,omitempty"`
|
||||||
|
Tag *bool `url:"tag,omitempty" json:"tag,omitempty"`
|
||||||
|
Status *DeploymentStatusValue `url:"status,omitempty" json:"status,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateProjectDeployment creates a project deployment.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/deployments.html#create-a-deployment
|
||||||
|
func (s *DeploymentsService) CreateProjectDeployment(pid interface{}, opt *CreateProjectDeploymentOptions, options ...RequestOptionFunc) (*Deployment, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/deployments", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
d := new(Deployment)
|
||||||
|
resp, err := s.client.Do(req, &d)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return d, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateProjectDeploymentOptions represents the available
|
||||||
|
// UpdateProjectDeployment() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/deployments.html#updating-a-deployment
|
||||||
|
type UpdateProjectDeploymentOptions struct {
|
||||||
|
Status *DeploymentStatusValue `url:"status,omitempty" json:"status,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateProjectDeployment updates a project deployment.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/deployments.html#updating-a-deployment
|
||||||
|
func (s *DeploymentsService) UpdateProjectDeployment(pid interface{}, deployment int, opt *UpdateProjectDeploymentOptions, options ...RequestOptionFunc) (*Deployment, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/deployments/%d", pathEscape(project), deployment)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
d := new(Deployment)
|
||||||
|
resp, err := s.client.Do(req, &d)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return d, resp, err
|
||||||
|
}
|
1114
vendor/github.com/xanzy/go-gitlab/discussions.go
generated
vendored
Normal file
1114
vendor/github.com/xanzy/go-gitlab/discussions.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
218
vendor/github.com/xanzy/go-gitlab/environments.go
generated
vendored
Normal file
218
vendor/github.com/xanzy/go-gitlab/environments.go
generated
vendored
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EnvironmentsService handles communication with the environment related methods
|
||||||
|
// of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/environments.html
|
||||||
|
type EnvironmentsService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Environment represents a GitLab environment.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/environments.html
|
||||||
|
type Environment struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Slug string `json:"slug"`
|
||||||
|
State string `json:"state"`
|
||||||
|
ExternalURL string `json:"external_url"`
|
||||||
|
Project *Project `json:"project"`
|
||||||
|
LastDeployment *Deployment `json:"last_deployment"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (env Environment) String() string {
|
||||||
|
return Stringify(env)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListEnvironmentsOptions represents the available ListEnvironments() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/environments.html#list-environments
|
||||||
|
type ListEnvironmentsOptions struct {
|
||||||
|
ListOptions
|
||||||
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
|
Search *string `url:"search,omitempty" json:"search,omitempty"`
|
||||||
|
States *string `url:"states,omitempty" json:"states,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListEnvironments gets a list of environments from a project, sorted by name
|
||||||
|
// alphabetically.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/environments.html#list-environments
|
||||||
|
func (s *EnvironmentsService) ListEnvironments(pid interface{}, opts *ListEnvironmentsOptions, options ...RequestOptionFunc) ([]*Environment, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/environments", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opts, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var envs []*Environment
|
||||||
|
resp, err := s.client.Do(req, &envs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return envs, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEnvironment gets a specific environment from a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/environments.html#get-a-specific-environment
|
||||||
|
func (s *EnvironmentsService) GetEnvironment(pid interface{}, environment int, options ...RequestOptionFunc) (*Environment, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/environments/%d", pathEscape(project), environment)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
env := new(Environment)
|
||||||
|
resp, err := s.client.Do(req, env)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return env, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateEnvironmentOptions represents the available CreateEnvironment() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/environments.html#create-a-new-environment
|
||||||
|
type CreateEnvironmentOptions struct {
|
||||||
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
|
ExternalURL *string `url:"external_url,omitempty" json:"external_url,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateEnvironment adds an environment to a project. This is an idempotent
|
||||||
|
// method and can be called multiple times with the same parameters. Createing
|
||||||
|
// an environment that is already a environment does not affect the
|
||||||
|
// existing environmentship.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/environments.html#create-a-new-environment
|
||||||
|
func (s *EnvironmentsService) CreateEnvironment(pid interface{}, opt *CreateEnvironmentOptions, options ...RequestOptionFunc) (*Environment, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/environments", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
env := new(Environment)
|
||||||
|
resp, err := s.client.Do(req, env)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return env, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditEnvironmentOptions represents the available EditEnvironment() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/environments.html#edit-an-existing-environment
|
||||||
|
type EditEnvironmentOptions struct {
|
||||||
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
|
ExternalURL *string `url:"external_url,omitempty" json:"external_url,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditEnvironment updates a project team environment to a specified access level..
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/environments.html#edit-an-existing-environment
|
||||||
|
func (s *EnvironmentsService) EditEnvironment(pid interface{}, environment int, opt *EditEnvironmentOptions, options ...RequestOptionFunc) (*Environment, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/environments/%d", pathEscape(project), environment)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
env := new(Environment)
|
||||||
|
resp, err := s.client.Do(req, env)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return env, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteEnvironment removes an environment from a project team.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/environments.html#remove-a-environment-from-a-group-or-project
|
||||||
|
func (s *EnvironmentsService) DeleteEnvironment(pid interface{}, environment int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/environments/%d", pathEscape(project), environment)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StopEnvironment stop an environment from a project team.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/environments.html#stop-an-environment
|
||||||
|
func (s *EnvironmentsService) StopEnvironment(pid interface{}, environmentID int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/environments/%d/stop", pathEscape(project), environmentID)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
152
vendor/github.com/xanzy/go-gitlab/epic_issues.go
generated
vendored
Normal file
152
vendor/github.com/xanzy/go-gitlab/epic_issues.go
generated
vendored
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EpicIssuesService handles communication with the epic issue related methods
|
||||||
|
// of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/epic_issues.html
|
||||||
|
type EpicIssuesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// EpicIssueAssignment contains both the epic and issue objects returned from
|
||||||
|
// Gitlab with the assignment ID.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/epic_issues.html
|
||||||
|
type EpicIssueAssignment struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Epic *Epic `json:"epic"`
|
||||||
|
Issue *Issue `json:"issue"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListEpicIssues get a list of epic issues.
|
||||||
|
//
|
||||||
|
// Gitlab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/epic_issues.html#list-issues-for-an-epic
|
||||||
|
func (s *EpicIssuesService) ListEpicIssues(gid interface{}, epic int, opt *ListOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/epics/%d/issues", pathEscape(group), epic)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var is []*Issue
|
||||||
|
resp, err := s.client.Do(req, &is)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return is, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssignEpicIssue assigns an existing issue to an epic.
|
||||||
|
//
|
||||||
|
// Gitlab API Docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/epic_issues.html#assign-an-issue-to-the-epic
|
||||||
|
func (s *EpicIssuesService) AssignEpicIssue(gid interface{}, epic, issue int, options ...RequestOptionFunc) (*EpicIssueAssignment, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/epics/%d/issues/%d", pathEscape(group), epic, issue)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
a := new(EpicIssueAssignment)
|
||||||
|
resp, err := s.client.Do(req, a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveEpicIssue removes an issue from an epic.
|
||||||
|
//
|
||||||
|
// Gitlab API Docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/epic_issues.html#remove-an-issue-from-the-epic
|
||||||
|
func (s *EpicIssuesService) RemoveEpicIssue(gid interface{}, epic, epicIssue int, options ...RequestOptionFunc) (*EpicIssueAssignment, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/epics/%d/issues/%d", pathEscape(group), epic, epicIssue)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
a := new(EpicIssueAssignment)
|
||||||
|
resp, err := s.client.Do(req, a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateEpicIsssueAssignmentOptions describes the UpdateEpicIssueAssignment()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// Gitlab API Docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/epic_issues.html#update-epic---issue-association
|
||||||
|
type UpdateEpicIsssueAssignmentOptions struct {
|
||||||
|
*ListOptions
|
||||||
|
MoveBeforeID *int `url:"move_before_id,omitempty" json:"move_before_id,omitempty"`
|
||||||
|
MoveAfterID *int `url:"move_after_id,omitempty" json:"move_after_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateEpicIssueAssignment moves an issue before or after another issue in an
|
||||||
|
// epic issue list.
|
||||||
|
//
|
||||||
|
// Gitlab API Docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/epic_issues.html#update-epic---issue-association
|
||||||
|
func (s *EpicIssuesService) UpdateEpicIssueAssignment(gid interface{}, epic, epicIssue int, opt *UpdateEpicIsssueAssignmentOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/epics/%d/issues/%d", pathEscape(group), epic, epicIssue)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var is []*Issue
|
||||||
|
resp, err := s.client.Do(req, &is)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return is, resp, err
|
||||||
|
}
|
263
vendor/github.com/xanzy/go-gitlab/epics.go
generated
vendored
Normal file
263
vendor/github.com/xanzy/go-gitlab/epics.go
generated
vendored
Normal file
|
@ -0,0 +1,263 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EpicsService handles communication with the epic related methods
|
||||||
|
// of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html
|
||||||
|
type EpicsService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// EpicAuthor represents a author of the epic.
|
||||||
|
type EpicAuthor struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
State string `json:"state"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Epic represents a GitLab epic.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html
|
||||||
|
type Epic struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
IID int `json:"iid"`
|
||||||
|
GroupID int `json:"group_id"`
|
||||||
|
ParentID int `json:"parent_id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
State string `json:"state"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
Author *EpicAuthor `json:"author"`
|
||||||
|
StartDate *ISOTime `json:"start_date"`
|
||||||
|
StartDateIsFixed bool `json:"start_date_is_fixed"`
|
||||||
|
StartDateFixed *ISOTime `json:"start_date_fixed"`
|
||||||
|
StartDateFromMilestones *ISOTime `json:"start_date_from_milestones"`
|
||||||
|
DueDate *ISOTime `json:"due_date"`
|
||||||
|
DueDateIsFixed bool `json:"due_date_is_fixed"`
|
||||||
|
DueDateFixed *ISOTime `json:"due_date_fixed"`
|
||||||
|
DueDateFromMilestones *ISOTime `json:"due_date_from_milestones"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
UpdatedAt *time.Time `json:"updated_at"`
|
||||||
|
Labels []string `json:"labels"`
|
||||||
|
Upvotes int `json:"upvotes"`
|
||||||
|
Downvotes int `json:"downvotes"`
|
||||||
|
UserNotesCount int `json:"user_notes_count"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Epic) String() string {
|
||||||
|
return Stringify(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupEpicsOptions represents the available ListGroupEpics() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#list-epics-for-a-group
|
||||||
|
type ListGroupEpicsOptions struct {
|
||||||
|
ListOptions
|
||||||
|
AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"`
|
||||||
|
Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"`
|
||||||
|
WithLabelDetails *bool `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"`
|
||||||
|
OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
|
||||||
|
Sort *string `url:"sort,omitempty" json:"sort,omitempty"`
|
||||||
|
Search *string `url:"search,omitempty" json:"search,omitempty"`
|
||||||
|
State *string `url:"state,omitempty" json:"state,omitempty"`
|
||||||
|
CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
|
||||||
|
CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
|
||||||
|
UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
|
||||||
|
UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
|
||||||
|
IncludeAncestorGroups *bool `url:"include_ancestor_groups,omitempty" json:"include_ancestor_groups,omitempty"`
|
||||||
|
IncludeDescendantGroups *bool `url:"include_descendant_groups,omitempty" json:"include_descendant_groups,omitempty"`
|
||||||
|
MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupEpics gets a list of group epics. This function accepts pagination
|
||||||
|
// parameters page and per_page to return the list of group epics.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#list-epics-for-a-group
|
||||||
|
func (s *EpicsService) ListGroupEpics(gid interface{}, opt *ListGroupEpicsOptions, options ...RequestOptionFunc) ([]*Epic, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/epics", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var es []*Epic
|
||||||
|
resp, err := s.client.Do(req, &es)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return es, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEpic gets a single group epic.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#single-epic
|
||||||
|
func (s *EpicsService) GetEpic(gid interface{}, epic int, options ...RequestOptionFunc) (*Epic, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/epics/%d", pathEscape(group), epic)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
e := new(Epic)
|
||||||
|
resp, err := s.client.Do(req, e)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return e, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEpicLinks gets all child epics of an epic.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/epic_links.html
|
||||||
|
func (s *EpicsService) GetEpicLinks(gid interface{}, epic int, options ...RequestOptionFunc) ([]*Epic, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/epics/%d/epics", pathEscape(group), epic)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var e []*Epic
|
||||||
|
resp, err := s.client.Do(req, &e)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return e, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateEpicOptions represents the available CreateEpic() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#new-epic
|
||||||
|
type CreateEpicOptions struct {
|
||||||
|
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
||||||
|
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||||
|
Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"`
|
||||||
|
StartDateIsFixed *bool `url:"start_date_is_fixed,omitempty" json:"start_date_is_fixed,omitempty"`
|
||||||
|
StartDateFixed *ISOTime `url:"start_date_fixed,omitempty" json:"start_date_fixed,omitempty"`
|
||||||
|
DueDateIsFixed *bool `url:"due_date_is_fixed,omitempty" json:"due_date_is_fixed,omitempty"`
|
||||||
|
DueDateFixed *ISOTime `url:"due_date_fixed,omitempty" json:"due_date_fixed,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateEpic creates a new group epic.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#new-epic
|
||||||
|
func (s *EpicsService) CreateEpic(gid interface{}, opt *CreateEpicOptions, options ...RequestOptionFunc) (*Epic, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/epics", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
e := new(Epic)
|
||||||
|
resp, err := s.client.Do(req, e)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return e, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateEpicOptions represents the available UpdateEpic() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#update-epic
|
||||||
|
type UpdateEpicOptions struct {
|
||||||
|
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
||||||
|
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||||
|
Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"`
|
||||||
|
StartDateIsFixed *bool `url:"start_date_is_fixed,omitempty" json:"start_date_is_fixed,omitempty"`
|
||||||
|
StartDateFixed *ISOTime `url:"start_date_fixed,omitempty" json:"start_date_fixed,omitempty"`
|
||||||
|
DueDateIsFixed *bool `url:"due_date_is_fixed,omitempty" json:"due_date_is_fixed,omitempty"`
|
||||||
|
DueDateFixed *ISOTime `url:"due_date_fixed,omitempty" json:"due_date_fixed,omitempty"`
|
||||||
|
StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateEpic updates an existing group epic. This function is also used
|
||||||
|
// to mark an epic as closed.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#update-epic
|
||||||
|
func (s *EpicsService) UpdateEpic(gid interface{}, epic int, opt *UpdateEpicOptions, options ...RequestOptionFunc) (*Epic, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/epics/%d", pathEscape(group), epic)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
e := new(Epic)
|
||||||
|
resp, err := s.client.Do(req, e)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return e, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteEpic deletes a single group epic.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#delete-epic
|
||||||
|
func (s *EpicsService) DeleteEpic(gid interface{}, epic int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/epics/%d", pathEscape(group), epic)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
255
vendor/github.com/xanzy/go-gitlab/event_parsing.go
generated
vendored
Normal file
255
vendor/github.com/xanzy/go-gitlab/event_parsing.go
generated
vendored
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EventType represents a Gitlab event type.
|
||||||
|
type EventType string
|
||||||
|
|
||||||
|
// List of available event types.
|
||||||
|
const (
|
||||||
|
EventTypeBuild EventType = "Build Hook"
|
||||||
|
EventTypeDeployment EventType = "Deployment Hook"
|
||||||
|
EventTypeIssue EventType = "Issue Hook"
|
||||||
|
EventConfidentialIssue EventType = "Confidential Issue Hook"
|
||||||
|
EventTypeJob EventType = "Job Hook"
|
||||||
|
EventTypeMergeRequest EventType = "Merge Request Hook"
|
||||||
|
EventTypeNote EventType = "Note Hook"
|
||||||
|
EventConfidentialNote EventType = "Confidential Note Hook"
|
||||||
|
EventTypePipeline EventType = "Pipeline Hook"
|
||||||
|
EventTypePush EventType = "Push Hook"
|
||||||
|
EventTypeRelease EventType = "Release Hook"
|
||||||
|
EventTypeSystemHook EventType = "System Hook"
|
||||||
|
EventTypeTagPush EventType = "Tag Push Hook"
|
||||||
|
EventTypeWikiPage EventType = "Wiki Page Hook"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
noteableTypeCommit = "Commit"
|
||||||
|
noteableTypeMergeRequest = "MergeRequest"
|
||||||
|
noteableTypeIssue = "Issue"
|
||||||
|
noteableTypeSnippet = "Snippet"
|
||||||
|
)
|
||||||
|
|
||||||
|
type noteEvent struct {
|
||||||
|
ObjectKind string `json:"object_kind"`
|
||||||
|
ObjectAttributes struct {
|
||||||
|
NoteableType string `json:"noteable_type"`
|
||||||
|
} `json:"object_attributes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const eventTypeHeader = "X-Gitlab-Event"
|
||||||
|
|
||||||
|
// HookEventType returns the event type for the given request.
|
||||||
|
func HookEventType(r *http.Request) EventType {
|
||||||
|
return EventType(r.Header.Get(eventTypeHeader))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseHook tries to parse both web- and system hooks.
|
||||||
|
//
|
||||||
|
// Example usage:
|
||||||
|
//
|
||||||
|
// func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// payload, err := ioutil.ReadAll(r.Body)
|
||||||
|
// if err != nil { ... }
|
||||||
|
// event, err := gitlab.ParseHook(gitlab.HookEventType(r), payload)
|
||||||
|
// if err != nil { ... }
|
||||||
|
// switch event := event.(type) {
|
||||||
|
// case *gitlab.PushEvent:
|
||||||
|
// processPushEvent(event)
|
||||||
|
// case *gitlab.MergeEvent:
|
||||||
|
// processMergeEvent(event)
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
func ParseHook(eventType EventType, payload []byte) (event interface{}, err error) {
|
||||||
|
switch eventType {
|
||||||
|
case EventTypeSystemHook:
|
||||||
|
return ParseSystemhook(payload)
|
||||||
|
default:
|
||||||
|
return ParseWebhook(eventType, payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseSystemhook parses the event payload. For recognized event types, a
|
||||||
|
// value of the corresponding struct type will be returned. An error will be
|
||||||
|
// returned for unrecognized event types.
|
||||||
|
//
|
||||||
|
// Example usage:
|
||||||
|
//
|
||||||
|
// func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// payload, err := ioutil.ReadAll(r.Body)
|
||||||
|
// if err != nil { ... }
|
||||||
|
// event, err := gitlab.ParseSystemhook(payload)
|
||||||
|
// if err != nil { ... }
|
||||||
|
// switch event := event.(type) {
|
||||||
|
// case *gitlab.PushSystemEvent:
|
||||||
|
// processPushSystemEvent(event)
|
||||||
|
// case *gitlab.MergeSystemEvent:
|
||||||
|
// processMergeSystemEvent(event)
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
func ParseSystemhook(payload []byte) (event interface{}, err error) {
|
||||||
|
e := &systemHookEvent{}
|
||||||
|
err = json.Unmarshal(payload, e)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e.EventName {
|
||||||
|
case "push":
|
||||||
|
event = &PushSystemEvent{}
|
||||||
|
case "tag_push":
|
||||||
|
event = &TagPushSystemEvent{}
|
||||||
|
case "repository_update":
|
||||||
|
event = &RepositoryUpdateSystemEvent{}
|
||||||
|
case
|
||||||
|
"project_create",
|
||||||
|
"project_update",
|
||||||
|
"project_destroy",
|
||||||
|
"project_transfer",
|
||||||
|
"project_rename":
|
||||||
|
event = &ProjectSystemEvent{}
|
||||||
|
case
|
||||||
|
"group_create",
|
||||||
|
"group_destroy",
|
||||||
|
"group_rename":
|
||||||
|
event = &GroupSystemEvent{}
|
||||||
|
case
|
||||||
|
"key_create",
|
||||||
|
"key_destroy":
|
||||||
|
event = &KeySystemEvent{}
|
||||||
|
case
|
||||||
|
"user_create",
|
||||||
|
"user_destroy",
|
||||||
|
"user_rename":
|
||||||
|
event = &UserSystemEvent{}
|
||||||
|
case
|
||||||
|
"user_add_to_group",
|
||||||
|
"user_remove_from_group",
|
||||||
|
"user_update_for_group":
|
||||||
|
event = &UserGroupSystemEvent{}
|
||||||
|
case
|
||||||
|
"user_add_to_team",
|
||||||
|
"user_remove_from_team",
|
||||||
|
"user_update_for_team":
|
||||||
|
event = &UserTeamSystemEvent{}
|
||||||
|
default:
|
||||||
|
switch e.ObjectKind {
|
||||||
|
case string(MergeRequestEventTargetType):
|
||||||
|
event = &MergeEvent{}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unexpected system hook type %s", e.EventName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(payload, event); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return event, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebhookEventType returns the event type for the given request.
|
||||||
|
func WebhookEventType(r *http.Request) EventType {
|
||||||
|
return EventType(r.Header.Get(eventTypeHeader))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseWebhook parses the event payload. For recognized event types, a
|
||||||
|
// value of the corresponding struct type will be returned. An error will
|
||||||
|
// be returned for unrecognized event types.
|
||||||
|
//
|
||||||
|
// Example usage:
|
||||||
|
//
|
||||||
|
// func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// payload, err := ioutil.ReadAll(r.Body)
|
||||||
|
// if err != nil { ... }
|
||||||
|
// event, err := gitlab.ParseWebhook(gitlab.HookEventType(r), payload)
|
||||||
|
// if err != nil { ... }
|
||||||
|
// switch event := event.(type) {
|
||||||
|
// case *gitlab.PushEvent:
|
||||||
|
// processPushEvent(event)
|
||||||
|
// case *gitlab.MergeEvent:
|
||||||
|
// processMergeEvent(event)
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
func ParseWebhook(eventType EventType, payload []byte) (event interface{}, err error) {
|
||||||
|
switch eventType {
|
||||||
|
case EventTypeBuild:
|
||||||
|
event = &BuildEvent{}
|
||||||
|
case EventTypeDeployment:
|
||||||
|
event = &DeploymentEvent{}
|
||||||
|
case EventTypeIssue, EventConfidentialIssue:
|
||||||
|
event = &IssueEvent{}
|
||||||
|
case EventTypeJob:
|
||||||
|
event = &JobEvent{}
|
||||||
|
case EventTypeMergeRequest:
|
||||||
|
event = &MergeEvent{}
|
||||||
|
case EventTypePipeline:
|
||||||
|
event = &PipelineEvent{}
|
||||||
|
case EventTypePush:
|
||||||
|
event = &PushEvent{}
|
||||||
|
case EventTypeRelease:
|
||||||
|
event = &ReleaseEvent{}
|
||||||
|
case EventTypeTagPush:
|
||||||
|
event = &TagEvent{}
|
||||||
|
case EventTypeWikiPage:
|
||||||
|
event = &WikiPageEvent{}
|
||||||
|
case EventTypeNote, EventConfidentialNote:
|
||||||
|
note := ¬eEvent{}
|
||||||
|
err := json.Unmarshal(payload, note)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if note.ObjectKind != string(NoteEventTargetType) {
|
||||||
|
return nil, fmt.Errorf("unexpected object kind %s", note.ObjectKind)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch note.ObjectAttributes.NoteableType {
|
||||||
|
case noteableTypeCommit:
|
||||||
|
event = &CommitCommentEvent{}
|
||||||
|
case noteableTypeMergeRequest:
|
||||||
|
event = &MergeCommentEvent{}
|
||||||
|
case noteableTypeIssue:
|
||||||
|
event = &IssueCommentEvent{}
|
||||||
|
case noteableTypeSnippet:
|
||||||
|
event = &SnippetCommentEvent{}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unexpected noteable type %s", note.ObjectAttributes.NoteableType)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unexpected event type: %s", eventType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(payload, event); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return event, nil
|
||||||
|
}
|
149
vendor/github.com/xanzy/go-gitlab/event_systemhook_types.go
generated
vendored
Normal file
149
vendor/github.com/xanzy/go-gitlab/event_systemhook_types.go
generated
vendored
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
// systemHookEvent is used to pre-process events to determine the
|
||||||
|
// system hook event type.
|
||||||
|
type systemHookEvent struct {
|
||||||
|
BaseSystemEvent
|
||||||
|
ObjectKind string `json:"object_kind"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BaseSystemEvent contains system hook's common properties.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/system_hooks/system_hooks.html
|
||||||
|
type BaseSystemEvent struct {
|
||||||
|
EventName string `json:"event_name"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectSystemEvent represents a project system event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/system_hooks/system_hooks.html
|
||||||
|
type ProjectSystemEvent struct {
|
||||||
|
BaseSystemEvent
|
||||||
|
Name string `json:"name"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
PathWithNamespace string `json:"path_with_namespace"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
OwnerName string `json:"owner_name"`
|
||||||
|
OwnerEmail string `json:"owner_email"`
|
||||||
|
ProjectVisibility string `json:"project_visibility"`
|
||||||
|
OldPathWithNamespace string `json:"old_path_with_namespace,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupSystemEvent represents a group system event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/system_hooks/system_hooks.html
|
||||||
|
type GroupSystemEvent struct {
|
||||||
|
BaseSystemEvent
|
||||||
|
Name string `json:"name"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
PathWithNamespace string `json:"full_path"`
|
||||||
|
GroupID int `json:"group_id"`
|
||||||
|
OwnerName string `json:"owner_name"`
|
||||||
|
OwnerEmail string `json:"owner_email"`
|
||||||
|
ProjectVisibility string `json:"project_visibility"`
|
||||||
|
OldPath string `json:"old_path,omitempty"`
|
||||||
|
OldPathWithNamespace string `json:"old_full_path,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeySystemEvent represents a key system event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/system_hooks/system_hooks.html
|
||||||
|
type KeySystemEvent struct {
|
||||||
|
BaseSystemEvent
|
||||||
|
ID int `json:"id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Key string `json:"key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserSystemEvent represents a user system event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/system_hooks/system_hooks.html
|
||||||
|
type UserSystemEvent struct {
|
||||||
|
BaseSystemEvent
|
||||||
|
ID int `json:"user_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
OldUsername string `json:"old_username,omitempty"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserGroupSystemEvent represents a user group system event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/system_hooks/system_hooks.html
|
||||||
|
type UserGroupSystemEvent struct {
|
||||||
|
BaseSystemEvent
|
||||||
|
ID int `json:"user_id"`
|
||||||
|
Name string `json:"user_name"`
|
||||||
|
Username string `json:"user_username"`
|
||||||
|
Email string `json:"user_email"`
|
||||||
|
GroupID int `json:"group_id"`
|
||||||
|
GroupName string `json:"group_name"`
|
||||||
|
GroupPath string `json:"group_path"`
|
||||||
|
GroupAccess string `json:"group_access"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserTeamSystemEvent represents a user team system event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/system_hooks/system_hooks.html
|
||||||
|
type UserTeamSystemEvent struct {
|
||||||
|
BaseSystemEvent
|
||||||
|
ID int `json:"user_id"`
|
||||||
|
Name string `json:"user_name"`
|
||||||
|
Username string `json:"user_username"`
|
||||||
|
Email string `json:"user_email"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
ProjectName string `json:"project_name"`
|
||||||
|
ProjectPath string `json:"project_path"`
|
||||||
|
ProjectPathWithNamespace string `json:"project_path_with_namespace"`
|
||||||
|
ProjectVisibility string `json:"project_visibility"`
|
||||||
|
AccessLevel string `json:"access_level"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushSystemEvent represents a push system event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/system_hooks/system_hooks.html
|
||||||
|
type PushSystemEvent struct {
|
||||||
|
BaseSystemEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
// TagPushSystemEvent represents a tag push system event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/system_hooks/system_hooks.html
|
||||||
|
type TagPushSystemEvent struct {
|
||||||
|
BaseSystemEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepositoryUpdateSystemEvent represents a repository updated system event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/system_hooks/system_hooks.html
|
||||||
|
type RepositoryUpdateSystemEvent struct {
|
||||||
|
BaseSystemEvent
|
||||||
|
}
|
951
vendor/github.com/xanzy/go-gitlab/event_webhook_types.go
generated
vendored
Normal file
951
vendor/github.com/xanzy/go-gitlab/event_webhook_types.go
generated
vendored
Normal file
|
@ -0,0 +1,951 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
//BuildEvent represents a build event
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#build-events
|
||||||
|
type BuildEvent struct {
|
||||||
|
ObjectKind string `json:"object_kind"`
|
||||||
|
Ref string `json:"ref"`
|
||||||
|
Tag bool `json:"tag"`
|
||||||
|
BeforeSHA string `json:"before_sha"`
|
||||||
|
SHA string `json:"sha"`
|
||||||
|
BuildID int `json:"build_id"`
|
||||||
|
BuildName string `json:"build_name"`
|
||||||
|
BuildStage string `json:"build_stage"`
|
||||||
|
BuildStatus string `json:"build_status"`
|
||||||
|
BuildStartedAt string `json:"build_started_at"`
|
||||||
|
BuildFinishedAt string `json:"build_finished_at"`
|
||||||
|
BuildDuration float64 `json:"build_duration"`
|
||||||
|
BuildAllowFailure bool `json:"build_allow_failure"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
ProjectName string `json:"project_name"`
|
||||||
|
User *EventUser `json:"user"`
|
||||||
|
Commit struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
SHA string `json:"sha"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
AuthorName string `json:"author_name"`
|
||||||
|
AuthorEmail string `json:"author_email"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Duration int `json:"duration"`
|
||||||
|
StartedAt string `json:"started_at"`
|
||||||
|
FinishedAt string `json:"finished_at"`
|
||||||
|
} `json:"commit"`
|
||||||
|
Repository *Repository `json:"repository"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitCommentEvent represents a comment on a commit event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#comment-on-commit
|
||||||
|
type CommitCommentEvent struct {
|
||||||
|
ObjectKind string `json:"object_kind"`
|
||||||
|
User *User `json:"user"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
Project struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
GitSSHURL string `json:"git_ssh_url"`
|
||||||
|
GitHTTPURL string `json:"git_http_url"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
PathWithNamespace string `json:"path_with_namespace"`
|
||||||
|
DefaultBranch string `json:"default_branch"`
|
||||||
|
Homepage string `json:"homepage"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
SSHURL string `json:"ssh_url"`
|
||||||
|
HTTPURL string `json:"http_url"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
Visibility VisibilityValue `json:"visibility"`
|
||||||
|
} `json:"project"`
|
||||||
|
Repository *Repository `json:"repository"`
|
||||||
|
ObjectAttributes struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Note string `json:"note"`
|
||||||
|
NoteableType string `json:"noteable_type"`
|
||||||
|
AuthorID int `json:"author_id"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
Attachment string `json:"attachment"`
|
||||||
|
LineCode string `json:"line_code"`
|
||||||
|
CommitID string `json:"commit_id"`
|
||||||
|
NoteableID int `json:"noteable_id"`
|
||||||
|
System bool `json:"system"`
|
||||||
|
StDiff struct {
|
||||||
|
Diff string `json:"diff"`
|
||||||
|
NewPath string `json:"new_path"`
|
||||||
|
OldPath string `json:"old_path"`
|
||||||
|
AMode string `json:"a_mode"`
|
||||||
|
BMode string `json:"b_mode"`
|
||||||
|
NewFile bool `json:"new_file"`
|
||||||
|
RenamedFile bool `json:"renamed_file"`
|
||||||
|
DeletedFile bool `json:"deleted_file"`
|
||||||
|
} `json:"st_diff"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
} `json:"object_attributes"`
|
||||||
|
Commit *struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Timestamp *time.Time `json:"timestamp"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
Author struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
} `json:"author"`
|
||||||
|
} `json:"commit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeploymentEvent represents a deployment event
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#deployment-events
|
||||||
|
type DeploymentEvent struct {
|
||||||
|
ObjectKind string `json:"object_kind"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
DeployableID int `json:"deployable_id"`
|
||||||
|
DeployableURL string `json:"deployable_url"`
|
||||||
|
Environment string `json:"environment"`
|
||||||
|
Project struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
AvatarURL *string `json:"avatar_url"`
|
||||||
|
GitSSHURL string `json:"git_ssh_url"`
|
||||||
|
GitHTTPURL string `json:"git_http_url"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
VisibilityLevel int `json:"visibility_level"`
|
||||||
|
PathWithNamespace string `json:"path_with_namespace"`
|
||||||
|
DefaultBranch string `json:"default_branch"`
|
||||||
|
CIConfigPath string `json:"ci_config_path"`
|
||||||
|
Homepage string `json:"homepage"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
SSHURL string `json:"ssh_url"`
|
||||||
|
HTTPURL string `json:"http_url"`
|
||||||
|
} `json:"project"`
|
||||||
|
ShortSHA string `json:"short_sha"`
|
||||||
|
User *EventUser `json:"user"`
|
||||||
|
UserURL string `json:"user_url"`
|
||||||
|
CommitURL string `json:"commit_url"`
|
||||||
|
CommitTitle string `json:"commit_title"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// IssueCommentEvent represents a comment on an issue event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#comment-on-issue
|
||||||
|
type IssueCommentEvent struct {
|
||||||
|
ObjectKind string `json:"object_kind"`
|
||||||
|
User *User `json:"user"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
Project struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
GitSSHURL string `json:"git_ssh_url"`
|
||||||
|
GitHTTPURL string `json:"git_http_url"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
PathWithNamespace string `json:"path_with_namespace"`
|
||||||
|
DefaultBranch string `json:"default_branch"`
|
||||||
|
Homepage string `json:"homepage"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
SSHURL string `json:"ssh_url"`
|
||||||
|
HTTPURL string `json:"http_url"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
Visibility VisibilityValue `json:"visibility"`
|
||||||
|
} `json:"project"`
|
||||||
|
Repository *Repository `json:"repository"`
|
||||||
|
ObjectAttributes struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Note string `json:"note"`
|
||||||
|
NoteableType string `json:"noteable_type"`
|
||||||
|
AuthorID int `json:"author_id"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
Attachment string `json:"attachment"`
|
||||||
|
LineCode string `json:"line_code"`
|
||||||
|
CommitID string `json:"commit_id"`
|
||||||
|
NoteableID int `json:"noteable_id"`
|
||||||
|
System bool `json:"system"`
|
||||||
|
StDiff []*Diff `json:"st_diff"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
} `json:"object_attributes"`
|
||||||
|
Issue struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
IID int `json:"iid"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
MilestoneID int `json:"milestone_id"`
|
||||||
|
AuthorID int `json:"author_id"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
State string `json:"state"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Labels []Label `json:"labels"`
|
||||||
|
LastEditedAt string `json:"last_edit_at"`
|
||||||
|
LastEditedByID int `json:"last_edited_by_id"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
UpdatedByID int `json:"updated_by_id"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
ClosedAt string `json:"closed_at"`
|
||||||
|
DueDate *ISOTime `json:"due_date"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
TimeEstimate int `json:"time_estimate"`
|
||||||
|
Confidential bool `json:"confidential"`
|
||||||
|
TotalTimeSpent int `json:"total_time_spent"`
|
||||||
|
HumanTotalTimeSpent string `json:"human_total_time_spent"`
|
||||||
|
HumanTimeEstimate string `json:"human_time_estimate"`
|
||||||
|
AssigneeIDs []int `json:"assignee_ids"`
|
||||||
|
AssigneeID int `json:"assignee_id"`
|
||||||
|
} `json:"issue"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// IssueEvent represents a issue event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#issues-events
|
||||||
|
type IssueEvent struct {
|
||||||
|
ObjectKind string `json:"object_kind"`
|
||||||
|
User *EventUser `json:"user"`
|
||||||
|
Project struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
GitSSHURL string `json:"git_ssh_url"`
|
||||||
|
GitHTTPURL string `json:"git_http_url"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
PathWithNamespace string `json:"path_with_namespace"`
|
||||||
|
DefaultBranch string `json:"default_branch"`
|
||||||
|
Homepage string `json:"homepage"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
SSHURL string `json:"ssh_url"`
|
||||||
|
HTTPURL string `json:"http_url"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
Visibility VisibilityValue `json:"visibility"`
|
||||||
|
} `json:"project"`
|
||||||
|
Repository *Repository `json:"repository"`
|
||||||
|
ObjectAttributes struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
AssigneeID int `json:"assignee_id"`
|
||||||
|
AuthorID int `json:"author_id"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
CreatedAt string `json:"created_at"` // Should be *time.Time (see Gitlab issue #21468)
|
||||||
|
UpdatedAt string `json:"updated_at"` // Should be *time.Time (see Gitlab issue #21468)
|
||||||
|
Position int `json:"position"`
|
||||||
|
BranchName string `json:"branch_name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
MilestoneID int `json:"milestone_id"`
|
||||||
|
State string `json:"state"`
|
||||||
|
IID int `json:"iid"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
Action string `json:"action"`
|
||||||
|
} `json:"object_attributes"`
|
||||||
|
Assignee *EventUser `json:"assignee"`
|
||||||
|
Assignees *[]EventUser `json:"assignees"`
|
||||||
|
Labels []Label `json:"labels"`
|
||||||
|
Changes struct {
|
||||||
|
Description struct {
|
||||||
|
Previous string `json:"previous"`
|
||||||
|
Current string `json:"current"`
|
||||||
|
} `json:"description"`
|
||||||
|
Labels struct {
|
||||||
|
Previous []Label `json:"previous"`
|
||||||
|
Current []Label `json:"current"`
|
||||||
|
} `json:"labels"`
|
||||||
|
Title struct {
|
||||||
|
Previous string `json:"previous"`
|
||||||
|
Current string `json:"current"`
|
||||||
|
} `json:"title"`
|
||||||
|
UpdatedByID struct {
|
||||||
|
Previous int `json:"previous"`
|
||||||
|
Current int `json:"current"`
|
||||||
|
} `json:"updated_by_id"`
|
||||||
|
TotalTimeSpent struct {
|
||||||
|
Previous int `json:"previous"`
|
||||||
|
Current int `json:"current"`
|
||||||
|
} `json:"total_time_spent"`
|
||||||
|
} `json:"changes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// JobEvent represents a job event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// TODO: link to docs instead of src once they are published.
|
||||||
|
// https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/data_builder/build.rb
|
||||||
|
type JobEvent struct {
|
||||||
|
ObjectKind string `json:"object_kind"`
|
||||||
|
Ref string `json:"ref"`
|
||||||
|
Tag bool `json:"tag"`
|
||||||
|
BeforeSHA string `json:"before_sha"`
|
||||||
|
SHA string `json:"sha"`
|
||||||
|
BuildID int `json:"build_id"`
|
||||||
|
BuildName string `json:"build_name"`
|
||||||
|
BuildStage string `json:"build_stage"`
|
||||||
|
BuildStatus string `json:"build_status"`
|
||||||
|
BuildStartedAt string `json:"build_started_at"`
|
||||||
|
BuildFinishedAt string `json:"build_finished_at"`
|
||||||
|
BuildDuration float64 `json:"build_duration"`
|
||||||
|
BuildAllowFailure bool `json:"build_allow_failure"`
|
||||||
|
BuildFailureReason string `json:"build_failure_reason"`
|
||||||
|
PipelineID int `json:"pipeline_id"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
ProjectName string `json:"project_name"`
|
||||||
|
User *EventUser `json:"user"`
|
||||||
|
Commit struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
SHA string `json:"sha"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
AuthorName string `json:"author_name"`
|
||||||
|
AuthorEmail string `json:"author_email"`
|
||||||
|
AuthorURL string `json:"author_url"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Duration int `json:"duration"`
|
||||||
|
StartedAt string `json:"started_at"`
|
||||||
|
FinishedAt string `json:"finished_at"`
|
||||||
|
} `json:"commit"`
|
||||||
|
Repository *Repository `json:"repository"`
|
||||||
|
Runner struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Active bool `json:"active"`
|
||||||
|
Shared bool `json:"is_shared"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
} `json:"runner"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeCommentEvent represents a comment on a merge event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#comment-on-merge-request
|
||||||
|
type MergeCommentEvent struct {
|
||||||
|
ObjectKind string `json:"object_kind"`
|
||||||
|
User *EventUser `json:"user"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
Project struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
GitSSHURL string `json:"git_ssh_url"`
|
||||||
|
GitHTTPURL string `json:"git_http_url"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
PathWithNamespace string `json:"path_with_namespace"`
|
||||||
|
DefaultBranch string `json:"default_branch"`
|
||||||
|
Homepage string `json:"homepage"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
SSHURL string `json:"ssh_url"`
|
||||||
|
HTTPURL string `json:"http_url"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
Visibility VisibilityValue `json:"visibility"`
|
||||||
|
} `json:"project"`
|
||||||
|
ObjectAttributes struct {
|
||||||
|
Attachment string `json:"attachment"`
|
||||||
|
AuthorID int `json:"author_id"`
|
||||||
|
ChangePosition *NotePosition `json:"change_position"`
|
||||||
|
CommitID string `json:"commit_id"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
DiscussionID string `json:"discussion_id"`
|
||||||
|
ID int `json:"id"`
|
||||||
|
LineCode string `json:"line_code"`
|
||||||
|
Note string `json:"note"`
|
||||||
|
NoteableID int `json:"noteable_id"`
|
||||||
|
NoteableType string `json:"noteable_type"`
|
||||||
|
OriginalPosition *NotePosition `json:"original_position"`
|
||||||
|
Position *NotePosition `json:"position"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
ResolvedAt string `json:"resolved_at"`
|
||||||
|
ResolvedByID int `json:"resolved_by_id"`
|
||||||
|
ResolvedByPush bool `json:"resolved_by_push"`
|
||||||
|
StDiff *Diff `json:"st_diff"`
|
||||||
|
System bool `json:"system"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
UpdatedByID string `json:"updated_by_id"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
} `json:"object_attributes"`
|
||||||
|
Repository *Repository `json:"repository"`
|
||||||
|
MergeRequest struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
TargetBranch string `json:"target_branch"`
|
||||||
|
SourceBranch string `json:"source_branch"`
|
||||||
|
SourceProjectID int `json:"source_project_id"`
|
||||||
|
AuthorID int `json:"author_id"`
|
||||||
|
AssigneeID int `json:"assignee_id"`
|
||||||
|
AssigneeIDs []int `json:"assignee_ids"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
MilestoneID int `json:"milestone_id"`
|
||||||
|
State string `json:"state"`
|
||||||
|
MergeStatus string `json:"merge_status"`
|
||||||
|
TargetProjectID int `json:"target_project_id"`
|
||||||
|
IID int `json:"iid"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Position int `json:"position"`
|
||||||
|
LockedAt string `json:"locked_at"`
|
||||||
|
UpdatedByID int `json:"updated_by_id"`
|
||||||
|
MergeError string `json:"merge_error"`
|
||||||
|
MergeParams *MergeParams `json:"merge_params"`
|
||||||
|
MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"`
|
||||||
|
MergeUserID int `json:"merge_user_id"`
|
||||||
|
MergeCommitSHA string `json:"merge_commit_sha"`
|
||||||
|
DeletedAt string `json:"deleted_at"`
|
||||||
|
InProgressMergeCommitSHA string `json:"in_progress_merge_commit_sha"`
|
||||||
|
LockVersion int `json:"lock_version"`
|
||||||
|
ApprovalsBeforeMerge string `json:"approvals_before_merge"`
|
||||||
|
RebaseCommitSHA string `json:"rebase_commit_sha"`
|
||||||
|
TimeEstimate int `json:"time_estimate"`
|
||||||
|
Squash bool `json:"squash"`
|
||||||
|
LastEditedAt string `json:"last_edited_at"`
|
||||||
|
LastEditedByID int `json:"last_edited_by_id"`
|
||||||
|
Source *Repository `json:"source"`
|
||||||
|
Target *Repository `json:"target"`
|
||||||
|
LastCommit struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Timestamp *time.Time `json:"timestamp"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
Author struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
} `json:"author"`
|
||||||
|
} `json:"last_commit"`
|
||||||
|
WorkInProgress bool `json:"work_in_progress"`
|
||||||
|
TotalTimeSpent int `json:"total_time_spent"`
|
||||||
|
HeadPipelineID int `json:"head_pipeline_id"`
|
||||||
|
} `json:"merge_request"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeEvent represents a merge event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#merge-request-events
|
||||||
|
type MergeEvent struct {
|
||||||
|
ObjectKind string `json:"object_kind"`
|
||||||
|
User *EventUser `json:"user"`
|
||||||
|
Project struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
GitSSHURL string `json:"git_ssh_url"`
|
||||||
|
GitHTTPURL string `json:"git_http_url"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
PathWithNamespace string `json:"path_with_namespace"`
|
||||||
|
DefaultBranch string `json:"default_branch"`
|
||||||
|
Homepage string `json:"homepage"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
SSHURL string `json:"ssh_url"`
|
||||||
|
HTTPURL string `json:"http_url"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
Visibility VisibilityValue `json:"visibility"`
|
||||||
|
} `json:"project"`
|
||||||
|
ObjectAttributes struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
TargetBranch string `json:"target_branch"`
|
||||||
|
SourceBranch string `json:"source_branch"`
|
||||||
|
SourceProjectID int `json:"source_project_id"`
|
||||||
|
AuthorID int `json:"author_id"`
|
||||||
|
AssigneeID int `json:"assignee_id"`
|
||||||
|
AssigneeIDs []int `json:"assignee_ids"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
CreatedAt string `json:"created_at"` // Should be *time.Time (see Gitlab issue #21468)
|
||||||
|
UpdatedAt string `json:"updated_at"` // Should be *time.Time (see Gitlab issue #21468)
|
||||||
|
StCommits []*Commit `json:"st_commits"`
|
||||||
|
StDiffs []*Diff `json:"st_diffs"`
|
||||||
|
MilestoneID int `json:"milestone_id"`
|
||||||
|
State string `json:"state"`
|
||||||
|
MergeStatus string `json:"merge_status"`
|
||||||
|
TargetProjectID int `json:"target_project_id"`
|
||||||
|
IID int `json:"iid"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Position int `json:"position"`
|
||||||
|
LockedAt string `json:"locked_at"`
|
||||||
|
UpdatedByID int `json:"updated_by_id"`
|
||||||
|
MergeError string `json:"merge_error"`
|
||||||
|
MergeParams *MergeParams `json:"merge_params"`
|
||||||
|
MergeWhenBuildSucceeds bool `json:"merge_when_build_succeeds"`
|
||||||
|
MergeUserID int `json:"merge_user_id"`
|
||||||
|
MergeCommitSHA string `json:"merge_commit_sha"`
|
||||||
|
DeletedAt string `json:"deleted_at"`
|
||||||
|
ApprovalsBeforeMerge string `json:"approvals_before_merge"`
|
||||||
|
RebaseCommitSHA string `json:"rebase_commit_sha"`
|
||||||
|
InProgressMergeCommitSHA string `json:"in_progress_merge_commit_sha"`
|
||||||
|
LockVersion int `json:"lock_version"`
|
||||||
|
TimeEstimate int `json:"time_estimate"`
|
||||||
|
Source *Repository `json:"source"`
|
||||||
|
Target *Repository `json:"target"`
|
||||||
|
HeadPipelineID *int `json:"head_pipeline_id"`
|
||||||
|
LastCommit struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Timestamp *time.Time `json:"timestamp"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
Author struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
} `json:"author"`
|
||||||
|
} `json:"last_commit"`
|
||||||
|
WorkInProgress bool `json:"work_in_progress"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
Action string `json:"action"`
|
||||||
|
OldRev string `json:"oldrev"`
|
||||||
|
Assignee *EventUser `json:"assignee"`
|
||||||
|
} `json:"object_attributes"`
|
||||||
|
Repository *Repository `json:"repository"`
|
||||||
|
Assignee *EventUser `json:"assignee"`
|
||||||
|
Assignees []*EventUser `json:"assignees"`
|
||||||
|
Labels []*Label `json:"labels"`
|
||||||
|
Changes struct {
|
||||||
|
Assignees struct {
|
||||||
|
Previous []*EventUser `json:"previous"`
|
||||||
|
Current []*EventUser `json:"current"`
|
||||||
|
} `json:"assignees"`
|
||||||
|
Description struct {
|
||||||
|
Previous string `json:"previous"`
|
||||||
|
Current string `json:"current"`
|
||||||
|
} `json:"description"`
|
||||||
|
Labels struct {
|
||||||
|
Previous []*Label `json:"previous"`
|
||||||
|
Current []*Label `json:"current"`
|
||||||
|
} `json:"labels"`
|
||||||
|
SourceBranch struct {
|
||||||
|
Previous string `json:"previous"`
|
||||||
|
Current string `json:"current"`
|
||||||
|
} `json:"source_branch"`
|
||||||
|
SourceProjectID struct {
|
||||||
|
Previous int `json:"previous"`
|
||||||
|
Current int `json:"current"`
|
||||||
|
} `json:"source_project_id"`
|
||||||
|
StateID struct {
|
||||||
|
Previous int `json:"previous"`
|
||||||
|
Current int `json:"current"`
|
||||||
|
} `json:"state_id"`
|
||||||
|
TargetBranch struct {
|
||||||
|
Previous string `json:"previous"`
|
||||||
|
Current string `json:"current"`
|
||||||
|
} `json:"target_branch"`
|
||||||
|
TargetProjectID struct {
|
||||||
|
Previous int `json:"previous"`
|
||||||
|
Current int `json:"current"`
|
||||||
|
} `json:"target_project_id"`
|
||||||
|
Title struct {
|
||||||
|
Previous string `json:"previous"`
|
||||||
|
Current string `json:"current"`
|
||||||
|
} `json:"title"`
|
||||||
|
UpdatedByID struct {
|
||||||
|
Previous int `json:"previous"`
|
||||||
|
Current int `json:"current"`
|
||||||
|
} `json:"updated_by_id"`
|
||||||
|
MilestoneID struct {
|
||||||
|
Previous int `json:"previous"`
|
||||||
|
Current int `json:"current"`
|
||||||
|
} `json:"milestone_id"`
|
||||||
|
} `json:"changes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventUser represents a user record in an event and is used as an even initiator or a merge assignee.
|
||||||
|
type EventUser struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeParams represents the merge params.
|
||||||
|
type MergeParams struct {
|
||||||
|
ForceRemoveSourceBranch bool `json:"force_remove_source_branch"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON decodes the merge parameters
|
||||||
|
//
|
||||||
|
// This allows support of ForceRemoveSourceBranch for both type bool (>11.9) and string (<11.9)
|
||||||
|
func (p *MergeParams) UnmarshalJSON(b []byte) error {
|
||||||
|
type Alias MergeParams
|
||||||
|
raw := struct {
|
||||||
|
*Alias
|
||||||
|
ForceRemoveSourceBranch interface{} `json:"force_remove_source_branch"`
|
||||||
|
}{
|
||||||
|
Alias: (*Alias)(p),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := json.Unmarshal(b, &raw)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := raw.ForceRemoveSourceBranch.(type) {
|
||||||
|
case nil:
|
||||||
|
// No action needed.
|
||||||
|
case bool:
|
||||||
|
p.ForceRemoveSourceBranch = v
|
||||||
|
case string:
|
||||||
|
p.ForceRemoveSourceBranch, err = strconv.ParseBool(v)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("failed to unmarshal ForceRemoveSourceBranch of type: %T", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PipelineEvent represents a pipeline event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#pipeline-events
|
||||||
|
type PipelineEvent struct {
|
||||||
|
ObjectKind string `json:"object_kind"`
|
||||||
|
ObjectAttributes struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Ref string `json:"ref"`
|
||||||
|
Tag bool `json:"tag"`
|
||||||
|
SHA string `json:"sha"`
|
||||||
|
BeforeSHA string `json:"before_sha"`
|
||||||
|
Source string `json:"source"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
DetailedStatus string `json:"detailed_status"`
|
||||||
|
Stages []string `json:"stages"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
FinishedAt string `json:"finished_at"`
|
||||||
|
Duration int `json:"duration"`
|
||||||
|
QueuedDuration int `json:"queued_duration"`
|
||||||
|
} `json:"object_attributes"`
|
||||||
|
MergeRequest struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
IID int `json:"iid"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
SourceBranch string `json:"source_branch"`
|
||||||
|
SourceProjectID int `json:"source_project_id"`
|
||||||
|
TargetBranch string `json:"target_branch"`
|
||||||
|
TargetProjectID int `json:"target_project_id"`
|
||||||
|
State string `json:"state"`
|
||||||
|
MergeRequestStatus string `json:"merge_status"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
} `json:"merge_request"`
|
||||||
|
User *EventUser `json:"user"`
|
||||||
|
Project struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
GitSSHURL string `json:"git_ssh_url"`
|
||||||
|
GitHTTPURL string `json:"git_http_url"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
PathWithNamespace string `json:"path_with_namespace"`
|
||||||
|
DefaultBranch string `json:"default_branch"`
|
||||||
|
Homepage string `json:"homepage"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
SSHURL string `json:"ssh_url"`
|
||||||
|
HTTPURL string `json:"http_url"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
Visibility VisibilityValue `json:"visibility"`
|
||||||
|
} `json:"project"`
|
||||||
|
Commit struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Timestamp *time.Time `json:"timestamp"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
Author struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
} `json:"author"`
|
||||||
|
} `json:"commit"`
|
||||||
|
Builds []struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Stage string `json:"stage"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
StartedAt string `json:"started_at"`
|
||||||
|
FinishedAt string `json:"finished_at"`
|
||||||
|
When string `json:"when"`
|
||||||
|
Manual bool `json:"manual"`
|
||||||
|
AllowFailure bool `json:"allow_failure"`
|
||||||
|
User *EventUser `json:"user"`
|
||||||
|
Runner struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Active bool `json:"active"`
|
||||||
|
IsShared bool `json:"is_shared"`
|
||||||
|
} `json:"runner"`
|
||||||
|
ArtifactsFile struct {
|
||||||
|
Filename string `json:"filename"`
|
||||||
|
Size int `json:"size"`
|
||||||
|
} `json:"artifacts_file"`
|
||||||
|
} `json:"builds"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushEvent represents a push event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#push-events
|
||||||
|
type PushEvent struct {
|
||||||
|
ObjectKind string `json:"object_kind"`
|
||||||
|
Before string `json:"before"`
|
||||||
|
After string `json:"after"`
|
||||||
|
Ref string `json:"ref"`
|
||||||
|
CheckoutSHA string `json:"checkout_sha"`
|
||||||
|
UserID int `json:"user_id"`
|
||||||
|
UserName string `json:"user_name"`
|
||||||
|
UserUsername string `json:"user_username"`
|
||||||
|
UserEmail string `json:"user_email"`
|
||||||
|
UserAvatar string `json:"user_avatar"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
Project struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
GitSSHURL string `json:"git_ssh_url"`
|
||||||
|
GitHTTPURL string `json:"git_http_url"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
PathWithNamespace string `json:"path_with_namespace"`
|
||||||
|
DefaultBranch string `json:"default_branch"`
|
||||||
|
Homepage string `json:"homepage"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
SSHURL string `json:"ssh_url"`
|
||||||
|
HTTPURL string `json:"http_url"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
Visibility VisibilityValue `json:"visibility"`
|
||||||
|
} `json:"project"`
|
||||||
|
Repository *Repository `json:"repository"`
|
||||||
|
Commits []*struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Timestamp *time.Time `json:"timestamp"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
Author struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
} `json:"author"`
|
||||||
|
Added []string `json:"added"`
|
||||||
|
Modified []string `json:"modified"`
|
||||||
|
Removed []string `json:"removed"`
|
||||||
|
} `json:"commits"`
|
||||||
|
TotalCommitsCount int `json:"total_commits_count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReleaseEvent represents a release event
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#release-events
|
||||||
|
type ReleaseEvent struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
CreatedAt string `json:"created_at"` // Should be *time.Time (see Gitlab issue #21468)
|
||||||
|
Description string `json:"description"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Tag string `json:"tag"`
|
||||||
|
ReleasedAt string `json:"released_at"` // Should be *time.Time (see Gitlab issue #21468)
|
||||||
|
ObjectKind string `json:"object_kind"`
|
||||||
|
Project struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
AvatarURL *string `json:"avatar_url"`
|
||||||
|
GitSSHURL string `json:"git_ssh_url"`
|
||||||
|
GitHTTPURL string `json:"git_http_url"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
VisibilityLevel int `json:"visibility_level"`
|
||||||
|
PathWithNamespace string `json:"path_with_namespace"`
|
||||||
|
DefaultBranch string `json:"default_branch"`
|
||||||
|
CIConfigPath string `json:"ci_config_path"`
|
||||||
|
Homepage string `json:"homepage"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
SSHURL string `json:"ssh_url"`
|
||||||
|
HTTPURL string `json:"http_url"`
|
||||||
|
} `json:"project"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
Action string `json:"action"`
|
||||||
|
Assets struct {
|
||||||
|
Count int `json:"count"`
|
||||||
|
Links []struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
External bool `json:"external"`
|
||||||
|
LinkType string `json:"link_type"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
} `json:"links"`
|
||||||
|
Sources []struct {
|
||||||
|
Format string `json:"format"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
} `json:"sources"`
|
||||||
|
} `json:"assets"`
|
||||||
|
Commit struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Timestamp string `json:"timestamp"` // Should be *time.Time (see Gitlab issue #21468)
|
||||||
|
URL string `json:"url"`
|
||||||
|
Author struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
} `json:"author"`
|
||||||
|
} `json:"commit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SnippetCommentEvent represents a comment on a snippet event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#comment-on-code-snippet
|
||||||
|
type SnippetCommentEvent struct {
|
||||||
|
ObjectKind string `json:"object_kind"`
|
||||||
|
User *EventUser `json:"user"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
Project struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
GitSSHURL string `json:"git_ssh_url"`
|
||||||
|
GitHTTPURL string `json:"git_http_url"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
PathWithNamespace string `json:"path_with_namespace"`
|
||||||
|
DefaultBranch string `json:"default_branch"`
|
||||||
|
Homepage string `json:"homepage"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
SSHURL string `json:"ssh_url"`
|
||||||
|
HTTPURL string `json:"http_url"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
Visibility VisibilityValue `json:"visibility"`
|
||||||
|
} `json:"project"`
|
||||||
|
Repository *Repository `json:"repository"`
|
||||||
|
ObjectAttributes struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Note string `json:"note"`
|
||||||
|
NoteableType string `json:"noteable_type"`
|
||||||
|
AuthorID int `json:"author_id"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
Attachment string `json:"attachment"`
|
||||||
|
LineCode string `json:"line_code"`
|
||||||
|
CommitID string `json:"commit_id"`
|
||||||
|
NoteableID int `json:"noteable_id"`
|
||||||
|
System bool `json:"system"`
|
||||||
|
StDiff *Diff `json:"st_diff"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
} `json:"object_attributes"`
|
||||||
|
Snippet *Snippet `json:"snippet"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TagEvent represents a tag event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#tag-events
|
||||||
|
type TagEvent struct {
|
||||||
|
ObjectKind string `json:"object_kind"`
|
||||||
|
Before string `json:"before"`
|
||||||
|
After string `json:"after"`
|
||||||
|
Ref string `json:"ref"`
|
||||||
|
CheckoutSHA string `json:"checkout_sha"`
|
||||||
|
UserID int `json:"user_id"`
|
||||||
|
UserName string `json:"user_name"`
|
||||||
|
UserUsername string `json:"user_username"`
|
||||||
|
UserAvatar string `json:"user_avatar"`
|
||||||
|
UserEmail string `json:"user_email"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Project struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
GitSSHURL string `json:"git_ssh_url"`
|
||||||
|
GitHTTPURL string `json:"git_http_url"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
PathWithNamespace string `json:"path_with_namespace"`
|
||||||
|
DefaultBranch string `json:"default_branch"`
|
||||||
|
Homepage string `json:"homepage"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
SSHURL string `json:"ssh_url"`
|
||||||
|
HTTPURL string `json:"http_url"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
Visibility VisibilityValue `json:"visibility"`
|
||||||
|
} `json:"project"`
|
||||||
|
Repository *Repository `json:"repository"`
|
||||||
|
Commits []*struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Timestamp *time.Time `json:"timestamp"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
Author struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
} `json:"author"`
|
||||||
|
Added []string `json:"added"`
|
||||||
|
Modified []string `json:"modified"`
|
||||||
|
Removed []string `json:"removed"`
|
||||||
|
} `json:"commits"`
|
||||||
|
TotalCommitsCount int `json:"total_commits_count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// WikiPageEvent represents a wiki page event.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#wiki-page-events
|
||||||
|
type WikiPageEvent struct {
|
||||||
|
ObjectKind string `json:"object_kind"`
|
||||||
|
User *EventUser `json:"user"`
|
||||||
|
Project struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
GitSSHURL string `json:"git_ssh_url"`
|
||||||
|
GitHTTPURL string `json:"git_http_url"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
PathWithNamespace string `json:"path_with_namespace"`
|
||||||
|
DefaultBranch string `json:"default_branch"`
|
||||||
|
Homepage string `json:"homepage"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
SSHURL string `json:"ssh_url"`
|
||||||
|
HTTPURL string `json:"http_url"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
Visibility VisibilityValue `json:"visibility"`
|
||||||
|
} `json:"project"`
|
||||||
|
Wiki struct {
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
GitSSHURL string `json:"git_ssh_url"`
|
||||||
|
GitHTTPURL string `json:"git_http_url"`
|
||||||
|
PathWithNamespace string `json:"path_with_namespace"`
|
||||||
|
DefaultBranch string `json:"default_branch"`
|
||||||
|
} `json:"wiki"`
|
||||||
|
ObjectAttributes struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
Format string `json:"format"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Slug string `json:"slug"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
Action string `json:"action"`
|
||||||
|
} `json:"object_attributes"`
|
||||||
|
}
|
148
vendor/github.com/xanzy/go-gitlab/events.go
generated
vendored
Normal file
148
vendor/github.com/xanzy/go-gitlab/events.go
generated
vendored
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EventsService handles communication with the event related methods of
|
||||||
|
// the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/events.html
|
||||||
|
type EventsService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContributionEvent represents a user's contribution
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/events.html#get-user-contribution-events
|
||||||
|
type ContributionEvent struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
|
ActionName string `json:"action_name"`
|
||||||
|
TargetID int `json:"target_id"`
|
||||||
|
TargetIID int `json:"target_iid"`
|
||||||
|
TargetType string `json:"target_type"`
|
||||||
|
AuthorID int `json:"author_id"`
|
||||||
|
TargetTitle string `json:"target_title"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
PushData struct {
|
||||||
|
CommitCount int `json:"commit_count"`
|
||||||
|
Action string `json:"action"`
|
||||||
|
RefType string `json:"ref_type"`
|
||||||
|
CommitFrom string `json:"commit_from"`
|
||||||
|
CommitTo string `json:"commit_to"`
|
||||||
|
Ref string `json:"ref"`
|
||||||
|
CommitTitle string `json:"commit_title"`
|
||||||
|
} `json:"push_data"`
|
||||||
|
Note *Note `json:"note"`
|
||||||
|
Author struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
ID int `json:"id"`
|
||||||
|
State string `json:"state"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
} `json:"author"`
|
||||||
|
AuthorUsername string `json:"author_username"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListContributionEventsOptions represents the options for GetUserContributionEvents
|
||||||
|
//
|
||||||
|
// GitLap API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/events.html#get-user-contribution-events
|
||||||
|
type ListContributionEventsOptions struct {
|
||||||
|
ListOptions
|
||||||
|
Action *EventTypeValue `url:"action,omitempty" json:"action,omitempty"`
|
||||||
|
TargetType *EventTargetTypeValue `url:"target_type,omitempty" json:"target_type,omitempty"`
|
||||||
|
Before *ISOTime `url:"before,omitempty" json:"before,omitempty"`
|
||||||
|
After *ISOTime `url:"after,omitempty" json:"after,omitempty"`
|
||||||
|
Sort *string `url:"sort,omitempty" json:"sort,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListUserContributionEvents retrieves user contribution events
|
||||||
|
// for the specified user, sorted from newest to oldest.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/events.html#get-user-contribution-events
|
||||||
|
func (s *UsersService) ListUserContributionEvents(uid interface{}, opt *ListContributionEventsOptions, options ...RequestOptionFunc) ([]*ContributionEvent, *Response, error) {
|
||||||
|
user, err := parseID(uid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("users/%s/events", user)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var cs []*ContributionEvent
|
||||||
|
resp, err := s.client.Do(req, &cs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cs, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListCurrentUserContributionEvents gets a list currently authenticated user's events
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/events.html#list-currently-authenticated-user-39-s-events
|
||||||
|
func (s *EventsService) ListCurrentUserContributionEvents(opt *ListContributionEventsOptions, options ...RequestOptionFunc) ([]*ContributionEvent, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, "events", opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var cs []*ContributionEvent
|
||||||
|
resp, err := s.client.Do(req, &cs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cs, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListProjectVisibleEvents gets a list of visible events for a particular project
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/events.html#list-a-project-s-visible-events
|
||||||
|
func (s *EventsService) ListProjectVisibleEvents(pid interface{}, opt *ListContributionEventsOptions, options ...RequestOptionFunc) ([]*ContributionEvent, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/events", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var cs []*ContributionEvent
|
||||||
|
resp, err := s.client.Do(req, &cs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cs, resp, err
|
||||||
|
}
|
96
vendor/github.com/xanzy/go-gitlab/feature_flags.go
generated
vendored
Normal file
96
vendor/github.com/xanzy/go-gitlab/feature_flags.go
generated
vendored
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FeaturesService handles the communication with the application FeaturesService
|
||||||
|
// related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/features.html
|
||||||
|
type FeaturesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feature represents a GitLab feature flag.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/features.html
|
||||||
|
type Feature struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
State string `json:"state"`
|
||||||
|
Gates []Gate
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gate represents a gate of a GitLab feature flag.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/features.html
|
||||||
|
type Gate struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value interface{} `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Feature) String() string {
|
||||||
|
return Stringify(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListFeatures gets a list of feature flags
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/features.html#list-all-features
|
||||||
|
func (s *FeaturesService) ListFeatures(options ...RequestOptionFunc) ([]*Feature, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, "features", nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var f []*Feature
|
||||||
|
resp, err := s.client.Do(req, &f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
return f, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFeatureFlag sets or creates a feature flag gate
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/features.html#set-or-create-a-feature
|
||||||
|
func (s *FeaturesService) SetFeatureFlag(name string, value interface{}, options ...RequestOptionFunc) (*Feature, *Response, error) {
|
||||||
|
u := fmt.Sprintf("features/%s", url.PathEscape(name))
|
||||||
|
|
||||||
|
opt := struct {
|
||||||
|
Value interface{} `url:"value" json:"value"`
|
||||||
|
}{
|
||||||
|
value,
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
f := &Feature{}
|
||||||
|
resp, err := s.client.Do(req, f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
return f, resp, err
|
||||||
|
}
|
194
vendor/github.com/xanzy/go-gitlab/freeze_periods.go
generated
vendored
Normal file
194
vendor/github.com/xanzy/go-gitlab/freeze_periods.go
generated
vendored
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021 Paul Cioanca
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FreezePeriodsService handles the communication with the freeze periods
|
||||||
|
// related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// https://docs.gitlab.com/ce/api/freeze_periods.html
|
||||||
|
type FreezePeriodsService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// FreezePeriod represents a freeze period object.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/freeze_periods.html#list-freeze-periods
|
||||||
|
type FreezePeriod struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
FreezeStart string `json:"freeze_start"`
|
||||||
|
FreezeEnd string `json:"freeze_end"`
|
||||||
|
CronTimezone string `json:"cron_timezone"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
UpdatedAt *time.Time `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListFreezePeriodsOptions represents the available ListFreezePeriodsOptions()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/freeze_periods.html#list-freeze-periods
|
||||||
|
type ListFreezePeriodsOptions ListOptions
|
||||||
|
|
||||||
|
// ListFreezePeriods gets a list of project project freeze periods.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/freeze_periods.html#list-freeze-periods
|
||||||
|
func (s *FreezePeriodsService) ListFreezePeriods(pid interface{}, opt *ListFreezePeriodsOptions, options ...RequestOptionFunc) ([]*FreezePeriod, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/freeze_periods", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var fp []*FreezePeriod
|
||||||
|
resp, err := s.client.Do(req, &fp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fp, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFreezePeriod gets a specific freeze period for a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/freeze_periods.html#get-a-freeze-period-by-a-freeze_period_id
|
||||||
|
func (s *FreezePeriodsService) GetFreezePeriod(pid interface{}, freezePeriod int, options ...RequestOptionFunc) (*FreezePeriod, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/freeze_periods/%d", pathEscape(project), freezePeriod)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fp := new(FreezePeriod)
|
||||||
|
resp, err := s.client.Do(req, fp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fp, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateFreezePeriodOptions represents the available CreateFreezePeriodOptions()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/freeze_periods.html#create-a-freeze-period
|
||||||
|
type CreateFreezePeriodOptions struct {
|
||||||
|
FreezeStart *string `url:"freeze_start,omitempty" json:"freeze_start,omitempty"`
|
||||||
|
FreezeEnd *string `url:"freeze_end,omitempty" json:"freeze_end,omitempty"`
|
||||||
|
CronTimezone *string `url:"cron_timezone,omitempty" json:"cron_timezone,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateFreezePeriodOptions adds a freeze period to a specified project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/freeze_periods.html#create-a-freeze-period
|
||||||
|
func (s *FreezePeriodsService) CreateFreezePeriodOptions(pid interface{}, opt *CreateFreezePeriodOptions, options ...RequestOptionFunc) (*FreezePeriod, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/freeze_periods", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fp := new(FreezePeriod)
|
||||||
|
resp, err := s.client.Do(req, fp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fp, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateFreezePeriodOptions represents the available UpdateFreezePeriodOptions()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/freeze_periods.html#update-a-freeze-period
|
||||||
|
type UpdateFreezePeriodOptions struct {
|
||||||
|
FreezeStart *string `url:"freeze_start,omitempty" json:"freeze_start,omitempty"`
|
||||||
|
FreezeEnd *string `url:"freeze_end,omitempty" json:"freeze_end,omitempty"`
|
||||||
|
CronTimezone *string `url:"cron_timezone,omitempty" json:"cron_timezone,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateFreezePeriodOptions edits a freeze period for a specified project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/freeze_periods.html#update-a-freeze-period
|
||||||
|
func (s *FreezePeriodsService) UpdateFreezePeriodOptions(pid interface{}, freezePeriod int, opt *UpdateFreezePeriodOptions, options ...RequestOptionFunc) (*FreezePeriod, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/freeze_periods/%d", pathEscape(project), freezePeriod)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fp := new(FreezePeriod)
|
||||||
|
resp, err := s.client.Do(req, fp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fp, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteFreezePeriod removes a freeze period from a project. This is an
|
||||||
|
// idempotent method and can be called multiple times. Either the hook is
|
||||||
|
// available or not.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/freeze_periods.html#delete-a-freeze-period
|
||||||
|
func (s *FreezePeriodsService) DeleteFreezePeriod(pid interface{}, freezePeriod int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/freeze_periods/%d", pathEscape(project), freezePeriod)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
85
vendor/github.com/xanzy/go-gitlab/gitignore_templates.go
generated
vendored
Normal file
85
vendor/github.com/xanzy/go-gitlab/gitignore_templates.go
generated
vendored
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GitIgnoreTemplatesService handles communication with the gitignore
|
||||||
|
// templates related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/templates/gitignores.html
|
||||||
|
type GitIgnoreTemplatesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// GitIgnoreTemplate represents a GitLab gitignore template.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/templates/gitignores.html
|
||||||
|
type GitIgnoreTemplate struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListTemplatesOptions represents the available ListAllTemplates() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/gitignores.html#list-gitignore-templates
|
||||||
|
type ListTemplatesOptions ListOptions
|
||||||
|
|
||||||
|
// ListTemplates get a list of available git ignore templates
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/gitignores.html#list-gitignore-templates
|
||||||
|
func (s *GitIgnoreTemplatesService) ListTemplates(opt *ListTemplatesOptions, options ...RequestOptionFunc) ([]*GitIgnoreTemplate, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, "templates/gitignores", opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var gs []*GitIgnoreTemplate
|
||||||
|
resp, err := s.client.Do(req, &gs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gs, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTemplate get a git ignore template
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/gitignores.html#get-a-single-gitignore-template
|
||||||
|
func (s *GitIgnoreTemplatesService) GetTemplate(key string, options ...RequestOptionFunc) (*GitIgnoreTemplate, *Response, error) {
|
||||||
|
u := fmt.Sprintf("templates/gitignores/%s", url.PathEscape(key))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
g := new(GitIgnoreTemplate)
|
||||||
|
resp, err := s.client.Do(req, g)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return g, resp, err
|
||||||
|
}
|
830
vendor/github.com/xanzy/go-gitlab/gitlab.go
generated
vendored
Normal file
830
vendor/github.com/xanzy/go-gitlab/gitlab.go
generated
vendored
Normal file
|
@ -0,0 +1,830 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Package gitlab implements a GitLab API client.
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/go-querystring/query"
|
||||||
|
"github.com/hashicorp/go-cleanhttp"
|
||||||
|
retryablehttp "github.com/hashicorp/go-retryablehttp"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
"golang.org/x/time/rate"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultBaseURL = "https://gitlab.com/"
|
||||||
|
apiVersionPath = "api/v4/"
|
||||||
|
userAgent = "go-gitlab"
|
||||||
|
|
||||||
|
headerRateLimit = "RateLimit-Limit"
|
||||||
|
headerRateReset = "RateLimit-Reset"
|
||||||
|
)
|
||||||
|
|
||||||
|
// authType represents an authentication type within GitLab.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/
|
||||||
|
type authType int
|
||||||
|
|
||||||
|
// List of available authentication types.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/
|
||||||
|
const (
|
||||||
|
basicAuth authType = iota
|
||||||
|
jobToken
|
||||||
|
oAuthToken
|
||||||
|
privateToken
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Client manages communication with the GitLab API.
|
||||||
|
type Client struct {
|
||||||
|
// HTTP client used to communicate with the API.
|
||||||
|
client *retryablehttp.Client
|
||||||
|
|
||||||
|
// Base URL for API requests. Defaults to the public GitLab API, but can be
|
||||||
|
// set to a domain endpoint to use with a self hosted GitLab server. baseURL
|
||||||
|
// should always be specified with a trailing slash.
|
||||||
|
baseURL *url.URL
|
||||||
|
|
||||||
|
// disableRetries is used to disable the default retry logic.
|
||||||
|
disableRetries bool
|
||||||
|
|
||||||
|
// configureLimiterOnce is used to make sure the limiter is configured exactly
|
||||||
|
// once and block all other calls until the initial (one) call is done.
|
||||||
|
configureLimiterOnce sync.Once
|
||||||
|
|
||||||
|
// Limiter is used to limit API calls and prevent 429 responses.
|
||||||
|
limiter RateLimiter
|
||||||
|
|
||||||
|
// Token type used to make authenticated API calls.
|
||||||
|
authType authType
|
||||||
|
|
||||||
|
// Username and password used for basix authentication.
|
||||||
|
username, password string
|
||||||
|
|
||||||
|
// Token used to make authenticated API calls.
|
||||||
|
token string
|
||||||
|
|
||||||
|
// Protects the token field from concurrent read/write accesses.
|
||||||
|
tokenLock sync.RWMutex
|
||||||
|
|
||||||
|
// User agent used when communicating with the GitLab API.
|
||||||
|
UserAgent string
|
||||||
|
|
||||||
|
// Services used for talking to different parts of the GitLab API.
|
||||||
|
AccessRequests *AccessRequestsService
|
||||||
|
Applications *ApplicationsService
|
||||||
|
AuditEvents *AuditEventsService
|
||||||
|
Avatar *AvatarRequestsService
|
||||||
|
AwardEmoji *AwardEmojiService
|
||||||
|
Boards *IssueBoardsService
|
||||||
|
Branches *BranchesService
|
||||||
|
BroadcastMessage *BroadcastMessagesService
|
||||||
|
CIYMLTemplate *CIYMLTemplatesService
|
||||||
|
Commits *CommitsService
|
||||||
|
ContainerRegistry *ContainerRegistryService
|
||||||
|
CustomAttribute *CustomAttributesService
|
||||||
|
DeployKeys *DeployKeysService
|
||||||
|
DeployTokens *DeployTokensService
|
||||||
|
Deployments *DeploymentsService
|
||||||
|
Discussions *DiscussionsService
|
||||||
|
Environments *EnvironmentsService
|
||||||
|
EpicIssues *EpicIssuesService
|
||||||
|
Epics *EpicsService
|
||||||
|
Events *EventsService
|
||||||
|
Features *FeaturesService
|
||||||
|
FreezePeriods *FreezePeriodsService
|
||||||
|
GitIgnoreTemplates *GitIgnoreTemplatesService
|
||||||
|
GroupBadges *GroupBadgesService
|
||||||
|
GroupCluster *GroupClustersService
|
||||||
|
GroupImportExport *GroupImportExportService
|
||||||
|
GroupIssueBoards *GroupIssueBoardsService
|
||||||
|
GroupLabels *GroupLabelsService
|
||||||
|
GroupMembers *GroupMembersService
|
||||||
|
GroupMilestones *GroupMilestonesService
|
||||||
|
GroupVariables *GroupVariablesService
|
||||||
|
GroupWikis *GroupWikisService
|
||||||
|
Groups *GroupsService
|
||||||
|
InstanceCluster *InstanceClustersService
|
||||||
|
InstanceVariables *InstanceVariablesService
|
||||||
|
Invites *InvitesService
|
||||||
|
IssueLinks *IssueLinksService
|
||||||
|
Issues *IssuesService
|
||||||
|
IssuesStatistics *IssuesStatisticsService
|
||||||
|
Jobs *JobsService
|
||||||
|
Keys *KeysService
|
||||||
|
Labels *LabelsService
|
||||||
|
License *LicenseService
|
||||||
|
LicenseTemplates *LicenseTemplatesService
|
||||||
|
ManagedLicenses *ManagedLicensesService
|
||||||
|
MergeRequestApprovals *MergeRequestApprovalsService
|
||||||
|
MergeRequests *MergeRequestsService
|
||||||
|
Milestones *MilestonesService
|
||||||
|
Namespaces *NamespacesService
|
||||||
|
Notes *NotesService
|
||||||
|
NotificationSettings *NotificationSettingsService
|
||||||
|
Packages *PackagesService
|
||||||
|
Pages *PagesService
|
||||||
|
PagesDomains *PagesDomainsService
|
||||||
|
PipelineSchedules *PipelineSchedulesService
|
||||||
|
PipelineTriggers *PipelineTriggersService
|
||||||
|
Pipelines *PipelinesService
|
||||||
|
ProjectBadges *ProjectBadgesService
|
||||||
|
ProjectAccessTokens *ProjectAccessTokensService
|
||||||
|
ProjectCluster *ProjectClustersService
|
||||||
|
ProjectImportExport *ProjectImportExportService
|
||||||
|
ProjectMembers *ProjectMembersService
|
||||||
|
ProjectMirrors *ProjectMirrorService
|
||||||
|
ProjectSnippets *ProjectSnippetsService
|
||||||
|
ProjectVariables *ProjectVariablesService
|
||||||
|
Projects *ProjectsService
|
||||||
|
ProtectedBranches *ProtectedBranchesService
|
||||||
|
ProtectedEnvironments *ProtectedEnvironmentsService
|
||||||
|
ProtectedTags *ProtectedTagsService
|
||||||
|
ReleaseLinks *ReleaseLinksService
|
||||||
|
Releases *ReleasesService
|
||||||
|
Repositories *RepositoriesService
|
||||||
|
RepositoryFiles *RepositoryFilesService
|
||||||
|
ResourceLabelEvents *ResourceLabelEventsService
|
||||||
|
ResourceStateEvents *ResourceStateEventsService
|
||||||
|
Runners *RunnersService
|
||||||
|
Search *SearchService
|
||||||
|
Services *ServicesService
|
||||||
|
Settings *SettingsService
|
||||||
|
Sidekiq *SidekiqService
|
||||||
|
Snippets *SnippetsService
|
||||||
|
SystemHooks *SystemHooksService
|
||||||
|
Tags *TagsService
|
||||||
|
Todos *TodosService
|
||||||
|
Users *UsersService
|
||||||
|
Validate *ValidateService
|
||||||
|
Version *VersionService
|
||||||
|
Wikis *WikisService
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListOptions specifies the optional parameters to various List methods that
|
||||||
|
// support pagination.
|
||||||
|
type ListOptions struct {
|
||||||
|
// For paginated result sets, page of results to retrieve.
|
||||||
|
Page int `url:"page,omitempty" json:"page,omitempty"`
|
||||||
|
|
||||||
|
// For paginated result sets, the number of results to include per page.
|
||||||
|
PerPage int `url:"per_page,omitempty" json:"per_page,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RateLimiter describes the interface that all (custom) rate limiters must implement.
|
||||||
|
type RateLimiter interface {
|
||||||
|
Wait(context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient returns a new GitLab API client. To use API methods which require
|
||||||
|
// authentication, provide a valid private or personal token.
|
||||||
|
func NewClient(token string, options ...ClientOptionFunc) (*Client, error) {
|
||||||
|
client, err := newClient(options...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
client.authType = privateToken
|
||||||
|
client.token = token
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBasicAuthClient returns a new GitLab API client. To use API methods which
|
||||||
|
// require authentication, provide a valid username and password.
|
||||||
|
func NewBasicAuthClient(username, password string, options ...ClientOptionFunc) (*Client, error) {
|
||||||
|
client, err := newClient(options...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
client.authType = basicAuth
|
||||||
|
client.username = username
|
||||||
|
client.password = password
|
||||||
|
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewJobClient returns a new GitLab API client. To use API methods which require
|
||||||
|
// authentication, provide a valid job token.
|
||||||
|
func NewJobClient(token string, options ...ClientOptionFunc) (*Client, error) {
|
||||||
|
client, err := newClient(options...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
client.authType = jobToken
|
||||||
|
client.token = token
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOAuthClient returns a new GitLab API client. To use API methods which
|
||||||
|
// require authentication, provide a valid oauth token.
|
||||||
|
func NewOAuthClient(token string, options ...ClientOptionFunc) (*Client, error) {
|
||||||
|
client, err := newClient(options...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
client.authType = oAuthToken
|
||||||
|
client.token = token
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newClient(options ...ClientOptionFunc) (*Client, error) {
|
||||||
|
c := &Client{UserAgent: userAgent}
|
||||||
|
|
||||||
|
// Configure the HTTP client.
|
||||||
|
c.client = &retryablehttp.Client{
|
||||||
|
Backoff: c.retryHTTPBackoff,
|
||||||
|
CheckRetry: c.retryHTTPCheck,
|
||||||
|
ErrorHandler: retryablehttp.PassthroughErrorHandler,
|
||||||
|
HTTPClient: cleanhttp.DefaultPooledClient(),
|
||||||
|
RetryWaitMin: 100 * time.Millisecond,
|
||||||
|
RetryWaitMax: 400 * time.Millisecond,
|
||||||
|
RetryMax: 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the default base URL.
|
||||||
|
c.setBaseURL(defaultBaseURL)
|
||||||
|
|
||||||
|
// Apply any given client options.
|
||||||
|
for _, fn := range options {
|
||||||
|
if fn == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := fn(c); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the internal timeStats service.
|
||||||
|
timeStats := &timeStatsService{client: c}
|
||||||
|
|
||||||
|
// Create all the public services.
|
||||||
|
c.AccessRequests = &AccessRequestsService{client: c}
|
||||||
|
c.Applications = &ApplicationsService{client: c}
|
||||||
|
c.AuditEvents = &AuditEventsService{client: c}
|
||||||
|
c.Avatar = &AvatarRequestsService{client: c}
|
||||||
|
c.AwardEmoji = &AwardEmojiService{client: c}
|
||||||
|
c.Boards = &IssueBoardsService{client: c}
|
||||||
|
c.Branches = &BranchesService{client: c}
|
||||||
|
c.BroadcastMessage = &BroadcastMessagesService{client: c}
|
||||||
|
c.CIYMLTemplate = &CIYMLTemplatesService{client: c}
|
||||||
|
c.Commits = &CommitsService{client: c}
|
||||||
|
c.ContainerRegistry = &ContainerRegistryService{client: c}
|
||||||
|
c.CustomAttribute = &CustomAttributesService{client: c}
|
||||||
|
c.DeployKeys = &DeployKeysService{client: c}
|
||||||
|
c.DeployTokens = &DeployTokensService{client: c}
|
||||||
|
c.Deployments = &DeploymentsService{client: c}
|
||||||
|
c.Discussions = &DiscussionsService{client: c}
|
||||||
|
c.Environments = &EnvironmentsService{client: c}
|
||||||
|
c.EpicIssues = &EpicIssuesService{client: c}
|
||||||
|
c.Epics = &EpicsService{client: c}
|
||||||
|
c.Events = &EventsService{client: c}
|
||||||
|
c.Features = &FeaturesService{client: c}
|
||||||
|
c.FreezePeriods = &FreezePeriodsService{client: c}
|
||||||
|
c.GitIgnoreTemplates = &GitIgnoreTemplatesService{client: c}
|
||||||
|
c.GroupBadges = &GroupBadgesService{client: c}
|
||||||
|
c.GroupCluster = &GroupClustersService{client: c}
|
||||||
|
c.GroupImportExport = &GroupImportExportService{client: c}
|
||||||
|
c.GroupIssueBoards = &GroupIssueBoardsService{client: c}
|
||||||
|
c.GroupLabels = &GroupLabelsService{client: c}
|
||||||
|
c.GroupMembers = &GroupMembersService{client: c}
|
||||||
|
c.GroupMilestones = &GroupMilestonesService{client: c}
|
||||||
|
c.GroupVariables = &GroupVariablesService{client: c}
|
||||||
|
c.GroupWikis = &GroupWikisService{client: c}
|
||||||
|
c.Groups = &GroupsService{client: c}
|
||||||
|
c.InstanceCluster = &InstanceClustersService{client: c}
|
||||||
|
c.InstanceVariables = &InstanceVariablesService{client: c}
|
||||||
|
c.Invites = &InvitesService{client: c}
|
||||||
|
c.IssueLinks = &IssueLinksService{client: c}
|
||||||
|
c.Issues = &IssuesService{client: c, timeStats: timeStats}
|
||||||
|
c.IssuesStatistics = &IssuesStatisticsService{client: c}
|
||||||
|
c.Jobs = &JobsService{client: c}
|
||||||
|
c.Keys = &KeysService{client: c}
|
||||||
|
c.Labels = &LabelsService{client: c}
|
||||||
|
c.License = &LicenseService{client: c}
|
||||||
|
c.LicenseTemplates = &LicenseTemplatesService{client: c}
|
||||||
|
c.ManagedLicenses = &ManagedLicensesService{client: c}
|
||||||
|
c.MergeRequestApprovals = &MergeRequestApprovalsService{client: c}
|
||||||
|
c.MergeRequests = &MergeRequestsService{client: c, timeStats: timeStats}
|
||||||
|
c.Milestones = &MilestonesService{client: c}
|
||||||
|
c.Namespaces = &NamespacesService{client: c}
|
||||||
|
c.Notes = &NotesService{client: c}
|
||||||
|
c.NotificationSettings = &NotificationSettingsService{client: c}
|
||||||
|
c.Packages = &PackagesService{client: c}
|
||||||
|
c.Pages = &PagesService{client: c}
|
||||||
|
c.PagesDomains = &PagesDomainsService{client: c}
|
||||||
|
c.PipelineSchedules = &PipelineSchedulesService{client: c}
|
||||||
|
c.PipelineTriggers = &PipelineTriggersService{client: c}
|
||||||
|
c.Pipelines = &PipelinesService{client: c}
|
||||||
|
c.ProjectBadges = &ProjectBadgesService{client: c}
|
||||||
|
c.ProjectAccessTokens = &ProjectAccessTokensService{client: c}
|
||||||
|
c.ProjectCluster = &ProjectClustersService{client: c}
|
||||||
|
c.ProjectImportExport = &ProjectImportExportService{client: c}
|
||||||
|
c.ProjectMembers = &ProjectMembersService{client: c}
|
||||||
|
c.ProjectMirrors = &ProjectMirrorService{client: c}
|
||||||
|
c.ProjectSnippets = &ProjectSnippetsService{client: c}
|
||||||
|
c.ProjectVariables = &ProjectVariablesService{client: c}
|
||||||
|
c.Projects = &ProjectsService{client: c}
|
||||||
|
c.ProtectedBranches = &ProtectedBranchesService{client: c}
|
||||||
|
c.ProtectedEnvironments = &ProtectedEnvironmentsService{client: c}
|
||||||
|
c.ProtectedTags = &ProtectedTagsService{client: c}
|
||||||
|
c.ReleaseLinks = &ReleaseLinksService{client: c}
|
||||||
|
c.Releases = &ReleasesService{client: c}
|
||||||
|
c.Repositories = &RepositoriesService{client: c}
|
||||||
|
c.RepositoryFiles = &RepositoryFilesService{client: c}
|
||||||
|
c.ResourceLabelEvents = &ResourceLabelEventsService{client: c}
|
||||||
|
c.ResourceStateEvents = &ResourceStateEventsService{client: c}
|
||||||
|
c.Runners = &RunnersService{client: c}
|
||||||
|
c.Search = &SearchService{client: c}
|
||||||
|
c.Services = &ServicesService{client: c}
|
||||||
|
c.Settings = &SettingsService{client: c}
|
||||||
|
c.Sidekiq = &SidekiqService{client: c}
|
||||||
|
c.Snippets = &SnippetsService{client: c}
|
||||||
|
c.SystemHooks = &SystemHooksService{client: c}
|
||||||
|
c.Tags = &TagsService{client: c}
|
||||||
|
c.Todos = &TodosService{client: c}
|
||||||
|
c.Users = &UsersService{client: c}
|
||||||
|
c.Validate = &ValidateService{client: c}
|
||||||
|
c.Version = &VersionService{client: c}
|
||||||
|
c.Wikis = &WikisService{client: c}
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// retryHTTPCheck provides a callback for Client.CheckRetry which
|
||||||
|
// will retry both rate limit (429) and server (>= 500) errors.
|
||||||
|
func (c *Client) retryHTTPCheck(ctx context.Context, resp *http.Response, err error) (bool, error) {
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return false, ctx.Err()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !c.disableRetries && (resp.StatusCode == 429 || resp.StatusCode >= 500) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// retryHTTPBackoff provides a generic callback for Client.Backoff which
|
||||||
|
// will pass through all calls based on the status code of the response.
|
||||||
|
func (c *Client) retryHTTPBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration {
|
||||||
|
// Use the rate limit backoff function when we are rate limited.
|
||||||
|
if resp != nil && resp.StatusCode == 429 {
|
||||||
|
return rateLimitBackoff(min, max, attemptNum, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set custom duration's when we experience a service interruption.
|
||||||
|
min = 700 * time.Millisecond
|
||||||
|
max = 900 * time.Millisecond
|
||||||
|
|
||||||
|
return retryablehttp.LinearJitterBackoff(min, max, attemptNum, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// rateLimitBackoff provides a callback for Client.Backoff which will use the
|
||||||
|
// RateLimit-Reset header to determine the time to wait. We add some jitter
|
||||||
|
// to prevent a thundering herd.
|
||||||
|
//
|
||||||
|
// min and max are mainly used for bounding the jitter that will be added to
|
||||||
|
// the reset time retrieved from the headers. But if the final wait time is
|
||||||
|
// less then min, min will be used instead.
|
||||||
|
func rateLimitBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration {
|
||||||
|
// rnd is used to generate pseudo-random numbers.
|
||||||
|
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
|
||||||
|
// First create some jitter bounded by the min and max durations.
|
||||||
|
jitter := time.Duration(rnd.Float64() * float64(max-min))
|
||||||
|
|
||||||
|
if resp != nil {
|
||||||
|
if v := resp.Header.Get(headerRateReset); v != "" {
|
||||||
|
if reset, _ := strconv.ParseInt(v, 10, 64); reset > 0 {
|
||||||
|
// Only update min if the given time to wait is longer.
|
||||||
|
if wait := time.Until(time.Unix(reset, 0)); wait > min {
|
||||||
|
min = wait
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return min + jitter
|
||||||
|
}
|
||||||
|
|
||||||
|
// configureLimiter configures the rate limiter.
|
||||||
|
func (c *Client) configureLimiter(ctx context.Context) error {
|
||||||
|
// Set default values for when rate limiting is disabled.
|
||||||
|
limit := rate.Inf
|
||||||
|
burst := 0
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
// Create a new limiter using the calculated values.
|
||||||
|
c.limiter = rate.NewLimiter(limit, burst)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Create a new request.
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.baseURL.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a single request to retrieve the rate limit headers.
|
||||||
|
resp, err := c.client.HTTPClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
|
||||||
|
if v := resp.Header.Get(headerRateLimit); v != "" {
|
||||||
|
if rateLimit, _ := strconv.ParseFloat(v, 64); rateLimit > 0 {
|
||||||
|
// The rate limit is based on requests per minute, so for our limiter to
|
||||||
|
// work correctly we divide the limit by 60 to get the limit per second.
|
||||||
|
rateLimit /= 60
|
||||||
|
// Configure the limit and burst using a split of 2/3 for the limit and
|
||||||
|
// 1/3 for the burst. This enables clients to burst 1/3 of the allowed
|
||||||
|
// calls before the limiter kicks in. The remaining calls will then be
|
||||||
|
// spread out evenly using intervals of time.Second / limit which should
|
||||||
|
// prevent hitting the rate limit.
|
||||||
|
limit = rate.Limit(rateLimit * 0.66)
|
||||||
|
burst = int(rateLimit * 0.33)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BaseURL return a copy of the baseURL.
|
||||||
|
func (c *Client) BaseURL() *url.URL {
|
||||||
|
u := *c.baseURL
|
||||||
|
return &u
|
||||||
|
}
|
||||||
|
|
||||||
|
// setBaseURL sets the base URL for API requests to a custom endpoint.
|
||||||
|
func (c *Client) setBaseURL(urlStr string) error {
|
||||||
|
// Make sure the given URL end with a slash
|
||||||
|
if !strings.HasSuffix(urlStr, "/") {
|
||||||
|
urlStr += "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
baseURL, err := url.Parse(urlStr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasSuffix(baseURL.Path, apiVersionPath) {
|
||||||
|
baseURL.Path += apiVersionPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the base URL of the client.
|
||||||
|
c.baseURL = baseURL
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRequest creates an API request. A relative URL path can be provided in
|
||||||
|
// path, in which case it is resolved relative to the base URL of the Client.
|
||||||
|
// Relative URL paths should always be specified without a preceding slash. If
|
||||||
|
// specified, the value pointed to by body is JSON encoded and included as the
|
||||||
|
// request body.
|
||||||
|
func (c *Client) NewRequest(method, path string, opt interface{}, options []RequestOptionFunc) (*retryablehttp.Request, error) {
|
||||||
|
u := *c.baseURL
|
||||||
|
unescaped, err := url.PathUnescape(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the encoded path data
|
||||||
|
u.RawPath = c.baseURL.Path + path
|
||||||
|
u.Path = c.baseURL.Path + unescaped
|
||||||
|
|
||||||
|
// Create a request specific headers map.
|
||||||
|
reqHeaders := make(http.Header)
|
||||||
|
reqHeaders.Set("Accept", "application/json")
|
||||||
|
|
||||||
|
if c.UserAgent != "" {
|
||||||
|
reqHeaders.Set("User-Agent", c.UserAgent)
|
||||||
|
}
|
||||||
|
|
||||||
|
var body interface{}
|
||||||
|
switch {
|
||||||
|
case method == http.MethodPost || method == http.MethodPut:
|
||||||
|
reqHeaders.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
if opt != nil {
|
||||||
|
body, err = json.Marshal(opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case opt != nil:
|
||||||
|
q, err := query.Values(opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u.RawQuery = q.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := retryablehttp.NewRequest(method, u.String(), body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fn := range options {
|
||||||
|
if fn == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := fn(req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the request specific headers.
|
||||||
|
for k, v := range reqHeaders {
|
||||||
|
req.Header[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return req, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response is a GitLab API response. This wraps the standard http.Response
|
||||||
|
// returned from GitLab and provides convenient access to things like
|
||||||
|
// pagination links.
|
||||||
|
type Response struct {
|
||||||
|
*http.Response
|
||||||
|
|
||||||
|
// These fields provide the page values for paginating through a set of
|
||||||
|
// results. Any or all of these may be set to the zero value for
|
||||||
|
// responses that are not part of a paginated set, or for which there
|
||||||
|
// are no additional pages.
|
||||||
|
TotalItems int
|
||||||
|
TotalPages int
|
||||||
|
ItemsPerPage int
|
||||||
|
CurrentPage int
|
||||||
|
NextPage int
|
||||||
|
PreviousPage int
|
||||||
|
}
|
||||||
|
|
||||||
|
// newResponse creates a new Response for the provided http.Response.
|
||||||
|
func newResponse(r *http.Response) *Response {
|
||||||
|
response := &Response{Response: r}
|
||||||
|
response.populatePageValues()
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
xTotal = "X-Total"
|
||||||
|
xTotalPages = "X-Total-Pages"
|
||||||
|
xPerPage = "X-Per-Page"
|
||||||
|
xPage = "X-Page"
|
||||||
|
xNextPage = "X-Next-Page"
|
||||||
|
xPrevPage = "X-Prev-Page"
|
||||||
|
)
|
||||||
|
|
||||||
|
// populatePageValues parses the HTTP Link response headers and populates the
|
||||||
|
// various pagination link values in the Response.
|
||||||
|
func (r *Response) populatePageValues() {
|
||||||
|
if totalItems := r.Response.Header.Get(xTotal); totalItems != "" {
|
||||||
|
r.TotalItems, _ = strconv.Atoi(totalItems)
|
||||||
|
}
|
||||||
|
if totalPages := r.Response.Header.Get(xTotalPages); totalPages != "" {
|
||||||
|
r.TotalPages, _ = strconv.Atoi(totalPages)
|
||||||
|
}
|
||||||
|
if itemsPerPage := r.Response.Header.Get(xPerPage); itemsPerPage != "" {
|
||||||
|
r.ItemsPerPage, _ = strconv.Atoi(itemsPerPage)
|
||||||
|
}
|
||||||
|
if currentPage := r.Response.Header.Get(xPage); currentPage != "" {
|
||||||
|
r.CurrentPage, _ = strconv.Atoi(currentPage)
|
||||||
|
}
|
||||||
|
if nextPage := r.Response.Header.Get(xNextPage); nextPage != "" {
|
||||||
|
r.NextPage, _ = strconv.Atoi(nextPage)
|
||||||
|
}
|
||||||
|
if previousPage := r.Response.Header.Get(xPrevPage); previousPage != "" {
|
||||||
|
r.PreviousPage, _ = strconv.Atoi(previousPage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do sends an API request and returns the API response. The API response is
|
||||||
|
// JSON decoded and stored in the value pointed to by v, or returned as an
|
||||||
|
// error if an API error has occurred. If v implements the io.Writer
|
||||||
|
// interface, the raw response body will be written to v, without attempting to
|
||||||
|
// first decode it.
|
||||||
|
func (c *Client) Do(req *retryablehttp.Request, v interface{}) (*Response, error) {
|
||||||
|
// If not yet configured, try to configure the rate limiter. Fail
|
||||||
|
// silently as the limiter will be disabled in case of an error.
|
||||||
|
c.configureLimiterOnce.Do(func() { c.configureLimiter(req.Context()) })
|
||||||
|
|
||||||
|
// Wait will block until the limiter can obtain a new token.
|
||||||
|
err := c.limiter.Wait(req.Context())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the correct authentication header. If using basic auth, then check
|
||||||
|
// if we already have a token and if not first authenticate and get one.
|
||||||
|
var basicAuthToken string
|
||||||
|
switch c.authType {
|
||||||
|
case basicAuth:
|
||||||
|
c.tokenLock.RLock()
|
||||||
|
basicAuthToken = c.token
|
||||||
|
c.tokenLock.RUnlock()
|
||||||
|
if basicAuthToken == "" {
|
||||||
|
// If we don't have a token yet, we first need to request one.
|
||||||
|
basicAuthToken, err = c.requestOAuthToken(req.Context(), basicAuthToken)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req.Header.Set("Authorization", "Bearer "+basicAuthToken)
|
||||||
|
case jobToken:
|
||||||
|
req.Header.Set("JOB-TOKEN", c.token)
|
||||||
|
case oAuthToken:
|
||||||
|
req.Header.Set("Authorization", "Bearer "+c.token)
|
||||||
|
case privateToken:
|
||||||
|
req.Header.Set("PRIVATE-TOKEN", c.token)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusUnauthorized && c.authType == basicAuth {
|
||||||
|
resp.Body.Close()
|
||||||
|
// The token most likely expired, so we need to request a new one and try again.
|
||||||
|
if _, err := c.requestOAuthToken(req.Context(), basicAuthToken); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.Do(req, v)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
response := newResponse(resp)
|
||||||
|
|
||||||
|
err = CheckResponse(resp)
|
||||||
|
if err != nil {
|
||||||
|
// Even though there was an error, we still return the response
|
||||||
|
// in case the caller wants to inspect it further.
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if v != nil {
|
||||||
|
if w, ok := v.(io.Writer); ok {
|
||||||
|
_, err = io.Copy(w, resp.Body)
|
||||||
|
} else {
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) requestOAuthToken(ctx context.Context, token string) (string, error) {
|
||||||
|
c.tokenLock.Lock()
|
||||||
|
defer c.tokenLock.Unlock()
|
||||||
|
|
||||||
|
// Return early if the token was updated while waiting for the lock.
|
||||||
|
if c.token != token {
|
||||||
|
return c.token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
config := &oauth2.Config{
|
||||||
|
Endpoint: oauth2.Endpoint{
|
||||||
|
AuthURL: strings.TrimSuffix(c.baseURL.String(), apiVersionPath) + "oauth/authorize",
|
||||||
|
TokenURL: strings.TrimSuffix(c.baseURL.String(), apiVersionPath) + "oauth/token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = context.WithValue(ctx, oauth2.HTTPClient, c.client.HTTPClient)
|
||||||
|
t, err := config.PasswordCredentialsToken(ctx, c.username, c.password)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
c.token = t.AccessToken
|
||||||
|
|
||||||
|
return c.token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to accept and format both the project ID or name as project
|
||||||
|
// identifier for all API calls.
|
||||||
|
func parseID(id interface{}) (string, error) {
|
||||||
|
switch v := id.(type) {
|
||||||
|
case int:
|
||||||
|
return strconv.Itoa(v), nil
|
||||||
|
case string:
|
||||||
|
return v, nil
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("invalid ID type %#v, the ID must be an int or a string", id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to escape a project identifier.
|
||||||
|
func pathEscape(s string) string {
|
||||||
|
return strings.Replace(url.PathEscape(s), ".", "%2E", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// An ErrorResponse reports one or more errors caused by an API request.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/README.html#data-validation-and-error-reporting
|
||||||
|
type ErrorResponse struct {
|
||||||
|
Body []byte
|
||||||
|
Response *http.Response
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ErrorResponse) Error() string {
|
||||||
|
path, _ := url.QueryUnescape(e.Response.Request.URL.Path)
|
||||||
|
u := fmt.Sprintf("%s://%s%s", e.Response.Request.URL.Scheme, e.Response.Request.URL.Host, path)
|
||||||
|
return fmt.Sprintf("%s %s: %d %s", e.Response.Request.Method, u, e.Response.StatusCode, e.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckResponse checks the API response for errors, and returns them if present.
|
||||||
|
func CheckResponse(r *http.Response) error {
|
||||||
|
switch r.StatusCode {
|
||||||
|
case 200, 201, 202, 204, 304:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
errorResponse := &ErrorResponse{Response: r}
|
||||||
|
data, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err == nil && data != nil {
|
||||||
|
errorResponse.Body = data
|
||||||
|
|
||||||
|
var raw interface{}
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
errorResponse.Message = "failed to parse unknown error format"
|
||||||
|
} else {
|
||||||
|
errorResponse.Message = parseError(raw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errorResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format:
|
||||||
|
// {
|
||||||
|
// "message": {
|
||||||
|
// "<property-name>": [
|
||||||
|
// "<error-message>",
|
||||||
|
// "<error-message>",
|
||||||
|
// ...
|
||||||
|
// ],
|
||||||
|
// "<embed-entity>": {
|
||||||
|
// "<property-name>": [
|
||||||
|
// "<error-message>",
|
||||||
|
// "<error-message>",
|
||||||
|
// ...
|
||||||
|
// ],
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "error": "<error-message>"
|
||||||
|
// }
|
||||||
|
func parseError(raw interface{}) string {
|
||||||
|
switch raw := raw.(type) {
|
||||||
|
case string:
|
||||||
|
return raw
|
||||||
|
|
||||||
|
case []interface{}:
|
||||||
|
var errs []string
|
||||||
|
for _, v := range raw {
|
||||||
|
errs = append(errs, parseError(v))
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("[%s]", strings.Join(errs, ", "))
|
||||||
|
|
||||||
|
case map[string]interface{}:
|
||||||
|
var errs []string
|
||||||
|
for k, v := range raw {
|
||||||
|
errs = append(errs, fmt.Sprintf("{%s: %s}", k, parseError(v)))
|
||||||
|
}
|
||||||
|
sort.Strings(errs)
|
||||||
|
return strings.Join(errs, ", ")
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("failed to parse unexpected error type: %T", raw)
|
||||||
|
}
|
||||||
|
}
|
15
vendor/github.com/xanzy/go-gitlab/go.mod
generated
vendored
Normal file
15
vendor/github.com/xanzy/go-gitlab/go.mod
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
module github.com/xanzy/go-gitlab
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/google/go-querystring v1.0.0
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.6.8
|
||||||
|
github.com/stretchr/testify v1.4.0
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974 // indirect
|
||||||
|
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 // indirect
|
||||||
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
|
||||||
|
google.golang.org/appengine v1.3.0 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
|
go 1.13
|
48
vendor/github.com/xanzy/go-gitlab/go.sum
generated
vendored
Normal file
48
vendor/github.com/xanzy/go-gitlab/go.sum
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||||
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.6.8 h1:92lWxgpa+fF3FozM4B3UZtHZMJX8T5XT+TFdCxsPyWs=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/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-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288 h1:JIqe8uIcRBHXDQVvZtHwp80ai3Lw3IJAeJEs55Dc1W0=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
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-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
||||||
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
google.golang.org/appengine v1.3.0 h1:FBSsiFRMz3LBeXIomRnVzrQwSDj4ibvcRexLG0LZGQk=
|
||||||
|
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
230
vendor/github.com/xanzy/go-gitlab/group_badges.go
generated
vendored
Normal file
230
vendor/github.com/xanzy/go-gitlab/group_badges.go
generated
vendored
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupBadgesService handles communication with the group badges
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_badges.html
|
||||||
|
type GroupBadgesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// BadgeKind represents a GitLab Badge Kind
|
||||||
|
type BadgeKind string
|
||||||
|
|
||||||
|
// all possible values Badge Kind
|
||||||
|
const (
|
||||||
|
ProjectBadgeKind BadgeKind = "project"
|
||||||
|
GroupBadgeKind BadgeKind = "group"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupBadge represents a group badge.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_badges.html
|
||||||
|
type GroupBadge struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
LinkURL string `json:"link_url"`
|
||||||
|
ImageURL string `json:"image_url"`
|
||||||
|
RenderedLinkURL string `json:"rendered_link_url"`
|
||||||
|
RenderedImageURL string `json:"rendered_image_url"`
|
||||||
|
Kind BadgeKind `json:"kind"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupBadgesOptions represents the available ListGroupBadges() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_badges.html#list-all-badges-of-a-group
|
||||||
|
type ListGroupBadgesOptions ListOptions
|
||||||
|
|
||||||
|
// ListGroupBadges gets a list of a group badges.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_badges.html#list-all-badges-of-a-group
|
||||||
|
func (s *GroupBadgesService) ListGroupBadges(gid interface{}, opt *ListGroupBadgesOptions, options ...RequestOptionFunc) ([]*GroupBadge, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/badges", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var gb []*GroupBadge
|
||||||
|
resp, err := s.client.Do(req, &gb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gb, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupBadge gets a group badge.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_badges.html#get-a-badge-of-a-group
|
||||||
|
func (s *GroupBadgesService) GetGroupBadge(gid interface{}, badge int, options ...RequestOptionFunc) (*GroupBadge, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/badges/%d", pathEscape(group), badge)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gb := new(GroupBadge)
|
||||||
|
resp, err := s.client.Do(req, gb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gb, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddGroupBadgeOptions represents the available AddGroupBadge() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_badges.html#add-a-badge-to-a-group
|
||||||
|
type AddGroupBadgeOptions struct {
|
||||||
|
LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"`
|
||||||
|
ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddGroupBadge adds a badge to a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_badges.html#add-a-badge-to-a-group
|
||||||
|
func (s *GroupBadgesService) AddGroupBadge(gid interface{}, opt *AddGroupBadgeOptions, options ...RequestOptionFunc) (*GroupBadge, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/badges", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gb := new(GroupBadge)
|
||||||
|
resp, err := s.client.Do(req, gb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gb, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditGroupBadgeOptions represents the available EditGroupBadge() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_badges.html#edit-a-badge-of-a-group
|
||||||
|
type EditGroupBadgeOptions struct {
|
||||||
|
LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"`
|
||||||
|
ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditGroupBadge updates a badge of a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_badges.html#edit-a-badge-of-a-group
|
||||||
|
func (s *GroupBadgesService) EditGroupBadge(gid interface{}, badge int, opt *EditGroupBadgeOptions, options ...RequestOptionFunc) (*GroupBadge, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/badges/%d", pathEscape(group), badge)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gb := new(GroupBadge)
|
||||||
|
resp, err := s.client.Do(req, gb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gb, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteGroupBadge removes a badge from a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_badges.html#remove-a-badge-from-a-group
|
||||||
|
func (s *GroupBadgesService) DeleteGroupBadge(gid interface{}, badge int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/badges/%d", pathEscape(group), badge)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupBadgePreviewOptions represents the available PreviewGroupBadge() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_badges.html#preview-a-badge-from-a-group
|
||||||
|
type GroupBadgePreviewOptions struct {
|
||||||
|
LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"`
|
||||||
|
ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreviewGroupBadge returns how the link_url and image_url final URLs would be after
|
||||||
|
// resolving the placeholder interpolation.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_badges.html#preview-a-badge-from-a-group
|
||||||
|
func (s *GroupBadgesService) PreviewGroupBadge(gid interface{}, opt *GroupBadgePreviewOptions, options ...RequestOptionFunc) (*GroupBadge, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/badges/render", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gb := new(GroupBadge)
|
||||||
|
resp, err := s.client.Do(req, &gb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gb, resp, err
|
||||||
|
}
|
352
vendor/github.com/xanzy/go-gitlab/group_boards.go
generated
vendored
Normal file
352
vendor/github.com/xanzy/go-gitlab/group_boards.go
generated
vendored
Normal file
|
@ -0,0 +1,352 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Patrick Webster
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupIssueBoardsService handles communication with the group issue board
|
||||||
|
// related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_boards.html
|
||||||
|
type GroupIssueBoardsService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupIssueBoard represents a GitLab group issue board.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_boards.html
|
||||||
|
type GroupIssueBoard struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Group *Group `json:"group"`
|
||||||
|
Milestone *Milestone `json:"milestone"`
|
||||||
|
Lists []*BoardList `json:"lists"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b GroupIssueBoard) String() string {
|
||||||
|
return Stringify(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupIssueBoardsOptions represents the available
|
||||||
|
// ListGroupIssueBoards() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_boards.html#group-board
|
||||||
|
type ListGroupIssueBoardsOptions ListOptions
|
||||||
|
|
||||||
|
// ListGroupIssueBoards gets a list of all issue boards in a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_boards.html#group-board
|
||||||
|
func (s *GroupIssueBoardsService) ListGroupIssueBoards(gid interface{}, opt *ListGroupIssueBoardsOptions, options ...RequestOptionFunc) ([]*GroupIssueBoard, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/boards", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var gs []*GroupIssueBoard
|
||||||
|
resp, err := s.client.Do(req, &gs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gs, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateGroupIssueBoardOptions represents the available
|
||||||
|
// CreateGroupIssueBoard() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_boards.html#create-a-group-issue-board-premium
|
||||||
|
type CreateGroupIssueBoardOptions struct {
|
||||||
|
Name *string `url:"name" json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateGroupIssueBoard creates a new issue board.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_boards.html#create-a-group-issue-board-premium
|
||||||
|
func (s *GroupIssueBoardsService) CreateGroupIssueBoard(gid interface{}, opt *CreateGroupIssueBoardOptions, options ...RequestOptionFunc) (*GroupIssueBoard, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/boards", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gib := new(GroupIssueBoard)
|
||||||
|
resp, err := s.client.Do(req, gib)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gib, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupIssueBoard gets a single issue board of a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_boards.html#single-board
|
||||||
|
func (s *GroupIssueBoardsService) GetGroupIssueBoard(gid interface{}, board int, options ...RequestOptionFunc) (*GroupIssueBoard, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/boards/%d", pathEscape(group), board)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gib := new(GroupIssueBoard)
|
||||||
|
resp, err := s.client.Do(req, gib)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gib, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateGroupIssueBoardOptions represents a group issue board.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_boards.html#update-a-group-issue-board-premium
|
||||||
|
type UpdateGroupIssueBoardOptions struct {
|
||||||
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
|
AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
|
||||||
|
MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"`
|
||||||
|
Labels Labels `url:"labels,omitempty" json:"labels,omitempty"`
|
||||||
|
Weight *int `url:"weight,omitempty" json:"weight,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateIssueBoard updates a single issue board of a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_boards.html#update-a-group-issue-board-premium
|
||||||
|
func (s *GroupIssueBoardsService) UpdateIssueBoard(gid interface{}, board int, opt *UpdateGroupIssueBoardOptions, options ...RequestOptionFunc) (*GroupIssueBoard, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/boards/%d", pathEscape(group), board)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gib := new(GroupIssueBoard)
|
||||||
|
resp, err := s.client.Do(req, gib)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gib, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteIssueBoard delete a single issue board of a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_boards.html#delete-a-group-issue-board-premium
|
||||||
|
func (s *GroupIssueBoardsService) DeleteIssueBoard(gid interface{}, board int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/boards/%d", pathEscape(group), board)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupIssueBoardListsOptions represents the available
|
||||||
|
// ListGroupIssueBoardLists() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_boards.html#list-board-lists
|
||||||
|
type ListGroupIssueBoardListsOptions ListOptions
|
||||||
|
|
||||||
|
// ListGroupIssueBoardLists gets a list of the issue board's lists. Does not include
|
||||||
|
// backlog and closed lists.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/group_boards.html#list-board-lists
|
||||||
|
func (s *GroupIssueBoardsService) ListGroupIssueBoardLists(gid interface{}, board int, opt *ListGroupIssueBoardListsOptions, options ...RequestOptionFunc) ([]*BoardList, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/boards/%d/lists", pathEscape(group), board)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var gbl []*BoardList
|
||||||
|
resp, err := s.client.Do(req, &gbl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gbl, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupIssueBoardList gets a single issue board list.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_boards.html#single-board-list
|
||||||
|
func (s *GroupIssueBoardsService) GetGroupIssueBoardList(gid interface{}, board, list int, options ...RequestOptionFunc) (*BoardList, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/boards/%d/lists/%d",
|
||||||
|
pathEscape(group),
|
||||||
|
board,
|
||||||
|
list,
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gbl := new(BoardList)
|
||||||
|
resp, err := s.client.Do(req, gbl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gbl, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateGroupIssueBoardListOptions represents the available
|
||||||
|
// CreateGroupIssueBoardList() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_boards.html#new-board-list
|
||||||
|
type CreateGroupIssueBoardListOptions struct {
|
||||||
|
LabelID *int `url:"label_id" json:"label_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateGroupIssueBoardList creates a new issue board list.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_boards.html#new-board-list
|
||||||
|
func (s *GroupIssueBoardsService) CreateGroupIssueBoardList(gid interface{}, board int, opt *CreateGroupIssueBoardListOptions, options ...RequestOptionFunc) (*BoardList, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/boards/%d/lists", pathEscape(group), board)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gbl := new(BoardList)
|
||||||
|
resp, err := s.client.Do(req, gbl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gbl, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateGroupIssueBoardListOptions represents the available
|
||||||
|
// UpdateGroupIssueBoardList() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_boards.html#edit-board-list
|
||||||
|
type UpdateGroupIssueBoardListOptions struct {
|
||||||
|
Position *int `url:"position" json:"position"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateIssueBoardList updates the position of an existing
|
||||||
|
// group issue board list.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_boards.html#edit-board-list
|
||||||
|
func (s *GroupIssueBoardsService) UpdateIssueBoardList(gid interface{}, board, list int, opt *UpdateGroupIssueBoardListOptions, options ...RequestOptionFunc) ([]*BoardList, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/boards/%d/lists/%d",
|
||||||
|
pathEscape(group),
|
||||||
|
board,
|
||||||
|
list,
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var gbl []*BoardList
|
||||||
|
resp, err := s.client.Do(req, gbl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gbl, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteGroupIssueBoardList soft deletes a group issue board list.
|
||||||
|
// Only for admins and group owners.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_boards.html#delete-a-board-list
|
||||||
|
func (s *GroupIssueBoardsService) DeleteGroupIssueBoardList(gid interface{}, board, list int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/boards/%d/lists/%d",
|
||||||
|
pathEscape(group),
|
||||||
|
board,
|
||||||
|
list,
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
217
vendor/github.com/xanzy/go-gitlab/group_clusters.go
generated
vendored
Normal file
217
vendor/github.com/xanzy/go-gitlab/group_clusters.go
generated
vendored
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Paul Shoemaker
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupClustersService handles communication with the
|
||||||
|
// group clusters related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_clusters.html
|
||||||
|
type GroupClustersService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupCluster represents a GitLab Group Cluster.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/group_clusters.html
|
||||||
|
type GroupCluster struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
Managed bool `json:"managed"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
ProviderType string `json:"provider_type"`
|
||||||
|
PlatformType string `json:"platform_type"`
|
||||||
|
EnvironmentScope string `json:"environment_scope"`
|
||||||
|
ClusterType string `json:"cluster_type"`
|
||||||
|
User *User `json:"user"`
|
||||||
|
PlatformKubernetes *PlatformKubernetes `json:"platform_kubernetes"`
|
||||||
|
ManagementProject *ManagementProject `json:"management_project"`
|
||||||
|
Group *Group `json:"group"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v GroupCluster) String() string {
|
||||||
|
return Stringify(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListClusters gets a list of all clusters in a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_clusters.html#list-group-clusters
|
||||||
|
func (s *GroupClustersService) ListClusters(pid interface{}, options ...RequestOptionFunc) ([]*GroupCluster, *Response, error) {
|
||||||
|
group, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/clusters", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var pcs []*GroupCluster
|
||||||
|
resp, err := s.client.Do(req, &pcs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pcs, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCluster gets a cluster.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_clusters.html#get-a-single-group-cluster
|
||||||
|
func (s *GroupClustersService) GetCluster(pid interface{}, cluster int, options ...RequestOptionFunc) (*GroupCluster, *Response, error) {
|
||||||
|
group, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/clusters/%d", pathEscape(group), cluster)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gc := new(GroupCluster)
|
||||||
|
resp, err := s.client.Do(req, &gc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gc, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddGroupClusterOptions represents the available AddCluster() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_clusters.html#add-existing-cluster-to-group
|
||||||
|
type AddGroupClusterOptions struct {
|
||||||
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
|
Domain *string `url:"domain,omitempty" json:"domain,omitempty"`
|
||||||
|
ManagementProjectID *string `url:"management_project_id,omitempty" json:"management_project_id,omitempty"`
|
||||||
|
Enabled *bool `url:"enabled,omitempty" json:"enabled,omitempty"`
|
||||||
|
Managed *bool `url:"managed,omitempty" json:"managed,omitempty"`
|
||||||
|
EnvironmentScope *string `url:"environment_scope,omitempty" json:"environment_scope,omitempty"`
|
||||||
|
PlatformKubernetes *AddGroupPlatformKubernetesOptions `url:"platform_kubernetes_attributes,omitempty" json:"platform_kubernetes_attributes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddGroupPlatformKubernetesOptions represents the available PlatformKubernetes options for adding.
|
||||||
|
type AddGroupPlatformKubernetesOptions struct {
|
||||||
|
APIURL *string `url:"api_url,omitempty" json:"api_url,omitempty"`
|
||||||
|
Token *string `url:"token,omitempty" json:"token,omitempty"`
|
||||||
|
CaCert *string `url:"ca_cert,omitempty" json:"ca_cert,omitempty"`
|
||||||
|
Namespace *string `url:"namespace,omitempty" json:"namespace,omitempty"`
|
||||||
|
AuthorizationType *string `url:"authorization_type,omitempty" json:"authorization_type,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCluster adds an existing cluster to the group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_clusters.html#add-existing-cluster-to-group
|
||||||
|
func (s *GroupClustersService) AddCluster(pid interface{}, opt *AddGroupClusterOptions, options ...RequestOptionFunc) (*GroupCluster, *Response, error) {
|
||||||
|
group, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/clusters/user", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gc := new(GroupCluster)
|
||||||
|
resp, err := s.client.Do(req, gc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gc, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditGroupClusterOptions represents the available EditCluster() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_clusters.html#edit-group-cluster
|
||||||
|
type EditGroupClusterOptions struct {
|
||||||
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
|
Domain *string `url:"domain,omitempty" json:"domain,omitempty"`
|
||||||
|
EnvironmentScope *string `url:"environment_scope,omitempty" json:"environment_scope,omitempty"`
|
||||||
|
PlatformKubernetes *EditGroupPlatformKubernetesOptions `url:"platform_kubernetes_attributes,omitempty" json:"platform_kubernetes_attributes,omitempty"`
|
||||||
|
ManagementProjectID *string `url:"management_project_id,omitempty" json:"management_project_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditGroupPlatformKubernetesOptions represents the available PlatformKubernetes options for editing.
|
||||||
|
type EditGroupPlatformKubernetesOptions struct {
|
||||||
|
APIURL *string `url:"api_url,omitempty" json:"api_url,omitempty"`
|
||||||
|
Token *string `url:"token,omitempty" json:"token,omitempty"`
|
||||||
|
CaCert *string `url:"ca_cert,omitempty" json:"ca_cert,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditCluster updates an existing group cluster.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_clusters.html#edit-group-cluster
|
||||||
|
func (s *GroupClustersService) EditCluster(pid interface{}, cluster int, opt *EditGroupClusterOptions, options ...RequestOptionFunc) (*GroupCluster, *Response, error) {
|
||||||
|
group, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/clusters/%d", pathEscape(group), cluster)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gc := new(GroupCluster)
|
||||||
|
resp, err := s.client.Do(req, gc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gc, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteCluster deletes an existing group cluster.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_clusters.html#delete-group-cluster
|
||||||
|
func (s *GroupClustersService) DeleteCluster(pid interface{}, cluster int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/clusters/%d", pathEscape(group), cluster)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
206
vendor/github.com/xanzy/go-gitlab/group_hooks.go
generated
vendored
Normal file
206
vendor/github.com/xanzy/go-gitlab/group_hooks.go
generated
vendored
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Eric Stevens
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupHook represents a GitLab group hook.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#list-group-hooks
|
||||||
|
type GroupHook struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
GroupID int `json:"group_id"`
|
||||||
|
PushEvents bool `json:"push_events"`
|
||||||
|
IssuesEvents bool `json:"issues_events"`
|
||||||
|
ConfidentialIssuesEvents bool `json:"confidential_issues_events"`
|
||||||
|
ConfidentialNoteEvents bool `json:"confidential_note_events"`
|
||||||
|
MergeRequestsEvents bool `json:"merge_requests_events"`
|
||||||
|
TagPushEvents bool `json:"tag_push_events"`
|
||||||
|
NoteEvents bool `json:"note_events"`
|
||||||
|
JobEvents bool `json:"job_events"`
|
||||||
|
PipelineEvents bool `json:"pipeline_events"`
|
||||||
|
WikiPageEvents bool `json:"wiki_page_events"`
|
||||||
|
DeploymentEvents bool `json:"deployment_events"`
|
||||||
|
ReleasesEvents bool `json:"releases_events"`
|
||||||
|
EnableSSLVerification bool `json:"enable_ssl_verification"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupHooks gets a list of group hooks.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#list-group-hooks
|
||||||
|
func (s *GroupsService) ListGroupHooks(gid interface{}) ([]*GroupHook, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/hooks", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
var gh []*GroupHook
|
||||||
|
resp, err := s.client.Do(req, &gh)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gh, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupHook gets a specific hook for a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/groups.html#get-group-hook
|
||||||
|
func (s *GroupsService) GetGroupHook(pid interface{}, hook int, options ...RequestOptionFunc) (*GroupHook, *Response, error) {
|
||||||
|
group, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/hooks/%d", pathEscape(group), hook)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gh := new(GroupHook)
|
||||||
|
resp, err := s.client.Do(req, gh)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gh, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddGroupHookOptions represents the available AddGroupHook() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#add-group-hook
|
||||||
|
type AddGroupHookOptions struct {
|
||||||
|
URL *string `url:"url,omitempty" json:"url,omitempty"`
|
||||||
|
PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"`
|
||||||
|
IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"`
|
||||||
|
ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"`
|
||||||
|
ConfidentialNoteEvents *bool `url:"confidential_note_events,omitempty" json:"confidential_note_events,omitempty"`
|
||||||
|
MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"`
|
||||||
|
TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"`
|
||||||
|
NoteEvents *bool `url:"note_events,omitempty" json:"note_events,omitempty"`
|
||||||
|
JobEvents *bool `url:"job_events,omitempty" json:"job_events,omitempty"`
|
||||||
|
PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"`
|
||||||
|
WikiPageEvents *bool `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"`
|
||||||
|
DeploymentEvents *bool `url:"deployment_events,omitempty" json:"deployment_events,omitempty"`
|
||||||
|
ReleasesEvents *bool `url:"releases_events,omitempty" json:"releases_events,omitempty"`
|
||||||
|
EnableSSLVerification *bool `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"`
|
||||||
|
Token *string `url:"token,omitempty" json:"token,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddGroupHook create a new group scoped webhook.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#add-group-hook
|
||||||
|
func (s *GroupsService) AddGroupHook(gid interface{}, opt *AddGroupHookOptions, options ...RequestOptionFunc) (*GroupHook, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/hooks", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gh := new(GroupHook)
|
||||||
|
resp, err := s.client.Do(req, gh)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gh, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditGroupHookOptions represents the available EditGroupHook() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/groups.html#edit-group-hook
|
||||||
|
type EditGroupHookOptions struct {
|
||||||
|
URL *string `url:"url,omitempty" json:"url,omitempty"`
|
||||||
|
PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"`
|
||||||
|
IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"`
|
||||||
|
ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"`
|
||||||
|
ConfidentialNoteEvents *bool `url:"confidential_note_events,omitempty" json:"confidential_note_events,omitempty"`
|
||||||
|
MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"`
|
||||||
|
TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"`
|
||||||
|
NoteEvents *bool `url:"note_events,omitempty" json:"note_events,omitempty"`
|
||||||
|
JobEvents *bool `url:"job_events,omitempty" json:"job_events,omitempty"`
|
||||||
|
PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"`
|
||||||
|
WikiPageEvents *bool `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"`
|
||||||
|
DeploymentEvents *bool `url:"deployment_events,omitempty" json:"deployment_events,omitempty"`
|
||||||
|
ReleasesEvents *bool `url:"releases_events,omitempty" json:"releases_events,omitempty"`
|
||||||
|
EnableSSLVerification *bool `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"`
|
||||||
|
Token *string `url:"token,omitempty" json:"token,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditGroupHook edits a hook for a specified group.
|
||||||
|
//
|
||||||
|
// Gitlab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/groups.html#edit-group-hook
|
||||||
|
func (s *GroupsService) EditGroupHook(pid interface{}, hook int, opt *EditGroupHookOptions, options ...RequestOptionFunc) (*GroupHook, *Response, error) {
|
||||||
|
group, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/hooks/%d", pathEscape(group), hook)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gh := new(GroupHook)
|
||||||
|
resp, err := s.client.Do(req, gh)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gh, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteGroupHook removes a hook from a group. This is an idempotent
|
||||||
|
// method and can be called multiple times.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/groups.html#delete-group-hook
|
||||||
|
func (s *GroupsService) DeleteGroupHook(pid interface{}, hook int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/hooks/%d", pathEscape(group), hook)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
180
vendor/github.com/xanzy/go-gitlab/group_import_export.go
generated
vendored
Normal file
180
vendor/github.com/xanzy/go-gitlab/group_import_export.go
generated
vendored
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupImportExportService handles communication with the group import export
|
||||||
|
// related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/group_import_export.html
|
||||||
|
type GroupImportExportService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScheduleExport starts a new group export.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_import_export.html#schedule-new-export
|
||||||
|
func (s *GroupImportExportService) ScheduleExport(gid interface{}, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/export", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExportDownload downloads the finished export.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_import_export.html#export-download
|
||||||
|
func (s *GroupImportExportService) ExportDownload(gid interface{}, options ...RequestOptionFunc) (*bytes.Reader, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/export/download", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
exportDownload := new(bytes.Buffer)
|
||||||
|
resp, err := s.client.Do(req, exportDownload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes.NewReader(exportDownload.Bytes()), resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupImportFileOptions represents the available ImportFile() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_import_export.html#import-a-file
|
||||||
|
type GroupImportFileOptions struct {
|
||||||
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
|
Path *string `url:"path,omitempty" json:"path,omitempty"`
|
||||||
|
File *string `url:"file,omitempty" json:"file,omitempty"`
|
||||||
|
ParentID *int `url:"parent_id,omitempty" json:"parent_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportFile imports a file.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_import_export.html#import-a-file
|
||||||
|
func (s *GroupImportExportService) ImportFile(opt *GroupImportFileOptions, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
// First check if we got all required options.
|
||||||
|
if opt.Name == nil || *opt.Name == "" {
|
||||||
|
return nil, fmt.Errorf("Missing required option: Name")
|
||||||
|
}
|
||||||
|
if opt.Path == nil || *opt.Path == "" {
|
||||||
|
return nil, fmt.Errorf("Missing required option: Path")
|
||||||
|
}
|
||||||
|
if opt.File == nil || *opt.File == "" {
|
||||||
|
return nil, fmt.Errorf("Missing required option: File")
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(*opt.File)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
b := &bytes.Buffer{}
|
||||||
|
w := multipart.NewWriter(b)
|
||||||
|
|
||||||
|
_, filename := filepath.Split(*opt.File)
|
||||||
|
fw, err := w.CreateFormFile("file", filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(fw, f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate the additional fields.
|
||||||
|
fw, err = w.CreateFormField("name")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = fw.Write([]byte(*opt.Name))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fw, err = w.CreateFormField("path")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = fw.Write([]byte(*opt.Path))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if opt.ParentID != nil {
|
||||||
|
fw, err = w.CreateFormField("parent_id")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = fw.Write([]byte(strconv.Itoa(*opt.ParentID)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = w.Close(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, "groups/import", nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the buffer as the request body.
|
||||||
|
if err = req.SetBody(b); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrite the default content type.
|
||||||
|
req.Header.Set("Content-Type", w.FormDataContentType())
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
242
vendor/github.com/xanzy/go-gitlab/group_labels.go
generated
vendored
Normal file
242
vendor/github.com/xanzy/go-gitlab/group_labels.go
generated
vendored
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupLabelsService handles communication with the label related methods of the
|
||||||
|
// GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/group_labels.html
|
||||||
|
type GroupLabelsService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupLabel represents a GitLab group label.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/group_labels.html
|
||||||
|
type GroupLabel Label
|
||||||
|
|
||||||
|
func (l GroupLabel) String() string {
|
||||||
|
return Stringify(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupLabelsOptions represents the available ListGroupLabels() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels
|
||||||
|
type ListGroupLabelsOptions ListOptions
|
||||||
|
|
||||||
|
// ListGroupLabels gets all labels for given group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_labels.html#list-group-labels
|
||||||
|
func (s *GroupLabelsService) ListGroupLabels(gid interface{}, opt *ListGroupLabelsOptions, options ...RequestOptionFunc) ([]*GroupLabel, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/labels", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var l []*GroupLabel
|
||||||
|
resp, err := s.client.Do(req, &l)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return l, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupLabel get a single label for a given group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_labels.html#get-a-single-group-label
|
||||||
|
func (s *GroupLabelsService) GetGroupLabel(gid interface{}, labelID interface{}, options ...RequestOptionFunc) (*GroupLabel, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
label, err := parseID(labelID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/labels/%s", pathEscape(group), label)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var l *GroupLabel
|
||||||
|
resp, err := s.client.Do(req, &l)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return l, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateGroupLabelOptions represents the available CreateGroupLabel() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_labels.html#create-a-new-group-label
|
||||||
|
type CreateGroupLabelOptions CreateLabelOptions
|
||||||
|
|
||||||
|
// CreateGroupLabel creates a new label for given group with given name and
|
||||||
|
// color.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_labels.html#create-a-new-group-label
|
||||||
|
func (s *GroupLabelsService) CreateGroupLabel(gid interface{}, opt *CreateGroupLabelOptions, options ...RequestOptionFunc) (*GroupLabel, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/labels", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
l := new(GroupLabel)
|
||||||
|
resp, err := s.client.Do(req, l)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return l, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteGroupLabelOptions represents the available DeleteGroupLabel() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_labels.html#delete-a-group-label
|
||||||
|
type DeleteGroupLabelOptions DeleteLabelOptions
|
||||||
|
|
||||||
|
// DeleteGroupLabel deletes a group label given by its name.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label
|
||||||
|
func (s *GroupLabelsService) DeleteGroupLabel(gid interface{}, opt *DeleteGroupLabelOptions, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/labels", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateGroupLabelOptions represents the available UpdateGroupLabel() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_labels.html#update-a-group-label
|
||||||
|
type UpdateGroupLabelOptions UpdateLabelOptions
|
||||||
|
|
||||||
|
// UpdateGroupLabel updates an existing label with new name or now color. At least
|
||||||
|
// one parameter is required, to update the label.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_labels.html#update-a-group-label
|
||||||
|
func (s *GroupLabelsService) UpdateGroupLabel(gid interface{}, opt *UpdateGroupLabelOptions, options ...RequestOptionFunc) (*GroupLabel, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/labels", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
l := new(GroupLabel)
|
||||||
|
resp, err := s.client.Do(req, l)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return l, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubscribeToGroupLabel subscribes the authenticated user to a label to receive
|
||||||
|
// notifications. If the user is already subscribed to the label, the status
|
||||||
|
// code 304 is returned.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_labels.html#subscribe-to-a-group-label
|
||||||
|
func (s *GroupLabelsService) SubscribeToGroupLabel(gid interface{}, labelID interface{}, options ...RequestOptionFunc) (*GroupLabel, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
label, err := parseID(labelID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/labels/%s/subscribe", pathEscape(group), label)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
l := new(GroupLabel)
|
||||||
|
resp, err := s.client.Do(req, l)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return l, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnsubscribeFromGroupLabel unsubscribes the authenticated user from a label to not
|
||||||
|
// receive notifications from it. If the user is not subscribed to the label, the
|
||||||
|
// status code 304 is returned.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_labels.html#unsubscribe-from-a-group-label
|
||||||
|
func (s *GroupLabelsService) UnsubscribeFromGroupLabel(gid interface{}, labelID interface{}, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
label, err := parseID(labelID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/labels/%s/unsubscribe", pathEscape(group), label)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
347
vendor/github.com/xanzy/go-gitlab/group_members.go
generated
vendored
Normal file
347
vendor/github.com/xanzy/go-gitlab/group_members.go
generated
vendored
Normal file
|
@ -0,0 +1,347 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupMembersService handles communication with the group members
|
||||||
|
// related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/members.html
|
||||||
|
type GroupMembersService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupMemberSAMLIdentity represents the SAML Identity link for the group member.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project
|
||||||
|
// Gitlab MR for API change: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20357
|
||||||
|
// Gitlab MR for API Doc change: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25652
|
||||||
|
type GroupMemberSAMLIdentity struct {
|
||||||
|
ExternUID string `json:"extern_uid"`
|
||||||
|
Provider string `json:"provider"`
|
||||||
|
SAMLProviderID int `json:"saml_provider_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupMember represents a GitLab group member.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/members.html
|
||||||
|
type GroupMember struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
State string `json:"state"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
ExpiresAt *ISOTime `json:"expires_at"`
|
||||||
|
AccessLevel AccessLevelValue `json:"access_level"`
|
||||||
|
GroupSAMLIdentity *GroupMemberSAMLIdentity `json:"group_saml_identity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupMembersOptions represents the available ListGroupMembers() and
|
||||||
|
// ListAllGroupMembers() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project
|
||||||
|
type ListGroupMembersOptions struct {
|
||||||
|
ListOptions
|
||||||
|
Query *string `url:"query,omitempty" json:"query,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupMembers get a list of group members viewable by the authenticated
|
||||||
|
// user. Inherited members through ancestor groups are not included.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project
|
||||||
|
func (s *GroupsService) ListGroupMembers(gid interface{}, opt *ListGroupMembersOptions, options ...RequestOptionFunc) ([]*GroupMember, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/members", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var gm []*GroupMember
|
||||||
|
resp, err := s.client.Do(req, &gm)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gm, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAllGroupMembers get a list of group members viewable by the authenticated
|
||||||
|
// user. Returns a list including inherited members through ancestor groups.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project-including-inherited-members
|
||||||
|
func (s *GroupsService) ListAllGroupMembers(gid interface{}, opt *ListGroupMembersOptions, options ...RequestOptionFunc) ([]*GroupMember, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/members/all", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var gm []*GroupMember
|
||||||
|
resp, err := s.client.Do(req, &gm)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gm, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddGroupMemberOptions represents the available AddGroupMember() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project
|
||||||
|
type AddGroupMemberOptions struct {
|
||||||
|
UserID *int `url:"user_id,omitempty" json:"user_id,omitempty"`
|
||||||
|
AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
|
||||||
|
ExpiresAt *string `url:"expires_at,omitempty" json:"expires_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupMember gets a member of a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/members.html#get-a-member-of-a-group-or-project
|
||||||
|
func (s *GroupMembersService) GetGroupMember(gid interface{}, user int, options ...RequestOptionFunc) (*GroupMember, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/members/%d", pathEscape(group), user)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gm := new(GroupMember)
|
||||||
|
resp, err := s.client.Do(req, gm)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gm, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// BillableGroupMember represents a GitLab billable group member.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/members.html#list-all-billable-members-of-a-group
|
||||||
|
type BillableGroupMember struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
State string `json:"state"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
LastActivityOn ISOTime `json:"last_activity_on"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListBillableGroupMembersOptions represents the available ListBillableGroupMembers() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/members.html#list-all-billable-members-of-a-group
|
||||||
|
type ListBillableGroupMembersOptions struct {
|
||||||
|
ListOptions
|
||||||
|
Search *string `url:"search,omitempty" json:"search,omitempty"`
|
||||||
|
Sort *string `url:"sort,omitempty" json:"sort,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListBillableGroupMembers Gets a list of group members that count as billable.
|
||||||
|
// The list includes members in the subgroup or subproject.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/members.html#list-all-billable-members-of-a-group
|
||||||
|
func (s *GroupsService) ListBillableGroupMembers(gid interface{}, opt *ListBillableGroupMembersOptions, options ...RequestOptionFunc) ([]*BillableGroupMember, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/billable_members", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var bgm []*BillableGroupMember
|
||||||
|
resp, err := s.client.Do(req, &bgm)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bgm, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveBillableGroupMember removes a given group members that count as billable.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/members.html#remove-a-billable-member-from-a-group
|
||||||
|
func (s *GroupsService) RemoveBillableGroupMember(gid interface{}, user int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/billable_members/%d", pathEscape(group), user)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddGroupMember adds a user to the list of group members.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project
|
||||||
|
func (s *GroupMembersService) AddGroupMember(gid interface{}, opt *AddGroupMemberOptions, options ...RequestOptionFunc) (*GroupMember, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/members", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gm := new(GroupMember)
|
||||||
|
resp, err := s.client.Do(req, gm)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gm, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShareWithGroup shares a group with the group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/groups.html#share-groups-with-groups
|
||||||
|
func (s *GroupMembersService) ShareWithGroup(gid interface{}, opt *ShareWithGroupOptions, options ...RequestOptionFunc) (*Group, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/share", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
g := new(Group)
|
||||||
|
resp, err := s.client.Do(req, g)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return g, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteShareWithGroup allows to unshare a group from a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/groups.html#delete-link-sharing-group-with-another-group
|
||||||
|
func (s *GroupMembersService) DeleteShareWithGroup(gid interface{}, groupID int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/share/%d", pathEscape(group), groupID)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditGroupMemberOptions represents the available EditGroupMember()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project
|
||||||
|
type EditGroupMemberOptions struct {
|
||||||
|
AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
|
||||||
|
ExpiresAt *string `url:"expires_at,omitempty" json:"expires_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditGroupMember updates a member of a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project
|
||||||
|
func (s *GroupMembersService) EditGroupMember(gid interface{}, user int, opt *EditGroupMemberOptions, options ...RequestOptionFunc) (*GroupMember, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/members/%d", pathEscape(group), user)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gm := new(GroupMember)
|
||||||
|
resp, err := s.client.Do(req, gm)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gm, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveGroupMember removes user from user team.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/members.html#remove-a-member-from-a-group-or-project
|
||||||
|
func (s *GroupMembersService) RemoveGroupMember(gid interface{}, user int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/members/%d", pathEscape(group), user)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
296
vendor/github.com/xanzy/go-gitlab/group_milestones.go
generated
vendored
Normal file
296
vendor/github.com/xanzy/go-gitlab/group_milestones.go
generated
vendored
Normal file
|
@ -0,0 +1,296 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupMilestonesService handles communication with the milestone related
|
||||||
|
// methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/group_milestones.html
|
||||||
|
type GroupMilestonesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupMilestone represents a GitLab milestone.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/group_milestones.html
|
||||||
|
type GroupMilestone struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
IID int `json:"iid"`
|
||||||
|
GroupID int `json:"group_id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
StartDate *ISOTime `json:"start_date"`
|
||||||
|
DueDate *ISOTime `json:"due_date"`
|
||||||
|
State string `json:"state"`
|
||||||
|
UpdatedAt *time.Time `json:"updated_at"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
Expired *bool `json:"expired"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m GroupMilestone) String() string {
|
||||||
|
return Stringify(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupMilestonesOptions represents the available
|
||||||
|
// ListGroupMilestones() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_milestones.html#list-group-milestones
|
||||||
|
type ListGroupMilestonesOptions struct {
|
||||||
|
ListOptions
|
||||||
|
IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"`
|
||||||
|
State *string `url:"state,omitempty" json:"state,omitempty"`
|
||||||
|
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
||||||
|
Search *string `url:"search,omitempty" json:"search,omitempty"`
|
||||||
|
IncludeParentMilestones *bool `url:"include_parent_milestones,omitempty" json:"include_parent_milestones,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupMilestones returns a list of group milestones.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_milestones.html#list-group-milestones
|
||||||
|
func (s *GroupMilestonesService) ListGroupMilestones(gid interface{}, opt *ListGroupMilestonesOptions, options ...RequestOptionFunc) ([]*GroupMilestone, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/milestones", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var m []*GroupMilestone
|
||||||
|
resp, err := s.client.Do(req, &m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupMilestone gets a single group milestone.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_milestones.html#get-single-milestone
|
||||||
|
func (s *GroupMilestonesService) GetGroupMilestone(gid interface{}, milestone int, options ...RequestOptionFunc) (*GroupMilestone, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/milestones/%d", pathEscape(group), milestone)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
m := new(GroupMilestone)
|
||||||
|
resp, err := s.client.Do(req, m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateGroupMilestoneOptions represents the available CreateGroupMilestone() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_milestones.html#create-new-milestone
|
||||||
|
type CreateGroupMilestoneOptions struct {
|
||||||
|
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
||||||
|
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||||
|
StartDate *ISOTime `url:"start_date,omitempty" json:"start_date,omitempty"`
|
||||||
|
DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateGroupMilestone creates a new group milestone.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_milestones.html#create-new-milestone
|
||||||
|
func (s *GroupMilestonesService) CreateGroupMilestone(gid interface{}, opt *CreateGroupMilestoneOptions, options ...RequestOptionFunc) (*GroupMilestone, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/milestones", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
m := new(GroupMilestone)
|
||||||
|
resp, err := s.client.Do(req, m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateGroupMilestoneOptions represents the available UpdateGroupMilestone() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_milestones.html#edit-milestone
|
||||||
|
type UpdateGroupMilestoneOptions struct {
|
||||||
|
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
||||||
|
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||||
|
StartDate *ISOTime `url:"start_date,omitempty" json:"start_date,omitempty"`
|
||||||
|
DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"`
|
||||||
|
StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateGroupMilestone updates an existing group milestone.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_milestones.html#edit-milestone
|
||||||
|
func (s *GroupMilestonesService) UpdateGroupMilestone(gid interface{}, milestone int, opt *UpdateGroupMilestoneOptions, options ...RequestOptionFunc) (*GroupMilestone, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/milestones/%d", pathEscape(group), milestone)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
m := new(GroupMilestone)
|
||||||
|
resp, err := s.client.Do(req, m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupMilestoneIssuesOptions represents the available GetGroupMilestoneIssues() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_milestones.html#get-all-issues-assigned-to-a-single-milestone
|
||||||
|
type GetGroupMilestoneIssuesOptions ListOptions
|
||||||
|
|
||||||
|
// GetGroupMilestoneIssues gets all issues assigned to a single group milestone.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_milestones.html#get-all-issues-assigned-to-a-single-milestone
|
||||||
|
func (s *GroupMilestonesService) GetGroupMilestoneIssues(gid interface{}, milestone int, opt *GetGroupMilestoneIssuesOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/milestones/%d/issues", pathEscape(group), milestone)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var i []*Issue
|
||||||
|
resp, err := s.client.Do(req, &i)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return i, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupMilestoneMergeRequestsOptions represents the available
|
||||||
|
// GetGroupMilestoneMergeRequests() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_milestones.html#get-all-merge-requests-assigned-to-a-single-milestone
|
||||||
|
type GetGroupMilestoneMergeRequestsOptions ListOptions
|
||||||
|
|
||||||
|
// GetGroupMilestoneMergeRequests gets all merge requests assigned to a
|
||||||
|
// single group milestone.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/group_milestones.html#get-all-merge-requests-assigned-to-a-single-milestone
|
||||||
|
func (s *GroupMilestonesService) GetGroupMilestoneMergeRequests(gid interface{}, milestone int, opt *GetGroupMilestoneMergeRequestsOptions, options ...RequestOptionFunc) ([]*MergeRequest, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/milestones/%d/merge_requests", pathEscape(group), milestone)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var mr []*MergeRequest
|
||||||
|
resp, err := s.client.Do(req, &mr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return mr, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// BurndownChartEvent reprensents a burnout chart event
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_milestones.html#get-all-burndown-chart-events-for-a-single-milestone-starter
|
||||||
|
type BurndownChartEvent struct {
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
Weight *int `json:"weight"`
|
||||||
|
Action *string `json:"action"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupMilestoneBurndownChartEventsOptions represents the available
|
||||||
|
// GetGroupMilestoneBurndownChartEventsOptions() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_milestones.html#get-all-burndown-chart-events-for-a-single-milestone-starter
|
||||||
|
type GetGroupMilestoneBurndownChartEventsOptions ListOptions
|
||||||
|
|
||||||
|
// GetGroupMilestoneBurndownChartEvents gets all merge requests assigned to a
|
||||||
|
// single group milestone.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_milestones.html#get-all-burndown-chart-events-for-a-single-milestone-starter
|
||||||
|
func (s *GroupMilestonesService) GetGroupMilestoneBurndownChartEvents(gid interface{}, milestone int, opt *GetGroupMilestoneBurndownChartEventsOptions, options ...RequestOptionFunc) ([]*BurndownChartEvent, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/milestones/%d/burndown_events", pathEscape(group), milestone)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var be []*BurndownChartEvent
|
||||||
|
resp, err := s.client.Do(req, &be)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return be, resp, err
|
||||||
|
}
|
203
vendor/github.com/xanzy/go-gitlab/group_variables.go
generated
vendored
Normal file
203
vendor/github.com/xanzy/go-gitlab/group_variables.go
generated
vendored
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Patrick Webster
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupVariablesService handles communication with the
|
||||||
|
// group variables related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_level_variables.html
|
||||||
|
type GroupVariablesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupVariable represents a GitLab group Variable.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_level_variables.html
|
||||||
|
type GroupVariable struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
VariableType VariableTypeValue `json:"variable_type"`
|
||||||
|
Protected bool `json:"protected"`
|
||||||
|
Masked bool `json:"masked"`
|
||||||
|
EnvironmentScope string `json:"environment_scope"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v GroupVariable) String() string {
|
||||||
|
return Stringify(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupVariablesOptions represents the available options for listing variables
|
||||||
|
// for a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_level_variables.html#list-group-variables
|
||||||
|
type ListGroupVariablesOptions ListOptions
|
||||||
|
|
||||||
|
// ListVariables gets a list of all variables for a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_level_variables.html#list-group-variables
|
||||||
|
func (s *GroupVariablesService) ListVariables(gid interface{}, opt *ListGroupVariablesOptions, options ...RequestOptionFunc) ([]*GroupVariable, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/variables", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var vs []*GroupVariable
|
||||||
|
resp, err := s.client.Do(req, &vs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return vs, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVariable gets a variable.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_level_variables.html#show-variable-details
|
||||||
|
func (s *GroupVariablesService) GetVariable(gid interface{}, key string, options ...RequestOptionFunc) (*GroupVariable, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/variables/%s", pathEscape(group), url.PathEscape(key))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v := new(GroupVariable)
|
||||||
|
resp, err := s.client.Do(req, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return v, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateGroupVariableOptions represents the available CreateVariable()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_level_variables.html#create-variable
|
||||||
|
type CreateGroupVariableOptions struct {
|
||||||
|
Key *string `url:"key,omitempty" json:"key,omitempty"`
|
||||||
|
Value *string `url:"value,omitempty" json:"value,omitempty"`
|
||||||
|
VariableType *VariableTypeValue `url:"variable_type,omitempty" json:"variable_type,omitempty"`
|
||||||
|
Protected *bool `url:"protected,omitempty" json:"protected,omitempty"`
|
||||||
|
Masked *bool `url:"masked,omitempty" json:"masked,omitempty"`
|
||||||
|
EnvironmentScope *string `url:"environment_scope,omitempty" json:"environment_scope,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateVariable creates a new group variable.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_level_variables.html#create-variable
|
||||||
|
func (s *GroupVariablesService) CreateVariable(gid interface{}, opt *CreateGroupVariableOptions, options ...RequestOptionFunc) (*GroupVariable, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/variables", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v := new(GroupVariable)
|
||||||
|
resp, err := s.client.Do(req, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return v, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateGroupVariableOptions represents the available UpdateVariable()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_level_variables.html#update-variable
|
||||||
|
type UpdateGroupVariableOptions struct {
|
||||||
|
Value *string `url:"value,omitempty" json:"value,omitempty"`
|
||||||
|
VariableType *VariableTypeValue `url:"variable_type,omitempty" json:"variable_type,omitempty"`
|
||||||
|
Protected *bool `url:"protected,omitempty" json:"protected,omitempty"`
|
||||||
|
Masked *bool `url:"masked,omitempty" json:"masked,omitempty"`
|
||||||
|
EnvironmentScope *string `url:"environment_scope,omitempty" json:"environment_scope,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateVariable updates the position of an existing
|
||||||
|
// group issue board list.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_level_variables.html#update-variable
|
||||||
|
func (s *GroupVariablesService) UpdateVariable(gid interface{}, key string, opt *UpdateGroupVariableOptions, options ...RequestOptionFunc) (*GroupVariable, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/variables/%s", pathEscape(group), url.PathEscape(key))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v := new(GroupVariable)
|
||||||
|
resp, err := s.client.Do(req, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return v, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveVariable removes a group's variable.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_level_variables.html#remove-variable
|
||||||
|
func (s *GroupVariablesService) RemoveVariable(gid interface{}, key string, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/variables/%s", pathEscape(group), url.PathEscape(key))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
194
vendor/github.com/xanzy/go-gitlab/group_wikis.go
generated
vendored
Normal file
194
vendor/github.com/xanzy/go-gitlab/group_wikis.go
generated
vendored
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Markus Lackner
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupWikisService handles communication with the group wikis related methods of
|
||||||
|
// the Gitlab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/group_wikis.html
|
||||||
|
type GroupWikisService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupWiki represents a GitLab groups wiki.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/group_wikis.html
|
||||||
|
type GroupWiki struct {
|
||||||
|
Content string `json:"content"`
|
||||||
|
Format WikiFormatValue `json:"format"`
|
||||||
|
Slug string `json:"slug"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w GroupWiki) String() string {
|
||||||
|
return Stringify(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupWikisOptions represents the available ListGroupWikis options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_wikis.html#list-wiki-pages
|
||||||
|
type ListGroupWikisOptions struct {
|
||||||
|
WithContent *bool `url:"with_content,omitempty" json:"with_content,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupWikis lists all pages of the wiki of the given group id.
|
||||||
|
// When with_content is set, it also returns the content of the pages.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_wikis.html#list-wiki-pages
|
||||||
|
func (s *GroupWikisService) ListGroupWikis(gid interface{}, opt *ListGroupWikisOptions, options ...RequestOptionFunc) ([]*GroupWiki, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/wikis", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var gws []*GroupWiki
|
||||||
|
resp, err := s.client.Do(req, &gws)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gws, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupWikiPage gets a wiki page for a given group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_wikis.html#get-a-wiki-page
|
||||||
|
func (s *GroupWikisService) GetGroupWikiPage(gid interface{}, slug string, options ...RequestOptionFunc) (*GroupWiki, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/wikis/%s", pathEscape(group), url.PathEscape(slug))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gw := new(GroupWiki)
|
||||||
|
resp, err := s.client.Do(req, gw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gw, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateGroupWikiPageOptions represents options to CreateGroupWikiPage.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_wikis.html#create-a-new-wiki-page
|
||||||
|
type CreateGroupWikiPageOptions struct {
|
||||||
|
Content *string `url:"content,omitempty" json:"content,omitempty"`
|
||||||
|
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
||||||
|
Format *WikiFormatValue `url:"format,omitempty" json:"format,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateGroupWikiPage creates a new wiki page for the given group with
|
||||||
|
// the given title, slug, and content.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/13.8/ee/api/group_wikis.html#create-a-new-wiki-page
|
||||||
|
func (s *GroupWikisService) CreateGroupWikiPage(gid interface{}, opt *CreateGroupWikiPageOptions, options ...RequestOptionFunc) (*GroupWiki, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/wikis", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
w := new(GroupWiki)
|
||||||
|
resp, err := s.client.Do(req, w)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return w, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditGroupWikiPageOptions represents options to EditGroupWikiPage.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_wikis.html#edit-an-existing-wiki-page
|
||||||
|
type EditGroupWikiPageOptions struct {
|
||||||
|
Content *string `url:"content,omitempty" json:"content,omitempty"`
|
||||||
|
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
||||||
|
Format *WikiFormatValue `url:"format,omitempty" json:"format,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditGroupWikiPage Updates an existing wiki page. At least one parameter is
|
||||||
|
// required to update the wiki page.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_wikis.html#edit-an-existing-wiki-page
|
||||||
|
func (s *GroupWikisService) EditGroupWikiPage(gid interface{}, slug string, opt *EditGroupWikiPageOptions, options ...RequestOptionFunc) (*GroupWiki, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/wikis/%s", pathEscape(group), url.PathEscape(slug))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
w := new(GroupWiki)
|
||||||
|
resp, err := s.client.Do(req, w)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return w, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteGroupWikiPage deletes a wiki page with a given slug.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/group_wikis.html#delete-a-wiki-page
|
||||||
|
func (s *GroupWikisService) DeleteGroupWikiPage(gid interface{}, slug string, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/wikis/%s", pathEscape(group), url.PathEscape(slug))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
805
vendor/github.com/xanzy/go-gitlab/groups.go
generated
vendored
Normal file
805
vendor/github.com/xanzy/go-gitlab/groups.go
generated
vendored
Normal file
|
@ -0,0 +1,805 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupsService handles communication with the group related methods of
|
||||||
|
// the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html
|
||||||
|
type GroupsService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group represents a GitLab group.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html
|
||||||
|
type Group struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
MembershipLock bool `json:"membership_lock"`
|
||||||
|
Visibility VisibilityValue `json:"visibility"`
|
||||||
|
LFSEnabled bool `json:"lfs_enabled"`
|
||||||
|
DefaultBranchProtection int `json:"default_branch_protection"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
RequestAccessEnabled bool `json:"request_access_enabled"`
|
||||||
|
FullName string `json:"full_name"`
|
||||||
|
FullPath string `json:"full_path"`
|
||||||
|
ParentID int `json:"parent_id"`
|
||||||
|
Projects []*Project `json:"projects"`
|
||||||
|
Statistics *StorageStatistics `json:"statistics"`
|
||||||
|
CustomAttributes []*CustomAttribute `json:"custom_attributes"`
|
||||||
|
ShareWithGroupLock bool `json:"share_with_group_lock"`
|
||||||
|
RequireTwoFactorAuth bool `json:"require_two_factor_authentication"`
|
||||||
|
TwoFactorGracePeriod int `json:"two_factor_grace_period"`
|
||||||
|
ProjectCreationLevel ProjectCreationLevelValue `json:"project_creation_level"`
|
||||||
|
AutoDevopsEnabled bool `json:"auto_devops_enabled"`
|
||||||
|
SubGroupCreationLevel SubGroupCreationLevelValue `json:"subgroup_creation_level"`
|
||||||
|
EmailsDisabled bool `json:"emails_disabled"`
|
||||||
|
MentionsDisabled bool `json:"mentions_disabled"`
|
||||||
|
RunnersToken string `json:"runners_token"`
|
||||||
|
SharedProjects []*Project `json:"shared_projects"`
|
||||||
|
SharedWithGroups []struct {
|
||||||
|
GroupID int `json:"group_id"`
|
||||||
|
GroupName string `json:"group_name"`
|
||||||
|
GroupFullPath string `json:"group_full_path"`
|
||||||
|
GroupAccessLevel int `json:"group_access_level"`
|
||||||
|
ExpiresAt *ISOTime `json:"expires_at"`
|
||||||
|
} `json:"shared_with_groups"`
|
||||||
|
LDAPCN string `json:"ldap_cn"`
|
||||||
|
LDAPAccess AccessLevelValue `json:"ldap_access"`
|
||||||
|
LDAPGroupLinks []*LDAPGroupLink `json:"ldap_group_links"`
|
||||||
|
SharedRunnersMinutesLimit int `json:"shared_runners_minutes_limit"`
|
||||||
|
ExtraSharedRunnersMinutesLimit int `json:"extra_shared_runners_minutes_limit"`
|
||||||
|
MarkedForDeletionOn *ISOTime `json:"marked_for_deletion_on"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LDAPGroupLink represents a GitLab LDAP group link.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#ldap-group-links
|
||||||
|
type LDAPGroupLink struct {
|
||||||
|
CN string `json:"cn"`
|
||||||
|
Filter string `json:"filter"`
|
||||||
|
GroupAccess AccessLevelValue `json:"group_access"`
|
||||||
|
Provider string `json:"provider"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupsOptions represents the available ListGroups() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#list-project-groups
|
||||||
|
type ListGroupsOptions struct {
|
||||||
|
ListOptions
|
||||||
|
AllAvailable *bool `url:"all_available,omitempty" json:"all_available,omitempty"`
|
||||||
|
MinAccessLevel *AccessLevelValue `url:"min_access_level,omitempty" json:"min_access_level,omitempty"`
|
||||||
|
OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
|
||||||
|
Owned *bool `url:"owned,omitempty" json:"owned,omitempty"`
|
||||||
|
Search *string `url:"search,omitempty" json:"search,omitempty"`
|
||||||
|
SkipGroups []int `url:"skip_groups,omitempty" json:"skip_groups,omitempty"`
|
||||||
|
Sort *string `url:"sort,omitempty" json:"sort,omitempty"`
|
||||||
|
Statistics *bool `url:"statistics,omitempty" json:"statistics,omitempty"`
|
||||||
|
TopLevelOnly *bool `url:"top_level_only,omitempty" json:"top_level_only,omitempty"`
|
||||||
|
WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroups gets a list of groups (as user: my groups, as admin: all groups).
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/groups.html#list-project-groups
|
||||||
|
func (s *GroupsService) ListGroups(opt *ListGroupsOptions, options ...RequestOptionFunc) ([]*Group, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, "groups", opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var g []*Group
|
||||||
|
resp, err := s.client.Do(req, &g)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return g, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupOptions represents the available GetGroup() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#details-of-a-group
|
||||||
|
type GetGroupOptions struct {
|
||||||
|
ListOptions
|
||||||
|
WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"`
|
||||||
|
WithProjects *bool `url:"with_projects,omitempty" json:"with_projects,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroup gets all details of a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#details-of-a-group
|
||||||
|
func (s *GroupsService) GetGroup(gid interface{}, opt *GetGroupOptions, options ...RequestOptionFunc) (*Group, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
g := new(Group)
|
||||||
|
resp, err := s.client.Do(req, g)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return g, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateGroupOptions represents the available CreateGroup() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#new-group
|
||||||
|
type CreateGroupOptions struct {
|
||||||
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
|
Path *string `url:"path,omitempty" json:"path,omitempty"`
|
||||||
|
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||||
|
MembershipLock *bool `url:"membership_lock,omitempty" json:"membership_lock,omitempty"`
|
||||||
|
Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"`
|
||||||
|
ShareWithGroupLock *bool `url:"share_with_group_lock,omitempty" json:"share_with_group_lock,omitempty"`
|
||||||
|
RequireTwoFactorAuth *bool `url:"require_two_factor_authentication,omitempty" json:"require_two_factor_authentication,omitempty"`
|
||||||
|
TwoFactorGracePeriod *int `url:"two_factor_grace_period,omitempty" json:"two_factor_grace_period,omitempty"`
|
||||||
|
ProjectCreationLevel *ProjectCreationLevelValue `url:"project_creation_level,omitempty" json:"project_creation_level,omitempty"`
|
||||||
|
AutoDevopsEnabled *bool `url:"auto_devops_enabled,omitempty" json:"auto_devops_enabled,omitempty"`
|
||||||
|
SubGroupCreationLevel *SubGroupCreationLevelValue `url:"subgroup_creation_level,omitempty" json:"subgroup_creation_level,omitempty"`
|
||||||
|
EmailsDisabled *bool `url:"emails_disabled,omitempty" json:"emails_disabled,omitempty"`
|
||||||
|
MentionsDisabled *bool `url:"mentions_disabled,omitempty" json:"mentions_disabled,omitempty"`
|
||||||
|
LFSEnabled *bool `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"`
|
||||||
|
DefaultBranchProtection *int `url:"default_branch_protection,omitempty" json:"default_branch_protection"`
|
||||||
|
RequestAccessEnabled *bool `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"`
|
||||||
|
ParentID *int `url:"parent_id,omitempty" json:"parent_id,omitempty"`
|
||||||
|
SharedRunnersMinutesLimit *int `url:"shared_runners_minutes_limit,omitempty" json:"shared_runners_minutes_limit,omitempty"`
|
||||||
|
ExtraSharedRunnersMinutesLimit *int `url:"extra_shared_runners_minutes_limit,omitempty" json:"extra_shared_runners_minutes_limit,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateGroup creates a new project group. Available only for users who can
|
||||||
|
// create groups.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#new-group
|
||||||
|
func (s *GroupsService) CreateGroup(opt *CreateGroupOptions, options ...RequestOptionFunc) (*Group, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, "groups", opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
g := new(Group)
|
||||||
|
resp, err := s.client.Do(req, g)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return g, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TransferGroup transfers a project to the Group namespace. Available only
|
||||||
|
// for admin.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/groups.html#transfer-project-to-group
|
||||||
|
func (s *GroupsService) TransferGroup(gid interface{}, pid interface{}, options ...RequestOptionFunc) (*Group, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/projects/%s", pathEscape(group), pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
g := new(Group)
|
||||||
|
resp, err := s.client.Do(req, g)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return g, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateGroupOptions represents the available UpdateGroup() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#update-group
|
||||||
|
type UpdateGroupOptions struct {
|
||||||
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
|
Path *string `url:"path,omitempty" json:"path,omitempty"`
|
||||||
|
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||||
|
MembershipLock *bool `url:"membership_lock,omitempty" json:"membership_lock,omitempty"`
|
||||||
|
Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"`
|
||||||
|
ShareWithGroupLock *bool `url:"share_with_group_lock,omitempty" json:"share_with_group_lock,omitempty"`
|
||||||
|
RequireTwoFactorAuth *bool `url:"require_two_factor_authentication,omitempty" json:"require_two_factor_authentication,omitempty"`
|
||||||
|
TwoFactorGracePeriod *int `url:"two_factor_grace_period,omitempty" json:"two_factor_grace_period,omitempty"`
|
||||||
|
ProjectCreationLevel *ProjectCreationLevelValue `url:"project_creation_level,omitempty" json:"project_creation_level,omitempty"`
|
||||||
|
AutoDevopsEnabled *bool `url:"auto_devops_enabled,omitempty" json:"auto_devops_enabled,omitempty"`
|
||||||
|
SubGroupCreationLevel *SubGroupCreationLevelValue `url:"subgroup_creation_level,omitempty" json:"subgroup_creation_level,omitempty"`
|
||||||
|
EmailsDisabled *bool `url:"emails_disabled,omitempty" json:"emails_disabled,omitempty"`
|
||||||
|
MentionsDisabled *bool `url:"mentions_disabled,omitempty" json:"mentions_disabled,omitempty"`
|
||||||
|
LFSEnabled *bool `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"`
|
||||||
|
RequestAccessEnabled *bool `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"`
|
||||||
|
DefaultBranchProtection *int `url:"default_branch_protection,omitempty" json:"default_branch_protection,omitempty"`
|
||||||
|
FileTemplateProjectID *int `url:"file_template_project_id,omitempty" json:"file_template_project_id,omitempty"`
|
||||||
|
SharedRunnersMinutesLimit *int `url:"shared_runners_minutes_limit,omitempty" json:"shared_runners_minutes_limit,omitempty"`
|
||||||
|
ExtraSharedRunnersMinutesLimit *int `url:"extra_shared_runners_minutes_limit,omitempty" json:"extra_shared_runners_minutes_limit,omitempty"`
|
||||||
|
PreventForkingOutsideGroup *bool `url:"prevent_forking_outside_group,omitempty" json:"prevent_forking_outside_group,omitempty"`
|
||||||
|
SharedRunnersSetting *SharedRunnersSettingValue `url:"shared_runners_setting,omitempty" json:"shared_runners_setting,omitempty"`
|
||||||
|
PreventSharingGroupsOutsideHierarchy *bool `url:"prevent_sharing_groups_outside_hierarchy,omitempty" json:"prevent_sharing_groups_outside_hierarchy,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateGroup updates an existing group; only available to group owners and
|
||||||
|
// administrators.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#update-group
|
||||||
|
func (s *GroupsService) UpdateGroup(gid interface{}, opt *UpdateGroupOptions, options ...RequestOptionFunc) (*Group, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
g := new(Group)
|
||||||
|
resp, err := s.client.Do(req, g)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return g, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteGroup removes group with all projects inside.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#remove-group
|
||||||
|
func (s *GroupsService) DeleteGroup(gid interface{}, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestoreGroup restores a previously deleted group
|
||||||
|
//
|
||||||
|
// GitLap API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#restore-group-marked-for-deletion
|
||||||
|
func (s *GroupsService) RestoreGroup(gid interface{}, options ...RequestOptionFunc) (*Group, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/restore", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
g := new(Group)
|
||||||
|
resp, err := s.client.Do(req, g)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return g, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchGroup get all groups that match your string in their name or path.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#search-for-group
|
||||||
|
func (s *GroupsService) SearchGroup(query string, options ...RequestOptionFunc) ([]*Group, *Response, error) {
|
||||||
|
var q struct {
|
||||||
|
Search string `url:"search,omitempty" json:"search,omitempty"`
|
||||||
|
}
|
||||||
|
q.Search = query
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, "groups", &q, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var g []*Group
|
||||||
|
resp, err := s.client.Do(req, &g)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return g, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupProjectsOptions represents the available ListGroup() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/groups.html#list-a-group-39-s-projects
|
||||||
|
type ListGroupProjectsOptions struct {
|
||||||
|
ListOptions
|
||||||
|
Archived *bool `url:"archived,omitempty" json:"archived,omitempty"`
|
||||||
|
IncludeSubgroups *bool `url:"include_subgroups,omitempty" json:"include_subgroups,omitempty"`
|
||||||
|
MinAccessLevel *AccessLevelValue `url:"min_access_level,omitempty" json:"min_access_level,omitempty"`
|
||||||
|
OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
|
||||||
|
Owned *bool `url:"owned,omitempty" json:"owned,omitempty"`
|
||||||
|
Search *string `url:"search,omitempty" json:"search,omitempty"`
|
||||||
|
Simple *bool `url:"simple,omitempty" json:"simple,omitempty"`
|
||||||
|
Sort *string `url:"sort,omitempty" json:"sort,omitempty"`
|
||||||
|
Starred *bool `url:"starred,omitempty" json:"starred,omitempty"`
|
||||||
|
Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"`
|
||||||
|
WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"`
|
||||||
|
WithIssuesEnabled *bool `url:"with_issues_enabled,omitempty" json:"with_issues_enabled,omitempty"`
|
||||||
|
WithMergeRequestsEnabled *bool `url:"with_merge_requests_enabled,omitempty" json:"with_merge_requests_enabled,omitempty"`
|
||||||
|
WithSecurityReports *bool `url:"with_security_reports,omitempty" json:"with_security_reports,omitempty"`
|
||||||
|
WithShared *bool `url:"with_shared,omitempty" json:"with_shared,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupProjects get a list of group projects
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/groups.html#list-a-group-39-s-projects
|
||||||
|
func (s *GroupsService) ListGroupProjects(gid interface{}, opt *ListGroupProjectsOptions, options ...RequestOptionFunc) ([]*Project, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/projects", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var p []*Project
|
||||||
|
resp, err := s.client.Do(req, &p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListSubgroupsOptions represents the available ListSubgroups() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/groups.html#list-a-groups-s-subgroups
|
||||||
|
type ListSubgroupsOptions ListGroupsOptions
|
||||||
|
|
||||||
|
// ListSubgroups gets a list of subgroups for a given group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/groups.html#list-a-groups-s-subgroups
|
||||||
|
func (s *GroupsService) ListSubgroups(gid interface{}, opt *ListSubgroupsOptions, options ...RequestOptionFunc) ([]*Group, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/subgroups", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var g []*Group
|
||||||
|
resp, err := s.client.Do(req, &g)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return g, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListDescendantGroupsOptions represents the available ListDescendantGroups()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/groups.html#list-a-groups-descendant-groups
|
||||||
|
type ListDescendantGroupsOptions ListGroupsOptions
|
||||||
|
|
||||||
|
// ListDescendantGroups gets a list of subgroups for a given project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/groups.html#list-a-groups-descendant-groups
|
||||||
|
func (s *GroupsService) ListDescendantGroups(gid interface{}, opt *ListDescendantGroupsOptions, options ...RequestOptionFunc) ([]*Group, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/descendant_groups", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var g []*Group
|
||||||
|
resp, err := s.client.Do(req, &g)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return g, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupLDAPLinks lists the group's LDAP links. Available only for users who
|
||||||
|
// can edit groups.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#list-ldap-group-links-starter
|
||||||
|
func (s *GroupsService) ListGroupLDAPLinks(gid interface{}, options ...RequestOptionFunc) ([]*LDAPGroupLink, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/ldap_group_links", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var gl []*LDAPGroupLink
|
||||||
|
resp, err := s.client.Do(req, &gl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gl, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddGroupLDAPLinkOptions represents the available AddGroupLDAPLink() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#add-ldap-group-link-starter
|
||||||
|
type AddGroupLDAPLinkOptions struct {
|
||||||
|
CN *string `url:"cn,omitempty" json:"cn,omitempty"`
|
||||||
|
Filter *string `url:"filter,omitempty" json:"filter,omitempty"`
|
||||||
|
GroupAccess *AccessLevelValue `url:"group_access,omitempty" json:"group_access,omitempty"`
|
||||||
|
Provider *string `url:"provider,omitempty" json:"provider,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteGroupLDAPLinkWithCNOrFilterOptions represents the available DeleteGroupLDAPLinkWithCNOrFilter() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#delete-ldap-group-link-with-cn-or-filter
|
||||||
|
type DeleteGroupLDAPLinkWithCNOrFilterOptions struct {
|
||||||
|
CN *string `url:"cn,omitempty" json:"cn,omitempty"`
|
||||||
|
Filter *string `url:"filter,omitempty" json:"filter,omitempty"`
|
||||||
|
Provider *string `url:"provider,omitempty" json:"provider,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddGroupLDAPLink creates a new group LDAP link. Available only for users who
|
||||||
|
// can edit groups.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#add-ldap-group-link-starter
|
||||||
|
func (s *GroupsService) AddGroupLDAPLink(gid interface{}, opt *AddGroupLDAPLinkOptions, options ...RequestOptionFunc) (*LDAPGroupLink, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/ldap_group_links", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gl := new(LDAPGroupLink)
|
||||||
|
resp, err := s.client.Do(req, gl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gl, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteGroupLDAPLink deletes a group LDAP link. Available only for users who
|
||||||
|
// can edit groups.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#delete-ldap-group-link-starter
|
||||||
|
func (s *GroupsService) DeleteGroupLDAPLink(gid interface{}, cn string, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/ldap_group_links/%s", pathEscape(group), pathEscape(cn))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteGroupLDAPLinkWithCNOrFilter deletes a group LDAP link. Available only for users who
|
||||||
|
// can edit groups.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#delete-ldap-group-link-with-cn-or-filter
|
||||||
|
func (s *GroupsService) DeleteGroupLDAPLinkWithCNOrFilter(gid interface{}, opts *DeleteGroupLDAPLinkWithCNOrFilterOptions, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/ldap_group_links", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, opts, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteGroupLDAPLinkForProvider deletes a group LDAP link from a specific
|
||||||
|
// provider. Available only for users who can edit groups.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#delete-ldap-group-link-starter
|
||||||
|
func (s *GroupsService) DeleteGroupLDAPLinkForProvider(gid interface{}, provider, cn string, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf(
|
||||||
|
"groups/%s/ldap_group_links/%s/%s",
|
||||||
|
pathEscape(group),
|
||||||
|
pathEscape(provider),
|
||||||
|
pathEscape(cn),
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShareGroupWithGroupOptions represents the available ShareGroupWithGroup() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#share-groups-with-groups
|
||||||
|
type ShareGroupWithGroupOptions struct {
|
||||||
|
GroupID *int `url:"group_id,omitempty" json:"group_id,omitempty"`
|
||||||
|
GroupAccess *AccessLevelValue `url:"group_access,omitempty" json:"group_access,omitempty"`
|
||||||
|
ExpiresAt *ISOTime `url:"expires_at,omitempty" json:"expires_at,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShareGroupWithGroup shares a group with another group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#create-a-link-to-share-a-group-with-another-group
|
||||||
|
func (s *GroupsService) ShareGroupWithGroup(gid interface{}, opt *ShareGroupWithGroupOptions, options ...RequestOptionFunc) (*Group, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/share", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
g := new(Group)
|
||||||
|
resp, err := s.client.Do(req, g)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return g, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnshareGroupFromGroup unshares a group from another group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#delete-link-sharing-group-with-another-group
|
||||||
|
func (s *GroupsService) UnshareGroupFromGroup(gid interface{}, groupID int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/share/%d", pathEscape(group), groupID)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupPushRules represents a group push rule.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#get-group-push-rules
|
||||||
|
type GroupPushRules struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
CommitMessageRegex string `json:"commit_message_regex"`
|
||||||
|
CommitMessageNegativeRegex string `json:"commit_message_negative_regex"`
|
||||||
|
BranchNameRegex string `json:"branch_name_regex"`
|
||||||
|
DenyDeleteTag bool `json:"deny_delete_tag"`
|
||||||
|
MemberCheck bool `json:"member_check"`
|
||||||
|
PreventSecrets bool `json:"prevent_secrets"`
|
||||||
|
AuthorEmailRegex string `json:"author_email_regex"`
|
||||||
|
FileNameRegex string `json:"file_name_regex"`
|
||||||
|
MaxFileSize int `json:"max_file_size"`
|
||||||
|
CommitCommitterCheck bool `json:"commit_committer_check"`
|
||||||
|
RejectUnsignedCommits bool `json:"reject_unsigned_commits"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupPushRules gets the push rules of a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#get-group-push-rules
|
||||||
|
func (s *GroupsService) GetGroupPushRules(gid interface{}, options ...RequestOptionFunc) (*GroupPushRules, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/push_rule", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gpr := new(GroupPushRules)
|
||||||
|
resp, err := s.client.Do(req, gpr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gpr, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddGroupPushRuleOptions represents the available AddGroupPushRule()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#add-group-push-rule
|
||||||
|
type AddGroupPushRuleOptions struct {
|
||||||
|
AuthorEmailRegex *string `url:"author_email_regex,omitempty" json:"author_email_regex,omitempty"`
|
||||||
|
BranchNameRegex *string `url:"branch_name_regex,omitempty" json:"branch_name_regex,omitempty"`
|
||||||
|
CommitCommitterCheck *bool `url:"commit_committer_check,omitempty" json:"commit_committer_check,omitempty"`
|
||||||
|
CommitMessageNegativeRegex *string `url:"commit_message_negative_regex,omitempty" json:"commit_message_negative_regex,omitempty"`
|
||||||
|
CommitMessageRegex *string `url:"commit_message_regex,omitempty" json:"commit_message_regex,omitempty"`
|
||||||
|
DenyDeleteTag *bool `url:"deny_delete_tag,omitempty" json:"deny_delete_tag,omitempty"`
|
||||||
|
FileNameRegex *string `url:"file_name_regex,omitempty" json:"file_name_regex,omitempty"`
|
||||||
|
MaxFileSize *int `url:"max_file_size,omitempty" json:"max_file_size,omitempty"`
|
||||||
|
MemberCheck *bool `url:"member_check,omitempty" json:"member_check,omitempty"`
|
||||||
|
PreventSecrets *bool `url:"prevent_secrets,omitempty" json:"prevent_secrets,omitempty"`
|
||||||
|
RejectUnsignedCommits *bool `url:"reject_unsigned_commits,omitempty" json:"reject_unsigned_commits,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddGroupPushRule adds push rules to the specified group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#add-group-push-rule
|
||||||
|
func (s *GroupsService) AddGroupPushRule(gid interface{}, opt *AddGroupPushRuleOptions, options ...RequestOptionFunc) (*GroupPushRules, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/push_rule", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gpr := new(GroupPushRules)
|
||||||
|
resp, err := s.client.Do(req, gpr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gpr, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditGroupPushRuleOptions represents the available EditGroupPushRule()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#edit-group-push-rule
|
||||||
|
type EditGroupPushRuleOptions struct {
|
||||||
|
AuthorEmailRegex *string `url:"author_email_regex,omitempty" json:"author_email_regex,omitempty"`
|
||||||
|
BranchNameRegex *string `url:"branch_name_regex,omitempty" json:"branch_name_regex,omitempty"`
|
||||||
|
CommitCommitterCheck *bool `url:"commit_committer_check,omitempty" json:"commit_committer_check,omitempty"`
|
||||||
|
CommitMessageNegativeRegex *string `url:"commit_message_negative_regex,omitempty" json:"commit_message_negative_regex,omitempty"`
|
||||||
|
CommitMessageRegex *string `url:"commit_message_regex,omitempty" json:"commit_message_regex,omitempty"`
|
||||||
|
DenyDeleteTag *bool `url:"deny_delete_tag,omitempty" json:"deny_delete_tag,omitempty"`
|
||||||
|
FileNameRegex *string `url:"file_name_regex,omitempty" json:"file_name_regex,omitempty"`
|
||||||
|
MaxFileSize *int `url:"max_file_size,omitempty" json:"max_file_size,omitempty"`
|
||||||
|
MemberCheck *bool `url:"member_check,omitempty" json:"member_check,omitempty"`
|
||||||
|
PreventSecrets *bool `url:"prevent_secrets,omitempty" json:"prevent_secrets,omitempty"`
|
||||||
|
RejectUnsignedCommits *bool `url:"reject_unsigned_commits,omitempty" json:"reject_unsigned_commits,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditGroupPushRule edits a push rule for a specified group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#edit-group-push-rule
|
||||||
|
func (s *GroupsService) EditGroupPushRule(gid interface{}, opt *EditGroupPushRuleOptions, options ...RequestOptionFunc) (*GroupPushRules, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/push_rule", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gpr := new(GroupPushRules)
|
||||||
|
resp, err := s.client.Do(req, gpr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gpr, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteGroupPushRule deletes the push rules of a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/groups.html#delete-group-push-rule
|
||||||
|
func (s *GroupsService) DeleteGroupPushRule(gid interface{}, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/push_rule", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
153
vendor/github.com/xanzy/go-gitlab/instance_clusters.go
generated
vendored
Normal file
153
vendor/github.com/xanzy/go-gitlab/instance_clusters.go
generated
vendored
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Serena Fang
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InstanceClustersService handles communication with the
|
||||||
|
// instance clusters related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/instance_clusters.html
|
||||||
|
type InstanceClustersService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceCluster represents a GitLab Instance Cluster.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/instance_clusters.html
|
||||||
|
type InstanceCluster struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
Managed bool `json:"managed"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
ProviderType string `json:"provider_type"`
|
||||||
|
PlatformType string `json:"platform_type"`
|
||||||
|
EnvironmentScope string `json:"environment_scope"`
|
||||||
|
ClusterType string `json:"cluster_type"`
|
||||||
|
User *User `json:"user"`
|
||||||
|
PlatformKubernetes *PlatformKubernetes `json:"platform_kubernetes"`
|
||||||
|
ManagementProject *ManagementProject `json:"management_project"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v InstanceCluster) String() string {
|
||||||
|
return Stringify(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListClusters gets a list of all instance clusters.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/instance_clusters.html#list-instance-clusters
|
||||||
|
func (s *InstanceClustersService) ListClusters(options ...RequestOptionFunc) ([]*InstanceCluster, *Response, error) {
|
||||||
|
u := "admin/clusters"
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ics []*InstanceCluster
|
||||||
|
resp, err := s.client.Do(req, &ics)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ics, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCluster gets an instance cluster.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/instance_clusters.html#get-a-single-instance-cluster
|
||||||
|
func (s *InstanceClustersService) GetCluster(cluster int, options ...RequestOptionFunc) (*InstanceCluster, *Response, error) {
|
||||||
|
u := fmt.Sprintf("admin/clusters/%d", cluster)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ic := new(InstanceCluster)
|
||||||
|
resp, err := s.client.Do(req, &ic)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ic, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCluster adds an existing cluster to the instance.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/instance_clusters.html#add-existing-instance-cluster
|
||||||
|
func (s *InstanceClustersService) AddCluster(opt *AddClusterOptions, options ...RequestOptionFunc) (*InstanceCluster, *Response, error) {
|
||||||
|
u := "admin/clusters/add"
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ic := new(InstanceCluster)
|
||||||
|
resp, err := s.client.Do(req, ic)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ic, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditCluster updates an existing instance cluster.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/instance_clusters.html#edit-instance-cluster
|
||||||
|
func (s *InstanceClustersService) EditCluster(cluster int, opt *EditClusterOptions, options ...RequestOptionFunc) (*InstanceCluster, *Response, error) {
|
||||||
|
u := fmt.Sprintf("admin/clusters/%d", cluster)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ic := new(InstanceCluster)
|
||||||
|
resp, err := s.client.Do(req, ic)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ic, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteCluster deletes an existing instance cluster.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/instance_clusters.html#delete-instance-cluster
|
||||||
|
func (s *InstanceClustersService) DeleteCluster(cluster int, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
u := fmt.Sprintf("admin/clusters/%d", cluster)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
180
vendor/github.com/xanzy/go-gitlab/instance_variables.go
generated
vendored
Normal file
180
vendor/github.com/xanzy/go-gitlab/instance_variables.go
generated
vendored
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Patrick Webster
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InstanceVariablesService handles communication with the
|
||||||
|
// instance level CI variables related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html
|
||||||
|
type InstanceVariablesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceVariable represents a GitLab instance level CI Variable.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html
|
||||||
|
type InstanceVariable struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
VariableType VariableTypeValue `json:"variable_type"`
|
||||||
|
Protected bool `json:"protected"`
|
||||||
|
Masked bool `json:"masked"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v InstanceVariable) String() string {
|
||||||
|
return Stringify(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListInstanceVariablesOptions represents the available options for listing variables
|
||||||
|
// for an instance.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#list-all-instance-variables
|
||||||
|
type ListInstanceVariablesOptions ListOptions
|
||||||
|
|
||||||
|
// ListVariables gets a list of all variables for an instance.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#list-all-instance-variables
|
||||||
|
func (s *InstanceVariablesService) ListVariables(opt *ListInstanceVariablesOptions, options ...RequestOptionFunc) ([]*InstanceVariable, *Response, error) {
|
||||||
|
u := "admin/ci/variables"
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var vs []*InstanceVariable
|
||||||
|
resp, err := s.client.Do(req, &vs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return vs, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVariable gets a variable.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#show-instance-variable-details
|
||||||
|
func (s *InstanceVariablesService) GetVariable(key string, options ...RequestOptionFunc) (*InstanceVariable, *Response, error) {
|
||||||
|
u := fmt.Sprintf("admin/ci/variables/%s", url.PathEscape(key))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v := new(InstanceVariable)
|
||||||
|
resp, err := s.client.Do(req, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return v, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateInstanceVariableOptions represents the available CreateVariable()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#create-instance-variable
|
||||||
|
type CreateInstanceVariableOptions struct {
|
||||||
|
Key *string `url:"key,omitempty" json:"key,omitempty"`
|
||||||
|
Value *string `url:"value,omitempty" json:"value,omitempty"`
|
||||||
|
VariableType *VariableTypeValue `url:"variable_type,omitempty" json:"variable_type,omitempty"`
|
||||||
|
Protected *bool `url:"protected,omitempty" json:"protected,omitempty"`
|
||||||
|
Masked *bool `url:"masked,omitempty" json:"masked,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateVariable creates a new instance level CI variable.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#create-instance-variable
|
||||||
|
func (s *InstanceVariablesService) CreateVariable(opt *CreateInstanceVariableOptions, options ...RequestOptionFunc) (*InstanceVariable, *Response, error) {
|
||||||
|
u := "admin/ci/variables"
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v := new(InstanceVariable)
|
||||||
|
resp, err := s.client.Do(req, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return v, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateInstanceVariableOptions represents the available UpdateVariable()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#update-instance-variable
|
||||||
|
type UpdateInstanceVariableOptions struct {
|
||||||
|
Value *string `url:"value,omitempty" json:"value,omitempty"`
|
||||||
|
VariableType *VariableTypeValue `url:"variable_type,omitempty" json:"variable_type,omitempty"`
|
||||||
|
Protected *bool `url:"protected,omitempty" json:"protected,omitempty"`
|
||||||
|
Masked *bool `url:"masked,omitempty" json:"masked,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateVariable updates the position of an existing
|
||||||
|
// instance level CI variable.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#update-instance-variable
|
||||||
|
func (s *InstanceVariablesService) UpdateVariable(key string, opt *UpdateInstanceVariableOptions, options ...RequestOptionFunc) (*InstanceVariable, *Response, error) {
|
||||||
|
u := fmt.Sprintf("admin/ci/variables/%s", url.PathEscape(key))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v := new(InstanceVariable)
|
||||||
|
resp, err := s.client.Do(req, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return v, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveVariable removes an instance level CI variable.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#remove-instance-variable
|
||||||
|
func (s *InstanceVariablesService) RemoveVariable(key string, options ...RequestOptionFunc) (*Response, error) {
|
||||||
|
u := fmt.Sprintf("admin/ci/variables/%s", url.PathEscape(key))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
175
vendor/github.com/xanzy/go-gitlab/invites.go
generated
vendored
Normal file
175
vendor/github.com/xanzy/go-gitlab/invites.go
generated
vendored
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021, Sander van Harmelen
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InvitesService handles communication with the invitation related
|
||||||
|
// methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/invitations.html
|
||||||
|
type InvitesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// PendingInvite represents a pending invite.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/invitations.html
|
||||||
|
type PendingInvite struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
InviteEmail string `json:"invite_email"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
AccessLevel AccessLevelValue `json:"access_level"`
|
||||||
|
ExpiresAt *time.Time `json:"expires_at"`
|
||||||
|
UserName string `json:"user_name"`
|
||||||
|
CreatedByName string `json:"created_by_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListPendingInvitationsOptions represents the available
|
||||||
|
// ListPendingInvitations() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/invitations.html#list-all-invitations-pending-for-a-group-or-project
|
||||||
|
type ListPendingInvitationsOptions struct {
|
||||||
|
ListOptions
|
||||||
|
Query *string `url:"query,omitempty" json:"query,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListPendingGroupInvitations gets a list of invited group members.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/invitations.html#list-all-invitations-pending-for-a-group-or-project
|
||||||
|
func (s *InvitesService) ListPendingGroupInvitations(gid interface{}, opt *ListPendingInvitationsOptions, options ...RequestOptionFunc) ([]*PendingInvite, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/invitations", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var pis []*PendingInvite
|
||||||
|
resp, err := s.client.Do(req, &pis)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pis, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListPendingProjectInvitations gets a list of invited project members.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/invitations.html#list-all-invitations-pending-for-a-group-or-project
|
||||||
|
func (s *InvitesService) ListPendingProjectInvitations(pid interface{}, opt *ListPendingInvitationsOptions, options ...RequestOptionFunc) ([]*PendingInvite, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/invitations", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var pis []*PendingInvite
|
||||||
|
resp, err := s.client.Do(req, &pis)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pis, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvitesOptions represents the available GroupInvites() and ProjectInvites()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/invitations.html#invite-by-email-to-group-or-project
|
||||||
|
type InvitesOptions struct {
|
||||||
|
ID interface{} `url:"id,omitempty" json:"id,omitempty"`
|
||||||
|
Email *string `url:"email,omitempty" json:"email,omitempty"`
|
||||||
|
AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
|
||||||
|
ExpiresAt *ISOTime `url:"expires_at,omitempty" json:"expires_at,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvitesResult represents an invitations result.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/invitations.html#invite-by-email-to-group-or-project
|
||||||
|
type InvitesResult struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Message map[string]string `json:"message,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupInvites invites new users by email to join a group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/invitations.html#invite-by-email-to-group-or-project
|
||||||
|
func (s *InvitesService) GroupInvites(gid interface{}, opt *InvitesOptions, options ...RequestOptionFunc) (*InvitesResult, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/invitations", pathEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ir := new(InvitesResult)
|
||||||
|
resp, err := s.client.Do(req, ir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ir, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectInvites invites new users by email to join a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/invitations.html#invite-by-email-to-group-or-project
|
||||||
|
func (s *InvitesService) ProjectInvites(pid interface{}, opt *InvitesOptions, options ...RequestOptionFunc) (*InvitesResult, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/invitations", pathEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ir := new(InvitesResult)
|
||||||
|
resp, err := s.client.Do(req, ir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ir, resp, err
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue