mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-07-28 23:18:15 +00:00
8
Gopkg.lock
generated
8
Gopkg.lock
generated
@@ -85,6 +85,12 @@
|
||||
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/lkysow/go-gitlab"
|
||||
packages = ["."]
|
||||
revision = "5aba7769280ffa5408f98e1b95290989cc1428c5"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/magiconair/properties"
|
||||
packages = ["."]
|
||||
@@ -232,6 +238,6 @@
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "ff26f498317e49b0c36b98f2ec0b91a1b7c9ccfb4b04777a3f1e8f7e143828b7"
|
||||
inputs-digest = "ae2f51ff70354344e93c471a531b44a57822ea9dcc57dddbb8b476d0e1f1d3a8"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
@@ -88,3 +88,7 @@
|
||||
[[constraint]]
|
||||
branch = "v2"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/lkysow/go-gitlab"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Package cmd holds all our cli commands.
|
||||
// These are different from the commands that get run via GitHub comments
|
||||
// These are different from the commands that get run via pull request comments.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
|
||||
@@ -25,6 +25,10 @@ const (
|
||||
GHTokenFlag = "gh-token"
|
||||
GHUserFlag = "gh-user"
|
||||
GHWebHookSecret = "gh-webhook-secret"
|
||||
GitlabHostnameFlag = "gitlab-hostname"
|
||||
GitlabTokenFlag = "gitlab-token"
|
||||
GitlabUserFlag = "gitlab-user"
|
||||
GitlabWebHookSecret = "gitlab-webhook-secret"
|
||||
LogLevelFlag = "log-level"
|
||||
PortFlag = "port"
|
||||
RequireApprovalFlag = "require-approval"
|
||||
@@ -49,19 +53,42 @@ var stringFlags = []stringFlag{
|
||||
description: "Hostname of your Github Enterprise installation. If using github.com, no need to set.",
|
||||
value: "github.com",
|
||||
},
|
||||
{
|
||||
name: GHUserFlag,
|
||||
description: "GitHub username of API user.",
|
||||
},
|
||||
{
|
||||
name: GHTokenFlag,
|
||||
description: "[REQUIRED] GitHub token of API user. Can also be specified via the ATLANTIS_GH_TOKEN environment variable.",
|
||||
description: "GitHub token of API user. Can also be specified via the ATLANTIS_GH_TOKEN environment variable.",
|
||||
env: "ATLANTIS_GH_TOKEN",
|
||||
},
|
||||
{
|
||||
name: GHUserFlag,
|
||||
description: "[REQUIRED] GitHub username of API user.",
|
||||
name: GHWebHookSecret,
|
||||
description: "Optional secret used to validate GitHub webhooks (see https://developer.github.com/webhooks/securing/)." +
|
||||
" If not specified, Atlantis won't be able to validate that the incoming webhook call came from GitHub. " +
|
||||
"Can also be specified via the ATLANTIS_GH_WEBHOOK_SECRET environment variable.",
|
||||
env: "ATLANTIS_GH_WEBHOOK_SECRET",
|
||||
},
|
||||
{
|
||||
name: GHWebHookSecret,
|
||||
description: "Optional secret used for GitHub webhooks (see https://developer.github.com/webhooks/securing/). If not specified, Atlantis won't validate the incoming webhook call.",
|
||||
env: "ATLANTIS_GH_WEBHOOK_SECRET",
|
||||
name: GitlabHostnameFlag,
|
||||
description: "Hostname of your GitLab Enterprise installation. If using gitlab.com, no need to set.",
|
||||
value: "gitlab.com",
|
||||
},
|
||||
{
|
||||
name: GitlabUserFlag,
|
||||
description: "GitLab username of API user.",
|
||||
},
|
||||
{
|
||||
name: GitlabTokenFlag,
|
||||
description: "GitLab token of API user. Can also be specified via the ATLANTIS_GITLAB_TOKEN environment variable.",
|
||||
env: "ATLANTIS_GITLAB_TOKEN",
|
||||
},
|
||||
{
|
||||
name: GitlabWebHookSecret,
|
||||
description: "Optional secret used to validate GitLab webhooks." +
|
||||
" If not specified, Atlantis won't be able to validate that the incoming webhook call came from GitLab. " +
|
||||
"Can also be specified via the ATLANTIS_GITLAB_WEBHOOK_SECRET environment variable.",
|
||||
env: "ATLANTIS_GITLAB_WEBHOOK_SECRET",
|
||||
},
|
||||
{
|
||||
name: LogLevelFlag,
|
||||
@@ -206,7 +233,7 @@ func (s *ServerCmd) run() error {
|
||||
if err := setDataDir(&config); err != nil {
|
||||
return err
|
||||
}
|
||||
sanitizeGithubUser(&config)
|
||||
trimAtSymbolFromUsers(&config)
|
||||
|
||||
// Config looks good. Start the server.
|
||||
server, err := s.ServerCreator.NewServer(config)
|
||||
@@ -221,11 +248,23 @@ func validate(config server.Config) error {
|
||||
if logLevel != "debug" && logLevel != "info" && logLevel != "warn" && logLevel != "error" {
|
||||
return errors.New("invalid log level: not one of debug, info, warn, error")
|
||||
}
|
||||
if config.GithubUser == "" {
|
||||
return fmt.Errorf("--%s must be set", GHUserFlag)
|
||||
vcsErr := fmt.Errorf("--%s/--%s or --%s/--%s must be set", GHUserFlag, GHTokenFlag, GitlabUserFlag, GitlabTokenFlag)
|
||||
|
||||
// The following combinations are valid.
|
||||
// 1. github user and token
|
||||
// 2. gitlab user and token
|
||||
// 3. all 4 set
|
||||
// We validate using contradiction (I think).
|
||||
if config.GithubUser != "" && config.GithubToken == "" || config.GithubToken != "" && config.GithubUser == "" {
|
||||
return vcsErr
|
||||
}
|
||||
if config.GithubToken == "" {
|
||||
return fmt.Errorf("--%s must be set", GHTokenFlag)
|
||||
if config.GitlabUser != "" && config.GitlabToken == "" || config.GitlabToken != "" && config.GitlabUser == "" {
|
||||
return vcsErr
|
||||
}
|
||||
// At this point, we know that there can't be a single user/token without
|
||||
// its pair, but we haven't checked if any user/token is set at all.
|
||||
if config.GithubUser == "" && config.GitlabUser == "" {
|
||||
return vcsErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -256,9 +295,10 @@ func setDataDir(config *server.Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// sanitizeGithubUser trims @ from the front of the github username if it exists.
|
||||
func sanitizeGithubUser(config *server.Config) {
|
||||
// trimAtSymbolFromUsers trims @ from the front of the github and gitlab usernames
|
||||
func trimAtSymbolFromUsers(config *server.Config) {
|
||||
config.GithubUser = strings.TrimPrefix(config.GithubUser, "@")
|
||||
config.GitlabUser = strings.TrimPrefix(config.GitlabUser, "@")
|
||||
}
|
||||
|
||||
// withErrPrint prints out any errors to a terminal in red.
|
||||
|
||||
@@ -90,42 +90,111 @@ func TestExecute_InvalidConfig(t *testing.T) {
|
||||
Assert(t, strings.Contains(err.Error(), "unmarshal errors"), "should be an unmarshal error")
|
||||
}
|
||||
|
||||
func TestExecute_Validation(t *testing.T) {
|
||||
cases := []struct {
|
||||
description string
|
||||
flags map[string]interface{}
|
||||
expErr string
|
||||
}{
|
||||
{
|
||||
"Should validate log level.",
|
||||
map[string]interface{}{
|
||||
func TestExecute_ValidateLogLevel(t *testing.T) {
|
||||
t.Log("Should validate log level.")
|
||||
c := setup(map[string]interface{}{
|
||||
cmd.LogLevelFlag: "invalid",
|
||||
cmd.GHUserFlag: "user",
|
||||
cmd.GHTokenFlag: "token",
|
||||
},
|
||||
"invalid log level: not one of debug, info, warn, error",
|
||||
})
|
||||
err := c.Execute()
|
||||
Assert(t, err != nil, "should be an error")
|
||||
Equals(t, "invalid log level: not one of debug, info, warn, error", err.Error())
|
||||
}
|
||||
|
||||
func TestExecute_ValidateVCSConfig(t *testing.T) {
|
||||
expErr := "--gh-user/--gh-token or --gitlab-user/--gitlab-token must be set"
|
||||
cases := []struct {
|
||||
description string
|
||||
flags map[string]interface{}
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
"no config set",
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Should ensure github user is set.",
|
||||
"just github token set",
|
||||
map[string]interface{}{
|
||||
cmd.GHTokenFlag: "token",
|
||||
},
|
||||
"--gh-user must be set",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Should ensure github token is set.",
|
||||
"just gitlab token set",
|
||||
map[string]interface{}{
|
||||
cmd.GitlabTokenFlag: "token",
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"just github user set",
|
||||
map[string]interface{}{
|
||||
cmd.GHUserFlag: "user",
|
||||
},
|
||||
"--gh-token must be set",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"just gitlab user set",
|
||||
map[string]interface{}{
|
||||
cmd.GitlabUserFlag: "user",
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"github user and gitlab token set",
|
||||
map[string]interface{}{
|
||||
cmd.GHUserFlag: "user",
|
||||
cmd.GitlabTokenFlag: "token",
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"gitlab user and github token set",
|
||||
map[string]interface{}{
|
||||
cmd.GitlabUserFlag: "user",
|
||||
cmd.GHTokenFlag: "token",
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"github user and github token set and should be successful",
|
||||
map[string]interface{}{
|
||||
cmd.GHUserFlag: "user",
|
||||
cmd.GHTokenFlag: "token",
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"gitlab user and gitlab token set and should be successful",
|
||||
map[string]interface{}{
|
||||
cmd.GitlabUserFlag: "user",
|
||||
cmd.GitlabTokenFlag: "token",
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"github and gitlab user and github and gitlab token set and should be successful",
|
||||
map[string]interface{}{
|
||||
cmd.GHUserFlag: "user",
|
||||
cmd.GHTokenFlag: "token",
|
||||
cmd.GitlabUserFlag: "user",
|
||||
cmd.GitlabTokenFlag: "token",
|
||||
},
|
||||
false,
|
||||
},
|
||||
}
|
||||
for _, testCase := range cases {
|
||||
t.Log(testCase.description)
|
||||
t.Log("Should validate vcs config when " + testCase.description)
|
||||
c := setup(testCase.flags)
|
||||
err := c.Execute()
|
||||
if testCase.expectError {
|
||||
Assert(t, err != nil, "should be an error")
|
||||
Equals(t, testCase.expErr, err.Error())
|
||||
Equals(t, expErr, err.Error())
|
||||
} else {
|
||||
Ok(t, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +203,8 @@ func TestExecute_Defaults(t *testing.T) {
|
||||
c := setup(map[string]interface{}{
|
||||
cmd.GHUserFlag: "user",
|
||||
cmd.GHTokenFlag: "token",
|
||||
cmd.GitlabUserFlag: "gitlab-user",
|
||||
cmd.GitlabTokenFlag: "gitlab-token",
|
||||
})
|
||||
err := c.Execute()
|
||||
Ok(t, err)
|
||||
@@ -141,6 +212,9 @@ func TestExecute_Defaults(t *testing.T) {
|
||||
Equals(t, "user", passedConfig.GithubUser)
|
||||
Equals(t, "token", passedConfig.GithubToken)
|
||||
Equals(t, "", passedConfig.GithubWebHookSecret)
|
||||
Equals(t, "gitlab-user", passedConfig.GitlabUser)
|
||||
Equals(t, "gitlab-token", passedConfig.GitlabToken)
|
||||
Equals(t, "", passedConfig.GitlabWebHookSecret)
|
||||
// Get our hostname since that's what gets defaulted to
|
||||
hostname, err := os.Hostname()
|
||||
Ok(t, err)
|
||||
@@ -151,6 +225,7 @@ func TestExecute_Defaults(t *testing.T) {
|
||||
Ok(t, err)
|
||||
Equals(t, dataDir, passedConfig.DataDir)
|
||||
Equals(t, "github.com", passedConfig.GithubHostname)
|
||||
Equals(t, "gitlab.com", passedConfig.GitlabHostname)
|
||||
Equals(t, "info", passedConfig.LogLevel)
|
||||
Equals(t, false, passedConfig.RequireApproval)
|
||||
Equals(t, 4141, passedConfig.Port)
|
||||
@@ -183,6 +258,18 @@ func TestExecute_GithubUser(t *testing.T) {
|
||||
Equals(t, "user", passedConfig.GithubUser)
|
||||
}
|
||||
|
||||
func TestExecute_GitlabUser(t *testing.T) {
|
||||
t.Log("Should remove the @ from the gitlab username if it's passed.")
|
||||
c := setup(map[string]interface{}{
|
||||
cmd.GitlabUserFlag: "@user",
|
||||
cmd.GitlabTokenFlag: "token",
|
||||
})
|
||||
err := c.Execute()
|
||||
Ok(t, err)
|
||||
|
||||
Equals(t, "user", passedConfig.GitlabUser)
|
||||
}
|
||||
|
||||
func TestExecute_Flags(t *testing.T) {
|
||||
t.Log("Should use all flags that are set.")
|
||||
c := setup(map[string]interface{}{
|
||||
@@ -192,6 +279,10 @@ func TestExecute_Flags(t *testing.T) {
|
||||
cmd.GHUserFlag: "user",
|
||||
cmd.GHTokenFlag: "token",
|
||||
cmd.GHWebHookSecret: "secret",
|
||||
cmd.GitlabHostnameFlag: "gitlab-hostname",
|
||||
cmd.GitlabUserFlag: "gitlab-user",
|
||||
cmd.GitlabTokenFlag: "gitlab-token",
|
||||
cmd.GitlabWebHookSecret: "gitlab-secret",
|
||||
cmd.LogLevelFlag: "debug",
|
||||
cmd.PortFlag: 8181,
|
||||
cmd.RequireApprovalFlag: true,
|
||||
@@ -205,6 +296,10 @@ func TestExecute_Flags(t *testing.T) {
|
||||
Equals(t, "user", passedConfig.GithubUser)
|
||||
Equals(t, "token", passedConfig.GithubToken)
|
||||
Equals(t, "secret", passedConfig.GithubWebHookSecret)
|
||||
Equals(t, "gitlab-hostname", passedConfig.GitlabHostname)
|
||||
Equals(t, "gitlab-user", passedConfig.GitlabUser)
|
||||
Equals(t, "gitlab-token", passedConfig.GitlabToken)
|
||||
Equals(t, "gitlab-secret", passedConfig.GitlabWebHookSecret)
|
||||
Equals(t, "debug", passedConfig.LogLevel)
|
||||
Equals(t, 8181, passedConfig.Port)
|
||||
Equals(t, true, passedConfig.RequireApproval)
|
||||
@@ -219,6 +314,10 @@ gh-hostname: "ghhostname"
|
||||
gh-user: "user"
|
||||
gh-token: "token"
|
||||
gh-webhook-secret: "secret"
|
||||
gitlab-hostname: "gitlab-hostname"
|
||||
gitlab-user: "gitlab-user"
|
||||
gitlab-token: "gitlab-token"
|
||||
gitlab-webhook-secret: "gitlab-secret"
|
||||
log-level: "debug"
|
||||
port: 8181
|
||||
require-approval: true`)
|
||||
@@ -235,6 +334,10 @@ require-approval: true`)
|
||||
Equals(t, "user", passedConfig.GithubUser)
|
||||
Equals(t, "token", passedConfig.GithubToken)
|
||||
Equals(t, "secret", passedConfig.GithubWebHookSecret)
|
||||
Equals(t, "gitlab-hostname", passedConfig.GitlabHostname)
|
||||
Equals(t, "gitlab-user", passedConfig.GitlabUser)
|
||||
Equals(t, "gitlab-token", passedConfig.GitlabToken)
|
||||
Equals(t, "gitlab-secret", passedConfig.GitlabWebHookSecret)
|
||||
Equals(t, "debug", passedConfig.LogLevel)
|
||||
Equals(t, 8181, passedConfig.Port)
|
||||
Equals(t, true, passedConfig.RequireApproval)
|
||||
@@ -279,6 +382,24 @@ func TestExecute_FlagEnvVarOverride(t *testing.T) {
|
||||
Equals(t, "override", passedConfig.GithubToken)
|
||||
}
|
||||
|
||||
func TestExecute_EnvVars(t *testing.T) {
|
||||
t.Log("Setting flags by env var should work.")
|
||||
os.Setenv("ATLANTIS_GH_TOKEN", "gh-token") // nolint: errcheck
|
||||
os.Setenv("ATLANTIS_GH_WEBHOOK_SECRET", "gh-webhook") // nolint: errcheck
|
||||
os.Setenv("ATLANTIS_GITLAB_TOKEN", "gitlab-token") // nolint: errcheck
|
||||
os.Setenv("ATLANTIS_GITLAB_WEBHOOK_SECRET", "gitlab-webhook") // nolint: errcheck
|
||||
c := setup(map[string]interface{}{
|
||||
cmd.GHUserFlag: "user",
|
||||
cmd.GitlabUserFlag: "user",
|
||||
})
|
||||
err := c.Execute()
|
||||
Ok(t, err)
|
||||
Equals(t, "gh-token", passedConfig.GithubToken)
|
||||
Equals(t, "gh-webhook", passedConfig.GithubWebHookSecret)
|
||||
Equals(t, "gitlab-token", passedConfig.GitlabToken)
|
||||
Equals(t, "gitlab-webhook", passedConfig.GitlabWebHookSecret)
|
||||
}
|
||||
|
||||
func setup(flags map[string]interface{}) *cobra.Command {
|
||||
viper := viper.New()
|
||||
for k, v := range flags {
|
||||
|
||||
@@ -8,14 +8,14 @@ import (
|
||||
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hootsuite/atlantis/server/events/github"
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
"github.com/hootsuite/atlantis/server/events/run"
|
||||
"github.com/hootsuite/atlantis/server/events/terraform"
|
||||
"github.com/hootsuite/atlantis/server/events/vcs"
|
||||
)
|
||||
|
||||
type ApplyExecutor struct {
|
||||
Github github.Client
|
||||
VCSClient vcs.ClientProxy
|
||||
Terraform *terraform.Client
|
||||
RequireApproval bool
|
||||
Run *run.Run
|
||||
@@ -25,7 +25,7 @@ type ApplyExecutor struct {
|
||||
|
||||
func (a *ApplyExecutor) Execute(ctx *CommandContext) CommandResponse {
|
||||
if a.RequireApproval {
|
||||
approved, err := a.Github.PullIsApproved(ctx.BaseRepo, ctx.Pull)
|
||||
approved, err := a.VCSClient.PullIsApproved(ctx.BaseRepo, ctx.Pull, ctx.VCSHost)
|
||||
if err != nil {
|
||||
return CommandResponse{Error: errors.Wrap(err, "checking if pull request was approved")}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package events
|
||||
|
||||
import (
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
"github.com/hootsuite/atlantis/server/events/vcs"
|
||||
"github.com/hootsuite/atlantis/server/logging"
|
||||
)
|
||||
|
||||
@@ -12,4 +13,5 @@ type CommandContext struct {
|
||||
User models.User
|
||||
Command *Command
|
||||
Log *logging.SimpleLogger
|
||||
VCSHost vcs.Host
|
||||
}
|
||||
|
||||
@@ -3,15 +3,31 @@ package events
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hootsuite/atlantis/server/events/github"
|
||||
"github.com/google/go-github/github"
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
"github.com/hootsuite/atlantis/server/events/vcs"
|
||||
"github.com/hootsuite/atlantis/server/logging"
|
||||
"github.com/hootsuite/atlantis/server/recovery"
|
||||
"github.com/lkysow/go-gitlab"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
//go:generate pegomock generate --use-experimental-model-gen --package mocks -o mocks/mock_command_runner.go CommandRunner
|
||||
|
||||
type CommandRunner interface {
|
||||
ExecuteCommand(ctx *CommandContext)
|
||||
ExecuteCommand(baseRepo models.Repo, headRepo models.Repo, user models.User, pullNum int, cmd *Command, vcsHost vcs.Host)
|
||||
}
|
||||
|
||||
//go:generate pegomock generate --use-experimental-model-gen --package mocks -o mocks/mock_github_pull_getter.go GithubPullGetter
|
||||
|
||||
type GithubPullGetter interface {
|
||||
GetPullRequest(repo models.Repo, pullNum int) (*github.PullRequest, error)
|
||||
}
|
||||
|
||||
//go:generate pegomock generate --use-experimental-model-gen --package mocks -o mocks/mock_gitlab_merge_request_getter.go GitlabMergeRequestGetter
|
||||
|
||||
type GitlabMergeRequestGetter interface {
|
||||
GetMergeRequest(repoFullName string, pullNum int) (*gitlab.MergeRequest, error)
|
||||
}
|
||||
|
||||
// CommandHandler is the first step when processing a comment command.
|
||||
@@ -20,48 +36,90 @@ type CommandHandler struct {
|
||||
ApplyExecutor Executor
|
||||
HelpExecutor Executor
|
||||
LockURLGenerator LockURLGenerator
|
||||
GHClient github.Client
|
||||
GHStatus GHStatusUpdater
|
||||
VCSClient vcs.ClientProxy
|
||||
GithubPullGetter GithubPullGetter
|
||||
GitlabMergeRequestGetter GitlabMergeRequestGetter
|
||||
CommitStatusUpdater CommitStatusUpdater
|
||||
EventParser EventParsing
|
||||
EnvLocker EnvLocker
|
||||
GHCommentRenderer *GithubCommentRenderer
|
||||
Logger *logging.SimpleLogger
|
||||
MarkdownRenderer *MarkdownRenderer
|
||||
Logger logging.SimpleLogging
|
||||
}
|
||||
|
||||
func (c *CommandHandler) ExecuteCommand(ctx *CommandContext) {
|
||||
// Set up logger specific to this command.
|
||||
// It's safe to reuse the underlying logger.
|
||||
src := fmt.Sprintf("%s/pull/%d", ctx.BaseRepo.FullName, ctx.Pull.Num)
|
||||
ctx.Log = logging.NewSimpleLogger(src, c.Logger.Logger, true, c.Logger.Level)
|
||||
defer c.logPanics(ctx)
|
||||
// ExecuteCommand executes the command
|
||||
func (c *CommandHandler) ExecuteCommand(baseRepo models.Repo, headRepo models.Repo, user models.User, pullNum int, cmd *Command, vcsHost vcs.Host) {
|
||||
var err error
|
||||
var pull models.PullRequest
|
||||
if vcsHost == vcs.Github {
|
||||
pull, headRepo, err = c.getGithubData(baseRepo, pullNum)
|
||||
} else if vcsHost == vcs.Gitlab {
|
||||
pull, err = c.getGitlabData(baseRepo.FullName, pullNum)
|
||||
}
|
||||
|
||||
// Get additional data from the pull request.
|
||||
ghPull, _, err := c.GHClient.GetPullRequest(ctx.BaseRepo, ctx.Pull.Num)
|
||||
log := c.buildLogger(baseRepo.FullName, pullNum)
|
||||
if err != nil {
|
||||
ctx.Log.Err("making pull request API call to GitHub: %s", err)
|
||||
log.Err(err.Error())
|
||||
return
|
||||
}
|
||||
if ghPull.GetState() != "open" {
|
||||
ctx.Log.Info("command was run on closed pull request")
|
||||
c.GHClient.CreateComment(ctx.BaseRepo, ctx.Pull, "Atlantis commands can't be run on closed pull requests") // nolint: errcheck
|
||||
return
|
||||
ctx := &CommandContext{
|
||||
User: user,
|
||||
Log: log,
|
||||
Pull: pull,
|
||||
HeadRepo: headRepo,
|
||||
Command: cmd,
|
||||
VCSHost: vcsHost,
|
||||
BaseRepo: baseRepo,
|
||||
}
|
||||
pull, headRepo, err := c.EventParser.ExtractPullData(ghPull)
|
||||
if err != nil {
|
||||
ctx.Log.Err("extracting required fields from comment data: %s", err)
|
||||
return
|
||||
}
|
||||
ctx.Pull = pull
|
||||
ctx.HeadRepo = headRepo
|
||||
c.run(ctx)
|
||||
}
|
||||
|
||||
func (c *CommandHandler) getGithubData(baseRepo models.Repo, pullNum int) (models.PullRequest, models.Repo, error) {
|
||||
if c.GithubPullGetter == nil {
|
||||
return models.PullRequest{}, models.Repo{}, errors.New("Atlantis not configured to support GitHub")
|
||||
}
|
||||
ghPull, err := c.GithubPullGetter.GetPullRequest(baseRepo, pullNum)
|
||||
if err != nil {
|
||||
return models.PullRequest{}, models.Repo{}, errors.Wrap(err, "making pull request API call to GitHub")
|
||||
}
|
||||
pull, repo, err := c.EventParser.ParseGithubPull(ghPull)
|
||||
if err != nil {
|
||||
return pull, repo, errors.Wrap(err, "extracting required fields from comment data")
|
||||
}
|
||||
return pull, repo, nil
|
||||
}
|
||||
|
||||
func (c *CommandHandler) getGitlabData(repoFullName string, pullNum int) (models.PullRequest, error) {
|
||||
if c.GitlabMergeRequestGetter == nil {
|
||||
return models.PullRequest{}, errors.New("Atlantis not configured to support GitLab")
|
||||
}
|
||||
mr, err := c.GitlabMergeRequestGetter.GetMergeRequest(repoFullName, pullNum)
|
||||
if err != nil {
|
||||
return models.PullRequest{}, errors.Wrap(err, "making merge request API call to GitLab")
|
||||
}
|
||||
pull := c.EventParser.ParseGitlabMergeRequest(mr)
|
||||
return pull, nil
|
||||
}
|
||||
|
||||
func (c *CommandHandler) buildLogger(repoFullName string, pullNum int) *logging.SimpleLogger {
|
||||
src := fmt.Sprintf("%s#%d", repoFullName, pullNum)
|
||||
return logging.NewSimpleLogger(src, c.Logger.Underlying(), true, c.Logger.GetLevel())
|
||||
}
|
||||
|
||||
func (c *CommandHandler) SetLockURL(f func(id string) (url string)) {
|
||||
c.LockURLGenerator.SetLockURL(f)
|
||||
}
|
||||
|
||||
func (c *CommandHandler) run(ctx *CommandContext) {
|
||||
c.GHStatus.Update(ctx.BaseRepo, ctx.Pull, Pending, ctx.Command) // nolint: errcheck
|
||||
log := c.buildLogger(ctx.BaseRepo.FullName, ctx.Pull.Num)
|
||||
ctx.Log = log
|
||||
defer c.logPanics(ctx)
|
||||
|
||||
if ctx.Pull.State != models.Open {
|
||||
ctx.Log.Info("command was run on closed pull request")
|
||||
c.VCSClient.CreateComment(ctx.BaseRepo, ctx.Pull, "Atlantis commands can't be run on closed pull requests", ctx.VCSHost) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
|
||||
c.CommitStatusUpdater.Update(ctx.BaseRepo, ctx.Pull, vcs.Pending, ctx.Command, ctx.VCSHost) // nolint: errcheck
|
||||
if !c.EnvLocker.TryLock(ctx.BaseRepo.FullName, ctx.Command.Environment, ctx.Pull.Num) {
|
||||
errMsg := fmt.Sprintf(
|
||||
"The %s environment is currently locked by another"+
|
||||
@@ -97,17 +155,17 @@ func (c *CommandHandler) updatePull(ctx *CommandContext, res CommandResponse) {
|
||||
}
|
||||
|
||||
// Update the pull request's status icon and comment back.
|
||||
c.GHStatus.UpdateProjectResult(ctx, res) // nolint: errcheck
|
||||
comment := c.GHCommentRenderer.Render(res, ctx.Command.Name, ctx.Log.History.String(), ctx.Command.Verbose)
|
||||
c.GHClient.CreateComment(ctx.BaseRepo, ctx.Pull, comment) // nolint: errcheck
|
||||
c.CommitStatusUpdater.UpdateProjectResult(ctx, res) // nolint: errcheck
|
||||
comment := c.MarkdownRenderer.Render(res, ctx.Command.Name, ctx.Log.History.String(), ctx.Command.Verbose)
|
||||
c.VCSClient.CreateComment(ctx.BaseRepo, ctx.Pull, comment, ctx.VCSHost) // nolint: errcheck
|
||||
}
|
||||
|
||||
// logPanics logs and creates a comment on the pull request for panics
|
||||
func (c *CommandHandler) logPanics(ctx *CommandContext) {
|
||||
if err := recover(); err != nil {
|
||||
stack := recovery.Stack(3)
|
||||
c.GHClient.CreateComment(ctx.BaseRepo, ctx.Pull, // nolint: errcheck
|
||||
fmt.Sprintf("**Error: goroutine panic. This is a bug.**\n```\n%s\n%s```", err, stack))
|
||||
c.VCSClient.CreateComment(ctx.BaseRepo, ctx.Pull, // nolint: errcheck
|
||||
fmt.Sprintf("**Error: goroutine panic. This is a bug.**\n```\n%s\n%s```", err, stack), ctx.VCSHost)
|
||||
ctx.Log.Err("PANIC: %s\n%s", err, stack)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,145 +1,164 @@
|
||||
package events_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"log"
|
||||
"reflect"
|
||||
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-github/github"
|
||||
"github.com/hootsuite/atlantis/server/events"
|
||||
gh "github.com/hootsuite/atlantis/server/events/github/fixtures"
|
||||
ghmocks "github.com/hootsuite/atlantis/server/events/github/mocks"
|
||||
"github.com/hootsuite/atlantis/server/events/mocks"
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
"github.com/hootsuite/atlantis/server/events/models/fixtures"
|
||||
"github.com/hootsuite/atlantis/server/logging"
|
||||
"github.com/hootsuite/atlantis/server/events/vcs"
|
||||
vcsmocks "github.com/hootsuite/atlantis/server/events/vcs/mocks"
|
||||
logmocks "github.com/hootsuite/atlantis/server/logging/mocks"
|
||||
. "github.com/hootsuite/atlantis/testing"
|
||||
"github.com/mohae/deepcopy"
|
||||
. "github.com/petergtz/pegomock"
|
||||
)
|
||||
|
||||
var applier *mocks.MockExecutor
|
||||
var helper *mocks.MockExecutor
|
||||
var planner *mocks.MockPlanner
|
||||
var planner *mocks.MockExecutor
|
||||
var eventParsing *mocks.MockEventParsing
|
||||
var ghClient *ghmocks.MockClient
|
||||
var ghStatus *mocks.MockGHStatusUpdater
|
||||
var vcsClient *vcsmocks.MockClientProxy
|
||||
var ghStatus *mocks.MockCommitStatusUpdater
|
||||
var githubGetter *mocks.MockGithubPullGetter
|
||||
var gitlabGetter *mocks.MockGitlabMergeRequestGetter
|
||||
var envLocker *mocks.MockEnvLocker
|
||||
var ch events.CommandHandler
|
||||
var logBytes *bytes.Buffer
|
||||
|
||||
func setup(t *testing.T) {
|
||||
RegisterMockTestingT(t)
|
||||
applier = mocks.NewMockExecutor()
|
||||
helper = mocks.NewMockExecutor()
|
||||
planner = mocks.NewMockPlanner()
|
||||
planner = mocks.NewMockExecutor()
|
||||
eventParsing = mocks.NewMockEventParsing()
|
||||
ghClient = ghmocks.NewMockClient()
|
||||
ghStatus = mocks.NewMockGHStatusUpdater()
|
||||
ghStatus = mocks.NewMockCommitStatusUpdater()
|
||||
envLocker = mocks.NewMockEnvLocker()
|
||||
vcsClient = vcsmocks.NewMockClientProxy()
|
||||
githubGetter = mocks.NewMockGithubPullGetter()
|
||||
gitlabGetter = mocks.NewMockGitlabMergeRequestGetter()
|
||||
logger := logmocks.NewMockSimpleLogging()
|
||||
logBytes = new(bytes.Buffer)
|
||||
When(logger.Underlying()).ThenReturn(log.New(logBytes, "", 0))
|
||||
ch = events.CommandHandler{
|
||||
PlanExecutor: planner,
|
||||
ApplyExecutor: applier,
|
||||
HelpExecutor: helper,
|
||||
GHClient: ghClient,
|
||||
GHStatus: ghStatus,
|
||||
VCSClient: vcsClient,
|
||||
CommitStatusUpdater: ghStatus,
|
||||
EventParser: eventParsing,
|
||||
EnvLocker: envLocker,
|
||||
GHCommentRenderer: &events.GithubCommentRenderer{},
|
||||
Logger: logging.NewNoopLogger(),
|
||||
MarkdownRenderer: &events.MarkdownRenderer{},
|
||||
GithubPullGetter: githubGetter,
|
||||
GitlabMergeRequestGetter: gitlabGetter,
|
||||
Logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteCommand_LogPanics(t *testing.T) {
|
||||
t.Log("if there is a panic it is commented back on the pull request")
|
||||
setup(t)
|
||||
When(ghClient.GetPullRequest(fixtures.Repo, fixtures.Pull.Num)).ThenPanic("panic")
|
||||
ch.ExecuteCommand(&events.CommandContext{
|
||||
BaseRepo: fixtures.Repo,
|
||||
Pull: fixtures.Pull,
|
||||
})
|
||||
_, _, comment := ghClient.VerifyWasCalledOnce().CreateComment(AnyRepo(), AnyPullRequest(), AnyString()).GetCapturedArguments()
|
||||
When(ghStatus.Update(fixtures.Repo, fixtures.Pull, vcs.Pending, nil, vcs.Github)).ThenPanic("panic")
|
||||
ch.ExecuteCommand(fixtures.Repo, fixtures.Repo, fixtures.User, 1, nil, vcs.Github)
|
||||
_, _, comment, _ := vcsClient.VerifyWasCalledOnce().CreateComment(AnyRepo(), AnyPullRequest(), AnyString(), AnyVCSHost()).GetCapturedArguments()
|
||||
Assert(t, strings.Contains(comment, "Error: goroutine panic"), "comment should be about a goroutine panic")
|
||||
}
|
||||
|
||||
func TestExecuteCommand_PullErr(t *testing.T) {
|
||||
t.Log("if getting the pull request fails nothing should continue")
|
||||
func TestExecuteCommand_NoGithubPullGetter(t *testing.T) {
|
||||
t.Log("if CommandHandler was constructed with a nil GithubPullGetter an error should be logged")
|
||||
setup(t)
|
||||
When(ghClient.GetPullRequest(fixtures.Repo, fixtures.Pull.Num)).ThenReturn(nil, nil, errors.New("err"))
|
||||
ch.ExecuteCommand(&events.CommandContext{
|
||||
BaseRepo: fixtures.Repo,
|
||||
Pull: fixtures.Pull,
|
||||
})
|
||||
ch.GithubPullGetter = nil
|
||||
ch.ExecuteCommand(fixtures.Repo, fixtures.Repo, fixtures.User, 1, nil, vcs.Github)
|
||||
Equals(t, "[ERROR] hootsuite/atlantis#1: Atlantis not configured to support GitHub\n", logBytes.String())
|
||||
}
|
||||
|
||||
func TestExecuteCommand_ExtractErr(t *testing.T) {
|
||||
t.Log("if extracting data from the pull request fails nothing should continue")
|
||||
func TestExecuteCommand_NoGitlabMergeGetter(t *testing.T) {
|
||||
t.Log("if CommandHandler was constructed with a nil GitlabMergeRequestGetter an error should be logged")
|
||||
setup(t)
|
||||
pull := deepcopy.Copy(gh.Pull).(github.PullRequest)
|
||||
pull.State = github.String("open")
|
||||
When(ghClient.GetPullRequest(fixtures.Repo, fixtures.Pull.Num)).ThenReturn(&pull, nil, nil)
|
||||
When(eventParsing.ExtractPullData(&pull)).ThenReturn(fixtures.Pull, fixtures.Repo, errors.New("err"))
|
||||
ch.GitlabMergeRequestGetter = nil
|
||||
ch.ExecuteCommand(fixtures.Repo, fixtures.Repo, fixtures.User, 1, nil, vcs.Gitlab)
|
||||
Equals(t, "[ERROR] hootsuite/atlantis#1: Atlantis not configured to support GitLab\n", logBytes.String())
|
||||
}
|
||||
|
||||
ch.ExecuteCommand(&events.CommandContext{
|
||||
BaseRepo: fixtures.Repo,
|
||||
Pull: fixtures.Pull,
|
||||
})
|
||||
func TestExecuteCommand_GithubPullErr(t *testing.T) {
|
||||
t.Log("if getting the github pull request fails an error should be logged")
|
||||
setup(t)
|
||||
When(githubGetter.GetPullRequest(fixtures.Repo, fixtures.Pull.Num)).ThenReturn(nil, errors.New("err"))
|
||||
ch.ExecuteCommand(fixtures.Repo, fixtures.Repo, fixtures.User, fixtures.Pull.Num, nil, vcs.Github)
|
||||
Equals(t, "[ERROR] hootsuite/atlantis#1: Making pull request API call to GitHub: err\n", logBytes.String())
|
||||
}
|
||||
|
||||
func TestExecuteCommand_GitlabMergeRequestErr(t *testing.T) {
|
||||
t.Log("if getting the gitlab merge request fails an error should be logged")
|
||||
setup(t)
|
||||
When(gitlabGetter.GetMergeRequest(fixtures.Repo.FullName, fixtures.Pull.Num)).ThenReturn(nil, errors.New("err"))
|
||||
ch.ExecuteCommand(fixtures.Repo, fixtures.Repo, fixtures.User, fixtures.Pull.Num, nil, vcs.Gitlab)
|
||||
Equals(t, "[ERROR] hootsuite/atlantis#1: Making merge request API call to GitLab: err\n", logBytes.String())
|
||||
}
|
||||
|
||||
func TestExecuteCommand_GithubPullParseErr(t *testing.T) {
|
||||
t.Log("if parsing the returned github pull request fails an error should be logged")
|
||||
setup(t)
|
||||
var pull github.PullRequest
|
||||
When(githubGetter.GetPullRequest(fixtures.Repo, fixtures.Pull.Num)).ThenReturn(&pull, nil)
|
||||
When(eventParsing.ParseGithubPull(&pull)).ThenReturn(fixtures.Pull, fixtures.Repo, errors.New("err"))
|
||||
|
||||
ch.ExecuteCommand(fixtures.Repo, fixtures.Repo, fixtures.User, fixtures.Pull.Num, nil, vcs.Github)
|
||||
Equals(t, "[ERROR] hootsuite/atlantis#1: Extracting required fields from comment data: err\n", logBytes.String())
|
||||
}
|
||||
|
||||
func TestExecuteCommand_ClosedPull(t *testing.T) {
|
||||
t.Log("if a command is run on a closed pull request atlantis should" +
|
||||
" comment saying that this is not allowed")
|
||||
setup(t)
|
||||
pull := deepcopy.Copy(gh.Pull).(github.PullRequest)
|
||||
pull.State = github.String("closed")
|
||||
When(ghClient.GetPullRequest(fixtures.Repo, fixtures.Pull.Num)).ThenReturn(&pull, nil, nil)
|
||||
pull := &github.PullRequest{
|
||||
State: github.String("closed"),
|
||||
}
|
||||
modelPull := models.PullRequest{State: models.Closed}
|
||||
When(githubGetter.GetPullRequest(fixtures.Repo, fixtures.Pull.Num)).ThenReturn(pull, nil)
|
||||
When(eventParsing.ParseGithubPull(pull)).ThenReturn(modelPull, fixtures.Repo, nil)
|
||||
|
||||
ch.ExecuteCommand(&events.CommandContext{
|
||||
BaseRepo: fixtures.Repo,
|
||||
User: fixtures.User,
|
||||
Pull: fixtures.Pull,
|
||||
Command: &events.Command{
|
||||
Name: events.Plan,
|
||||
},
|
||||
})
|
||||
ghClient.VerifyWasCalledOnce().CreateComment(fixtures.Repo, fixtures.Pull, "Atlantis commands can't be run on closed pull requests")
|
||||
ch.ExecuteCommand(fixtures.Repo, fixtures.Repo, fixtures.User, fixtures.Pull.Num, nil, vcs.Github)
|
||||
vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.Repo, modelPull, "Atlantis commands can't be run on closed pull requests", vcs.Github)
|
||||
}
|
||||
|
||||
func TestExecuteCommand_EnvLocked(t *testing.T) {
|
||||
t.Log("if the environment is locked, should comment back on the pull")
|
||||
setup(t)
|
||||
pull := deepcopy.Copy(gh.Pull).(github.PullRequest)
|
||||
pull.State = github.String("open")
|
||||
pull := &github.PullRequest{
|
||||
State: github.String("closed"),
|
||||
}
|
||||
cmd := events.Command{
|
||||
Name: events.Plan,
|
||||
Environment: "env",
|
||||
}
|
||||
baseCtx := events.CommandContext{
|
||||
BaseRepo: fixtures.Repo,
|
||||
User: fixtures.User,
|
||||
Pull: fixtures.Pull,
|
||||
Command: &cmd,
|
||||
}
|
||||
|
||||
When(ghClient.GetPullRequest(fixtures.Repo, fixtures.Pull.Num)).ThenReturn(&pull, nil, nil)
|
||||
When(eventParsing.ExtractPullData(&pull)).ThenReturn(fixtures.Pull, fixtures.Repo, nil)
|
||||
When(githubGetter.GetPullRequest(fixtures.Repo, fixtures.Pull.Num)).ThenReturn(pull, nil)
|
||||
When(eventParsing.ParseGithubPull(pull)).ThenReturn(fixtures.Pull, fixtures.Repo, nil)
|
||||
When(envLocker.TryLock(fixtures.Repo.FullName, cmd.Environment, fixtures.Pull.Num)).ThenReturn(false)
|
||||
ch.ExecuteCommand(&baseCtx)
|
||||
ch.ExecuteCommand(fixtures.Repo, fixtures.Repo, fixtures.User, fixtures.Pull.Num, &cmd, vcs.Github)
|
||||
|
||||
msg := "The env environment is currently locked by another" +
|
||||
" command that is running for this pull request." +
|
||||
" Wait until the previous command is complete and try again."
|
||||
ghStatus.VerifyWasCalledOnce().Update(fixtures.Repo, fixtures.Pull, events.Pending, &cmd)
|
||||
ghStatus.VerifyWasCalledOnce().UpdateProjectResult(&baseCtx, events.CommandResponse{Failure: msg})
|
||||
ghClient.VerifyWasCalledOnce().CreateComment(fixtures.Repo, fixtures.Pull,
|
||||
"**Plan Failed**: "+msg+"\n\n")
|
||||
ghStatus.VerifyWasCalledOnce().Update(fixtures.Repo, fixtures.Pull, vcs.Pending, &cmd, vcs.Github)
|
||||
_, response := ghStatus.VerifyWasCalledOnce().UpdateProjectResult(AnyCommandContext(), AnyCommandResponse()).GetCapturedArguments()
|
||||
Equals(t, msg, response.Failure)
|
||||
vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.Repo, fixtures.Pull,
|
||||
"**Plan Failed**: "+msg+"\n\n", vcs.Github)
|
||||
}
|
||||
|
||||
func TestExecuteCommand_FullRun(t *testing.T) {
|
||||
t.Log("when running a plan, apply or help should comment")
|
||||
pull := deepcopy.Copy(gh.Pull).(github.PullRequest)
|
||||
pull.State = github.String("open")
|
||||
pull := &github.PullRequest{
|
||||
State: github.String("closed"),
|
||||
}
|
||||
cmdResponse := events.CommandResponse{}
|
||||
for _, c := range []events.CommandName{events.Help, events.Plan, events.Apply} {
|
||||
setup(t)
|
||||
@@ -147,14 +166,8 @@ func TestExecuteCommand_FullRun(t *testing.T) {
|
||||
Name: c,
|
||||
Environment: "env",
|
||||
}
|
||||
baseCtx := events.CommandContext{
|
||||
BaseRepo: fixtures.Repo,
|
||||
User: fixtures.User,
|
||||
Pull: fixtures.Pull,
|
||||
Command: &cmd,
|
||||
}
|
||||
When(ghClient.GetPullRequest(fixtures.Repo, fixtures.Pull.Num)).ThenReturn(&pull, nil, nil)
|
||||
When(eventParsing.ExtractPullData(&pull)).ThenReturn(fixtures.Pull, fixtures.Repo, nil)
|
||||
When(githubGetter.GetPullRequest(fixtures.Repo, fixtures.Pull.Num)).ThenReturn(pull, nil)
|
||||
When(eventParsing.ParseGithubPull(pull)).ThenReturn(fixtures.Pull, fixtures.Repo, nil)
|
||||
When(envLocker.TryLock(fixtures.Repo.FullName, cmd.Environment, fixtures.Pull.Num)).ThenReturn(true)
|
||||
switch c {
|
||||
case events.Help:
|
||||
@@ -165,11 +178,12 @@ func TestExecuteCommand_FullRun(t *testing.T) {
|
||||
When(applier.Execute(AnyCommandContext())).ThenReturn(cmdResponse)
|
||||
}
|
||||
|
||||
ch.ExecuteCommand(&baseCtx)
|
||||
ch.ExecuteCommand(fixtures.Repo, fixtures.Repo, fixtures.User, fixtures.Pull.Num, &cmd, vcs.Github)
|
||||
|
||||
ghStatus.VerifyWasCalledOnce().Update(fixtures.Repo, fixtures.Pull, events.Pending, &cmd)
|
||||
ghStatus.VerifyWasCalledOnce().UpdateProjectResult(&baseCtx, cmdResponse)
|
||||
ghClient.VerifyWasCalledOnce().CreateComment(AnyRepo(), AnyPullRequest(), AnyString())
|
||||
ghStatus.VerifyWasCalledOnce().Update(fixtures.Repo, fixtures.Pull, vcs.Pending, &cmd, vcs.Github)
|
||||
_, response := ghStatus.VerifyWasCalledOnce().UpdateProjectResult(AnyCommandContext(), AnyCommandResponse()).GetCapturedArguments()
|
||||
Equals(t, cmdResponse, response)
|
||||
vcsClient.VerifyWasCalledOnce().CreateComment(AnyRepo(), AnyPullRequest(), AnyString(), AnyVCSHost())
|
||||
envLocker.VerifyWasCalledOnce().Unlock(fixtures.Repo.FullName, cmd.Environment, fixtures.Pull.Num)
|
||||
}
|
||||
}
|
||||
@@ -178,3 +192,13 @@ func AnyCommandContext() *events.CommandContext {
|
||||
RegisterMatcher(NewAnyMatcher(reflect.TypeOf(&events.CommandContext{})))
|
||||
return &events.CommandContext{}
|
||||
}
|
||||
|
||||
func AnyVCSHost() vcs.Host {
|
||||
RegisterMatcher(NewAnyMatcher(reflect.TypeOf(vcs.Github)))
|
||||
return vcs.Github
|
||||
}
|
||||
|
||||
func AnyCommandResponse() events.CommandResponse {
|
||||
RegisterMatcher(NewAnyMatcher(reflect.TypeOf(events.CommandResponse{})))
|
||||
return events.CommandResponse{}
|
||||
}
|
||||
|
||||
48
server/events/commit_status_updater.go
Normal file
48
server/events/commit_status_updater.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
"github.com/hootsuite/atlantis/server/events/vcs"
|
||||
)
|
||||
|
||||
//go:generate pegomock generate --use-experimental-model-gen --package mocks -o mocks/mock_commit_status_updater.go CommitStatusUpdater
|
||||
|
||||
type CommitStatusUpdater interface {
|
||||
Update(repo models.Repo, pull models.PullRequest, status vcs.CommitStatus, cmd *Command, host vcs.Host) error
|
||||
UpdateProjectResult(ctx *CommandContext, res CommandResponse) error
|
||||
}
|
||||
|
||||
type DefaultCommitStatusUpdater struct {
|
||||
Client vcs.ClientProxy
|
||||
}
|
||||
|
||||
func (d *DefaultCommitStatusUpdater) Update(repo models.Repo, pull models.PullRequest, status vcs.CommitStatus, cmd *Command, host vcs.Host) error {
|
||||
description := fmt.Sprintf("%s %s", strings.Title(cmd.Name.String()), strings.Title(status.String()))
|
||||
return d.Client.UpdateStatus(repo, pull, status, description, host)
|
||||
}
|
||||
|
||||
func (d *DefaultCommitStatusUpdater) UpdateProjectResult(ctx *CommandContext, res CommandResponse) error {
|
||||
var status vcs.CommitStatus
|
||||
if res.Error != nil || res.Failure != "" {
|
||||
status = vcs.Failed
|
||||
} else {
|
||||
var statuses []vcs.CommitStatus
|
||||
for _, p := range res.ProjectResults {
|
||||
statuses = append(statuses, p.Status())
|
||||
}
|
||||
status = d.worstStatus(statuses)
|
||||
}
|
||||
return d.Update(ctx.BaseRepo, ctx.Pull, status, ctx.Command, ctx.VCSHost)
|
||||
}
|
||||
|
||||
func (d *DefaultCommitStatusUpdater) worstStatus(ss []vcs.CommitStatus) vcs.CommitStatus {
|
||||
for _, s := range ss {
|
||||
if s == vcs.Failed {
|
||||
return vcs.Failed
|
||||
}
|
||||
}
|
||||
return vcs.Success
|
||||
}
|
||||
@@ -1,31 +1,30 @@
|
||||
package events_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hootsuite/atlantis/server/events"
|
||||
"github.com/hootsuite/atlantis/server/events/github/mocks"
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
"github.com/hootsuite/atlantis/server/events/vcs"
|
||||
"github.com/hootsuite/atlantis/server/events/vcs/mocks"
|
||||
. "github.com/hootsuite/atlantis/testing"
|
||||
. "github.com/petergtz/pegomock"
|
||||
)
|
||||
|
||||
var repoModel = models.Repo{}
|
||||
var pullModel = models.PullRequest{}
|
||||
var status = events.Success
|
||||
var status = vcs.Success
|
||||
var cmd = events.Command{
|
||||
Name: events.Plan,
|
||||
}
|
||||
|
||||
func TestStatus_String(t *testing.T) {
|
||||
cases := map[events.Status]string{
|
||||
events.Pending: "pending",
|
||||
events.Success: "success",
|
||||
events.Failure: "failure",
|
||||
events.Error: "error",
|
||||
cases := map[vcs.CommitStatus]string{
|
||||
vcs.Pending: "pending",
|
||||
vcs.Success: "success",
|
||||
vcs.Failed: "failed",
|
||||
}
|
||||
for k, v := range cases {
|
||||
Equals(t, v, k.String())
|
||||
@@ -34,11 +33,11 @@ func TestStatus_String(t *testing.T) {
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
RegisterMockTestingT(t)
|
||||
client := mocks.NewMockClient()
|
||||
s := events.GithubStatus{Client: client}
|
||||
err := s.Update(repoModel, pullModel, status, &cmd)
|
||||
client := mocks.NewMockClientProxy()
|
||||
s := events.DefaultCommitStatusUpdater{Client: client}
|
||||
err := s.Update(repoModel, pullModel, status, &cmd, vcs.Github)
|
||||
Ok(t, err)
|
||||
client.VerifyWasCalledOnce().UpdateStatus(repoModel, pullModel, "success", "Plan Success", "Atlantis")
|
||||
client.VerifyWasCalledOnce().UpdateStatus(repoModel, pullModel, status, "Plan Success", vcs.Github)
|
||||
}
|
||||
|
||||
func TestUpdateProjectResult_Error(t *testing.T) {
|
||||
@@ -47,12 +46,13 @@ func TestUpdateProjectResult_Error(t *testing.T) {
|
||||
BaseRepo: repoModel,
|
||||
Pull: pullModel,
|
||||
Command: &events.Command{Name: events.Plan},
|
||||
VCSHost: vcs.Github,
|
||||
}
|
||||
client := mocks.NewMockClient()
|
||||
s := events.GithubStatus{Client: client}
|
||||
client := mocks.NewMockClientProxy()
|
||||
s := events.DefaultCommitStatusUpdater{Client: client}
|
||||
err := s.UpdateProjectResult(ctx, events.CommandResponse{Error: errors.New("err")})
|
||||
Ok(t, err)
|
||||
client.VerifyWasCalledOnce().UpdateStatus(repoModel, pullModel, events.Error.String(), "Plan Error", "Atlantis")
|
||||
client.VerifyWasCalledOnce().UpdateStatus(repoModel, pullModel, vcs.Failed, "Plan Failed", vcs.Github)
|
||||
}
|
||||
|
||||
func TestUpdateProjectResult_Failure(t *testing.T) {
|
||||
@@ -61,12 +61,13 @@ func TestUpdateProjectResult_Failure(t *testing.T) {
|
||||
BaseRepo: repoModel,
|
||||
Pull: pullModel,
|
||||
Command: &events.Command{Name: events.Plan},
|
||||
VCSHost: vcs.Github,
|
||||
}
|
||||
client := mocks.NewMockClient()
|
||||
s := events.GithubStatus{Client: client}
|
||||
client := mocks.NewMockClientProxy()
|
||||
s := events.DefaultCommitStatusUpdater{Client: client}
|
||||
err := s.UpdateProjectResult(ctx, events.CommandResponse{Failure: "failure"})
|
||||
Ok(t, err)
|
||||
client.VerifyWasCalledOnce().UpdateStatus(repoModel, pullModel, events.Failure.String(), "Plan Failure", "Atlantis")
|
||||
client.VerifyWasCalledOnce().UpdateStatus(repoModel, pullModel, vcs.Failed, "Plan Failed", vcs.Github)
|
||||
}
|
||||
|
||||
func TestUpdateProjectResult(t *testing.T) {
|
||||
@@ -77,31 +78,40 @@ func TestUpdateProjectResult(t *testing.T) {
|
||||
BaseRepo: repoModel,
|
||||
Pull: pullModel,
|
||||
Command: &events.Command{Name: events.Plan},
|
||||
VCSHost: vcs.Github,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
Statuses []string
|
||||
Expected string
|
||||
Expected vcs.CommitStatus
|
||||
}{
|
||||
{
|
||||
[]string{"success", "failure", "error"},
|
||||
"error",
|
||||
vcs.Failed,
|
||||
},
|
||||
{
|
||||
[]string{"failure", "error", "success"},
|
||||
"error",
|
||||
vcs.Failed,
|
||||
},
|
||||
{
|
||||
[]string{"success", "failure"},
|
||||
"failure",
|
||||
vcs.Failed,
|
||||
},
|
||||
{
|
||||
[]string{"success", "error"},
|
||||
"error",
|
||||
vcs.Failed,
|
||||
},
|
||||
{
|
||||
[]string{"failure", "error"},
|
||||
"error",
|
||||
vcs.Failed,
|
||||
},
|
||||
{
|
||||
[]string{"success"},
|
||||
vcs.Success,
|
||||
},
|
||||
{
|
||||
[]string{"success", "success"},
|
||||
vcs.Success,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -121,10 +131,10 @@ func TestUpdateProjectResult(t *testing.T) {
|
||||
}
|
||||
resp := events.CommandResponse{ProjectResults: results}
|
||||
|
||||
client := mocks.NewMockClient()
|
||||
s := events.GithubStatus{Client: client}
|
||||
client := mocks.NewMockClientProxy()
|
||||
s := events.DefaultCommitStatusUpdater{Client: client}
|
||||
err := s.UpdateProjectResult(ctx, resp)
|
||||
Ok(t, err)
|
||||
client.VerifyWasCalledOnce().UpdateStatus(repoModel, pullModel, c.Expected, "Plan "+strings.Title(c.Expected), "Atlantis")
|
||||
client.VerifyWasCalledOnce().UpdateStatus(repoModel, pullModel, c.Expected, "Plan "+strings.Title(c.Expected.String()), vcs.Github)
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,12 @@ import (
|
||||
|
||||
"github.com/google/go-github/github"
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
"github.com/hootsuite/atlantis/server/events/vcs"
|
||||
"github.com/lkysow/go-gitlab"
|
||||
)
|
||||
|
||||
const gitlabPullOpened = "opened"
|
||||
|
||||
//go:generate pegomock generate --use-experimental-model-gen --package mocks -o mocks/mock_event_parsing.go EventParsing
|
||||
|
||||
type Command struct {
|
||||
@@ -19,20 +23,25 @@ type Command struct {
|
||||
}
|
||||
|
||||
type EventParsing interface {
|
||||
DetermineCommand(comment *github.IssueCommentEvent) (*Command, error)
|
||||
ExtractCommentData(comment *github.IssueCommentEvent) (baseRepo models.Repo, user models.User, pull models.PullRequest, err error)
|
||||
ExtractPullData(pull *github.PullRequest) (models.PullRequest, models.Repo, error)
|
||||
ExtractRepoData(ghRepo *github.Repository) (models.Repo, error)
|
||||
DetermineCommand(comment string, vcsHost vcs.Host) (*Command, error)
|
||||
ParseGithubIssueCommentEvent(comment *github.IssueCommentEvent) (baseRepo models.Repo, user models.User, pullNum int, err error)
|
||||
ParseGithubPull(pull *github.PullRequest) (models.PullRequest, models.Repo, error)
|
||||
ParseGithubRepo(ghRepo *github.Repository) (models.Repo, error)
|
||||
ParseGitlabMergeEvent(event gitlab.MergeEvent) (models.PullRequest, models.Repo)
|
||||
ParseGitlabMergeCommentEvent(event gitlab.MergeCommentEvent) (baseRepo models.Repo, headRepo models.Repo, user models.User)
|
||||
ParseGitlabMergeRequest(mr *gitlab.MergeRequest) models.PullRequest
|
||||
}
|
||||
|
||||
type EventParser struct {
|
||||
GithubUser string
|
||||
GithubToken string
|
||||
GitlabUser string
|
||||
GitlabToken string
|
||||
}
|
||||
|
||||
// DetermineCommand parses the comment as an atlantis command. If it succeeds,
|
||||
// it returns the command. Otherwise it returns error.
|
||||
func (e *EventParser) DetermineCommand(comment *github.IssueCommentEvent) (*Command, error) {
|
||||
func (e *EventParser) DetermineCommand(comment string, vcsHost vcs.Host) (*Command, error) {
|
||||
// valid commands contain:
|
||||
// the initial "executable" name, 'run' or 'atlantis' or '@GithubUser' where GithubUser is the api user atlantis is running as
|
||||
// then a command, either 'plan', 'apply', or 'help'
|
||||
@@ -44,12 +53,8 @@ func (e *EventParser) DetermineCommand(comment *github.IssueCommentEvent) (*Comm
|
||||
// @GithubUser plan staging
|
||||
// atlantis plan staging --verbose
|
||||
// atlantis plan staging --verbose -key=value -key2 value2
|
||||
commentBody := comment.Comment.GetBody()
|
||||
if commentBody == "" {
|
||||
return nil, errors.New("comment.body is null")
|
||||
}
|
||||
err := errors.New("not an Atlantis command")
|
||||
args := strings.Fields(commentBody)
|
||||
args := strings.Fields(comment)
|
||||
if len(args) < 2 {
|
||||
return nil, err
|
||||
}
|
||||
@@ -58,7 +63,11 @@ func (e *EventParser) DetermineCommand(comment *github.IssueCommentEvent) (*Comm
|
||||
verbose := false
|
||||
var flags []string
|
||||
|
||||
if !e.stringInSlice(args[0], []string{"run", "atlantis", "@" + e.GithubUser}) {
|
||||
vcsUser := e.GithubUser
|
||||
if vcsHost == vcs.Gitlab {
|
||||
vcsUser = e.GitlabUser
|
||||
}
|
||||
if !e.stringInSlice(args[0], []string{"run", "atlantis", "@" + vcsUser}) {
|
||||
return nil, err
|
||||
}
|
||||
if !e.stringInSlice(args[1], []string{"plan", "apply", "help"}) {
|
||||
@@ -99,41 +108,28 @@ func (e *EventParser) DetermineCommand(comment *github.IssueCommentEvent) (*Comm
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (e *EventParser) ExtractCommentData(comment *github.IssueCommentEvent) (baseRepo models.Repo, user models.User, pull models.PullRequest, err error) {
|
||||
baseRepo, err = e.ExtractRepoData(comment.Repo)
|
||||
func (e *EventParser) ParseGithubIssueCommentEvent(comment *github.IssueCommentEvent) (baseRepo models.Repo, user models.User, pullNum int, err error) {
|
||||
baseRepo, err = e.ParseGithubRepo(comment.Repo)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
pullNum := comment.Issue.GetNumber()
|
||||
if comment.Comment == nil || comment.Comment.User.GetLogin() == "" {
|
||||
err = errors.New("comment.user.login is null")
|
||||
return
|
||||
}
|
||||
commentorUsername := comment.Comment.User.GetLogin()
|
||||
user = models.User{
|
||||
Username: commentorUsername,
|
||||
}
|
||||
pullNum = comment.Issue.GetNumber()
|
||||
if pullNum == 0 {
|
||||
err = errors.New("issue.number is null")
|
||||
return
|
||||
}
|
||||
pullCreator := comment.Issue.User.GetLogin()
|
||||
if pullCreator == "" {
|
||||
err = errors.New("issue.user.login is null")
|
||||
return
|
||||
}
|
||||
htmlURL := comment.Issue.GetHTMLURL()
|
||||
if htmlURL == "" {
|
||||
err = errors.New("issue.html_url is null")
|
||||
return
|
||||
}
|
||||
commentorUsername := comment.Comment.User.GetLogin()
|
||||
if commentorUsername == "" {
|
||||
err = errors.New("comment.user.login is null")
|
||||
return
|
||||
}
|
||||
user = models.User{
|
||||
Username: commentorUsername,
|
||||
}
|
||||
pull = models.PullRequest{
|
||||
Num: pullNum,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (e *EventParser) ExtractPullData(pull *github.PullRequest) (models.PullRequest, models.Repo, error) {
|
||||
func (e *EventParser) ParseGithubPull(pull *github.PullRequest) (models.PullRequest, models.Repo, error) {
|
||||
var pullModel models.PullRequest
|
||||
var headRepoModel models.Repo
|
||||
|
||||
@@ -141,10 +137,6 @@ func (e *EventParser) ExtractPullData(pull *github.PullRequest) (models.PullRequ
|
||||
if commit == "" {
|
||||
return pullModel, headRepoModel, errors.New("head.sha is null")
|
||||
}
|
||||
base := pull.Base.GetSHA()
|
||||
if base == "" {
|
||||
return pullModel, headRepoModel, errors.New("base.sha is null")
|
||||
}
|
||||
url := pull.GetHTMLURL()
|
||||
if url == "" {
|
||||
return pullModel, headRepoModel, errors.New("html_url is null")
|
||||
@@ -162,22 +154,27 @@ func (e *EventParser) ExtractPullData(pull *github.PullRequest) (models.PullRequ
|
||||
return pullModel, headRepoModel, errors.New("number is null")
|
||||
}
|
||||
|
||||
headRepoModel, err := e.ExtractRepoData(pull.Head.Repo)
|
||||
headRepoModel, err := e.ParseGithubRepo(pull.Head.Repo)
|
||||
if err != nil {
|
||||
return pullModel, headRepoModel, err
|
||||
}
|
||||
|
||||
pullState := models.Closed
|
||||
if pull.GetState() == "open" {
|
||||
pullState = models.Open
|
||||
}
|
||||
|
||||
return models.PullRequest{
|
||||
BaseCommit: base,
|
||||
Author: authorUsername,
|
||||
Branch: branch,
|
||||
HeadCommit: commit,
|
||||
URL: url,
|
||||
Num: num,
|
||||
State: pullState,
|
||||
}, headRepoModel, nil
|
||||
}
|
||||
|
||||
func (e *EventParser) ExtractRepoData(ghRepo *github.Repository) (models.Repo, error) {
|
||||
func (e *EventParser) ParseGithubRepo(ghRepo *github.Repository) (models.Repo, error) {
|
||||
var repo models.Repo
|
||||
repoFullName := ghRepo.GetFullName()
|
||||
if repoFullName == "" {
|
||||
@@ -196,7 +193,7 @@ func (e *EventParser) ExtractRepoData(ghRepo *github.Repository) (models.Repo, e
|
||||
return repo, errors.New("repository.clone_url is null")
|
||||
}
|
||||
|
||||
// construct HTTPS repo clone url string with username and password
|
||||
// Construct HTTPS repo clone url string with username and password.
|
||||
repoCloneURL := strings.Replace(repoSanitizedCloneURL, "https://", fmt.Sprintf("https://%s:%s@", e.GithubUser, e.GithubToken), -1)
|
||||
|
||||
return models.Repo{
|
||||
@@ -208,6 +205,100 @@ func (e *EventParser) ExtractRepoData(ghRepo *github.Repository) (models.Repo, e
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *EventParser) ParseGitlabMergeEvent(event gitlab.MergeEvent) (models.PullRequest, models.Repo) {
|
||||
modelState := models.Closed
|
||||
if event.ObjectAttributes.State == gitlabPullOpened {
|
||||
modelState = models.Open
|
||||
}
|
||||
// GitLab also has a "merged" state, but we map that to Closed so we don't
|
||||
// need to check for it.
|
||||
|
||||
pull := models.PullRequest{
|
||||
URL: event.ObjectAttributes.URL,
|
||||
Author: event.User.Username,
|
||||
Num: event.ObjectAttributes.IID,
|
||||
HeadCommit: event.ObjectAttributes.LastCommit.ID,
|
||||
Branch: event.ObjectAttributes.SourceBranch,
|
||||
State: modelState,
|
||||
}
|
||||
|
||||
cloneURL := e.addGitlabAuth(event.Project.GitHTTPURL)
|
||||
// Get owner and name from PathWithNamespace because the fields
|
||||
// event.Project.Name and event.Project.Owner can have capitals.
|
||||
owner, name := e.getOwnerAndName(event.Project.PathWithNamespace)
|
||||
repo := models.Repo{
|
||||
FullName: event.Project.PathWithNamespace,
|
||||
Name: name,
|
||||
SanitizedCloneURL: event.Project.GitHTTPURL,
|
||||
Owner: owner,
|
||||
CloneURL: cloneURL,
|
||||
}
|
||||
return pull, repo
|
||||
}
|
||||
|
||||
// addGitlabAuth adds gitlab username/password to the cloneURL.
|
||||
// We support http and https URLs because GitLab's docs have http:// URLs whereas
|
||||
// their API responses have https://.
|
||||
// Ex. https://gitlab.com/owner/repo.git => https://uname:pass@gitlab.com/owner/repo.git
|
||||
func (e *EventParser) addGitlabAuth(cloneURL string) string {
|
||||
httpsReplaced := strings.Replace(cloneURL, "https://", fmt.Sprintf("https://%s:%s@", e.GitlabUser, e.GitlabToken), -1)
|
||||
return strings.Replace(httpsReplaced, "http://", fmt.Sprintf("http://%s:%s@", e.GitlabUser, e.GitlabToken), -1)
|
||||
}
|
||||
|
||||
// getOwnerAndName takes pathWithNamespace that should look like "owner/repo"
|
||||
// and returns "owner", "repo"
|
||||
func (e *EventParser) getOwnerAndName(pathWithNamespace string) (string, string) {
|
||||
pathSplit := strings.Split(pathWithNamespace, "/")
|
||||
if len(pathSplit) > 1 {
|
||||
return pathSplit[0], pathSplit[1]
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
|
||||
// ParseGitlabMergeCommentEvent creates Atlantis models out of a GitLab event.
|
||||
func (e *EventParser) ParseGitlabMergeCommentEvent(event gitlab.MergeCommentEvent) (baseRepo models.Repo, headRepo models.Repo, user models.User) {
|
||||
// Get owner and name from PathWithNamespace because the fields
|
||||
// event.Project.Name and event.Project.Owner can have capitals.
|
||||
owner, name := e.getOwnerAndName(event.Project.PathWithNamespace)
|
||||
baseRepo = models.Repo{
|
||||
FullName: event.Project.PathWithNamespace,
|
||||
Name: name,
|
||||
SanitizedCloneURL: event.Project.GitHTTPURL,
|
||||
Owner: owner,
|
||||
CloneURL: e.addGitlabAuth(event.Project.GitHTTPURL),
|
||||
}
|
||||
user = models.User{
|
||||
Username: event.User.Username,
|
||||
}
|
||||
owner, name = e.getOwnerAndName(event.MergeRequest.Source.PathWithNamespace)
|
||||
headRepo = models.Repo{
|
||||
FullName: event.MergeRequest.Source.PathWithNamespace,
|
||||
Name: name,
|
||||
SanitizedCloneURL: event.MergeRequest.Source.GitHTTPURL,
|
||||
Owner: owner,
|
||||
CloneURL: e.addGitlabAuth(event.MergeRequest.Source.GitHTTPURL),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (e *EventParser) ParseGitlabMergeRequest(mr *gitlab.MergeRequest) models.PullRequest {
|
||||
pullState := models.Closed
|
||||
if mr.State == gitlabPullOpened {
|
||||
pullState = models.Open
|
||||
}
|
||||
// GitLab also has a "merged" state, but we map that to Closed so we don't
|
||||
// need to check for it.
|
||||
|
||||
return models.PullRequest{
|
||||
URL: mr.WebURL,
|
||||
Author: mr.Author.Username,
|
||||
Num: mr.IID,
|
||||
HeadCommit: mr.SHA,
|
||||
Branch: mr.SourceBranch,
|
||||
State: pullState,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *EventParser) stringInSlice(a string, list []string) bool {
|
||||
for _, b := range list {
|
||||
if b == a {
|
||||
|
||||
@@ -6,22 +6,23 @@ import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"encoding/json"
|
||||
|
||||
"github.com/google/go-github/github"
|
||||
"github.com/hootsuite/atlantis/server/events"
|
||||
. "github.com/hootsuite/atlantis/server/events/github/fixtures"
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
"github.com/hootsuite/atlantis/server/events/vcs"
|
||||
. "github.com/hootsuite/atlantis/server/events/vcs/fixtures"
|
||||
. "github.com/hootsuite/atlantis/testing"
|
||||
"github.com/lkysow/go-gitlab"
|
||||
"github.com/mohae/deepcopy"
|
||||
)
|
||||
|
||||
var parser = events.EventParser{
|
||||
GithubUser: "user",
|
||||
GithubToken: "token",
|
||||
}
|
||||
|
||||
func TestDetermineCommandNoBody(t *testing.T) {
|
||||
_, err := parser.DetermineCommand(&github.IssueCommentEvent{})
|
||||
Equals(t, errors.New("comment.body is null"), err)
|
||||
GithubUser: "github-user",
|
||||
GithubToken: "github-token",
|
||||
GitlabUser: "gitlab-user",
|
||||
GitlabToken: "gitlab-token",
|
||||
}
|
||||
|
||||
func TestDetermineCommandInvalid(t *testing.T) {
|
||||
@@ -30,17 +31,17 @@ func TestDetermineCommandInvalid(t *testing.T) {
|
||||
// just the executable, no command
|
||||
"run",
|
||||
"atlantis",
|
||||
"@user",
|
||||
"@github-user",
|
||||
// invalid command
|
||||
"run slkjd",
|
||||
"atlantis slkjd",
|
||||
"@user slkjd",
|
||||
"@github-user slkjd",
|
||||
"atlantis plans",
|
||||
// misc
|
||||
"related comment mentioning atlantis",
|
||||
}
|
||||
for _, c := range comments {
|
||||
_, e := parser.DetermineCommand(buildComment(c))
|
||||
_, e := parser.DetermineCommand(c, vcs.Github)
|
||||
Assert(t, e != nil, "expected error for comment: "+c)
|
||||
}
|
||||
}
|
||||
@@ -50,18 +51,18 @@ func TestDetermineCommandHelp(t *testing.T) {
|
||||
comments := []string{
|
||||
"run help",
|
||||
"atlantis help",
|
||||
"@user help",
|
||||
"@github-user help",
|
||||
"atlantis help --verbose",
|
||||
}
|
||||
for _, c := range comments {
|
||||
command, e := parser.DetermineCommand(buildComment(c))
|
||||
command, e := parser.DetermineCommand(c, vcs.Github)
|
||||
Ok(t, e)
|
||||
Equals(t, events.Help, command.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetermineCommandPermutations(t *testing.T) {
|
||||
execNames := []string{"run", "atlantis", "@user"}
|
||||
execNames := []string{"run", "atlantis", "@github-user", "@gitlab-user"}
|
||||
commandNames := []events.CommandName{events.Plan, events.Apply}
|
||||
envs := []string{"", "default", "env", "env-dash", "env_underscore", "camelEnv"}
|
||||
flagCases := [][]string{
|
||||
@@ -86,7 +87,15 @@ func TestDetermineCommandPermutations(t *testing.T) {
|
||||
for _, lineEnding := range []string{"", "\r\n"} {
|
||||
comment := strings.Join(append([]string{exec, name.String(), env}, flags...), " ") + lineEnding
|
||||
t.Log("testing comment: " + comment)
|
||||
c, err := parser.DetermineCommand(buildComment(comment))
|
||||
|
||||
// In order to test gitlab without fully refactoring this test
|
||||
// we're just detecting if we're using the gitlab user as the
|
||||
// exec name.
|
||||
vcsHost := vcs.Github
|
||||
if exec == "@gitlab-user" {
|
||||
vcsHost = vcs.Gitlab
|
||||
}
|
||||
c, err := parser.DetermineCommand(comment, vcsHost)
|
||||
Ok(t, err)
|
||||
Equals(t, name, c.Name)
|
||||
if env == "" {
|
||||
@@ -114,42 +123,42 @@ func TestDetermineCommandPermutations(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractRepoData(t *testing.T) {
|
||||
func TestParseGithubRepo(t *testing.T) {
|
||||
testRepo := Repo
|
||||
testRepo.FullName = nil
|
||||
_, err := parser.ExtractRepoData(&testRepo)
|
||||
_, err := parser.ParseGithubRepo(&testRepo)
|
||||
Equals(t, errors.New("repository.full_name is null"), err)
|
||||
|
||||
testRepo = Repo
|
||||
testRepo.Owner = nil
|
||||
_, err = parser.ExtractRepoData(&testRepo)
|
||||
_, err = parser.ParseGithubRepo(&testRepo)
|
||||
Equals(t, errors.New("repository.owner.login is null"), err)
|
||||
|
||||
testRepo = Repo
|
||||
testRepo.Name = nil
|
||||
_, err = parser.ExtractRepoData(&testRepo)
|
||||
_, err = parser.ParseGithubRepo(&testRepo)
|
||||
Equals(t, errors.New("repository.name is null"), err)
|
||||
|
||||
testRepo = Repo
|
||||
testRepo.CloneURL = nil
|
||||
_, err = parser.ExtractRepoData(&testRepo)
|
||||
_, err = parser.ParseGithubRepo(&testRepo)
|
||||
Equals(t, errors.New("repository.clone_url is null"), err)
|
||||
|
||||
t.Log("should replace https clone with user/pass")
|
||||
{
|
||||
r, err := parser.ExtractRepoData(&Repo)
|
||||
r, err := parser.ParseGithubRepo(&Repo)
|
||||
Ok(t, err)
|
||||
Equals(t, models.Repo{
|
||||
Owner: "owner",
|
||||
FullName: "owner/repo",
|
||||
CloneURL: "https://user:token@github.com/lkysow/atlantis-example.git",
|
||||
CloneURL: "https://github-user:github-token@github.com/lkysow/atlantis-example.git",
|
||||
SanitizedCloneURL: Repo.GetCloneURL(),
|
||||
Name: "repo",
|
||||
}, r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractCommentData(t *testing.T) {
|
||||
func TestParseGithubIssueCommentEvent(t *testing.T) {
|
||||
comment := github.IssueCommentEvent{
|
||||
Repo: &Repo,
|
||||
Issue: &github.Issue{
|
||||
@@ -163,109 +172,169 @@ func TestExtractCommentData(t *testing.T) {
|
||||
}
|
||||
testComment := deepcopy.Copy(comment).(github.IssueCommentEvent)
|
||||
testComment.Repo = nil
|
||||
_, _, _, err := parser.ExtractCommentData(&testComment)
|
||||
_, _, _, err := parser.ParseGithubIssueCommentEvent(&testComment)
|
||||
Equals(t, errors.New("repository.full_name is null"), err)
|
||||
|
||||
testComment = deepcopy.Copy(comment).(github.IssueCommentEvent)
|
||||
testComment.Issue = nil
|
||||
_, _, _, err = parser.ExtractCommentData(&testComment)
|
||||
Equals(t, errors.New("issue.number is null"), err)
|
||||
testComment.Comment = nil
|
||||
_, _, _, err = parser.ParseGithubIssueCommentEvent(&testComment)
|
||||
Equals(t, errors.New("comment.user.login is null"), err)
|
||||
|
||||
testComment = deepcopy.Copy(comment).(github.IssueCommentEvent)
|
||||
testComment.Issue.User = nil
|
||||
_, _, _, err = parser.ExtractCommentData(&testComment)
|
||||
Equals(t, errors.New("issue.user.login is null"), err)
|
||||
|
||||
testComment = deepcopy.Copy(comment).(github.IssueCommentEvent)
|
||||
testComment.Issue.HTMLURL = nil
|
||||
_, _, _, err = parser.ExtractCommentData(&testComment)
|
||||
Equals(t, errors.New("issue.html_url is null"), err)
|
||||
testComment.Comment.User = nil
|
||||
_, _, _, err = parser.ParseGithubIssueCommentEvent(&testComment)
|
||||
Equals(t, errors.New("comment.user.login is null"), err)
|
||||
|
||||
testComment = deepcopy.Copy(comment).(github.IssueCommentEvent)
|
||||
testComment.Comment.User.Login = nil
|
||||
_, _, _, err = parser.ExtractCommentData(&testComment)
|
||||
_, _, _, err = parser.ParseGithubIssueCommentEvent(&testComment)
|
||||
Equals(t, errors.New("comment.user.login is null"), err)
|
||||
|
||||
testComment = deepcopy.Copy(comment).(github.IssueCommentEvent)
|
||||
testComment.Issue = nil
|
||||
_, _, _, err = parser.ParseGithubIssueCommentEvent(&testComment)
|
||||
Equals(t, errors.New("issue.number is null"), err)
|
||||
|
||||
// this should be successful
|
||||
repo, user, pull, err := parser.ExtractCommentData(&comment)
|
||||
repo, user, pullNum, err := parser.ParseGithubIssueCommentEvent(&comment)
|
||||
Ok(t, err)
|
||||
Equals(t, models.Repo{
|
||||
Owner: *comment.Repo.Owner.Login,
|
||||
FullName: *comment.Repo.FullName,
|
||||
CloneURL: "https://user:token@github.com/lkysow/atlantis-example.git",
|
||||
CloneURL: "https://github-user:github-token@github.com/lkysow/atlantis-example.git",
|
||||
SanitizedCloneURL: *comment.Repo.CloneURL,
|
||||
Name: "repo",
|
||||
}, repo)
|
||||
Equals(t, models.User{
|
||||
Username: *comment.Comment.User.Login,
|
||||
}, user)
|
||||
Equals(t, models.PullRequest{
|
||||
Num: *comment.Issue.Number,
|
||||
}, pull)
|
||||
Equals(t, *comment.Issue.Number, pullNum)
|
||||
}
|
||||
|
||||
func TestExtractPullData(t *testing.T) {
|
||||
func TestParseGithubPull(t *testing.T) {
|
||||
testPull := deepcopy.Copy(Pull).(github.PullRequest)
|
||||
testPull.Head.SHA = nil
|
||||
_, _, err := parser.ExtractPullData(&testPull)
|
||||
_, _, err := parser.ParseGithubPull(&testPull)
|
||||
Equals(t, errors.New("head.sha is null"), err)
|
||||
|
||||
testPull = deepcopy.Copy(Pull).(github.PullRequest)
|
||||
testPull.Base.SHA = nil
|
||||
_, _, err = parser.ExtractPullData(&testPull)
|
||||
Equals(t, errors.New("base.sha is null"), err)
|
||||
|
||||
testPull = deepcopy.Copy(Pull).(github.PullRequest)
|
||||
testPull.HTMLURL = nil
|
||||
_, _, err = parser.ExtractPullData(&testPull)
|
||||
_, _, err = parser.ParseGithubPull(&testPull)
|
||||
Equals(t, errors.New("html_url is null"), err)
|
||||
|
||||
testPull = deepcopy.Copy(Pull).(github.PullRequest)
|
||||
testPull.Head.Ref = nil
|
||||
_, _, err = parser.ExtractPullData(&testPull)
|
||||
_, _, err = parser.ParseGithubPull(&testPull)
|
||||
Equals(t, errors.New("head.ref is null"), err)
|
||||
|
||||
testPull = deepcopy.Copy(Pull).(github.PullRequest)
|
||||
testPull.User.Login = nil
|
||||
_, _, err = parser.ExtractPullData(&testPull)
|
||||
_, _, err = parser.ParseGithubPull(&testPull)
|
||||
Equals(t, errors.New("user.login is null"), err)
|
||||
|
||||
testPull = deepcopy.Copy(Pull).(github.PullRequest)
|
||||
testPull.Number = nil
|
||||
_, _, err = parser.ExtractPullData(&testPull)
|
||||
_, _, err = parser.ParseGithubPull(&testPull)
|
||||
Equals(t, errors.New("number is null"), err)
|
||||
|
||||
testPull = deepcopy.Copy(Pull).(github.PullRequest)
|
||||
testPull.Head.Repo = nil
|
||||
_, _, err = parser.ExtractPullData(&testPull)
|
||||
_, _, err = parser.ParseGithubPull(&testPull)
|
||||
Equals(t, errors.New("repository.full_name is null"), err)
|
||||
|
||||
PullRes, repoRes, err := parser.ExtractPullData(&Pull)
|
||||
pullRes, repoRes, err := parser.ParseGithubPull(&Pull)
|
||||
Ok(t, err)
|
||||
Equals(t, models.PullRequest{
|
||||
BaseCommit: Pull.Base.GetSHA(),
|
||||
URL: Pull.GetHTMLURL(),
|
||||
Author: Pull.User.GetLogin(),
|
||||
Branch: Pull.Head.GetRef(),
|
||||
HeadCommit: Pull.Head.GetSHA(),
|
||||
Num: Pull.GetNumber(),
|
||||
}, PullRes)
|
||||
State: models.Open,
|
||||
}, pullRes)
|
||||
|
||||
Equals(t, models.Repo{
|
||||
Owner: "owner",
|
||||
FullName: "owner/repo",
|
||||
CloneURL: "https://user:token@github.com/lkysow/atlantis-example.git",
|
||||
CloneURL: "https://github-user:github-token@github.com/lkysow/atlantis-example.git",
|
||||
SanitizedCloneURL: Repo.GetCloneURL(),
|
||||
Name: "repo",
|
||||
}, repoRes)
|
||||
}
|
||||
|
||||
func buildComment(c string) *github.IssueCommentEvent {
|
||||
return &github.IssueCommentEvent{
|
||||
Comment: &github.IssueComment{
|
||||
Body: github.String(c),
|
||||
},
|
||||
}
|
||||
func TestParseGitlabMergeEvent(t *testing.T) {
|
||||
t.Log("should properly parse a gitlab merge event")
|
||||
var event *gitlab.MergeEvent
|
||||
err := json.Unmarshal([]byte(mergeEventJSON), &event)
|
||||
Ok(t, err)
|
||||
pull, repo := parser.ParseGitlabMergeEvent(*event)
|
||||
Equals(t, models.PullRequest{
|
||||
URL: "http://example.com/diaspora/merge_requests/1",
|
||||
Author: "root",
|
||||
Num: 1,
|
||||
HeadCommit: "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
||||
Branch: "ms-viewport",
|
||||
State: models.Open,
|
||||
}, pull)
|
||||
|
||||
Equals(t, models.Repo{
|
||||
FullName: "gitlabhq/gitlab-test",
|
||||
Name: "gitlab-test",
|
||||
SanitizedCloneURL: "https://example.com/gitlabhq/gitlab-test.git",
|
||||
Owner: "gitlabhq",
|
||||
CloneURL: "https://gitlab-user:gitlab-token@example.com/gitlabhq/gitlab-test.git",
|
||||
}, repo)
|
||||
|
||||
t.Log("If the state is closed, should set field correctly.")
|
||||
event.ObjectAttributes.State = "closed"
|
||||
pull, _ = parser.ParseGitlabMergeEvent(*event)
|
||||
Equals(t, models.Closed, pull.State)
|
||||
}
|
||||
|
||||
func TestParseGitlabMergeRequest(t *testing.T) {
|
||||
t.Log("should properly parse a gitlab merge request")
|
||||
var event *gitlab.MergeRequest
|
||||
err := json.Unmarshal([]byte(mergeRequestJSON), &event)
|
||||
Ok(t, err)
|
||||
pull := parser.ParseGitlabMergeRequest(event)
|
||||
Equals(t, models.PullRequest{
|
||||
URL: "https://gitlab.com/lkysow/atlantis-example/merge_requests/8",
|
||||
Author: "lkysow",
|
||||
Num: 8,
|
||||
HeadCommit: "0b4ac85ea3063ad5f2974d10cd68dd1f937aaac2",
|
||||
Branch: "abc",
|
||||
State: models.Open,
|
||||
}, pull)
|
||||
|
||||
t.Log("If the state is closed, should set field correctly.")
|
||||
event.State = "closed"
|
||||
pull = parser.ParseGitlabMergeRequest(event)
|
||||
Equals(t, models.Closed, pull.State)
|
||||
}
|
||||
|
||||
func TestParseGitlabMergeCommentEvent(t *testing.T) {
|
||||
t.Log("should properly parse a gitlab merge comment event")
|
||||
var event *gitlab.MergeCommentEvent
|
||||
err := json.Unmarshal([]byte(mergeCommentEventJSON), &event)
|
||||
Ok(t, err)
|
||||
baseRepo, headRepo, user := parser.ParseGitlabMergeCommentEvent(*event)
|
||||
Equals(t, models.Repo{
|
||||
FullName: "gitlabhq/gitlab-test",
|
||||
Name: "gitlab-test",
|
||||
SanitizedCloneURL: "https://example.com/gitlabhq/gitlab-test.git",
|
||||
Owner: "gitlabhq",
|
||||
CloneURL: "https://gitlab-user:gitlab-token@example.com/gitlabhq/gitlab-test.git",
|
||||
}, baseRepo)
|
||||
Equals(t, models.Repo{
|
||||
FullName: "gitlab-org/gitlab-test",
|
||||
Name: "gitlab-test",
|
||||
SanitizedCloneURL: "https://example.com/gitlab-org/gitlab-test.git",
|
||||
Owner: "gitlab-org",
|
||||
CloneURL: "https://gitlab-user:gitlab-token@example.com/gitlab-org/gitlab-test.git",
|
||||
}, headRepo)
|
||||
Equals(t, models.User{
|
||||
Username: "root",
|
||||
}, user)
|
||||
}
|
||||
|
||||
func containsVerbose(list []string) bool {
|
||||
@@ -276,3 +345,310 @@ func containsVerbose(list []string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var mergeEventJSON = `{
|
||||
"object_kind": "merge_request",
|
||||
"user": {
|
||||
"name": "Administrator",
|
||||
"username": "root",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
|
||||
},
|
||||
"project": {
|
||||
"id": 1,
|
||||
"name":"Gitlab Test",
|
||||
"description":"Aut reprehenderit ut est.",
|
||||
"web_url":"http://example.com/gitlabhq/gitlab-test",
|
||||
"avatar_url":null,
|
||||
"git_ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
|
||||
"git_http_url":"https://example.com/gitlabhq/gitlab-test.git",
|
||||
"namespace":"GitlabHQ",
|
||||
"visibility_level":20,
|
||||
"path_with_namespace":"gitlabhq/gitlab-test",
|
||||
"default_branch":"master",
|
||||
"homepage":"http://example.com/gitlabhq/gitlab-test",
|
||||
"url":"https://example.com/gitlabhq/gitlab-test.git",
|
||||
"ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
|
||||
"http_url":"https://example.com/gitlabhq/gitlab-test.git"
|
||||
},
|
||||
"repository": {
|
||||
"name": "Gitlab Test",
|
||||
"url": "https://example.com/gitlabhq/gitlab-test.git",
|
||||
"description": "Aut reprehenderit ut est.",
|
||||
"homepage": "http://example.com/gitlabhq/gitlab-test"
|
||||
},
|
||||
"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":null,
|
||||
"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":null,
|
||||
"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"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"labels": [{
|
||||
"id": 206,
|
||||
"title": "API",
|
||||
"color": "#ffffff",
|
||||
"project_id": 14,
|
||||
"created_at": "2013-12-03T17:15:43Z",
|
||||
"updated_at": "2013-12-03T17:15:43Z",
|
||||
"template": false,
|
||||
"description": "API related issues",
|
||||
"type": "ProjectLabel",
|
||||
"group_id": 41
|
||||
}],
|
||||
"changes": {
|
||||
"updated_by_id": [null, 1],
|
||||
"updated_at": ["2017-09-15 16:50:55 UTC", "2017-09-15 16:52:00 UTC"],
|
||||
"labels": {
|
||||
"previous": [{
|
||||
"id": 206,
|
||||
"title": "API",
|
||||
"color": "#ffffff",
|
||||
"project_id": 14,
|
||||
"created_at": "2013-12-03T17:15:43Z",
|
||||
"updated_at": "2013-12-03T17:15:43Z",
|
||||
"template": false,
|
||||
"description": "API related issues",
|
||||
"type": "ProjectLabel",
|
||||
"group_id": 41
|
||||
}],
|
||||
"current": [{
|
||||
"id": 205,
|
||||
"title": "Platform",
|
||||
"color": "#123123",
|
||||
"project_id": 14,
|
||||
"created_at": "2013-12-03T17:15:43Z",
|
||||
"updated_at": "2013-12-03T17:15:43Z",
|
||||
"template": false,
|
||||
"description": "Platform related issues",
|
||||
"type": "ProjectLabel",
|
||||
"group_id": 41
|
||||
}]
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
var mergeCommentEventJSON = `{
|
||||
"object_kind": "note",
|
||||
"user": {
|
||||
"name": "Administrator",
|
||||
"username": "root",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
|
||||
},
|
||||
"project_id": 5,
|
||||
"project":{
|
||||
"id": 5,
|
||||
"name":"Gitlab Test",
|
||||
"description":"Aut reprehenderit ut est.",
|
||||
"web_url":"http://example.com/gitlabhq/gitlab-test",
|
||||
"avatar_url":null,
|
||||
"git_ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
|
||||
"git_http_url":"https://example.com/gitlabhq/gitlab-test.git",
|
||||
"namespace":"Gitlab Org",
|
||||
"visibility_level":10,
|
||||
"path_with_namespace":"gitlabhq/gitlab-test",
|
||||
"default_branch":"master",
|
||||
"homepage":"http://example.com/gitlabhq/gitlab-test",
|
||||
"url":"https://example.com/gitlabhq/gitlab-test.git",
|
||||
"ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
|
||||
"http_url":"https://example.com/gitlabhq/gitlab-test.git"
|
||||
},
|
||||
"repository":{
|
||||
"name": "Gitlab Test",
|
||||
"url": "http://localhost/gitlab-org/gitlab-test.git",
|
||||
"description": "Aut reprehenderit ut est.",
|
||||
"homepage": "http://example.com/gitlab-org/gitlab-test"
|
||||
},
|
||||
"object_attributes": {
|
||||
"id": 1244,
|
||||
"note": "This MR needs work.",
|
||||
"noteable_type": "MergeRequest",
|
||||
"author_id": 1,
|
||||
"created_at": "2015-05-17",
|
||||
"updated_at": "2015-05-17",
|
||||
"project_id": 5,
|
||||
"attachment": null,
|
||||
"line_code": null,
|
||||
"commit_id": "",
|
||||
"noteable_id": 7,
|
||||
"system": false,
|
||||
"st_diff": null,
|
||||
"url": "http://example.com/gitlab-org/gitlab-test/merge_requests/1#note_1244"
|
||||
},
|
||||
"merge_request": {
|
||||
"id": 7,
|
||||
"target_branch": "markdown",
|
||||
"source_branch": "master",
|
||||
"source_project_id": 5,
|
||||
"author_id": 8,
|
||||
"assignee_id": 28,
|
||||
"title": "Tempora et eos debitis quae laborum et.",
|
||||
"created_at": "2015-03-01 20:12:53 UTC",
|
||||
"updated_at": "2015-03-21 18:27:27 UTC",
|
||||
"milestone_id": 11,
|
||||
"state": "opened",
|
||||
"merge_status": "cannot_be_merged",
|
||||
"target_project_id": 5,
|
||||
"iid": 1,
|
||||
"description": "Et voluptas corrupti assumenda temporibus. Architecto cum animi eveniet amet asperiores. Vitae numquam voluptate est natus sit et ad id.",
|
||||
"position": 0,
|
||||
"source":{
|
||||
"name":"Gitlab Test",
|
||||
"description":"Aut reprehenderit ut est.",
|
||||
"web_url":"http://example.com/gitlab-org/gitlab-test",
|
||||
"avatar_url":null,
|
||||
"git_ssh_url":"git@example.com:gitlab-org/gitlab-test.git",
|
||||
"git_http_url":"https://example.com/gitlab-org/gitlab-test.git",
|
||||
"namespace":"Gitlab Org",
|
||||
"visibility_level":10,
|
||||
"path_with_namespace":"gitlab-org/gitlab-test",
|
||||
"default_branch":"master",
|
||||
"homepage":"http://example.com/gitlab-org/gitlab-test",
|
||||
"url":"https://example.com/gitlab-org/gitlab-test.git",
|
||||
"ssh_url":"git@example.com:gitlab-org/gitlab-test.git",
|
||||
"http_url":"https://example.com/gitlab-org/gitlab-test.git",
|
||||
"git_http_url":"https://example.com/gitlab-org/gitlab-test.git"
|
||||
},
|
||||
"target": {
|
||||
"name":"Gitlab Test",
|
||||
"description":"Aut reprehenderit ut est.",
|
||||
"web_url":"http://example.com/gitlabhq/gitlab-test",
|
||||
"avatar_url":null,
|
||||
"git_ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
|
||||
"git_http_url":"https://example.com/gitlabhq/gitlab-test.git",
|
||||
"namespace":"Gitlab Org",
|
||||
"visibility_level":10,
|
||||
"path_with_namespace":"gitlabhq/gitlab-test",
|
||||
"default_branch":"master",
|
||||
"homepage":"http://example.com/gitlabhq/gitlab-test",
|
||||
"url":"https://example.com/gitlabhq/gitlab-test.git",
|
||||
"ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
|
||||
"http_url":"https://example.com/gitlabhq/gitlab-test.git"
|
||||
},
|
||||
"last_commit": {
|
||||
"id": "562e173be03b8ff2efb05345d12df18815438a4b",
|
||||
"message": "Merge branch 'another-branch' into 'master'\n\nCheck in this test\n",
|
||||
"timestamp": "2002-10-02T10:00:00-05:00",
|
||||
"url": "http://example.com/gitlab-org/gitlab-test/commit/562e173be03b8ff2efb05345d12df18815438a4b",
|
||||
"author": {
|
||||
"name": "John Smith",
|
||||
"email": "john@example.com"
|
||||
}
|
||||
},
|
||||
"work_in_progress": false,
|
||||
"assignee": {
|
||||
"name": "User1",
|
||||
"username": "user1",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
var mergeRequestJSON = `{
|
||||
"id":6056811,
|
||||
"iid":8,
|
||||
"project_id":4580910,
|
||||
"title":"Update main.tf",
|
||||
"description":"",
|
||||
"state":"opened",
|
||||
"created_at":"2017-11-13T19:33:42.704Z",
|
||||
"updated_at":"2017-11-13T23:35:26.200Z",
|
||||
"target_branch":"master",
|
||||
"source_branch":"abc",
|
||||
"upvotes":0,
|
||||
"downvotes":0,
|
||||
"author":{
|
||||
"id":1755902,
|
||||
"name":"Luke Kysow",
|
||||
"username":"lkysow",
|
||||
"state":"active",
|
||||
"avatar_url":"https://secure.gravatar.com/avatar/25fd57e71590fe28736624ff24d41c5f?s=80\u0026d=identicon",
|
||||
"web_url":"https://gitlab.com/lkysow"
|
||||
},
|
||||
"assignee":null,
|
||||
"source_project_id":4580910,
|
||||
"target_project_id":4580910,
|
||||
"labels":[
|
||||
|
||||
],
|
||||
"work_in_progress":false,
|
||||
"milestone":null,
|
||||
"merge_when_pipeline_succeeds":false,
|
||||
"merge_status":"can_be_merged",
|
||||
"sha":"0b4ac85ea3063ad5f2974d10cd68dd1f937aaac2",
|
||||
"merge_commit_sha":null,
|
||||
"user_notes_count":10,
|
||||
"approvals_before_merge":null,
|
||||
"discussion_locked":null,
|
||||
"should_remove_source_branch":null,
|
||||
"force_remove_source_branch":false,
|
||||
"squash":false,
|
||||
"web_url":"https://gitlab.com/lkysow/atlantis-example/merge_requests/8",
|
||||
"time_stats":{
|
||||
"time_estimate":0,
|
||||
"total_time_spent":0,
|
||||
"human_time_estimate":null,
|
||||
"human_total_time_spent":null
|
||||
}
|
||||
}`
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/hootsuite/atlantis/server/events/github"
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
)
|
||||
|
||||
type Status int
|
||||
|
||||
const (
|
||||
statusContext = "Atlantis"
|
||||
)
|
||||
|
||||
const (
|
||||
Pending Status = iota
|
||||
Success
|
||||
Failure
|
||||
Error
|
||||
)
|
||||
|
||||
//go:generate pegomock generate --use-experimental-model-gen --package mocks -o mocks/mock_github_status.go GHStatusUpdater
|
||||
|
||||
type GHStatusUpdater interface {
|
||||
Update(repo models.Repo, pull models.PullRequest, status Status, cmd *Command) error
|
||||
UpdateProjectResult(ctx *CommandContext, res CommandResponse) error
|
||||
}
|
||||
|
||||
type GithubStatus struct {
|
||||
Client github.Client
|
||||
}
|
||||
|
||||
func (s Status) String() string {
|
||||
switch s {
|
||||
case Pending:
|
||||
return "pending"
|
||||
case Success:
|
||||
return "success"
|
||||
case Failure:
|
||||
return "failure"
|
||||
case Error:
|
||||
return "error"
|
||||
}
|
||||
return "error"
|
||||
}
|
||||
|
||||
func (g *GithubStatus) Update(repo models.Repo, pull models.PullRequest, status Status, cmd *Command) error {
|
||||
description := fmt.Sprintf("%s %s", strings.Title(cmd.Name.String()), strings.Title(status.String()))
|
||||
return g.Client.UpdateStatus(repo, pull, status.String(), description, statusContext)
|
||||
}
|
||||
|
||||
func (g *GithubStatus) UpdateProjectResult(ctx *CommandContext, res CommandResponse) error {
|
||||
var status Status
|
||||
if res.Error != nil {
|
||||
status = Error
|
||||
} else if res.Failure != "" {
|
||||
status = Failure
|
||||
} else {
|
||||
var statuses []Status
|
||||
for _, p := range res.ProjectResults {
|
||||
statuses = append(statuses, p.Status())
|
||||
}
|
||||
status = g.worstStatus(statuses)
|
||||
}
|
||||
return g.Update(ctx.BaseRepo, ctx.Pull, status, ctx.Command)
|
||||
}
|
||||
|
||||
func (g *GithubStatus) worstStatus(ss []Status) Status {
|
||||
worst := Success
|
||||
for _, s := range ss {
|
||||
if s > worst {
|
||||
worst = s
|
||||
}
|
||||
}
|
||||
return worst
|
||||
}
|
||||
@@ -4,9 +4,10 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
models "github.com/hootsuite/atlantis/server/events/models"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type MockBackend struct {
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
locking "github.com/hootsuite/atlantis/server/events/locking"
|
||||
models "github.com/hootsuite/atlantis/server/events/models"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type MockLocker struct {
|
||||
|
||||
@@ -63,8 +63,8 @@ var failureTmpl = template.Must(template.New("").Parse(failureTmplText))
|
||||
var failureWithLogTmpl = template.Must(template.New("").Parse(failureTmplText + logTmpl))
|
||||
var logTmpl = "{{if .Verbose}}\n<details><summary>Log</summary>\n <p>\n\n```\n{{.Log}}```\n</p></details>{{end}}\n"
|
||||
|
||||
// GithubCommentRenderer renders responses as GitHub comments
|
||||
type GithubCommentRenderer struct{}
|
||||
// MarkdownRenderer renders responses as markdown
|
||||
type MarkdownRenderer struct{}
|
||||
|
||||
type CommonData struct {
|
||||
Command string
|
||||
@@ -89,7 +89,7 @@ type ResultData struct {
|
||||
|
||||
// Render formats the data into a string that can be commented back to GitHub.
|
||||
// nolint: interfacer
|
||||
func (g *GithubCommentRenderer) Render(res CommandResponse, cmdName CommandName, log string, verbose bool) string {
|
||||
func (g *MarkdownRenderer) Render(res CommandResponse, cmdName CommandName, log string, verbose bool) string {
|
||||
if cmdName == Help {
|
||||
return g.renderTemplate(helpTmpl, nil)
|
||||
}
|
||||
@@ -104,7 +104,7 @@ func (g *GithubCommentRenderer) Render(res CommandResponse, cmdName CommandName,
|
||||
return g.renderProjectResults(res.ProjectResults, common)
|
||||
}
|
||||
|
||||
func (g *GithubCommentRenderer) renderProjectResults(pathResults []ProjectResult, common CommonData) string {
|
||||
func (g *MarkdownRenderer) renderProjectResults(pathResults []ProjectResult, common CommonData) string {
|
||||
results := make(map[string]string)
|
||||
for _, result := range pathResults {
|
||||
if result.Error != nil {
|
||||
@@ -141,7 +141,7 @@ func (g *GithubCommentRenderer) renderProjectResults(pathResults []ProjectResult
|
||||
return g.renderTemplate(tmpl, ResultData{results, common})
|
||||
}
|
||||
|
||||
func (g *GithubCommentRenderer) renderTemplate(tmpl *template.Template, data interface{}) string {
|
||||
func (g *MarkdownRenderer) renderTemplate(tmpl *template.Template, data interface{}) string {
|
||||
buf := &bytes.Buffer{}
|
||||
if err := tmpl.Execute(buf, data); err != nil {
|
||||
return fmt.Sprintf("Failed to render template, this is a bug: %v", err)
|
||||
@@ -30,7 +30,7 @@ func TestRenderErr(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
r := events.GithubCommentRenderer{}
|
||||
r := events.MarkdownRenderer{}
|
||||
for _, c := range cases {
|
||||
res := events.CommandResponse{
|
||||
Error: c.Error,
|
||||
@@ -68,7 +68,7 @@ func TestRenderFailure(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
r := events.GithubCommentRenderer{}
|
||||
r := events.MarkdownRenderer{}
|
||||
for _, c := range cases {
|
||||
res := events.CommandResponse{
|
||||
Failure: c.Failure,
|
||||
@@ -87,7 +87,7 @@ func TestRenderFailure(t *testing.T) {
|
||||
|
||||
func TestRenderErrAndFailure(t *testing.T) {
|
||||
t.Log("if there is an error and a failure, the error should be printed")
|
||||
r := events.GithubCommentRenderer{}
|
||||
r := events.MarkdownRenderer{}
|
||||
res := events.CommandResponse{
|
||||
Error: errors.New("error"),
|
||||
Failure: "failure",
|
||||
@@ -225,7 +225,7 @@ func TestRenderProjectResults(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
r := events.GithubCommentRenderer{}
|
||||
r := events.MarkdownRenderer{}
|
||||
for _, c := range cases {
|
||||
res := events.CommandResponse{
|
||||
ProjectResults: c.ProjectResults,
|
||||
@@ -4,9 +4,12 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
events "github.com/hootsuite/atlantis/server/events"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
"reflect"
|
||||
|
||||
events "github.com/hootsuite/atlantis/server/events"
|
||||
models "github.com/hootsuite/atlantis/server/events/models"
|
||||
vcs "github.com/hootsuite/atlantis/server/events/vcs"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
)
|
||||
|
||||
type MockCommandRunner struct {
|
||||
@@ -17,8 +20,8 @@ func NewMockCommandRunner() *MockCommandRunner {
|
||||
return &MockCommandRunner{fail: pegomock.GlobalFailHandler}
|
||||
}
|
||||
|
||||
func (mock *MockCommandRunner) ExecuteCommand(ctx *events.CommandContext) {
|
||||
params := []pegomock.Param{ctx}
|
||||
func (mock *MockCommandRunner) ExecuteCommand(baseRepo models.Repo, headRepo models.Repo, user models.User, pullNum int, cmd *events.Command, vcsHost vcs.Host) {
|
||||
params := []pegomock.Param{baseRepo, headRepo, user, pullNum, cmd, vcsHost}
|
||||
pegomock.GetGenericMockFrom(mock).Invoke("ExecuteCommand", params, []reflect.Type{})
|
||||
}
|
||||
|
||||
@@ -40,8 +43,8 @@ type VerifierCommandRunner struct {
|
||||
inOrderContext *pegomock.InOrderContext
|
||||
}
|
||||
|
||||
func (verifier *VerifierCommandRunner) ExecuteCommand(ctx *events.CommandContext) *CommandRunner_ExecuteCommand_OngoingVerification {
|
||||
params := []pegomock.Param{ctx}
|
||||
func (verifier *VerifierCommandRunner) ExecuteCommand(baseRepo models.Repo, headRepo models.Repo, user models.User, pullNum int, cmd *events.Command, vcsHost vcs.Host) *CommandRunner_ExecuteCommand_OngoingVerification {
|
||||
params := []pegomock.Param{baseRepo, headRepo, user, pullNum, cmd, vcsHost}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ExecuteCommand", params)
|
||||
return &CommandRunner_ExecuteCommand_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
@@ -51,17 +54,37 @@ type CommandRunner_ExecuteCommand_OngoingVerification struct {
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *CommandRunner_ExecuteCommand_OngoingVerification) GetCapturedArguments() *events.CommandContext {
|
||||
ctx := c.GetAllCapturedArguments()
|
||||
return ctx[len(ctx)-1]
|
||||
func (c *CommandRunner_ExecuteCommand_OngoingVerification) GetCapturedArguments() (models.Repo, models.Repo, models.User, int, *events.Command, vcs.Host) {
|
||||
baseRepo, headRepo, user, pullNum, cmd, vcsHost := c.GetAllCapturedArguments()
|
||||
return baseRepo[len(baseRepo)-1], headRepo[len(headRepo)-1], user[len(user)-1], pullNum[len(pullNum)-1], cmd[len(cmd)-1], vcsHost[len(vcsHost)-1]
|
||||
}
|
||||
|
||||
func (c *CommandRunner_ExecuteCommand_OngoingVerification) GetAllCapturedArguments() (_param0 []*events.CommandContext) {
|
||||
func (c *CommandRunner_ExecuteCommand_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.Repo, _param2 []models.User, _param3 []int, _param4 []*events.Command, _param5 []vcs.Host) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]*events.CommandContext, len(params[0]))
|
||||
_param0 = make([]models.Repo, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(*events.CommandContext)
|
||||
_param0[u] = param.(models.Repo)
|
||||
}
|
||||
_param1 = make([]models.Repo, len(params[1]))
|
||||
for u, param := range params[1] {
|
||||
_param1[u] = param.(models.Repo)
|
||||
}
|
||||
_param2 = make([]models.User, len(params[2]))
|
||||
for u, param := range params[2] {
|
||||
_param2[u] = param.(models.User)
|
||||
}
|
||||
_param3 = make([]int, len(params[3]))
|
||||
for u, param := range params[3] {
|
||||
_param3[u] = param.(int)
|
||||
}
|
||||
_param4 = make([]*events.Command, len(params[4]))
|
||||
for u, param := range params[4] {
|
||||
_param4[u] = param.(*events.Command)
|
||||
}
|
||||
_param5 = make([]vcs.Host, len(params[5]))
|
||||
for u, param := range params[5] {
|
||||
_param5[u] = param.(vcs.Host)
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
136
server/events/mocks/mock_commit_status_updater.go
Normal file
136
server/events/mocks/mock_commit_status_updater.go
Normal file
@@ -0,0 +1,136 @@
|
||||
// Automatically generated by pegomock. DO NOT EDIT!
|
||||
// Source: github.com/hootsuite/atlantis/server/events (interfaces: CommitStatusUpdater)
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
events "github.com/hootsuite/atlantis/server/events"
|
||||
models "github.com/hootsuite/atlantis/server/events/models"
|
||||
vcs "github.com/hootsuite/atlantis/server/events/vcs"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type MockCommitStatusUpdater struct {
|
||||
fail func(message string, callerSkip ...int)
|
||||
}
|
||||
|
||||
func NewMockCommitStatusUpdater() *MockCommitStatusUpdater {
|
||||
return &MockCommitStatusUpdater{fail: pegomock.GlobalFailHandler}
|
||||
}
|
||||
|
||||
func (mock *MockCommitStatusUpdater) Update(repo models.Repo, pull models.PullRequest, status vcs.CommitStatus, cmd *events.Command, host vcs.Host) error {
|
||||
params := []pegomock.Param{repo, pull, status, cmd, host}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("Update", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 error
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].(error)
|
||||
}
|
||||
}
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mock *MockCommitStatusUpdater) UpdateProjectResult(ctx *events.CommandContext, res events.CommandResponse) error {
|
||||
params := []pegomock.Param{ctx, res}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateProjectResult", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 error
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].(error)
|
||||
}
|
||||
}
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mock *MockCommitStatusUpdater) VerifyWasCalledOnce() *VerifierCommitStatusUpdater {
|
||||
return &VerifierCommitStatusUpdater{mock, pegomock.Times(1), nil}
|
||||
}
|
||||
|
||||
func (mock *MockCommitStatusUpdater) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierCommitStatusUpdater {
|
||||
return &VerifierCommitStatusUpdater{mock, invocationCountMatcher, nil}
|
||||
}
|
||||
|
||||
func (mock *MockCommitStatusUpdater) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierCommitStatusUpdater {
|
||||
return &VerifierCommitStatusUpdater{mock, invocationCountMatcher, inOrderContext}
|
||||
}
|
||||
|
||||
type VerifierCommitStatusUpdater struct {
|
||||
mock *MockCommitStatusUpdater
|
||||
invocationCountMatcher pegomock.Matcher
|
||||
inOrderContext *pegomock.InOrderContext
|
||||
}
|
||||
|
||||
func (verifier *VerifierCommitStatusUpdater) Update(repo models.Repo, pull models.PullRequest, status vcs.CommitStatus, cmd *events.Command, host vcs.Host) *CommitStatusUpdater_Update_OngoingVerification {
|
||||
params := []pegomock.Param{repo, pull, status, cmd, host}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Update", params)
|
||||
return &CommitStatusUpdater_Update_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type CommitStatusUpdater_Update_OngoingVerification struct {
|
||||
mock *MockCommitStatusUpdater
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *CommitStatusUpdater_Update_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, vcs.CommitStatus, *events.Command, vcs.Host) {
|
||||
repo, pull, status, cmd, host := c.GetAllCapturedArguments()
|
||||
return repo[len(repo)-1], pull[len(pull)-1], status[len(status)-1], cmd[len(cmd)-1], host[len(host)-1]
|
||||
}
|
||||
|
||||
func (c *CommitStatusUpdater_Update_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []vcs.CommitStatus, _param3 []*events.Command, _param4 []vcs.Host) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]models.Repo, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(models.Repo)
|
||||
}
|
||||
_param1 = make([]models.PullRequest, len(params[1]))
|
||||
for u, param := range params[1] {
|
||||
_param1[u] = param.(models.PullRequest)
|
||||
}
|
||||
_param2 = make([]vcs.CommitStatus, len(params[2]))
|
||||
for u, param := range params[2] {
|
||||
_param2[u] = param.(vcs.CommitStatus)
|
||||
}
|
||||
_param3 = make([]*events.Command, len(params[3]))
|
||||
for u, param := range params[3] {
|
||||
_param3[u] = param.(*events.Command)
|
||||
}
|
||||
_param4 = make([]vcs.Host, len(params[4]))
|
||||
for u, param := range params[4] {
|
||||
_param4[u] = param.(vcs.Host)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierCommitStatusUpdater) UpdateProjectResult(ctx *events.CommandContext, res events.CommandResponse) *CommitStatusUpdater_UpdateProjectResult_OngoingVerification {
|
||||
params := []pegomock.Param{ctx, res}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateProjectResult", params)
|
||||
return &CommitStatusUpdater_UpdateProjectResult_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type CommitStatusUpdater_UpdateProjectResult_OngoingVerification struct {
|
||||
mock *MockCommitStatusUpdater
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *CommitStatusUpdater_UpdateProjectResult_OngoingVerification) GetCapturedArguments() (*events.CommandContext, events.CommandResponse) {
|
||||
ctx, res := c.GetAllCapturedArguments()
|
||||
return ctx[len(ctx)-1], res[len(res)-1]
|
||||
}
|
||||
|
||||
func (c *CommitStatusUpdater_UpdateProjectResult_OngoingVerification) GetAllCapturedArguments() (_param0 []*events.CommandContext, _param1 []events.CommandResponse) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]*events.CommandContext, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(*events.CommandContext)
|
||||
}
|
||||
_param1 = make([]events.CommandResponse, len(params[1]))
|
||||
for u, param := range params[1] {
|
||||
_param1[u] = param.(events.CommandResponse)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -4,8 +4,9 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
"reflect"
|
||||
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
)
|
||||
|
||||
type MockEnvLocker struct {
|
||||
|
||||
@@ -4,11 +4,14 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
github "github.com/google/go-github/github"
|
||||
events "github.com/hootsuite/atlantis/server/events"
|
||||
models "github.com/hootsuite/atlantis/server/events/models"
|
||||
vcs "github.com/hootsuite/atlantis/server/events/vcs"
|
||||
go_gitlab "github.com/lkysow/go-gitlab"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type MockEventParsing struct {
|
||||
@@ -19,8 +22,8 @@ func NewMockEventParsing() *MockEventParsing {
|
||||
return &MockEventParsing{fail: pegomock.GlobalFailHandler}
|
||||
}
|
||||
|
||||
func (mock *MockEventParsing) DetermineCommand(comment *github.IssueCommentEvent) (*events.Command, error) {
|
||||
params := []pegomock.Param{comment}
|
||||
func (mock *MockEventParsing) DetermineCommand(comment string, vcsHost vcs.Host) (*events.Command, error) {
|
||||
params := []pegomock.Param{comment, vcsHost}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("DetermineCommand", params, []reflect.Type{reflect.TypeOf((**events.Command)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 *events.Command
|
||||
var ret1 error
|
||||
@@ -35,12 +38,12 @@ func (mock *MockEventParsing) DetermineCommand(comment *github.IssueCommentEvent
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
func (mock *MockEventParsing) ExtractCommentData(comment *github.IssueCommentEvent) (models.Repo, models.User, models.PullRequest, error) {
|
||||
func (mock *MockEventParsing) ParseGithubIssueCommentEvent(comment *github.IssueCommentEvent) (models.Repo, models.User, int, error) {
|
||||
params := []pegomock.Param{comment}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("ExtractCommentData", params, []reflect.Type{reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGithubIssueCommentEvent", params, []reflect.Type{reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*int)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 models.Repo
|
||||
var ret1 models.User
|
||||
var ret2 models.PullRequest
|
||||
var ret2 int
|
||||
var ret3 error
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
@@ -50,7 +53,7 @@ func (mock *MockEventParsing) ExtractCommentData(comment *github.IssueCommentEve
|
||||
ret1 = result[1].(models.User)
|
||||
}
|
||||
if result[2] != nil {
|
||||
ret2 = result[2].(models.PullRequest)
|
||||
ret2 = result[2].(int)
|
||||
}
|
||||
if result[3] != nil {
|
||||
ret3 = result[3].(error)
|
||||
@@ -59,9 +62,9 @@ func (mock *MockEventParsing) ExtractCommentData(comment *github.IssueCommentEve
|
||||
return ret0, ret1, ret2, ret3
|
||||
}
|
||||
|
||||
func (mock *MockEventParsing) ExtractPullData(pull *github.PullRequest) (models.PullRequest, models.Repo, error) {
|
||||
func (mock *MockEventParsing) ParseGithubPull(pull *github.PullRequest) (models.PullRequest, models.Repo, error) {
|
||||
params := []pegomock.Param{pull}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("ExtractPullData", params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGithubPull", params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 models.PullRequest
|
||||
var ret1 models.Repo
|
||||
var ret2 error
|
||||
@@ -79,9 +82,9 @@ func (mock *MockEventParsing) ExtractPullData(pull *github.PullRequest) (models.
|
||||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
func (mock *MockEventParsing) ExtractRepoData(ghRepo *github.Repository) (models.Repo, error) {
|
||||
func (mock *MockEventParsing) ParseGithubRepo(ghRepo *github.Repository) (models.Repo, error) {
|
||||
params := []pegomock.Param{ghRepo}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("ExtractRepoData", params, []reflect.Type{reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGithubRepo", params, []reflect.Type{reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 models.Repo
|
||||
var ret1 error
|
||||
if len(result) != 0 {
|
||||
@@ -95,6 +98,54 @@ func (mock *MockEventParsing) ExtractRepoData(ghRepo *github.Repository) (models
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
func (mock *MockEventParsing) ParseGitlabMergeEvent(event go_gitlab.MergeEvent) (models.PullRequest, models.Repo) {
|
||||
params := []pegomock.Param{event}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGitlabMergeEvent", params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem()})
|
||||
var ret0 models.PullRequest
|
||||
var ret1 models.Repo
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].(models.PullRequest)
|
||||
}
|
||||
if result[1] != nil {
|
||||
ret1 = result[1].(models.Repo)
|
||||
}
|
||||
}
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
func (mock *MockEventParsing) ParseGitlabMergeCommentEvent(event go_gitlab.MergeCommentEvent) (models.Repo, models.Repo, models.User) {
|
||||
params := []pegomock.Param{event}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGitlabMergeCommentEvent", params, []reflect.Type{reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem()})
|
||||
var ret0 models.Repo
|
||||
var ret1 models.Repo
|
||||
var ret2 models.User
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].(models.Repo)
|
||||
}
|
||||
if result[1] != nil {
|
||||
ret1 = result[1].(models.Repo)
|
||||
}
|
||||
if result[2] != nil {
|
||||
ret2 = result[2].(models.User)
|
||||
}
|
||||
}
|
||||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
func (mock *MockEventParsing) ParseGitlabMergeRequest(mr *go_gitlab.MergeRequest) models.PullRequest {
|
||||
params := []pegomock.Param{mr}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGitlabMergeRequest", params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem()})
|
||||
var ret0 models.PullRequest
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].(models.PullRequest)
|
||||
}
|
||||
}
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mock *MockEventParsing) VerifyWasCalledOnce() *VerifierEventParsing {
|
||||
return &VerifierEventParsing{mock, pegomock.Times(1), nil}
|
||||
}
|
||||
@@ -113,8 +164,8 @@ type VerifierEventParsing struct {
|
||||
inOrderContext *pegomock.InOrderContext
|
||||
}
|
||||
|
||||
func (verifier *VerifierEventParsing) DetermineCommand(comment *github.IssueCommentEvent) *EventParsing_DetermineCommand_OngoingVerification {
|
||||
params := []pegomock.Param{comment}
|
||||
func (verifier *VerifierEventParsing) DetermineCommand(comment string, vcsHost vcs.Host) *EventParsing_DetermineCommand_OngoingVerification {
|
||||
params := []pegomock.Param{comment, vcsHost}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DetermineCommand", params)
|
||||
return &EventParsing_DetermineCommand_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
@@ -124,39 +175,43 @@ type EventParsing_DetermineCommand_OngoingVerification struct {
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *EventParsing_DetermineCommand_OngoingVerification) GetCapturedArguments() *github.IssueCommentEvent {
|
||||
comment := c.GetAllCapturedArguments()
|
||||
return comment[len(comment)-1]
|
||||
func (c *EventParsing_DetermineCommand_OngoingVerification) GetCapturedArguments() (string, vcs.Host) {
|
||||
comment, vcsHost := c.GetAllCapturedArguments()
|
||||
return comment[len(comment)-1], vcsHost[len(vcsHost)-1]
|
||||
}
|
||||
|
||||
func (c *EventParsing_DetermineCommand_OngoingVerification) GetAllCapturedArguments() (_param0 []*github.IssueCommentEvent) {
|
||||
func (c *EventParsing_DetermineCommand_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []vcs.Host) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]*github.IssueCommentEvent, len(params[0]))
|
||||
_param0 = make([]string, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(*github.IssueCommentEvent)
|
||||
_param0[u] = param.(string)
|
||||
}
|
||||
_param1 = make([]vcs.Host, len(params[1]))
|
||||
for u, param := range params[1] {
|
||||
_param1[u] = param.(vcs.Host)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierEventParsing) ExtractCommentData(comment *github.IssueCommentEvent) *EventParsing_ExtractCommentData_OngoingVerification {
|
||||
func (verifier *VerifierEventParsing) ParseGithubIssueCommentEvent(comment *github.IssueCommentEvent) *EventParsing_ParseGithubIssueCommentEvent_OngoingVerification {
|
||||
params := []pegomock.Param{comment}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ExtractCommentData", params)
|
||||
return &EventParsing_ExtractCommentData_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGithubIssueCommentEvent", params)
|
||||
return &EventParsing_ParseGithubIssueCommentEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type EventParsing_ExtractCommentData_OngoingVerification struct {
|
||||
type EventParsing_ParseGithubIssueCommentEvent_OngoingVerification struct {
|
||||
mock *MockEventParsing
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *EventParsing_ExtractCommentData_OngoingVerification) GetCapturedArguments() *github.IssueCommentEvent {
|
||||
func (c *EventParsing_ParseGithubIssueCommentEvent_OngoingVerification) GetCapturedArguments() *github.IssueCommentEvent {
|
||||
comment := c.GetAllCapturedArguments()
|
||||
return comment[len(comment)-1]
|
||||
}
|
||||
|
||||
func (c *EventParsing_ExtractCommentData_OngoingVerification) GetAllCapturedArguments() (_param0 []*github.IssueCommentEvent) {
|
||||
func (c *EventParsing_ParseGithubIssueCommentEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []*github.IssueCommentEvent) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]*github.IssueCommentEvent, len(params[0]))
|
||||
@@ -167,23 +222,23 @@ func (c *EventParsing_ExtractCommentData_OngoingVerification) GetAllCapturedArgu
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierEventParsing) ExtractPullData(pull *github.PullRequest) *EventParsing_ExtractPullData_OngoingVerification {
|
||||
func (verifier *VerifierEventParsing) ParseGithubPull(pull *github.PullRequest) *EventParsing_ParseGithubPull_OngoingVerification {
|
||||
params := []pegomock.Param{pull}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ExtractPullData", params)
|
||||
return &EventParsing_ExtractPullData_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGithubPull", params)
|
||||
return &EventParsing_ParseGithubPull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type EventParsing_ExtractPullData_OngoingVerification struct {
|
||||
type EventParsing_ParseGithubPull_OngoingVerification struct {
|
||||
mock *MockEventParsing
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *EventParsing_ExtractPullData_OngoingVerification) GetCapturedArguments() *github.PullRequest {
|
||||
func (c *EventParsing_ParseGithubPull_OngoingVerification) GetCapturedArguments() *github.PullRequest {
|
||||
pull := c.GetAllCapturedArguments()
|
||||
return pull[len(pull)-1]
|
||||
}
|
||||
|
||||
func (c *EventParsing_ExtractPullData_OngoingVerification) GetAllCapturedArguments() (_param0 []*github.PullRequest) {
|
||||
func (c *EventParsing_ParseGithubPull_OngoingVerification) GetAllCapturedArguments() (_param0 []*github.PullRequest) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]*github.PullRequest, len(params[0]))
|
||||
@@ -194,23 +249,23 @@ func (c *EventParsing_ExtractPullData_OngoingVerification) GetAllCapturedArgumen
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierEventParsing) ExtractRepoData(ghRepo *github.Repository) *EventParsing_ExtractRepoData_OngoingVerification {
|
||||
func (verifier *VerifierEventParsing) ParseGithubRepo(ghRepo *github.Repository) *EventParsing_ParseGithubRepo_OngoingVerification {
|
||||
params := []pegomock.Param{ghRepo}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ExtractRepoData", params)
|
||||
return &EventParsing_ExtractRepoData_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGithubRepo", params)
|
||||
return &EventParsing_ParseGithubRepo_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type EventParsing_ExtractRepoData_OngoingVerification struct {
|
||||
type EventParsing_ParseGithubRepo_OngoingVerification struct {
|
||||
mock *MockEventParsing
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *EventParsing_ExtractRepoData_OngoingVerification) GetCapturedArguments() *github.Repository {
|
||||
func (c *EventParsing_ParseGithubRepo_OngoingVerification) GetCapturedArguments() *github.Repository {
|
||||
ghRepo := c.GetAllCapturedArguments()
|
||||
return ghRepo[len(ghRepo)-1]
|
||||
}
|
||||
|
||||
func (c *EventParsing_ExtractRepoData_OngoingVerification) GetAllCapturedArguments() (_param0 []*github.Repository) {
|
||||
func (c *EventParsing_ParseGithubRepo_OngoingVerification) GetAllCapturedArguments() (_param0 []*github.Repository) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]*github.Repository, len(params[0]))
|
||||
@@ -220,3 +275,84 @@ func (c *EventParsing_ExtractRepoData_OngoingVerification) GetAllCapturedArgumen
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierEventParsing) ParseGitlabMergeEvent(event go_gitlab.MergeEvent) *EventParsing_ParseGitlabMergeEvent_OngoingVerification {
|
||||
params := []pegomock.Param{event}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGitlabMergeEvent", params)
|
||||
return &EventParsing_ParseGitlabMergeEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type EventParsing_ParseGitlabMergeEvent_OngoingVerification struct {
|
||||
mock *MockEventParsing
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *EventParsing_ParseGitlabMergeEvent_OngoingVerification) GetCapturedArguments() go_gitlab.MergeEvent {
|
||||
event := c.GetAllCapturedArguments()
|
||||
return event[len(event)-1]
|
||||
}
|
||||
|
||||
func (c *EventParsing_ParseGitlabMergeEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []go_gitlab.MergeEvent) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]go_gitlab.MergeEvent, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(go_gitlab.MergeEvent)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierEventParsing) ParseGitlabMergeCommentEvent(event go_gitlab.MergeCommentEvent) *EventParsing_ParseGitlabMergeCommentEvent_OngoingVerification {
|
||||
params := []pegomock.Param{event}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGitlabMergeCommentEvent", params)
|
||||
return &EventParsing_ParseGitlabMergeCommentEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type EventParsing_ParseGitlabMergeCommentEvent_OngoingVerification struct {
|
||||
mock *MockEventParsing
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *EventParsing_ParseGitlabMergeCommentEvent_OngoingVerification) GetCapturedArguments() go_gitlab.MergeCommentEvent {
|
||||
event := c.GetAllCapturedArguments()
|
||||
return event[len(event)-1]
|
||||
}
|
||||
|
||||
func (c *EventParsing_ParseGitlabMergeCommentEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []go_gitlab.MergeCommentEvent) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]go_gitlab.MergeCommentEvent, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(go_gitlab.MergeCommentEvent)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierEventParsing) ParseGitlabMergeRequest(mr *go_gitlab.MergeRequest) *EventParsing_ParseGitlabMergeRequest_OngoingVerification {
|
||||
params := []pegomock.Param{mr}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGitlabMergeRequest", params)
|
||||
return &EventParsing_ParseGitlabMergeRequest_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type EventParsing_ParseGitlabMergeRequest_OngoingVerification struct {
|
||||
mock *MockEventParsing
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *EventParsing_ParseGitlabMergeRequest_OngoingVerification) GetCapturedArguments() *go_gitlab.MergeRequest {
|
||||
mr := c.GetAllCapturedArguments()
|
||||
return mr[len(mr)-1]
|
||||
}
|
||||
|
||||
func (c *EventParsing_ParseGitlabMergeRequest_OngoingVerification) GetAllCapturedArguments() (_param0 []*go_gitlab.MergeRequest) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]*go_gitlab.MergeRequest, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(*go_gitlab.MergeRequest)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
events "github.com/hootsuite/atlantis/server/events"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type MockExecutor struct {
|
||||
|
||||
85
server/events/mocks/mock_github_pull_getter.go
Normal file
85
server/events/mocks/mock_github_pull_getter.go
Normal file
@@ -0,0 +1,85 @@
|
||||
// Automatically generated by pegomock. DO NOT EDIT!
|
||||
// Source: github.com/hootsuite/atlantis/server/events (interfaces: GithubPullGetter)
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
github "github.com/google/go-github/github"
|
||||
models "github.com/hootsuite/atlantis/server/events/models"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
)
|
||||
|
||||
type MockGithubPullGetter struct {
|
||||
fail func(message string, callerSkip ...int)
|
||||
}
|
||||
|
||||
func NewMockGithubPullGetter() *MockGithubPullGetter {
|
||||
return &MockGithubPullGetter{fail: pegomock.GlobalFailHandler}
|
||||
}
|
||||
|
||||
func (mock *MockGithubPullGetter) GetPullRequest(repo models.Repo, pullNum int) (*github.PullRequest, error) {
|
||||
params := []pegomock.Param{repo, pullNum}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("GetPullRequest", params, []reflect.Type{reflect.TypeOf((**github.PullRequest)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 *github.PullRequest
|
||||
var ret1 error
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].(*github.PullRequest)
|
||||
}
|
||||
if result[1] != nil {
|
||||
ret1 = result[1].(error)
|
||||
}
|
||||
}
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
func (mock *MockGithubPullGetter) VerifyWasCalledOnce() *VerifierGithubPullGetter {
|
||||
return &VerifierGithubPullGetter{mock, pegomock.Times(1), nil}
|
||||
}
|
||||
|
||||
func (mock *MockGithubPullGetter) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierGithubPullGetter {
|
||||
return &VerifierGithubPullGetter{mock, invocationCountMatcher, nil}
|
||||
}
|
||||
|
||||
func (mock *MockGithubPullGetter) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierGithubPullGetter {
|
||||
return &VerifierGithubPullGetter{mock, invocationCountMatcher, inOrderContext}
|
||||
}
|
||||
|
||||
type VerifierGithubPullGetter struct {
|
||||
mock *MockGithubPullGetter
|
||||
invocationCountMatcher pegomock.Matcher
|
||||
inOrderContext *pegomock.InOrderContext
|
||||
}
|
||||
|
||||
func (verifier *VerifierGithubPullGetter) GetPullRequest(repo models.Repo, pullNum int) *GithubPullGetter_GetPullRequest_OngoingVerification {
|
||||
params := []pegomock.Param{repo, pullNum}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullRequest", params)
|
||||
return &GithubPullGetter_GetPullRequest_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type GithubPullGetter_GetPullRequest_OngoingVerification struct {
|
||||
mock *MockGithubPullGetter
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *GithubPullGetter_GetPullRequest_OngoingVerification) GetCapturedArguments() (models.Repo, int) {
|
||||
repo, pullNum := c.GetAllCapturedArguments()
|
||||
return repo[len(repo)-1], pullNum[len(pullNum)-1]
|
||||
}
|
||||
|
||||
func (c *GithubPullGetter_GetPullRequest_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []int) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]models.Repo, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(models.Repo)
|
||||
}
|
||||
_param1 = make([]int, len(params[1]))
|
||||
for u, param := range params[1] {
|
||||
_param1[u] = param.(int)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
// Automatically generated by pegomock. DO NOT EDIT!
|
||||
// Source: github.com/hootsuite/atlantis/server/events (interfaces: GHStatusUpdater)
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
events "github.com/hootsuite/atlantis/server/events"
|
||||
models "github.com/hootsuite/atlantis/server/events/models"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type MockGHStatusUpdater struct {
|
||||
fail func(message string, callerSkip ...int)
|
||||
}
|
||||
|
||||
func NewMockGHStatusUpdater() *MockGHStatusUpdater {
|
||||
return &MockGHStatusUpdater{fail: pegomock.GlobalFailHandler}
|
||||
}
|
||||
|
||||
func (mock *MockGHStatusUpdater) Update(repo models.Repo, pull models.PullRequest, status events.Status, cmd *events.Command) error {
|
||||
params := []pegomock.Param{repo, pull, status, cmd}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("Update", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 error
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].(error)
|
||||
}
|
||||
}
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mock *MockGHStatusUpdater) UpdateProjectResult(ctx *events.CommandContext, res events.CommandResponse) error {
|
||||
params := []pegomock.Param{ctx, res}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateProjectResult", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 error
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].(error)
|
||||
}
|
||||
}
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mock *MockGHStatusUpdater) VerifyWasCalledOnce() *VerifierGHStatusUpdater {
|
||||
return &VerifierGHStatusUpdater{mock, pegomock.Times(1), nil}
|
||||
}
|
||||
|
||||
func (mock *MockGHStatusUpdater) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierGHStatusUpdater {
|
||||
return &VerifierGHStatusUpdater{mock, invocationCountMatcher, nil}
|
||||
}
|
||||
|
||||
func (mock *MockGHStatusUpdater) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierGHStatusUpdater {
|
||||
return &VerifierGHStatusUpdater{mock, invocationCountMatcher, inOrderContext}
|
||||
}
|
||||
|
||||
type VerifierGHStatusUpdater struct {
|
||||
mock *MockGHStatusUpdater
|
||||
invocationCountMatcher pegomock.Matcher
|
||||
inOrderContext *pegomock.InOrderContext
|
||||
}
|
||||
|
||||
func (verifier *VerifierGHStatusUpdater) Update(repo models.Repo, pull models.PullRequest, status events.Status, cmd *events.Command) *GHStatusUpdater_Update_OngoingVerification {
|
||||
params := []pegomock.Param{repo, pull, status, cmd}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Update", params)
|
||||
return &GHStatusUpdater_Update_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type GHStatusUpdater_Update_OngoingVerification struct {
|
||||
mock *MockGHStatusUpdater
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *GHStatusUpdater_Update_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, events.Status, *events.Command) {
|
||||
repo, pull, status, cmd := c.GetAllCapturedArguments()
|
||||
return repo[len(repo)-1], pull[len(pull)-1], status[len(status)-1], cmd[len(cmd)-1]
|
||||
}
|
||||
|
||||
func (c *GHStatusUpdater_Update_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []events.Status, _param3 []*events.Command) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]models.Repo, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(models.Repo)
|
||||
}
|
||||
_param1 = make([]models.PullRequest, len(params[1]))
|
||||
for u, param := range params[1] {
|
||||
_param1[u] = param.(models.PullRequest)
|
||||
}
|
||||
_param2 = make([]events.Status, len(params[2]))
|
||||
for u, param := range params[2] {
|
||||
_param2[u] = param.(events.Status)
|
||||
}
|
||||
_param3 = make([]*events.Command, len(params[3]))
|
||||
for u, param := range params[3] {
|
||||
_param3[u] = param.(*events.Command)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierGHStatusUpdater) UpdateProjectResult(ctx *events.CommandContext, res events.CommandResponse) *GHStatusUpdater_UpdateProjectResult_OngoingVerification {
|
||||
params := []pegomock.Param{ctx, res}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateProjectResult", params)
|
||||
return &GHStatusUpdater_UpdateProjectResult_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type GHStatusUpdater_UpdateProjectResult_OngoingVerification struct {
|
||||
mock *MockGHStatusUpdater
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *GHStatusUpdater_UpdateProjectResult_OngoingVerification) GetCapturedArguments() (*events.CommandContext, events.CommandResponse) {
|
||||
ctx, res := c.GetAllCapturedArguments()
|
||||
return ctx[len(ctx)-1], res[len(res)-1]
|
||||
}
|
||||
|
||||
func (c *GHStatusUpdater_UpdateProjectResult_OngoingVerification) GetAllCapturedArguments() (_param0 []*events.CommandContext, _param1 []events.CommandResponse) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]*events.CommandContext, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(*events.CommandContext)
|
||||
}
|
||||
_param1 = make([]events.CommandResponse, len(params[1]))
|
||||
for u, param := range params[1] {
|
||||
_param1[u] = param.(events.CommandResponse)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
84
server/events/mocks/mock_gitlab_merge_request_getter.go
Normal file
84
server/events/mocks/mock_gitlab_merge_request_getter.go
Normal file
@@ -0,0 +1,84 @@
|
||||
// Automatically generated by pegomock. DO NOT EDIT!
|
||||
// Source: github.com/hootsuite/atlantis/server/events (interfaces: GitlabMergeRequestGetter)
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
go_gitlab "github.com/lkysow/go-gitlab"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
)
|
||||
|
||||
type MockGitlabMergeRequestGetter struct {
|
||||
fail func(message string, callerSkip ...int)
|
||||
}
|
||||
|
||||
func NewMockGitlabMergeRequestGetter() *MockGitlabMergeRequestGetter {
|
||||
return &MockGitlabMergeRequestGetter{fail: pegomock.GlobalFailHandler}
|
||||
}
|
||||
|
||||
func (mock *MockGitlabMergeRequestGetter) GetMergeRequest(repoFullName string, pullNum int) (*go_gitlab.MergeRequest, error) {
|
||||
params := []pegomock.Param{repoFullName, pullNum}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("GetMergeRequest", params, []reflect.Type{reflect.TypeOf((**go_gitlab.MergeRequest)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 *go_gitlab.MergeRequest
|
||||
var ret1 error
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].(*go_gitlab.MergeRequest)
|
||||
}
|
||||
if result[1] != nil {
|
||||
ret1 = result[1].(error)
|
||||
}
|
||||
}
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
func (mock *MockGitlabMergeRequestGetter) VerifyWasCalledOnce() *VerifierGitlabMergeRequestGetter {
|
||||
return &VerifierGitlabMergeRequestGetter{mock, pegomock.Times(1), nil}
|
||||
}
|
||||
|
||||
func (mock *MockGitlabMergeRequestGetter) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierGitlabMergeRequestGetter {
|
||||
return &VerifierGitlabMergeRequestGetter{mock, invocationCountMatcher, nil}
|
||||
}
|
||||
|
||||
func (mock *MockGitlabMergeRequestGetter) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierGitlabMergeRequestGetter {
|
||||
return &VerifierGitlabMergeRequestGetter{mock, invocationCountMatcher, inOrderContext}
|
||||
}
|
||||
|
||||
type VerifierGitlabMergeRequestGetter struct {
|
||||
mock *MockGitlabMergeRequestGetter
|
||||
invocationCountMatcher pegomock.Matcher
|
||||
inOrderContext *pegomock.InOrderContext
|
||||
}
|
||||
|
||||
func (verifier *VerifierGitlabMergeRequestGetter) GetMergeRequest(repoFullName string, pullNum int) *GitlabMergeRequestGetter_GetMergeRequest_OngoingVerification {
|
||||
params := []pegomock.Param{repoFullName, pullNum}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetMergeRequest", params)
|
||||
return &GitlabMergeRequestGetter_GetMergeRequest_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type GitlabMergeRequestGetter_GetMergeRequest_OngoingVerification struct {
|
||||
mock *MockGitlabMergeRequestGetter
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *GitlabMergeRequestGetter_GetMergeRequest_OngoingVerification) GetCapturedArguments() (string, int) {
|
||||
repoFullName, pullNum := c.GetAllCapturedArguments()
|
||||
return repoFullName[len(repoFullName)-1], pullNum[len(pullNum)-1]
|
||||
}
|
||||
|
||||
func (c *GitlabMergeRequestGetter_GetMergeRequest_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []int) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]string, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(string)
|
||||
}
|
||||
_param1 = make([]int, len(params[1]))
|
||||
for u, param := range params[1] {
|
||||
_param1[u] = param.(int)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -4,8 +4,9 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
"reflect"
|
||||
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
)
|
||||
|
||||
type MockLockURLGenerator struct {
|
||||
|
||||
@@ -19,7 +19,7 @@ func NewMockModifiedProjectFinder() *MockModifiedProjectFinder {
|
||||
return &MockModifiedProjectFinder{fail: pegomock.GlobalFailHandler}
|
||||
}
|
||||
|
||||
func (mock *MockModifiedProjectFinder) GetModified(log *logging.SimpleLogger, modifiedFiles []string, repoFullName string) []models.Project {
|
||||
func (mock *MockModifiedProjectFinder) FindModified(log *logging.SimpleLogger, modifiedFiles []string, repoFullName string) []models.Project {
|
||||
params := []pegomock.Param{log, modifiedFiles, repoFullName}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("FindModified", params, []reflect.Type{reflect.TypeOf((*[]models.Project)(nil)).Elem()})
|
||||
var ret0 []models.Project
|
||||
@@ -49,23 +49,23 @@ type VerifierModifiedProjectFinder struct {
|
||||
inOrderContext *pegomock.InOrderContext
|
||||
}
|
||||
|
||||
func (verifier *VerifierModifiedProjectFinder) GetModified(log *logging.SimpleLogger, modifiedFiles []string, repoFullName string) *ModifiedProjectFinder_GetModified_OngoingVerification {
|
||||
func (verifier *VerifierModifiedProjectFinder) FindModified(log *logging.SimpleLogger, modifiedFiles []string, repoFullName string) *ModifiedProjectFinder_FindModified_OngoingVerification {
|
||||
params := []pegomock.Param{log, modifiedFiles, repoFullName}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "FindModified", params)
|
||||
return &ModifiedProjectFinder_GetModified_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
return &ModifiedProjectFinder_FindModified_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type ModifiedProjectFinder_GetModified_OngoingVerification struct {
|
||||
type ModifiedProjectFinder_FindModified_OngoingVerification struct {
|
||||
mock *MockModifiedProjectFinder
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *ModifiedProjectFinder_GetModified_OngoingVerification) GetCapturedArguments() (*logging.SimpleLogger, []string, string) {
|
||||
func (c *ModifiedProjectFinder_FindModified_OngoingVerification) GetCapturedArguments() (*logging.SimpleLogger, []string, string) {
|
||||
log, modifiedFiles, repoFullName := c.GetAllCapturedArguments()
|
||||
return log[len(log)-1], modifiedFiles[len(modifiedFiles)-1], repoFullName[len(repoFullName)-1]
|
||||
}
|
||||
|
||||
func (c *ModifiedProjectFinder_GetModified_OngoingVerification) GetAllCapturedArguments() (_param0 []*logging.SimpleLogger, _param1 [][]string, _param2 []string) {
|
||||
func (c *ModifiedProjectFinder_FindModified_OngoingVerification) GetAllCapturedArguments() (_param0 []*logging.SimpleLogger, _param1 [][]string, _param2 []string) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]*logging.SimpleLogger, len(params[0]))
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
// Automatically generated by pegomock. DO NOT EDIT!
|
||||
// Source: github.com/hootsuite/atlantis/server/events (interfaces: Planner)
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
events "github.com/hootsuite/atlantis/server/events"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type MockPlanner struct {
|
||||
fail func(message string, callerSkip ...int)
|
||||
}
|
||||
|
||||
func NewMockPlanner() *MockPlanner {
|
||||
return &MockPlanner{fail: pegomock.GlobalFailHandler}
|
||||
}
|
||||
|
||||
func (mock *MockPlanner) Execute(ctx *events.CommandContext) events.CommandResponse {
|
||||
params := []pegomock.Param{ctx}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("Execute", params, []reflect.Type{reflect.TypeOf((*events.CommandResponse)(nil)).Elem()})
|
||||
var ret0 events.CommandResponse
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].(events.CommandResponse)
|
||||
}
|
||||
}
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mock *MockPlanner) SetLockURL(_param0 func(string) string) {
|
||||
params := []pegomock.Param{_param0}
|
||||
pegomock.GetGenericMockFrom(mock).Invoke("SetLockURL", params, []reflect.Type{})
|
||||
}
|
||||
|
||||
func (mock *MockPlanner) VerifyWasCalledOnce() *VerifierPlanner {
|
||||
return &VerifierPlanner{mock, pegomock.Times(1), nil}
|
||||
}
|
||||
|
||||
func (mock *MockPlanner) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierPlanner {
|
||||
return &VerifierPlanner{mock, invocationCountMatcher, nil}
|
||||
}
|
||||
|
||||
func (mock *MockPlanner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierPlanner {
|
||||
return &VerifierPlanner{mock, invocationCountMatcher, inOrderContext}
|
||||
}
|
||||
|
||||
type VerifierPlanner struct {
|
||||
mock *MockPlanner
|
||||
invocationCountMatcher pegomock.Matcher
|
||||
inOrderContext *pegomock.InOrderContext
|
||||
}
|
||||
|
||||
func (verifier *VerifierPlanner) Execute(ctx *events.CommandContext) *Planner_Execute_OngoingVerification {
|
||||
params := []pegomock.Param{ctx}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Execute", params)
|
||||
return &Planner_Execute_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type Planner_Execute_OngoingVerification struct {
|
||||
mock *MockPlanner
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *Planner_Execute_OngoingVerification) GetCapturedArguments() *events.CommandContext {
|
||||
ctx := c.GetAllCapturedArguments()
|
||||
return ctx[len(ctx)-1]
|
||||
}
|
||||
|
||||
func (c *Planner_Execute_OngoingVerification) GetAllCapturedArguments() (_param0 []*events.CommandContext) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]*events.CommandContext, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(*events.CommandContext)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierPlanner) SetLockURL(_param0 func(string) string) *Planner_SetLockURL_OngoingVerification {
|
||||
params := []pegomock.Param{_param0}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "SetLockURL", params)
|
||||
return &Planner_SetLockURL_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type Planner_SetLockURL_OngoingVerification struct {
|
||||
mock *MockPlanner
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *Planner_SetLockURL_OngoingVerification) GetCapturedArguments() func(string) string {
|
||||
_param0 := c.GetAllCapturedArguments()
|
||||
return _param0[len(_param0)-1]
|
||||
}
|
||||
|
||||
func (c *Planner_SetLockURL_OngoingVerification) GetAllCapturedArguments() (_param0 []func(string) string) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]func(string) string, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(func(string) string)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -4,9 +4,10 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
events "github.com/hootsuite/atlantis/server/events"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type MockProjectConfigReader struct {
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
models "github.com/hootsuite/atlantis/server/events/models"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
"reflect"
|
||||
|
||||
models "github.com/hootsuite/atlantis/server/events/models"
|
||||
vcs "github.com/hootsuite/atlantis/server/events/vcs"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
)
|
||||
|
||||
type MockPullCleaner struct {
|
||||
@@ -17,8 +19,8 @@ func NewMockPullCleaner() *MockPullCleaner {
|
||||
return &MockPullCleaner{fail: pegomock.GlobalFailHandler}
|
||||
}
|
||||
|
||||
func (mock *MockPullCleaner) CleanUpPull(repo models.Repo, pull models.PullRequest) error {
|
||||
params := []pegomock.Param{repo, pull}
|
||||
func (mock *MockPullCleaner) CleanUpPull(repo models.Repo, pull models.PullRequest, host vcs.Host) error {
|
||||
params := []pegomock.Param{repo, pull, host}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("CleanUpPull", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 error
|
||||
if len(result) != 0 {
|
||||
@@ -47,8 +49,8 @@ type VerifierPullCleaner struct {
|
||||
inOrderContext *pegomock.InOrderContext
|
||||
}
|
||||
|
||||
func (verifier *VerifierPullCleaner) CleanUpPull(repo models.Repo, pull models.PullRequest) *PullCleaner_CleanUpPull_OngoingVerification {
|
||||
params := []pegomock.Param{repo, pull}
|
||||
func (verifier *VerifierPullCleaner) CleanUpPull(repo models.Repo, pull models.PullRequest, host vcs.Host) *PullCleaner_CleanUpPull_OngoingVerification {
|
||||
params := []pegomock.Param{repo, pull, host}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CleanUpPull", params)
|
||||
return &PullCleaner_CleanUpPull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
@@ -58,12 +60,12 @@ type PullCleaner_CleanUpPull_OngoingVerification struct {
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *PullCleaner_CleanUpPull_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest) {
|
||||
repo, pull := c.GetAllCapturedArguments()
|
||||
return repo[len(repo)-1], pull[len(pull)-1]
|
||||
func (c *PullCleaner_CleanUpPull_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, vcs.Host) {
|
||||
repo, pull, host := c.GetAllCapturedArguments()
|
||||
return repo[len(repo)-1], pull[len(pull)-1], host[len(host)-1]
|
||||
}
|
||||
|
||||
func (c *PullCleaner_CleanUpPull_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest) {
|
||||
func (c *PullCleaner_CleanUpPull_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []vcs.Host) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]models.Repo, len(params[0]))
|
||||
@@ -74,6 +76,10 @@ func (c *PullCleaner_CleanUpPull_OngoingVerification) GetAllCapturedArguments()
|
||||
for u, param := range params[1] {
|
||||
_param1[u] = param.(models.PullRequest)
|
||||
}
|
||||
_param2 = make([]vcs.Host, len(params[2]))
|
||||
for u, param := range params[2] {
|
||||
_param2[u] = param.(vcs.Host)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
models "github.com/hootsuite/atlantis/server/events/models"
|
||||
logging "github.com/hootsuite/atlantis/server/logging"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type MockWorkspace struct {
|
||||
|
||||
@@ -8,7 +8,6 @@ var Pull = models.PullRequest{
|
||||
Branch: "branch",
|
||||
Author: "lkysow",
|
||||
URL: "url",
|
||||
BaseCommit: "8ed0280678d49d42cd286610aabcfceb5bb673c6",
|
||||
}
|
||||
|
||||
var Repo = models.Repo{
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Repo is a GitHub repository.
|
||||
// Repo is a VCS repository.
|
||||
type Repo struct {
|
||||
// FullName is the owner and repo name separated
|
||||
// by a "/", ex. "hootsuite/atlantis".
|
||||
@@ -25,26 +25,35 @@ type Repo struct {
|
||||
SanitizedCloneURL string
|
||||
}
|
||||
|
||||
// PullRequest is a GitHub pull request.
|
||||
// PullRequest is a VCS pull request.
|
||||
// GitLab calls these Merge Requests.
|
||||
type PullRequest struct {
|
||||
// Num is the pull request number or ID.
|
||||
Num int
|
||||
// HeadCommit points to the head of the branch that is being
|
||||
// pull requested into the base.
|
||||
HeadCommit string
|
||||
// BaseCommit points to the head of the branch that this
|
||||
// pull request will be merged into.
|
||||
BaseCommit string
|
||||
// URL is the url of the pull request.
|
||||
// ex. "https://github.com/hootsuite/atlantis/pull/1"
|
||||
URL string
|
||||
// Branch is the name of the head branch (not the base).
|
||||
Branch string
|
||||
// Author is the GitHub username of the pull request author.
|
||||
// Author is the username of the pull request author.
|
||||
Author string
|
||||
// State will be one of Open or Closed.
|
||||
// Gitlab supports an additional "merged" state but Github doesn't so we map
|
||||
// merged to Closed.
|
||||
State PullRequestState
|
||||
}
|
||||
|
||||
// User is a GitHub user.
|
||||
type PullRequestState int
|
||||
|
||||
const (
|
||||
Open PullRequestState = iota
|
||||
Closed
|
||||
)
|
||||
|
||||
// User is a VCS user.
|
||||
type User struct {
|
||||
Username string
|
||||
}
|
||||
@@ -56,7 +65,7 @@ type ProjectLock struct {
|
||||
// Pull is the pull request from which the command was run that
|
||||
// created this lock.
|
||||
Pull PullRequest
|
||||
// User is the GitHub username of the user that ran the command
|
||||
// User is the username of the user that ran the command
|
||||
// that created this lock.
|
||||
User User
|
||||
// Env is the Terraform environment that this
|
||||
|
||||
@@ -5,11 +5,11 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hootsuite/atlantis/server/events/github"
|
||||
"github.com/hootsuite/atlantis/server/events/locking"
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
"github.com/hootsuite/atlantis/server/events/run"
|
||||
"github.com/hootsuite/atlantis/server/events/terraform"
|
||||
"github.com/hootsuite/atlantis/server/events/vcs"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -22,20 +22,19 @@ type LockURLGenerator interface {
|
||||
}
|
||||
|
||||
// atlantisUserTFVar is the name of the variable we execute terraform
|
||||
// with containing the github username of who is running the command
|
||||
// with, containing the vcs username of who is running the command
|
||||
const atlantisUserTFVar = "atlantis_user"
|
||||
|
||||
// PlanExecutor handles everything related to running terraform plan
|
||||
// including integration with S3, Terraform, and GitHub
|
||||
// PlanExecutor handles everything related to running terraform plan.
|
||||
type PlanExecutor struct {
|
||||
Github github.Client
|
||||
VCSClient vcs.ClientProxy
|
||||
Terraform terraform.Runner
|
||||
Locker locking.Locker
|
||||
LockURL func(id string) (url string)
|
||||
Run run.Runner
|
||||
Workspace Workspace
|
||||
ProjectPreExecute ProjectPreExecutor
|
||||
ModifiedProject ModifiedProjectFinder
|
||||
ProjectFinder ModifiedProjectFinder
|
||||
}
|
||||
|
||||
type PlanSuccess struct {
|
||||
@@ -49,12 +48,12 @@ func (p *PlanExecutor) SetLockURL(f func(id string) (url string)) {
|
||||
|
||||
func (p *PlanExecutor) Execute(ctx *CommandContext) CommandResponse {
|
||||
// figure out what projects have been modified so we know where to run plan
|
||||
modifiedFiles, err := p.Github.GetModifiedFiles(ctx.BaseRepo, ctx.Pull)
|
||||
modifiedFiles, err := p.VCSClient.GetModifiedFiles(ctx.BaseRepo, ctx.Pull, ctx.VCSHost)
|
||||
if err != nil {
|
||||
return CommandResponse{Error: errors.Wrap(err, "getting modified files")}
|
||||
}
|
||||
ctx.Log.Info("found %d files modified in this pull request", len(modifiedFiles))
|
||||
projects := p.ModifiedProject.FindModified(ctx.Log, modifiedFiles, ctx.BaseRepo.FullName)
|
||||
projects := p.ProjectFinder.FindModified(ctx.Log, modifiedFiles, ctx.BaseRepo.FullName)
|
||||
if len(projects) == 0 {
|
||||
return CommandResponse{Failure: "No Terraform files were modified."}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
package events_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"errors"
|
||||
|
||||
"github.com/hootsuite/atlantis/server/events"
|
||||
ghmocks "github.com/hootsuite/atlantis/server/events/github/mocks"
|
||||
"github.com/hootsuite/atlantis/server/events/locking"
|
||||
lmocks "github.com/hootsuite/atlantis/server/events/locking/mocks"
|
||||
"github.com/hootsuite/atlantis/server/events/mocks"
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
rmocks "github.com/hootsuite/atlantis/server/events/run/mocks"
|
||||
tmocks "github.com/hootsuite/atlantis/server/events/terraform/mocks"
|
||||
vcsmocks "github.com/hootsuite/atlantis/server/events/vcs/mocks"
|
||||
"github.com/hootsuite/atlantis/server/logging"
|
||||
. "github.com/hootsuite/atlantis/testing"
|
||||
. "github.com/petergtz/pegomock"
|
||||
@@ -32,10 +31,10 @@ var planCtx = events.CommandContext{
|
||||
},
|
||||
}
|
||||
|
||||
func TestExecute_GithubErr(t *testing.T) {
|
||||
func TestExecute_ModifiedFilesErr(t *testing.T) {
|
||||
t.Log("If GetModifiedFiles returns an error we return an error")
|
||||
p, _, _ := setupPlanExecutorTest(t)
|
||||
When(p.Github.GetModifiedFiles(AnyRepo(), AnyPullRequest())).ThenReturn(nil, errors.New("err"))
|
||||
When(p.VCSClient.GetModifiedFiles(AnyRepo(), AnyPullRequest(), AnyVCSHost())).ThenReturn(nil, errors.New("err"))
|
||||
r := p.Execute(&planCtx)
|
||||
|
||||
Assert(t, r.Error != nil, "exp .Error to be set")
|
||||
@@ -45,7 +44,7 @@ func TestExecute_GithubErr(t *testing.T) {
|
||||
func TestExecute_NoModifiedProjects(t *testing.T) {
|
||||
t.Log("If there are no modified projects we return a failure")
|
||||
p, _, _ := setupPlanExecutorTest(t)
|
||||
// We don't need to actually mock Github.GetModifiedFiles because by
|
||||
// We don't need to actually mock VCSClient.GetModifiedFiles because by
|
||||
// default it will return an empty slice which is what we want for this test.
|
||||
r := p.Execute(&planCtx)
|
||||
|
||||
@@ -55,7 +54,7 @@ func TestExecute_NoModifiedProjects(t *testing.T) {
|
||||
func TestExecute_CloneErr(t *testing.T) {
|
||||
t.Log("If Workspace.Clone returns an error we return an error")
|
||||
p, _, _ := setupPlanExecutorTest(t)
|
||||
When(p.Github.GetModifiedFiles(AnyRepo(), AnyPullRequest())).ThenReturn([]string{"file.tf"}, nil)
|
||||
When(p.VCSClient.GetModifiedFiles(AnyRepo(), AnyPullRequest(), AnyVCSHost())).ThenReturn([]string{"file.tf"}, nil)
|
||||
When(p.Workspace.Clone(planCtx.Log, planCtx.BaseRepo, planCtx.HeadRepo, planCtx.Pull, "env")).ThenReturn("", errors.New("err"))
|
||||
r := p.Execute(&planCtx)
|
||||
|
||||
@@ -66,7 +65,7 @@ func TestExecute_CloneErr(t *testing.T) {
|
||||
func TestExecute_Success(t *testing.T) {
|
||||
t.Log("If there are no errors, the plan should be returned")
|
||||
p, runner, _ := setupPlanExecutorTest(t)
|
||||
When(p.Github.GetModifiedFiles(AnyRepo(), AnyPullRequest())).ThenReturn([]string{"file.tf"}, nil)
|
||||
When(p.VCSClient.GetModifiedFiles(AnyRepo(), AnyPullRequest(), AnyVCSHost())).ThenReturn([]string{"file.tf"}, nil)
|
||||
When(p.Workspace.Clone(planCtx.Log, planCtx.BaseRepo, planCtx.HeadRepo, planCtx.Pull, "env")).
|
||||
ThenReturn("/tmp/clone-repo", nil)
|
||||
When(p.ProjectPreExecute.Execute(&planCtx, "/tmp/clone-repo", models.Project{RepoFullName: "", Path: "."})).
|
||||
@@ -95,7 +94,7 @@ func TestExecute_Success(t *testing.T) {
|
||||
func TestExecute_PreExecuteResult(t *testing.T) {
|
||||
t.Log("If ProjectPreExecute.Execute returns a ProjectResult we should return it")
|
||||
p, _, _ := setupPlanExecutorTest(t)
|
||||
When(p.Github.GetModifiedFiles(AnyRepo(), AnyPullRequest())).ThenReturn([]string{"file.tf"}, nil)
|
||||
When(p.VCSClient.GetModifiedFiles(AnyRepo(), AnyPullRequest(), AnyVCSHost())).ThenReturn([]string{"file.tf"}, nil)
|
||||
When(p.Workspace.Clone(planCtx.Log, planCtx.BaseRepo, planCtx.HeadRepo, planCtx.Pull, "env")).
|
||||
ThenReturn("/tmp/clone-repo", nil)
|
||||
projectResult := events.ProjectResult{
|
||||
@@ -114,7 +113,7 @@ func TestExecute_MultiProjectFailure(t *testing.T) {
|
||||
t.Log("If is an error planning in one project it should be returned. It shouldn't affect another project though.")
|
||||
p, runner, locker := setupPlanExecutorTest(t)
|
||||
// Two projects have been modified so we should run plan in two paths.
|
||||
When(p.Github.GetModifiedFiles(AnyRepo(), AnyPullRequest())).ThenReturn([]string{"path1/file.tf", "path2/file.tf"}, nil)
|
||||
When(p.VCSClient.GetModifiedFiles(AnyRepo(), AnyPullRequest(), AnyVCSHost())).ThenReturn([]string{"path1/file.tf", "path2/file.tf"}, nil)
|
||||
When(p.Workspace.Clone(planCtx.Log, planCtx.BaseRepo, planCtx.HeadRepo, planCtx.Pull, "env")).
|
||||
ThenReturn("/tmp/clone-repo", nil)
|
||||
|
||||
@@ -154,7 +153,7 @@ func TestExecute_MultiProjectFailure(t *testing.T) {
|
||||
func TestExecute_PostPlanCommands(t *testing.T) {
|
||||
t.Log("Should execute post-plan commands and return if there is an error")
|
||||
p, _, _ := setupPlanExecutorTest(t)
|
||||
When(p.Github.GetModifiedFiles(AnyRepo(), AnyPullRequest())).ThenReturn([]string{"file.tf"}, nil)
|
||||
When(p.VCSClient.GetModifiedFiles(AnyRepo(), AnyPullRequest(), AnyVCSHost())).ThenReturn([]string{"file.tf"}, nil)
|
||||
When(p.Workspace.Clone(planCtx.Log, planCtx.BaseRepo, planCtx.HeadRepo, planCtx.Pull, "env")).
|
||||
ThenReturn("/tmp/clone-repo", nil)
|
||||
When(p.ProjectPreExecute.Execute(&planCtx, "/tmp/clone-repo", models.Project{RepoFullName: "", Path: "."})).
|
||||
@@ -174,15 +173,15 @@ func TestExecute_PostPlanCommands(t *testing.T) {
|
||||
|
||||
func setupPlanExecutorTest(t *testing.T) (*events.PlanExecutor, *tmocks.MockRunner, *lmocks.MockLocker) {
|
||||
RegisterMockTestingT(t)
|
||||
gh := ghmocks.NewMockClient()
|
||||
vcsProxy := vcsmocks.NewMockClientProxy()
|
||||
w := mocks.NewMockWorkspace()
|
||||
ppe := mocks.NewMockProjectPreExecutor()
|
||||
runner := tmocks.NewMockRunner()
|
||||
locker := lmocks.NewMockLocker()
|
||||
run := rmocks.NewMockRunner()
|
||||
p := events.PlanExecutor{
|
||||
Github: gh,
|
||||
ModifiedProject: &events.ProjectFinder{},
|
||||
VCSClient: vcsProxy,
|
||||
ProjectFinder: &events.ProjectFinder{},
|
||||
Workspace: w,
|
||||
ProjectPreExecute: ppe,
|
||||
Terraform: runner,
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
. "github.com/hootsuite/atlantis/testing"
|
||||
)
|
||||
|
||||
var log = logging.NewNoopLogger()
|
||||
var noopLogger = logging.NewNoopLogger()
|
||||
var modifiedRepo = "owner/repo"
|
||||
var m = events.ProjectFinder{}
|
||||
|
||||
@@ -66,7 +66,7 @@ func TestGetModified_NoFiles(t *testing.T) {
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Log(c.description)
|
||||
projects := m.FindModified(log, c.files, modifiedRepo)
|
||||
projects := m.FindModified(noopLogger, c.files, modifiedRepo)
|
||||
|
||||
// Extract the paths from the projects. We use a slice here instead of a
|
||||
// map so we can test whether there are duplicates returned.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package events
|
||||
|
||||
import "github.com/hootsuite/atlantis/server/events/vcs"
|
||||
|
||||
type ProjectResult struct {
|
||||
Path string
|
||||
Error error
|
||||
@@ -8,12 +10,12 @@ type ProjectResult struct {
|
||||
ApplySuccess string
|
||||
}
|
||||
|
||||
func (p ProjectResult) Status() Status {
|
||||
func (p ProjectResult) Status() vcs.CommitStatus {
|
||||
if p.Error != nil {
|
||||
return Error
|
||||
return vcs.Failed
|
||||
}
|
||||
if p.Failure != "" {
|
||||
return Failure
|
||||
return vcs.Failed
|
||||
}
|
||||
return Success
|
||||
return vcs.Success
|
||||
}
|
||||
|
||||
@@ -8,21 +8,21 @@ import (
|
||||
|
||||
"sort"
|
||||
|
||||
"github.com/hootsuite/atlantis/server/events/github"
|
||||
"github.com/hootsuite/atlantis/server/events/locking"
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
"github.com/hootsuite/atlantis/server/events/vcs"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
//go:generate pegomock generate --use-experimental-model-gen --package mocks -o mocks/mock_pull_cleaner.go PullCleaner
|
||||
|
||||
type PullCleaner interface {
|
||||
CleanUpPull(repo models.Repo, pull models.PullRequest) error
|
||||
CleanUpPull(repo models.Repo, pull models.PullRequest, host vcs.Host) error
|
||||
}
|
||||
|
||||
type PullClosedExecutor struct {
|
||||
Locker locking.Locker
|
||||
Github github.Client
|
||||
VCSClient vcs.ClientProxy
|
||||
Workspace Workspace
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ var pullClosedTemplate = template.Must(template.New("").Parse(
|
||||
"{{ range . }}\n" +
|
||||
"- path: `{{ .Path }}` {{ .Envs }}{{ end }}"))
|
||||
|
||||
func (p *PullClosedExecutor) CleanUpPull(repo models.Repo, pull models.PullRequest) error {
|
||||
func (p *PullClosedExecutor) CleanUpPull(repo models.Repo, pull models.PullRequest, host vcs.Host) error {
|
||||
// delete the workspace
|
||||
if err := p.Workspace.Delete(repo, pull); err != nil {
|
||||
return errors.Wrap(err, "cleaning workspace")
|
||||
@@ -60,11 +60,11 @@ func (p *PullClosedExecutor) CleanUpPull(repo models.Repo, pull models.PullReque
|
||||
if err = pullClosedTemplate.Execute(&buf, templateData); err != nil {
|
||||
return errors.Wrap(err, "rendering template for comment")
|
||||
}
|
||||
return p.Github.CreateComment(repo, pull, buf.String())
|
||||
return p.VCSClient.CreateComment(repo, pull, buf.String(), host)
|
||||
}
|
||||
|
||||
// buildTemplateData formats the lock data into a slice that can easily be templated
|
||||
// for the GitHub comment. We organize all the environments by their respective project paths
|
||||
// for the VCS comment. We organize all the environments by their respective project paths
|
||||
// so the comment can look like: path: {path}, environments: {all-envs}
|
||||
func (p *PullClosedExecutor) buildTemplateData(locks []models.ProjectLock) []templatedProject {
|
||||
envsByPath := make(map[string][]string)
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
package events_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/hootsuite/atlantis/server/events"
|
||||
ghmocks "github.com/hootsuite/atlantis/server/events/github/mocks"
|
||||
lockmocks "github.com/hootsuite/atlantis/server/events/locking/mocks"
|
||||
"github.com/hootsuite/atlantis/server/events/mocks"
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
"github.com/hootsuite/atlantis/server/events/models/fixtures"
|
||||
. "github.com/hootsuite/atlantis/testing"
|
||||
. "github.com/petergtz/pegomock"
|
||||
"testing"
|
||||
"github.com/hootsuite/atlantis/server/events/mocks"
|
||||
lockmocks "github.com/hootsuite/atlantis/server/events/locking/mocks"
|
||||
vcsmocks "github.com/hootsuite/atlantis/server/events/vcs/mocks"
|
||||
"github.com/hootsuite/atlantis/server/events"
|
||||
"errors"
|
||||
"github.com/hootsuite/atlantis/server/events/vcs"
|
||||
"github.com/hootsuite/atlantis/server/events/models/fixtures"
|
||||
)
|
||||
|
||||
func TestCleanUpPullWorkspaceErr(t *testing.T) {
|
||||
@@ -24,7 +25,7 @@ func TestCleanUpPullWorkspaceErr(t *testing.T) {
|
||||
}
|
||||
err := errors.New("err")
|
||||
When(w.Delete(fixtures.Repo, fixtures.Pull)).ThenReturn(err)
|
||||
actualErr := pce.CleanUpPull(fixtures.Repo, fixtures.Pull)
|
||||
actualErr := pce.CleanUpPull(fixtures.Repo, fixtures.Pull, vcs.Github)
|
||||
Equals(t, "cleaning workspace: err", actualErr.Error())
|
||||
}
|
||||
|
||||
@@ -39,7 +40,7 @@ func TestCleanUpPullUnlockErr(t *testing.T) {
|
||||
}
|
||||
err := errors.New("err")
|
||||
When(l.UnlockByPull(fixtures.Repo.FullName, fixtures.Pull.Num)).ThenReturn(nil, err)
|
||||
actualErr := pce.CleanUpPull(fixtures.Repo, fixtures.Pull)
|
||||
actualErr := pce.CleanUpPull(fixtures.Repo, fixtures.Pull, vcs.Github)
|
||||
Equals(t, "cleaning up locks: err", actualErr.Error())
|
||||
}
|
||||
|
||||
@@ -48,16 +49,16 @@ func TestCleanUpPullNoLocks(t *testing.T) {
|
||||
RegisterMockTestingT(t)
|
||||
w := mocks.NewMockWorkspace()
|
||||
l := lockmocks.NewMockLocker()
|
||||
gh := ghmocks.NewMockClient()
|
||||
cp := vcsmocks.NewMockClientProxy()
|
||||
pce := events.PullClosedExecutor{
|
||||
Locker: l,
|
||||
Github: gh,
|
||||
VCSClient: cp,
|
||||
Workspace: w,
|
||||
}
|
||||
When(l.UnlockByPull(fixtures.Repo.FullName, fixtures.Pull.Num)).ThenReturn(nil, nil)
|
||||
err := pce.CleanUpPull(fixtures.Repo, fixtures.Pull)
|
||||
err := pce.CleanUpPull(fixtures.Repo, fixtures.Pull, vcs.Github)
|
||||
Ok(t, err)
|
||||
gh.VerifyWasCalled(Never()).CreateComment(AnyRepo(), AnyPullRequest(), AnyString())
|
||||
cp.VerifyWasCalled(Never()).CreateComment(AnyRepo(), AnyPullRequest(), AnyString(), AnyVCSHost())
|
||||
}
|
||||
|
||||
func TestCleanUpPullComments(t *testing.T) {
|
||||
@@ -127,18 +128,18 @@ func TestCleanUpPullComments(t *testing.T) {
|
||||
}
|
||||
for _, c := range cases {
|
||||
w := mocks.NewMockWorkspace()
|
||||
gh := ghmocks.NewMockClient()
|
||||
cp := vcsmocks.NewMockClientProxy()
|
||||
l := lockmocks.NewMockLocker()
|
||||
pce := events.PullClosedExecutor{
|
||||
Locker: l,
|
||||
Github: gh,
|
||||
VCSClient: cp,
|
||||
Workspace: w,
|
||||
}
|
||||
t.Log("testing: " + c.Description)
|
||||
When(l.UnlockByPull(fixtures.Repo.FullName, fixtures.Pull.Num)).ThenReturn(c.Locks, nil)
|
||||
err := pce.CleanUpPull(fixtures.Repo, fixtures.Pull)
|
||||
err := pce.CleanUpPull(fixtures.Repo, fixtures.Pull, vcs.Github)
|
||||
Ok(t, err)
|
||||
_, _, comment := gh.VerifyWasCalledOnce().CreateComment(AnyRepo(), AnyPullRequest(), AnyString()).GetCapturedArguments()
|
||||
_, _, comment, _ := cp.VerifyWasCalledOnce().CreateComment(AnyRepo(), AnyPullRequest(), AnyString(), AnyVCSHost()).GetCapturedArguments()
|
||||
|
||||
expected := "Locks and plans deleted for the projects and environments modified in this pull request:\n\n" + c.Exp
|
||||
Equals(t, expected, comment)
|
||||
@@ -154,3 +155,4 @@ func AnyPullRequest() models.PullRequest {
|
||||
RegisterMatcher(NewAnyMatcher(reflect.TypeOf(models.PullRequest{})))
|
||||
return models.PullRequest{}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
go_version "github.com/hashicorp/go-version"
|
||||
logging "github.com/hootsuite/atlantis/server/logging"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type MockRunner struct {
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
go_version "github.com/hashicorp/go-version"
|
||||
logging "github.com/hootsuite/atlantis/server/logging"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type MockRunner struct {
|
||||
|
||||
15
server/events/vcs/client.go
Normal file
15
server/events/vcs/client.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package vcs
|
||||
|
||||
import (
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
)
|
||||
|
||||
//go:generate pegomock generate --use-experimental-model-gen --package mocks -o mocks/mock_client.go Client
|
||||
|
||||
// Client is used to make API calls to a VCS host like GitHub or GitLab.
|
||||
type Client interface {
|
||||
GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([]string, error)
|
||||
CreateComment(repo models.Repo, pull models.PullRequest, comment string) error
|
||||
PullIsApproved(repo models.Repo, pull models.PullRequest) (bool, error)
|
||||
UpdateStatus(repo models.Repo, pull models.PullRequest, state CommitStatus, description string) error
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package github_test
|
||||
package vcs
|
||||
|
||||
// todo: actually test
|
||||
// purposefully empty to trigger coverage report
|
||||
@@ -16,6 +16,7 @@ var Pull = github.PullRequest{
|
||||
Login: github.String("user"),
|
||||
},
|
||||
Number: github.Int(1),
|
||||
State: github.String("open"),
|
||||
}
|
||||
|
||||
var Repo = github.Repository{
|
||||
@@ -1,9 +1,7 @@
|
||||
// Package github provides convenience wrappers around the go-github package.
|
||||
package github
|
||||
package vcs
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
@@ -13,24 +11,14 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
//go:generate pegomock generate --package mocks -o mocks/mock_client.go client.go
|
||||
|
||||
type Client interface {
|
||||
GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([]string, error)
|
||||
CreateComment(repo models.Repo, pull models.PullRequest, comment string) error
|
||||
PullIsApproved(repo models.Repo, pull models.PullRequest) (bool, error)
|
||||
GetPullRequest(repo models.Repo, num int) (*github.PullRequest, *github.Response, error)
|
||||
UpdateStatus(repo models.Repo, pull models.PullRequest, state string, description string, context string) error
|
||||
}
|
||||
|
||||
// ConcreteClient is used to perform GitHub actions.
|
||||
type ConcreteClient struct {
|
||||
// GithubClient is used to perform GitHub actions.
|
||||
type GithubClient struct {
|
||||
client *github.Client
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewClient returns a valid GitHub client.
|
||||
func NewClient(hostname string, user string, pass string) (*ConcreteClient, error) {
|
||||
// NewGithubClient returns a valid GitHub client.
|
||||
func NewGithubClient(hostname string, user string, pass string) (*GithubClient, error) {
|
||||
tp := github.BasicAuthTransport{
|
||||
Username: strings.TrimSpace(user),
|
||||
Password: strings.TrimSpace(pass),
|
||||
@@ -48,7 +36,7 @@ func NewClient(hostname string, user string, pass string) (*ConcreteClient, erro
|
||||
client.BaseURL = base
|
||||
}
|
||||
|
||||
return &ConcreteClient{
|
||||
return &GithubClient{
|
||||
client: client,
|
||||
ctx: context.Background(),
|
||||
}, nil
|
||||
@@ -56,7 +44,7 @@ func NewClient(hostname string, user string, pass string) (*ConcreteClient, erro
|
||||
|
||||
// GetModifiedFiles returns the names of files that were modified in the pull request.
|
||||
// The names include the path to the file from the repo root, ex. parent/child/file.txt.
|
||||
func (c *ConcreteClient) GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([]string, error) {
|
||||
func (g *GithubClient) GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([]string, error) {
|
||||
var files []string
|
||||
nextPage := 0
|
||||
for {
|
||||
@@ -66,7 +54,7 @@ func (c *ConcreteClient) GetModifiedFiles(repo models.Repo, pull models.PullRequ
|
||||
if nextPage != 0 {
|
||||
opts.Page = nextPage
|
||||
}
|
||||
pageFiles, resp, err := c.client.PullRequests.ListFiles(c.ctx, repo.Owner, repo.Name, pull.Num, &opts)
|
||||
pageFiles, resp, err := g.client.PullRequests.ListFiles(g.ctx, repo.Owner, repo.Name, pull.Num, &opts)
|
||||
if err != nil {
|
||||
return files, err
|
||||
}
|
||||
@@ -82,14 +70,14 @@ func (c *ConcreteClient) GetModifiedFiles(repo models.Repo, pull models.PullRequ
|
||||
}
|
||||
|
||||
// CreateComment creates a comment on the pull request.
|
||||
func (c *ConcreteClient) CreateComment(repo models.Repo, pull models.PullRequest, comment string) error {
|
||||
_, _, err := c.client.Issues.CreateComment(c.ctx, repo.Owner, repo.Name, pull.Num, &github.IssueComment{Body: &comment})
|
||||
func (g *GithubClient) CreateComment(repo models.Repo, pull models.PullRequest, comment string) error {
|
||||
_, _, err := g.client.Issues.CreateComment(g.ctx, repo.Owner, repo.Name, pull.Num, &github.IssueComment{Body: &comment})
|
||||
return err
|
||||
}
|
||||
|
||||
// PullIsApproved returns true if the pull request was approved.
|
||||
func (c *ConcreteClient) PullIsApproved(repo models.Repo, pull models.PullRequest) (bool, error) {
|
||||
reviews, _, err := c.client.PullRequests.ListReviews(c.ctx, repo.Owner, repo.Name, pull.Num, nil)
|
||||
func (g *GithubClient) PullIsApproved(repo models.Repo, pull models.PullRequest) (bool, error) {
|
||||
reviews, _, err := g.client.PullRequests.ListReviews(g.ctx, repo.Owner, repo.Name, pull.Num, nil)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "getting reviews")
|
||||
}
|
||||
@@ -102,17 +90,28 @@ func (c *ConcreteClient) PullIsApproved(repo models.Repo, pull models.PullReques
|
||||
}
|
||||
|
||||
// GetPullRequest returns the pull request.
|
||||
func (c *ConcreteClient) GetPullRequest(repo models.Repo, num int) (*github.PullRequest, *github.Response, error) {
|
||||
return c.client.PullRequests.Get(c.ctx, repo.Owner, repo.Name, num)
|
||||
func (g *GithubClient) GetPullRequest(repo models.Repo, num int) (*github.PullRequest, error) {
|
||||
pull, _, err := g.client.PullRequests.Get(g.ctx, repo.Owner, repo.Name, num)
|
||||
return pull, err
|
||||
}
|
||||
|
||||
// UpdateStatus updates the status badge on the pull request.
|
||||
// See https://github.com/blog/1227-commit-status-api.
|
||||
func (c *ConcreteClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state string, description string, context string) error {
|
||||
func (g *GithubClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state CommitStatus, description string) error {
|
||||
const statusContext = "Atlantis"
|
||||
ghState := "error"
|
||||
switch state {
|
||||
case Pending:
|
||||
ghState = "pending"
|
||||
case Success:
|
||||
ghState = "success"
|
||||
case Failed:
|
||||
ghState = "failure"
|
||||
}
|
||||
status := &github.RepoStatus{
|
||||
State: github.String(state),
|
||||
State: github.String(ghState),
|
||||
Description: github.String(description),
|
||||
Context: github.String(context)}
|
||||
_, _, err := c.client.Repositories.CreateStatus(c.ctx, repo.Owner, repo.Name, pull.HeadCommit, status)
|
||||
Context: github.String(statusContext)}
|
||||
_, _, err := g.client.Repositories.CreateStatus(g.ctx, repo.Owner, repo.Name, pull.HeadCommit, status)
|
||||
return err
|
||||
}
|
||||
92
server/events/vcs/gitlab_client.go
Normal file
92
server/events/vcs/gitlab_client.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package vcs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
"github.com/lkysow/go-gitlab"
|
||||
)
|
||||
|
||||
type GitlabClient struct {
|
||||
Client *gitlab.Client
|
||||
}
|
||||
|
||||
// GetModifiedFiles returns the names of files that were modified in the merge request.
|
||||
// The names include the path to the file from the repo root, ex. parent/child/file.txt.
|
||||
func (g *GitlabClient) GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([]string, error) {
|
||||
const maxPerPage = 100
|
||||
var files []string
|
||||
nextPage := 1
|
||||
// Constructing the api url by hand so we can do pagination.
|
||||
apiURL := fmt.Sprintf("projects/%s/merge_requests/%d/changes", url.QueryEscape(repo.FullName), pull.Num)
|
||||
for {
|
||||
opts := gitlab.ListOptions{
|
||||
Page: nextPage,
|
||||
PerPage: maxPerPage,
|
||||
}
|
||||
req, err := g.Client.NewRequest("GET", apiURL, opts, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mr := new(gitlab.MergeRequest)
|
||||
resp, err := g.Client.Do(req, mr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, f := range mr.Changes {
|
||||
files = append(files, f.NewPath)
|
||||
}
|
||||
if resp.NextPage == 0 {
|
||||
break
|
||||
}
|
||||
nextPage = resp.NextPage
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
// CreateComment creates a comment on the merge request.
|
||||
func (g *GitlabClient) CreateComment(repo models.Repo, pull models.PullRequest, comment string) error {
|
||||
_, _, err := g.Client.Notes.CreateMergeRequestNote(repo.FullName, pull.Num, &gitlab.CreateMergeRequestNoteOptions{Body: gitlab.String(comment)})
|
||||
return err
|
||||
}
|
||||
|
||||
// PullIsApproved returns true if the merge request was approved.
|
||||
func (g *GitlabClient) PullIsApproved(repo models.Repo, pull models.PullRequest) (bool, error) {
|
||||
approvals, _, err := g.Client.MergeRequests.GetMergeRequestApprovals(repo.FullName, pull.Num)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if approvals.ApprovalsMissing > 0 {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// UpdateStatus updates the build status of a commit.
|
||||
func (g *GitlabClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state CommitStatus, description string) error {
|
||||
const statusContext = "Atlantis"
|
||||
|
||||
gitlabState := gitlab.Failed
|
||||
switch state {
|
||||
case Pending:
|
||||
gitlabState = gitlab.Pending
|
||||
case Failed:
|
||||
gitlabState = gitlab.Failed
|
||||
case Success:
|
||||
gitlabState = gitlab.Success
|
||||
}
|
||||
_, _, err := g.Client.Commits.SetCommitStatus(repo.FullName, pull.HeadCommit, &gitlab.SetCommitStatusOptions{
|
||||
State: gitlabState,
|
||||
Context: gitlab.String(statusContext),
|
||||
Description: gitlab.String(description),
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *GitlabClient) GetMergeRequest(repoFullName string, pullNum int) (*gitlab.MergeRequest, error) {
|
||||
mr, _, err := g.Client.MergeRequests.GetMergeRequest(repoFullName, pullNum)
|
||||
return mr, err
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
// Automatically generated by pegomock. DO NOT EDIT!
|
||||
// Source: client.go
|
||||
// Source: github.com/hootsuite/atlantis/server/events/vcs (interfaces: Client)
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
github "github.com/google/go-github/github"
|
||||
models "github.com/hootsuite/atlantis/server/events/models"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
"reflect"
|
||||
|
||||
models "github.com/hootsuite/atlantis/server/events/models"
|
||||
vcs "github.com/hootsuite/atlantis/server/events/vcs"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
)
|
||||
|
||||
type MockClient struct {
|
||||
@@ -62,28 +63,8 @@ func (mock *MockClient) PullIsApproved(repo models.Repo, pull models.PullRequest
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
func (mock *MockClient) GetPullRequest(repo models.Repo, num int) (*github.PullRequest, *github.Response, error) {
|
||||
params := []pegomock.Param{repo, num}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("GetPullRequest", params, []reflect.Type{reflect.TypeOf((**github.PullRequest)(nil)).Elem(), reflect.TypeOf((**github.Response)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 *github.PullRequest
|
||||
var ret1 *github.Response
|
||||
var ret2 error
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].(*github.PullRequest)
|
||||
}
|
||||
if result[1] != nil {
|
||||
ret1 = result[1].(*github.Response)
|
||||
}
|
||||
if result[2] != nil {
|
||||
ret2 = result[2].(error)
|
||||
}
|
||||
}
|
||||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
func (mock *MockClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state string, description string, context string) error {
|
||||
params := []pegomock.Param{repo, pull, state, description, context}
|
||||
func (mock *MockClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state vcs.CommitStatus, description string) error {
|
||||
params := []pegomock.Param{repo, pull, state, description}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateStatus", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 error
|
||||
if len(result) != 0 {
|
||||
@@ -209,39 +190,8 @@ func (c *Client_PullIsApproved_OngoingVerification) GetAllCapturedArguments() (_
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierClient) GetPullRequest(repo models.Repo, num int) *Client_GetPullRequest_OngoingVerification {
|
||||
params := []pegomock.Param{repo, num}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullRequest", params)
|
||||
return &Client_GetPullRequest_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type Client_GetPullRequest_OngoingVerification struct {
|
||||
mock *MockClient
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *Client_GetPullRequest_OngoingVerification) GetCapturedArguments() (models.Repo, int) {
|
||||
repo, num := c.GetAllCapturedArguments()
|
||||
return repo[len(repo)-1], num[len(num)-1]
|
||||
}
|
||||
|
||||
func (c *Client_GetPullRequest_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []int) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]models.Repo, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(models.Repo)
|
||||
}
|
||||
_param1 = make([]int, len(params[1]))
|
||||
for u, param := range params[1] {
|
||||
_param1[u] = param.(int)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state string, description string, context string) *Client_UpdateStatus_OngoingVerification {
|
||||
params := []pegomock.Param{repo, pull, state, description, context}
|
||||
func (verifier *VerifierClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state vcs.CommitStatus, description string) *Client_UpdateStatus_OngoingVerification {
|
||||
params := []pegomock.Param{repo, pull, state, description}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateStatus", params)
|
||||
return &Client_UpdateStatus_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
@@ -251,12 +201,12 @@ type Client_UpdateStatus_OngoingVerification struct {
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *Client_UpdateStatus_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, string, string, string) {
|
||||
repo, pull, state, description, context := c.GetAllCapturedArguments()
|
||||
return repo[len(repo)-1], pull[len(pull)-1], state[len(state)-1], description[len(description)-1], context[len(context)-1]
|
||||
func (c *Client_UpdateStatus_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, vcs.CommitStatus, string) {
|
||||
repo, pull, state, description := c.GetAllCapturedArguments()
|
||||
return repo[len(repo)-1], pull[len(pull)-1], state[len(state)-1], description[len(description)-1]
|
||||
}
|
||||
|
||||
func (c *Client_UpdateStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []string, _param3 []string, _param4 []string) {
|
||||
func (c *Client_UpdateStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []vcs.CommitStatus, _param3 []string) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]models.Repo, len(params[0]))
|
||||
@@ -267,18 +217,14 @@ func (c *Client_UpdateStatus_OngoingVerification) GetAllCapturedArguments() (_pa
|
||||
for u, param := range params[1] {
|
||||
_param1[u] = param.(models.PullRequest)
|
||||
}
|
||||
_param2 = make([]string, len(params[2]))
|
||||
_param2 = make([]vcs.CommitStatus, len(params[2]))
|
||||
for u, param := range params[2] {
|
||||
_param2[u] = param.(string)
|
||||
_param2[u] = param.(vcs.CommitStatus)
|
||||
}
|
||||
_param3 = make([]string, len(params[3]))
|
||||
for u, param := range params[3] {
|
||||
_param3[u] = param.(string)
|
||||
}
|
||||
_param4 = make([]string, len(params[4]))
|
||||
for u, param := range params[4] {
|
||||
_param4[u] = param.(string)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
246
server/events/vcs/mocks/mock_proxy.go
Normal file
246
server/events/vcs/mocks/mock_proxy.go
Normal file
@@ -0,0 +1,246 @@
|
||||
// Automatically generated by pegomock. DO NOT EDIT!
|
||||
// Source: github.com/hootsuite/atlantis/server/events/vcs (interfaces: ClientProxy)
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
models "github.com/hootsuite/atlantis/server/events/models"
|
||||
vcs "github.com/hootsuite/atlantis/server/events/vcs"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
)
|
||||
|
||||
type MockClientProxy struct {
|
||||
fail func(message string, callerSkip ...int)
|
||||
}
|
||||
|
||||
func NewMockClientProxy() *MockClientProxy {
|
||||
return &MockClientProxy{fail: pegomock.GlobalFailHandler}
|
||||
}
|
||||
|
||||
func (mock *MockClientProxy) GetModifiedFiles(repo models.Repo, pull models.PullRequest, host vcs.Host) ([]string, error) {
|
||||
params := []pegomock.Param{repo, pull, host}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("GetModifiedFiles", params, []reflect.Type{reflect.TypeOf((*[]string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 []string
|
||||
var ret1 error
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].([]string)
|
||||
}
|
||||
if result[1] != nil {
|
||||
ret1 = result[1].(error)
|
||||
}
|
||||
}
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
func (mock *MockClientProxy) CreateComment(repo models.Repo, pull models.PullRequest, comment string, host vcs.Host) error {
|
||||
params := []pegomock.Param{repo, pull, comment, host}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("CreateComment", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 error
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].(error)
|
||||
}
|
||||
}
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mock *MockClientProxy) PullIsApproved(repo models.Repo, pull models.PullRequest, host vcs.Host) (bool, error) {
|
||||
params := []pegomock.Param{repo, pull, host}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("PullIsApproved", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 bool
|
||||
var ret1 error
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].(bool)
|
||||
}
|
||||
if result[1] != nil {
|
||||
ret1 = result[1].(error)
|
||||
}
|
||||
}
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
func (mock *MockClientProxy) UpdateStatus(repo models.Repo, pull models.PullRequest, state vcs.CommitStatus, description string, host vcs.Host) error {
|
||||
params := []pegomock.Param{repo, pull, state, description, host}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateStatus", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 error
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].(error)
|
||||
}
|
||||
}
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mock *MockClientProxy) VerifyWasCalledOnce() *VerifierClientProxy {
|
||||
return &VerifierClientProxy{mock, pegomock.Times(1), nil}
|
||||
}
|
||||
|
||||
func (mock *MockClientProxy) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierClientProxy {
|
||||
return &VerifierClientProxy{mock, invocationCountMatcher, nil}
|
||||
}
|
||||
|
||||
func (mock *MockClientProxy) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierClientProxy {
|
||||
return &VerifierClientProxy{mock, invocationCountMatcher, inOrderContext}
|
||||
}
|
||||
|
||||
type VerifierClientProxy struct {
|
||||
mock *MockClientProxy
|
||||
invocationCountMatcher pegomock.Matcher
|
||||
inOrderContext *pegomock.InOrderContext
|
||||
}
|
||||
|
||||
func (verifier *VerifierClientProxy) GetModifiedFiles(repo models.Repo, pull models.PullRequest, host vcs.Host) *ClientProxy_GetModifiedFiles_OngoingVerification {
|
||||
params := []pegomock.Param{repo, pull, host}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetModifiedFiles", params)
|
||||
return &ClientProxy_GetModifiedFiles_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type ClientProxy_GetModifiedFiles_OngoingVerification struct {
|
||||
mock *MockClientProxy
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *ClientProxy_GetModifiedFiles_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, vcs.Host) {
|
||||
repo, pull, host := c.GetAllCapturedArguments()
|
||||
return repo[len(repo)-1], pull[len(pull)-1], host[len(host)-1]
|
||||
}
|
||||
|
||||
func (c *ClientProxy_GetModifiedFiles_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []vcs.Host) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]models.Repo, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(models.Repo)
|
||||
}
|
||||
_param1 = make([]models.PullRequest, len(params[1]))
|
||||
for u, param := range params[1] {
|
||||
_param1[u] = param.(models.PullRequest)
|
||||
}
|
||||
_param2 = make([]vcs.Host, len(params[2]))
|
||||
for u, param := range params[2] {
|
||||
_param2[u] = param.(vcs.Host)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierClientProxy) CreateComment(repo models.Repo, pull models.PullRequest, comment string, host vcs.Host) *ClientProxy_CreateComment_OngoingVerification {
|
||||
params := []pegomock.Param{repo, pull, comment, host}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CreateComment", params)
|
||||
return &ClientProxy_CreateComment_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type ClientProxy_CreateComment_OngoingVerification struct {
|
||||
mock *MockClientProxy
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *ClientProxy_CreateComment_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, string, vcs.Host) {
|
||||
repo, pull, comment, host := c.GetAllCapturedArguments()
|
||||
return repo[len(repo)-1], pull[len(pull)-1], comment[len(comment)-1], host[len(host)-1]
|
||||
}
|
||||
|
||||
func (c *ClientProxy_CreateComment_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []string, _param3 []vcs.Host) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]models.Repo, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(models.Repo)
|
||||
}
|
||||
_param1 = make([]models.PullRequest, len(params[1]))
|
||||
for u, param := range params[1] {
|
||||
_param1[u] = param.(models.PullRequest)
|
||||
}
|
||||
_param2 = make([]string, len(params[2]))
|
||||
for u, param := range params[2] {
|
||||
_param2[u] = param.(string)
|
||||
}
|
||||
_param3 = make([]vcs.Host, len(params[3]))
|
||||
for u, param := range params[3] {
|
||||
_param3[u] = param.(vcs.Host)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierClientProxy) PullIsApproved(repo models.Repo, pull models.PullRequest, host vcs.Host) *ClientProxy_PullIsApproved_OngoingVerification {
|
||||
params := []pegomock.Param{repo, pull, host}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PullIsApproved", params)
|
||||
return &ClientProxy_PullIsApproved_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type ClientProxy_PullIsApproved_OngoingVerification struct {
|
||||
mock *MockClientProxy
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *ClientProxy_PullIsApproved_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, vcs.Host) {
|
||||
repo, pull, host := c.GetAllCapturedArguments()
|
||||
return repo[len(repo)-1], pull[len(pull)-1], host[len(host)-1]
|
||||
}
|
||||
|
||||
func (c *ClientProxy_PullIsApproved_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []vcs.Host) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]models.Repo, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(models.Repo)
|
||||
}
|
||||
_param1 = make([]models.PullRequest, len(params[1]))
|
||||
for u, param := range params[1] {
|
||||
_param1[u] = param.(models.PullRequest)
|
||||
}
|
||||
_param2 = make([]vcs.Host, len(params[2]))
|
||||
for u, param := range params[2] {
|
||||
_param2[u] = param.(vcs.Host)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierClientProxy) UpdateStatus(repo models.Repo, pull models.PullRequest, state vcs.CommitStatus, description string, host vcs.Host) *ClientProxy_UpdateStatus_OngoingVerification {
|
||||
params := []pegomock.Param{repo, pull, state, description, host}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateStatus", params)
|
||||
return &ClientProxy_UpdateStatus_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type ClientProxy_UpdateStatus_OngoingVerification struct {
|
||||
mock *MockClientProxy
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *ClientProxy_UpdateStatus_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, vcs.CommitStatus, string, vcs.Host) {
|
||||
repo, pull, state, description, host := c.GetAllCapturedArguments()
|
||||
return repo[len(repo)-1], pull[len(pull)-1], state[len(state)-1], description[len(description)-1], host[len(host)-1]
|
||||
}
|
||||
|
||||
func (c *ClientProxy_UpdateStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []vcs.CommitStatus, _param3 []string, _param4 []vcs.Host) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]models.Repo, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(models.Repo)
|
||||
}
|
||||
_param1 = make([]models.PullRequest, len(params[1]))
|
||||
for u, param := range params[1] {
|
||||
_param1[u] = param.(models.PullRequest)
|
||||
}
|
||||
_param2 = make([]vcs.CommitStatus, len(params[2]))
|
||||
for u, param := range params[2] {
|
||||
_param2[u] = param.(vcs.CommitStatus)
|
||||
}
|
||||
_param3 = make([]string, len(params[3]))
|
||||
for u, param := range params[3] {
|
||||
_param3[u] = param.(string)
|
||||
}
|
||||
_param4 = make([]vcs.Host, len(params[4]))
|
||||
for u, param := range params[4] {
|
||||
_param4[u] = param.(vcs.Host)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
31
server/events/vcs/not_configured_vcs_client.go
Normal file
31
server/events/vcs/not_configured_vcs_client.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package vcs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
)
|
||||
|
||||
// NotConfiguredVCSClient is used as a placeholder when Atlantis isn't configured
|
||||
// on startup to support a certain VCS host. For example, if there is no GitHub
|
||||
// config then this client will be used which will error if it's ever called.
|
||||
type NotConfiguredVCSClient struct {
|
||||
Host Host
|
||||
}
|
||||
|
||||
func (a *NotConfiguredVCSClient) GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([]string, error) {
|
||||
return nil, a.err()
|
||||
}
|
||||
func (a *NotConfiguredVCSClient) CreateComment(repo models.Repo, pull models.PullRequest, comment string) error {
|
||||
return a.err()
|
||||
}
|
||||
func (a *NotConfiguredVCSClient) PullIsApproved(repo models.Repo, pull models.PullRequest) (bool, error) {
|
||||
return false, a.err()
|
||||
}
|
||||
func (a *NotConfiguredVCSClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state CommitStatus, description string) error {
|
||||
return a.err()
|
||||
}
|
||||
func (a *NotConfiguredVCSClient) err() error {
|
||||
//noinspection GoErrorStringFormat
|
||||
return fmt.Errorf("Atlantis was not configured to support repos from %s", a.Host.String())
|
||||
}
|
||||
79
server/events/vcs/proxy.go
Normal file
79
server/events/vcs/proxy.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package vcs
|
||||
|
||||
import (
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
//go:generate pegomock generate --use-experimental-model-gen --package mocks -o mocks/mock_proxy.go ClientProxy
|
||||
|
||||
// ClientProxy proxies calls to the correct VCS client depending on which
|
||||
// VCS host is required.
|
||||
type ClientProxy interface {
|
||||
GetModifiedFiles(repo models.Repo, pull models.PullRequest, host Host) ([]string, error)
|
||||
CreateComment(repo models.Repo, pull models.PullRequest, comment string, host Host) error
|
||||
PullIsApproved(repo models.Repo, pull models.PullRequest, host Host) (bool, error)
|
||||
UpdateStatus(repo models.Repo, pull models.PullRequest, state CommitStatus, description string, host Host) error
|
||||
}
|
||||
|
||||
// DefaultClientProxy proxies calls to the correct VCS client depending on which
|
||||
// VCS host is required.
|
||||
type DefaultClientProxy struct {
|
||||
GithubClient Client
|
||||
GitlabClient Client
|
||||
}
|
||||
|
||||
func NewDefaultClientProxy(githubClient Client, gitlabClient Client) *DefaultClientProxy {
|
||||
if githubClient == nil {
|
||||
githubClient = &NotConfiguredVCSClient{}
|
||||
}
|
||||
if gitlabClient == nil {
|
||||
gitlabClient = &NotConfiguredVCSClient{}
|
||||
}
|
||||
return &DefaultClientProxy{
|
||||
GitlabClient: gitlabClient,
|
||||
GithubClient: githubClient,
|
||||
}
|
||||
}
|
||||
|
||||
var invalidVCSErr = errors.New("Invalid VCS Host. This is a bug!")
|
||||
|
||||
func (d *DefaultClientProxy) GetModifiedFiles(repo models.Repo, pull models.PullRequest, host Host) ([]string, error) {
|
||||
switch host {
|
||||
case Github:
|
||||
return d.GithubClient.GetModifiedFiles(repo, pull)
|
||||
case Gitlab:
|
||||
return d.GitlabClient.GetModifiedFiles(repo, pull)
|
||||
}
|
||||
return nil, invalidVCSErr
|
||||
}
|
||||
|
||||
func (d *DefaultClientProxy) CreateComment(repo models.Repo, pull models.PullRequest, comment string, host Host) error {
|
||||
switch host {
|
||||
case Github:
|
||||
return d.GithubClient.CreateComment(repo, pull, comment)
|
||||
case Gitlab:
|
||||
return d.GitlabClient.CreateComment(repo, pull, comment)
|
||||
}
|
||||
return invalidVCSErr
|
||||
}
|
||||
|
||||
func (d *DefaultClientProxy) PullIsApproved(repo models.Repo, pull models.PullRequest, host Host) (bool, error) {
|
||||
switch host {
|
||||
case Github:
|
||||
return d.GithubClient.PullIsApproved(repo, pull)
|
||||
case Gitlab:
|
||||
return d.GitlabClient.PullIsApproved(repo, pull)
|
||||
}
|
||||
return false, invalidVCSErr
|
||||
}
|
||||
|
||||
func (d *DefaultClientProxy) UpdateStatus(repo models.Repo, pull models.PullRequest, state CommitStatus, description string, host Host) error {
|
||||
switch host {
|
||||
case Github:
|
||||
return d.GithubClient.UpdateStatus(repo, pull, state, description)
|
||||
case Gitlab:
|
||||
return d.GitlabClient.UpdateStatus(repo, pull, state, description)
|
||||
}
|
||||
return invalidVCSErr
|
||||
}
|
||||
42
server/events/vcs/vcs.go
Normal file
42
server/events/vcs/vcs.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package vcs
|
||||
|
||||
type Host int
|
||||
|
||||
const (
|
||||
Github Host = iota
|
||||
Gitlab
|
||||
)
|
||||
|
||||
func (h Host) String() string {
|
||||
switch h {
|
||||
case Github:
|
||||
return "Github"
|
||||
case Gitlab:
|
||||
return "Gitlab"
|
||||
}
|
||||
return "<missing String() implementation>"
|
||||
}
|
||||
|
||||
// CommitStatus is the result of executing an Atlantis command for the commit.
|
||||
// In Github the options are: error, failure, pending, success.
|
||||
// In Gitlab the options are: failed, canceled, pending, running, success.
|
||||
// We only support Failed, Pending, Success.
|
||||
type CommitStatus int
|
||||
|
||||
const (
|
||||
Pending CommitStatus = iota
|
||||
Success
|
||||
Failed
|
||||
)
|
||||
|
||||
func (s CommitStatus) String() string {
|
||||
switch s {
|
||||
case Pending:
|
||||
return "pending"
|
||||
case Success:
|
||||
return "success"
|
||||
case Failed:
|
||||
return "failed"
|
||||
}
|
||||
return "failed"
|
||||
}
|
||||
@@ -6,9 +6,15 @@ import (
|
||||
|
||||
"github.com/google/go-github/github"
|
||||
"github.com/hootsuite/atlantis/server/events"
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
"github.com/hootsuite/atlantis/server/events/vcs"
|
||||
"github.com/hootsuite/atlantis/server/logging"
|
||||
"github.com/lkysow/go-gitlab"
|
||||
)
|
||||
|
||||
const githubHeader = "X-Github-Event"
|
||||
const gitlabHeader = "X-Gitlab-Event"
|
||||
|
||||
type EventsController struct {
|
||||
CommandRunner events.CommandRunner
|
||||
PullCleaner events.PullCleaner
|
||||
@@ -18,12 +24,66 @@ type EventsController struct {
|
||||
// UI that identifies this call as coming from GitHub. If empty, no
|
||||
// request validation is done.
|
||||
GithubWebHookSecret []byte
|
||||
Validator GHRequestValidator
|
||||
GithubRequestValidator GithubRequestValidator
|
||||
GitlabRequestParser GitlabRequestParser
|
||||
// GitlabWebHookSecret is the secret added to this webhook via the GitLab
|
||||
// UI that identifies this call as coming from GitLab. If empty, no
|
||||
// request validation is done.
|
||||
GitlabWebHookSecret []byte
|
||||
// SupportedVCSHosts is which VCS hosts Atlantis was configured upon
|
||||
// startup to support.
|
||||
SupportedVCSHosts []vcs.Host
|
||||
}
|
||||
|
||||
func (e *EventsController) Post(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Header.Get(githubHeader) != "" {
|
||||
if !e.supportsHost(vcs.Github) {
|
||||
e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request since not configured to support GitHub")
|
||||
return
|
||||
}
|
||||
e.handleGithubPost(w, r)
|
||||
return
|
||||
} else if r.Header.Get(gitlabHeader) != "" {
|
||||
if !e.supportsHost(vcs.Gitlab) {
|
||||
e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request since not configured to support GitLab")
|
||||
return
|
||||
}
|
||||
e.handleGitlabPost(w, r)
|
||||
return
|
||||
}
|
||||
e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request")
|
||||
}
|
||||
|
||||
// supportsHost returns true if h is in e.SupportedVCSHosts and false otherwise
|
||||
func (e *EventsController) supportsHost(h vcs.Host) bool {
|
||||
for _, supported := range e.SupportedVCSHosts {
|
||||
if h == supported {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *EventsController) handleGitlabPost(w http.ResponseWriter, r *http.Request) {
|
||||
event, err := e.GitlabRequestParser.Validate(r, e.GitlabWebHookSecret)
|
||||
if err != nil {
|
||||
e.respond(w, logging.Warn, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
switch event := event.(type) {
|
||||
case gitlab.MergeCommentEvent:
|
||||
e.HandleGitlabCommentEvent(w, event)
|
||||
case gitlab.MergeEvent:
|
||||
e.HandleGitlabMergeRequestEvent(w, event)
|
||||
default:
|
||||
e.respond(w, logging.Debug, http.StatusOK, "Ignoring unsupported event")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (e *EventsController) handleGithubPost(w http.ResponseWriter, r *http.Request) {
|
||||
// Validate the request against the optional webhook secret.
|
||||
payload, err := e.Validator.Validate(r, e.GithubWebHookSecret)
|
||||
payload, err := e.GithubRequestValidator.Validate(r, e.GithubWebHookSecret)
|
||||
if err != nil {
|
||||
e.respond(w, logging.Warn, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
@@ -33,62 +93,87 @@ func (e *EventsController) Post(w http.ResponseWriter, r *http.Request) {
|
||||
event, _ := github.ParseWebHook(github.WebHookType(r), payload)
|
||||
switch event := event.(type) {
|
||||
case *github.IssueCommentEvent:
|
||||
e.HandleCommentEvent(w, event, githubReqID)
|
||||
e.HandleGithubCommentEvent(w, event, githubReqID)
|
||||
case *github.PullRequestEvent:
|
||||
e.HandlePullRequestEvent(w, event, githubReqID)
|
||||
e.HandleGithubPullRequestEvent(w, event, githubReqID)
|
||||
default:
|
||||
e.respond(w, logging.Debug, http.StatusOK, "Ignoring unsupported event %s", githubReqID)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *EventsController) HandleCommentEvent(w http.ResponseWriter, event *github.IssueCommentEvent, githubReqID string) {
|
||||
func (e *EventsController) HandleGithubCommentEvent(w http.ResponseWriter, event *github.IssueCommentEvent, githubReqID string) {
|
||||
if event.GetAction() != "created" {
|
||||
e.respond(w, logging.Debug, http.StatusOK, "Ignoring comment event since action was not created %s", githubReqID)
|
||||
return
|
||||
}
|
||||
|
||||
baseRepo, user, pull, err := e.Parser.ExtractCommentData(event)
|
||||
baseRepo, user, pullNum, err := e.Parser.ParseGithubIssueCommentEvent(event)
|
||||
if err != nil {
|
||||
e.respond(w, logging.Error, http.StatusBadRequest, "Failed parsing event: %v %s", err, githubReqID)
|
||||
return
|
||||
}
|
||||
ctx := &events.CommandContext{}
|
||||
ctx.BaseRepo = baseRepo
|
||||
ctx.User = user
|
||||
ctx.Pull = pull
|
||||
|
||||
command, err := e.Parser.DetermineCommand(event)
|
||||
command, err := e.Parser.DetermineCommand(event.Comment.GetBody(), vcs.Github)
|
||||
if err != nil {
|
||||
e.respond(w, logging.Debug, http.StatusOK, "Ignoring: %s %s", err, githubReqID)
|
||||
return
|
||||
}
|
||||
ctx.Command = command
|
||||
|
||||
// Respond with success and then actually execute the command asynchronously.
|
||||
// We use a goroutine so that this function returns and the connection is
|
||||
// closed.
|
||||
fmt.Fprintln(w, "Processing...")
|
||||
go e.CommandRunner.ExecuteCommand(ctx)
|
||||
go e.CommandRunner.ExecuteCommand(baseRepo, models.Repo{}, user, pullNum, command, vcs.Github)
|
||||
}
|
||||
|
||||
// HandlePullRequestEvent will delete any locks associated with the pull request
|
||||
func (e *EventsController) HandlePullRequestEvent(w http.ResponseWriter, pullEvent *github.PullRequestEvent, githubReqID string) {
|
||||
func (e *EventsController) HandleGitlabCommentEvent(w http.ResponseWriter, event gitlab.MergeCommentEvent) {
|
||||
baseRepo, headRepo, user := e.Parser.ParseGitlabMergeCommentEvent(event)
|
||||
command, err := e.Parser.DetermineCommand(event.ObjectAttributes.Note, vcs.Gitlab)
|
||||
if err != nil {
|
||||
e.respond(w, logging.Debug, http.StatusOK, "Ignoring: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Respond with success and then actually execute the command asynchronously.
|
||||
// We use a goroutine so that this function returns and the connection is
|
||||
// closed.
|
||||
fmt.Fprintln(w, "Processing...")
|
||||
go e.CommandRunner.ExecuteCommand(baseRepo, headRepo, user, event.MergeRequest.IID, command, vcs.Gitlab)
|
||||
}
|
||||
|
||||
// HandleGitlabMergeRequestEvent will delete any locks associated with the merge request
|
||||
func (e *EventsController) HandleGitlabMergeRequestEvent(w http.ResponseWriter, event gitlab.MergeEvent) {
|
||||
pull, repo := e.Parser.ParseGitlabMergeEvent(event)
|
||||
if pull.State != models.Closed {
|
||||
e.respond(w, logging.Debug, http.StatusOK, "Ignoring opened merge request event")
|
||||
return
|
||||
}
|
||||
if err := e.PullCleaner.CleanUpPull(repo, pull, vcs.Gitlab); err != nil {
|
||||
e.respond(w, logging.Error, http.StatusInternalServerError, "Error cleaning pull request: %s", err)
|
||||
return
|
||||
}
|
||||
e.Logger.Info("deleted locks and workspace for repo %s, pull %d", repo.FullName, pull.Num)
|
||||
fmt.Fprintln(w, "Merge request cleaned successfully")
|
||||
}
|
||||
|
||||
// HandleGithubPullRequestEvent will delete any locks associated with the pull request
|
||||
func (e *EventsController) HandleGithubPullRequestEvent(w http.ResponseWriter, pullEvent *github.PullRequestEvent, githubReqID string) {
|
||||
if pullEvent.GetAction() != "closed" {
|
||||
e.respond(w, logging.Debug, http.StatusOK, "Ignoring pull request event since action was not closed %s", githubReqID)
|
||||
return
|
||||
}
|
||||
pull, _, err := e.Parser.ExtractPullData(pullEvent.PullRequest)
|
||||
pull, _, err := e.Parser.ParseGithubPull(pullEvent.PullRequest)
|
||||
if err != nil {
|
||||
e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing pull data: %s", err)
|
||||
return
|
||||
}
|
||||
repo, err := e.Parser.ExtractRepoData(pullEvent.Repo)
|
||||
repo, err := e.Parser.ParseGithubRepo(pullEvent.Repo)
|
||||
if err != nil {
|
||||
e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing repo data: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := e.PullCleaner.CleanUpPull(repo, pull); err != nil {
|
||||
if err := e.PullCleaner.CleanUpPull(repo, pull, vcs.Github); err != nil {
|
||||
e.respond(w, logging.Error, http.StatusInternalServerError, "Error cleaning pull request: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -14,185 +14,303 @@ import (
|
||||
"github.com/hootsuite/atlantis/server/events"
|
||||
emocks "github.com/hootsuite/atlantis/server/events/mocks"
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
"github.com/hootsuite/atlantis/server/events/vcs"
|
||||
"github.com/hootsuite/atlantis/server/logging"
|
||||
"github.com/hootsuite/atlantis/server/mocks"
|
||||
. "github.com/hootsuite/atlantis/testing"
|
||||
"github.com/lkysow/go-gitlab"
|
||||
. "github.com/petergtz/pegomock"
|
||||
)
|
||||
|
||||
const secret = "secret"
|
||||
const githubHeader = "X-Github-Event"
|
||||
const gitlabHeader = "X-Gitlab-Event"
|
||||
|
||||
var secret = []byte("secret")
|
||||
var eventsReq *http.Request
|
||||
|
||||
func TestPost_InvalidSecret(t *testing.T) {
|
||||
t.Log("when the payload can't be validated a 400 is returned")
|
||||
e, v, _, _, _ := setup(t)
|
||||
func TestPost_NotGithubOrGitlab(t *testing.T) {
|
||||
t.Log("when the request is not for gitlab or github a 400 is returned")
|
||||
e, _, _, _, _, _ := setup(t)
|
||||
w := httptest.NewRecorder()
|
||||
When(v.Validate(eventsReq, []byte(secret))).ThenReturn(nil, errors.New("err"))
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusBadRequest, "Ignoring request")
|
||||
}
|
||||
|
||||
func TestPost_UnsupportedVCSGithub(t *testing.T) {
|
||||
t.Log("when the request is for an unsupported vcs a 400 is returned")
|
||||
e, _, _, _, _, _ := setup(t)
|
||||
e.SupportedVCSHosts = nil
|
||||
eventsReq.Header.Set(githubHeader, "value")
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusBadRequest, "Ignoring request since not configured to support GitHub")
|
||||
}
|
||||
|
||||
func TestPost_UnsupportedVCSGitlab(t *testing.T) {
|
||||
t.Log("when the request is for an unsupported vcs a 400 is returned")
|
||||
e, _, _, _, _, _ := setup(t)
|
||||
e.SupportedVCSHosts = nil
|
||||
eventsReq.Header.Set(gitlabHeader, "value")
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusBadRequest, "Ignoring request since not configured to support GitLab")
|
||||
}
|
||||
|
||||
func TestPost_InvalidGithubSecret(t *testing.T) {
|
||||
t.Log("when the github payload can't be validated a 400 is returned")
|
||||
e, v, _, _, _, _ := setup(t)
|
||||
w := httptest.NewRecorder()
|
||||
eventsReq.Header.Set(githubHeader, "value")
|
||||
When(v.Validate(eventsReq, secret)).ThenReturn(nil, errors.New("err"))
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusBadRequest, "err")
|
||||
}
|
||||
|
||||
func TestPost_UnsupportedEvent(t *testing.T) {
|
||||
t.Log("when the event type is unsupported we ignore it")
|
||||
e, v, _, _, _ := setup(t)
|
||||
func TestPost_InvalidGitlabSecret(t *testing.T) {
|
||||
t.Log("when the gitlab payload can't be validated a 400 is returned")
|
||||
e, _, gl, _, _, _ := setup(t)
|
||||
w := httptest.NewRecorder()
|
||||
eventsReq.Header.Set(gitlabHeader, "value")
|
||||
When(gl.Validate(eventsReq, secret)).ThenReturn(nil, errors.New("err"))
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusBadRequest, "err")
|
||||
}
|
||||
|
||||
func TestPost_UnsupportedGithubEvent(t *testing.T) {
|
||||
t.Log("when the event type is an unsupported github event we ignore it")
|
||||
e, v, _, _, _, _ := setup(t)
|
||||
w := httptest.NewRecorder()
|
||||
eventsReq.Header.Set(githubHeader, "value")
|
||||
When(v.Validate(eventsReq, nil)).ThenReturn([]byte(`{"not an event": ""}`), nil)
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusOK, "Ignoring unsupported event")
|
||||
}
|
||||
|
||||
func TestPost_CommentNotCreated(t *testing.T) {
|
||||
t.Log("when the event is a comment but it's not a created event we ignore it")
|
||||
e, v, _, _, _ := setup(t)
|
||||
eventsReq.Header.Set("X-Github-Event", "issue_comment")
|
||||
func TestPost_UnsupportedGitlabEvent(t *testing.T) {
|
||||
t.Log("when the event type is an unsupported gitlab event we ignore it")
|
||||
e, _, gl, _, _, _ := setup(t)
|
||||
w := httptest.NewRecorder()
|
||||
eventsReq.Header.Set(gitlabHeader, "value")
|
||||
When(gl.Validate(eventsReq, secret)).ThenReturn([]byte(`{"not an event": ""}`), nil)
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusOK, "Ignoring unsupported event")
|
||||
}
|
||||
|
||||
func TestPost_GithubCommentNotCreated(t *testing.T) {
|
||||
t.Log("when the event is a github comment but it's not a created event we ignore it")
|
||||
e, v, _, _, _, _ := setup(t)
|
||||
eventsReq.Header.Set(githubHeader, "issue_comment")
|
||||
// comment action is deleted, not created
|
||||
event := `{"action": "deleted"}`
|
||||
When(v.Validate(eventsReq, []byte(secret))).ThenReturn([]byte(event), nil)
|
||||
When(v.Validate(eventsReq, secret)).ThenReturn([]byte(event), nil)
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusOK, "Ignoring comment event since action was not created")
|
||||
}
|
||||
|
||||
func TestPost_CommentInvalidComment(t *testing.T) {
|
||||
t.Log("when the event is a comment without all expected data we return a 400")
|
||||
e, v, p, _, _ := setup(t)
|
||||
eventsReq.Header.Set("X-Github-Event", "issue_comment")
|
||||
func TestPost_GithubInvalidComment(t *testing.T) {
|
||||
t.Log("when the event is a github comment without all expected data we return a 400")
|
||||
e, v, _, p, _, _ := setup(t)
|
||||
eventsReq.Header.Set(githubHeader, "issue_comment")
|
||||
event := `{"action": "created"}`
|
||||
When(v.Validate(eventsReq, []byte(secret))).ThenReturn([]byte(event), nil)
|
||||
When(p.ExtractCommentData(AnyComment())).ThenReturn(models.Repo{}, models.User{}, models.PullRequest{}, errors.New("err"))
|
||||
When(v.Validate(eventsReq, secret)).ThenReturn([]byte(event), nil)
|
||||
When(p.ParseGithubIssueCommentEvent(AnyComment())).ThenReturn(models.Repo{}, models.User{}, 1, errors.New("err"))
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusBadRequest, "Failed parsing event")
|
||||
}
|
||||
|
||||
func TestPost_CommentInvalidCommand(t *testing.T) {
|
||||
t.Log("when the event is a comment with an invalid command we ignore it")
|
||||
e, v, p, _, _ := setup(t)
|
||||
eventsReq.Header.Set("X-Github-Event", "issue_comment")
|
||||
event := `{"action": "created"}`
|
||||
When(v.Validate(eventsReq, []byte(secret))).ThenReturn([]byte(event), nil)
|
||||
When(p.ExtractCommentData(AnyComment())).ThenReturn(models.Repo{}, models.User{}, models.PullRequest{}, nil)
|
||||
When(p.DetermineCommand(AnyComment())).ThenReturn(nil, errors.New("err"))
|
||||
func TestPost_GitlabCommentInvalidCommand(t *testing.T) {
|
||||
t.Log("when the event is a gitlab comment with an invalid command we ignore it")
|
||||
e, _, gl, p, _, _ := setup(t)
|
||||
eventsReq.Header.Set(gitlabHeader, "value")
|
||||
When(gl.Validate(eventsReq, secret)).ThenReturn(gitlab.MergeCommentEvent{}, nil)
|
||||
When(p.DetermineCommand("", vcs.Gitlab)).ThenReturn(nil, errors.New("err"))
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusOK, "Ignoring: err")
|
||||
}
|
||||
|
||||
func TestPost_CommentSuccess(t *testing.T) {
|
||||
t.Log("when the event is comment with a valid command we call the command handler")
|
||||
e, v, p, cr, _ := setup(t)
|
||||
eventsReq.Header.Set("X-Github-Event", "issue_comment")
|
||||
func TestPost_GithubCommentInvalidCommand(t *testing.T) {
|
||||
t.Log("when the event is a github comment with an invalid command we ignore it")
|
||||
e, v, _, p, _, _ := setup(t)
|
||||
eventsReq.Header.Set(githubHeader, "issue_comment")
|
||||
event := `{"action": "created"}`
|
||||
When(v.Validate(eventsReq, []byte(secret))).ThenReturn([]byte(event), nil)
|
||||
baseRepo := models.Repo{}
|
||||
user := models.User{}
|
||||
pull := models.PullRequest{}
|
||||
cmd := events.Command{}
|
||||
When(p.ExtractCommentData(AnyComment())).ThenReturn(baseRepo, user, pull, nil)
|
||||
When(p.DetermineCommand(AnyComment())).ThenReturn(&cmd, nil)
|
||||
When(v.Validate(eventsReq, secret)).ThenReturn([]byte(event), nil)
|
||||
When(p.ParseGithubIssueCommentEvent(AnyComment())).ThenReturn(models.Repo{}, models.User{}, 1, nil)
|
||||
When(p.DetermineCommand("", vcs.Github)).ThenReturn(nil, errors.New("err"))
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusOK, "Ignoring: err")
|
||||
}
|
||||
|
||||
func TestPost_GitlabCommentSuccess(t *testing.T) {
|
||||
t.Log("when the event is a gitlab comment with a valid command we call the command handler")
|
||||
e, _, gl, _, cr, _ := setup(t)
|
||||
eventsReq.Header.Set(gitlabHeader, "value")
|
||||
When(gl.Validate(eventsReq, secret)).ThenReturn(gitlab.MergeCommentEvent{}, nil)
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusOK, "Processing...")
|
||||
|
||||
// wait for 200ms so goroutine is called
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
ctx := cr.VerifyWasCalledOnce().ExecuteCommand(AnyCommandContext()).GetCapturedArguments()
|
||||
Equals(t, baseRepo, ctx.BaseRepo)
|
||||
Equals(t, user, ctx.User)
|
||||
Equals(t, pull, ctx.Pull)
|
||||
Equals(t, cmd, *ctx.Command)
|
||||
cr.VerifyWasCalledOnce().ExecuteCommand(models.Repo{}, models.Repo{}, models.User{}, 0, nil, vcs.Gitlab)
|
||||
}
|
||||
|
||||
func TestPost_PullRequestNotClosed(t *testing.T) {
|
||||
t.Log("when the event is pull reuqest but it's not a closed event we ignore it")
|
||||
e, v, _, _, _ := setup(t)
|
||||
eventsReq.Header.Set("X-Github-Event", "pull_request")
|
||||
func TestPost_GithubCommentSuccess(t *testing.T) {
|
||||
t.Log("when the event is a github comment with a valid command we call the command handler")
|
||||
e, v, _, p, cr, _ := setup(t)
|
||||
eventsReq.Header.Set(githubHeader, "issue_comment")
|
||||
event := `{"action": "created"}`
|
||||
When(v.Validate(eventsReq, secret)).ThenReturn([]byte(event), nil)
|
||||
baseRepo := models.Repo{}
|
||||
user := models.User{}
|
||||
cmd := events.Command{}
|
||||
When(p.ParseGithubIssueCommentEvent(AnyComment())).ThenReturn(baseRepo, user, 1, nil)
|
||||
When(p.DetermineCommand("", vcs.Github)).ThenReturn(&cmd, nil)
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusOK, "Processing...")
|
||||
|
||||
// wait for 200ms so goroutine is called
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
cr.VerifyWasCalledOnce().ExecuteCommand(baseRepo, baseRepo, user, 1, &cmd, vcs.Github)
|
||||
}
|
||||
|
||||
func TestPost_GithubPullRequestNotClosed(t *testing.T) {
|
||||
t.Log("when the event is a github pull reuqest but it's not a closed event we ignore it")
|
||||
e, v, _, _, _, _ := setup(t)
|
||||
eventsReq.Header.Set(githubHeader, "pull_request")
|
||||
event := `{"action": "opened"}`
|
||||
When(v.Validate(eventsReq, []byte(secret))).ThenReturn([]byte(event), nil)
|
||||
When(v.Validate(eventsReq, secret)).ThenReturn([]byte(event), nil)
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusOK, "Ignoring pull request event since action was not closed")
|
||||
}
|
||||
|
||||
func TestPost_PullRequestInvalid(t *testing.T) {
|
||||
t.Log("when the event is pull request with invalid data we return a 400")
|
||||
e, v, p, _, _ := setup(t)
|
||||
eventsReq.Header.Set("X-Github-Event", "pull_request")
|
||||
func TestPost_GitlabMergeRequestNotClosed(t *testing.T) {
|
||||
t.Log("when the event is a gitlab merge request but it's not a closed event we ignore it")
|
||||
e, _, gl, p, _, _ := setup(t)
|
||||
eventsReq.Header.Set(gitlabHeader, "value")
|
||||
event := gitlab.MergeEvent{}
|
||||
When(gl.Validate(eventsReq, secret)).ThenReturn(event, nil)
|
||||
When(p.ParseGitlabMergeEvent(event)).ThenReturn(models.PullRequest{State: models.Open}, models.Repo{})
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusOK, "Ignoring opened merge request event")
|
||||
}
|
||||
|
||||
func TestPost_GithubPullRequestInvalid(t *testing.T) {
|
||||
t.Log("when the event is a github pull request with invalid data we return a 400")
|
||||
e, v, _, p, _, _ := setup(t)
|
||||
eventsReq.Header.Set(githubHeader, "pull_request")
|
||||
|
||||
event := `{"action": "closed"}`
|
||||
When(v.Validate(eventsReq, []byte(secret))).ThenReturn([]byte(event), nil)
|
||||
When(p.ExtractPullData(AnyPull())).ThenReturn(models.PullRequest{}, models.Repo{}, errors.New("err"))
|
||||
When(v.Validate(eventsReq, secret)).ThenReturn([]byte(event), nil)
|
||||
When(p.ParseGithubPull(AnyPull())).ThenReturn(models.PullRequest{}, models.Repo{}, errors.New("err"))
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusBadRequest, "Error parsing pull data: err")
|
||||
}
|
||||
|
||||
func TestPost_PullRequestInvalidRepo(t *testing.T) {
|
||||
t.Log("when the event is pull reuqest with invalid repo data we return a 400")
|
||||
e, v, p, _, _ := setup(t)
|
||||
eventsReq.Header.Set("X-Github-Event", "pull_request")
|
||||
func TestPost_GithubPullRequestInvalidRepo(t *testing.T) {
|
||||
t.Log("when the event is a github pull request with invalid repo data we return a 400")
|
||||
e, v, _, p, _, _ := setup(t)
|
||||
eventsReq.Header.Set(githubHeader, "pull_request")
|
||||
|
||||
event := `{"action": "closed"}`
|
||||
When(v.Validate(eventsReq, []byte(secret))).ThenReturn([]byte(event), nil)
|
||||
When(p.ExtractPullData(AnyPull())).ThenReturn(models.PullRequest{}, models.Repo{}, nil)
|
||||
When(p.ExtractRepoData(AnyRepo())).ThenReturn(models.Repo{}, errors.New("err"))
|
||||
When(v.Validate(eventsReq, secret)).ThenReturn([]byte(event), nil)
|
||||
When(p.ParseGithubPull(AnyPull())).ThenReturn(models.PullRequest{}, models.Repo{}, nil)
|
||||
When(p.ParseGithubRepo(AnyRepo())).ThenReturn(models.Repo{}, errors.New("err"))
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusBadRequest, "Error parsing repo data: err")
|
||||
}
|
||||
|
||||
func TestPost_PullRequestErrCleaningPull(t *testing.T) {
|
||||
func TestPost_GithubPullRequestErrCleaningPull(t *testing.T) {
|
||||
t.Log("when the event is a pull request and we have an error calling CleanUpPull we return a 503")
|
||||
RegisterMockTestingT(t)
|
||||
e, v, p, _, c := setup(t)
|
||||
eventsReq.Header.Set("X-Github-Event", "pull_request")
|
||||
e, v, _, p, _, c := setup(t)
|
||||
eventsReq.Header.Set(githubHeader, "pull_request")
|
||||
|
||||
event := `{"action": "closed"}`
|
||||
When(v.Validate(eventsReq, []byte(secret))).ThenReturn([]byte(event), nil)
|
||||
When(v.Validate(eventsReq, secret)).ThenReturn([]byte(event), nil)
|
||||
repo := models.Repo{}
|
||||
pull := models.PullRequest{}
|
||||
When(p.ExtractPullData(AnyPull())).ThenReturn(pull, repo, nil)
|
||||
When(p.ExtractRepoData(AnyRepo())).ThenReturn(repo, nil)
|
||||
When(c.CleanUpPull(repo, pull)).ThenReturn(errors.New("cleanup err"))
|
||||
When(p.ParseGithubPull(AnyPull())).ThenReturn(pull, repo, nil)
|
||||
When(p.ParseGithubRepo(AnyRepo())).ThenReturn(repo, nil)
|
||||
When(c.CleanUpPull(repo, pull, vcs.Github)).ThenReturn(errors.New("cleanup err"))
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusInternalServerError, "Error cleaning pull request: cleanup err")
|
||||
}
|
||||
|
||||
func TestPost_PullRequestSuccess(t *testing.T) {
|
||||
func TestPost_GitlabMergeRequestErrCleaningPull(t *testing.T) {
|
||||
t.Log("when the event is a gitlab merge request and an error occurs calling CleanUpPull we return a 503")
|
||||
e, _, gl, p, _, c := setup(t)
|
||||
eventsReq.Header.Set(gitlabHeader, "value")
|
||||
event := gitlab.MergeEvent{}
|
||||
When(gl.Validate(eventsReq, secret)).ThenReturn(event, nil)
|
||||
repo := models.Repo{}
|
||||
pullRequest := models.PullRequest{State: models.Closed}
|
||||
When(p.ParseGitlabMergeEvent(event)).ThenReturn(pullRequest, repo)
|
||||
When(c.CleanUpPull(repo, pullRequest, vcs.Gitlab)).ThenReturn(errors.New("err"))
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusInternalServerError, "Error cleaning pull request: err")
|
||||
}
|
||||
|
||||
func TestPost_GithubPullRequestSuccess(t *testing.T) {
|
||||
t.Log("when the event is a pull request and everything works we return a 200")
|
||||
e, v, p, _, c := setup(t)
|
||||
eventsReq.Header.Set("X-Github-Event", "pull_request")
|
||||
e, v, _, p, _, c := setup(t)
|
||||
eventsReq.Header.Set(githubHeader, "pull_request")
|
||||
|
||||
event := `{"action": "closed"}`
|
||||
When(v.Validate(eventsReq, []byte(secret))).ThenReturn([]byte(event), nil)
|
||||
When(v.Validate(eventsReq, secret)).ThenReturn([]byte(event), nil)
|
||||
repo := models.Repo{}
|
||||
pull := models.PullRequest{}
|
||||
When(p.ExtractPullData(AnyPull())).ThenReturn(pull, repo, nil)
|
||||
When(p.ExtractRepoData(AnyRepo())).ThenReturn(repo, nil)
|
||||
When(c.CleanUpPull(repo, pull)).ThenReturn(nil)
|
||||
When(p.ParseGithubPull(AnyPull())).ThenReturn(pull, repo, nil)
|
||||
When(p.ParseGithubRepo(AnyRepo())).ThenReturn(repo, nil)
|
||||
When(c.CleanUpPull(repo, pull, vcs.Github)).ThenReturn(nil)
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusOK, "Pull request cleaned successfully")
|
||||
}
|
||||
|
||||
func setup(t *testing.T) (server.EventsController, *mocks.MockGHRequestValidator, *emocks.MockEventParsing, *emocks.MockCommandRunner, *emocks.MockPullCleaner) {
|
||||
func TestPost_GitlabMergeRequestSuccess(t *testing.T) {
|
||||
t.Log("when the event is a gitlab merge request and the cleanup works we return a 200")
|
||||
e, _, gl, p, _, _ := setup(t)
|
||||
eventsReq.Header.Set(gitlabHeader, "value")
|
||||
event := gitlab.MergeEvent{}
|
||||
When(gl.Validate(eventsReq, secret)).ThenReturn(event, nil)
|
||||
repo := models.Repo{}
|
||||
pullRequest := models.PullRequest{State: models.Closed}
|
||||
When(p.ParseGitlabMergeEvent(event)).ThenReturn(pullRequest, repo)
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, eventsReq)
|
||||
responseContains(t, w, http.StatusOK, "Merge request cleaned successfully")
|
||||
}
|
||||
|
||||
func setup(t *testing.T) (server.EventsController, *mocks.MockGithubRequestValidator, *mocks.MockGitlabRequestParser, *emocks.MockEventParsing, *emocks.MockCommandRunner, *emocks.MockPullCleaner) {
|
||||
RegisterMockTestingT(t)
|
||||
eventsReq, _ = http.NewRequest("GET", "", bytes.NewBuffer(nil))
|
||||
v := mocks.NewMockGHRequestValidator()
|
||||
v := mocks.NewMockGithubRequestValidator()
|
||||
gl := mocks.NewMockGitlabRequestParser()
|
||||
p := emocks.NewMockEventParsing()
|
||||
cr := emocks.NewMockCommandRunner()
|
||||
c := emocks.NewMockPullCleaner()
|
||||
e := server.EventsController{
|
||||
Logger: logging.NewNoopLogger(),
|
||||
Validator: v,
|
||||
GithubRequestValidator: v,
|
||||
Parser: p,
|
||||
CommandRunner: cr,
|
||||
PullCleaner: c,
|
||||
GithubWebHookSecret: []byte(secret),
|
||||
GithubWebHookSecret: secret,
|
||||
SupportedVCSHosts: []vcs.Host{vcs.Github, vcs.Gitlab},
|
||||
GitlabWebHookSecret: secret,
|
||||
GitlabRequestParser: gl,
|
||||
}
|
||||
return e, v, p, cr, c
|
||||
return e, v, gl, p, cr, c
|
||||
}
|
||||
|
||||
func AnyComment() *github.IssueCommentEvent {
|
||||
@@ -209,8 +327,3 @@ func AnyRepo() *github.Repository {
|
||||
RegisterMatcher(NewAnyMatcher(reflect.TypeOf(&github.Repository{})))
|
||||
return &github.Repository{}
|
||||
}
|
||||
|
||||
func AnyCommandContext() *events.CommandContext {
|
||||
RegisterMatcher(NewAnyMatcher(reflect.TypeOf(&events.CommandContext{})))
|
||||
return &events.CommandContext{}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ import (
|
||||
"github.com/google/go-github/github"
|
||||
)
|
||||
|
||||
//go:generate pegomock generate --use-experimental-model-gen --package mocks -o mocks/mock_gh_request_validation.go GHRequestValidator
|
||||
//go:generate pegomock generate --use-experimental-model-gen --package mocks -o mocks/mock_gh_request_validation.go GithubRequestValidator
|
||||
|
||||
// GHRequestValidator validates GitHub requests.
|
||||
type GHRequestValidator interface {
|
||||
// GithubRequestValidator validates GitHub requests.
|
||||
type GithubRequestValidator interface {
|
||||
// Validate returns the JSON payload of the request.
|
||||
// If secret is not empty, it checks that the request was signed
|
||||
// by secret and returns an error if it was not.
|
||||
@@ -20,21 +20,21 @@ type GHRequestValidator interface {
|
||||
Validate(r *http.Request, secret []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
// GHRequestValidation implements the GHRequestValidator interface.
|
||||
type GHRequestValidation struct{}
|
||||
// DefaultGithubRequestValidator validates GitHub requests.
|
||||
type DefaultGithubRequestValidator struct{}
|
||||
|
||||
// Validate returns the JSON payload of the request.
|
||||
// If secret is not empty, it checks that the request was signed
|
||||
// by secret and returns an error if it was not.
|
||||
// If secret is empty, it does not check if the request was signed.
|
||||
func (g *GHRequestValidation) Validate(r *http.Request, secret []byte) ([]byte, error) {
|
||||
func (d *DefaultGithubRequestValidator) Validate(r *http.Request, secret []byte) ([]byte, error) {
|
||||
if len(secret) != 0 {
|
||||
return g.validateAgainstSecret(r, secret)
|
||||
return d.validateAgainstSecret(r, secret)
|
||||
}
|
||||
return g.validateWithoutSecret(r)
|
||||
return d.validateWithoutSecret(r)
|
||||
}
|
||||
|
||||
func (g *GHRequestValidation) validateAgainstSecret(r *http.Request, secret []byte) ([]byte, error) {
|
||||
func (d *DefaultGithubRequestValidator) validateAgainstSecret(r *http.Request, secret []byte) ([]byte, error) {
|
||||
payload, err := github.ValidatePayload(r, secret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -42,7 +42,7 @@ func (g *GHRequestValidation) validateAgainstSecret(r *http.Request, secret []by
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
func (g *GHRequestValidation) validateWithoutSecret(r *http.Request) ([]byte, error) {
|
||||
func (d *DefaultGithubRequestValidator) validateWithoutSecret(r *http.Request) ([]byte, error) {
|
||||
switch ct := r.Header.Get("Content-Type"); ct {
|
||||
case "application/json":
|
||||
payload, err := ioutil.ReadAll(r.Body)
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
func TestValidate_WithSecretErr(t *testing.T) {
|
||||
t.Log("if the request is not valid against the secret there is an error")
|
||||
RegisterMockTestingT(t)
|
||||
g := server.GHRequestValidation{}
|
||||
g := server.DefaultGithubRequestValidator{}
|
||||
buf := bytes.NewBufferString("")
|
||||
req, err := http.NewRequest("POST", "http://localhost/event", buf)
|
||||
Ok(t, err)
|
||||
@@ -29,7 +29,7 @@ func TestValidate_WithSecretErr(t *testing.T) {
|
||||
func TestValidate_WithSecret(t *testing.T) {
|
||||
t.Log("if the request is valid against the secret the payload is returned")
|
||||
RegisterMockTestingT(t)
|
||||
g := server.GHRequestValidation{}
|
||||
g := server.DefaultGithubRequestValidator{}
|
||||
buf := bytes.NewBufferString(`{"yo":true}`)
|
||||
req, err := http.NewRequest("POST", "http://localhost/event", buf)
|
||||
Ok(t, err)
|
||||
@@ -44,7 +44,7 @@ func TestValidate_WithSecret(t *testing.T) {
|
||||
func TestValidate_WithoutSecretInvalidContentType(t *testing.T) {
|
||||
t.Log("if the request has an invalid content type an error is returned")
|
||||
RegisterMockTestingT(t)
|
||||
g := server.GHRequestValidation{}
|
||||
g := server.DefaultGithubRequestValidator{}
|
||||
buf := bytes.NewBufferString("")
|
||||
req, err := http.NewRequest("POST", "http://localhost/event", buf)
|
||||
Ok(t, err)
|
||||
@@ -58,7 +58,7 @@ func TestValidate_WithoutSecretInvalidContentType(t *testing.T) {
|
||||
func TestValidate_WithoutSecretJSON(t *testing.T) {
|
||||
t.Log("if the request is JSON the body is returned")
|
||||
RegisterMockTestingT(t)
|
||||
g := server.GHRequestValidation{}
|
||||
g := server.DefaultGithubRequestValidator{}
|
||||
buf := bytes.NewBufferString(`{"yo":true}`)
|
||||
req, err := http.NewRequest("POST", "http://localhost/event", buf)
|
||||
Ok(t, err)
|
||||
@@ -72,7 +72,7 @@ func TestValidate_WithoutSecretJSON(t *testing.T) {
|
||||
func TestValidate_WithoutSecretFormNoPayload(t *testing.T) {
|
||||
t.Log("if the request is form encoded and does not contain a payload param an error is returned")
|
||||
RegisterMockTestingT(t)
|
||||
g := server.GHRequestValidation{}
|
||||
g := server.DefaultGithubRequestValidator{}
|
||||
buf := bytes.NewBufferString("")
|
||||
req, err := http.NewRequest("POST", "http://localhost/event", buf)
|
||||
Ok(t, err)
|
||||
@@ -86,7 +86,7 @@ func TestValidate_WithoutSecretFormNoPayload(t *testing.T) {
|
||||
func TestValidate_WithoutSecretForm(t *testing.T) {
|
||||
t.Log("if the request is form encoded and does not contain a payload param an error is returned")
|
||||
RegisterMockTestingT(t)
|
||||
g := server.GHRequestValidation{}
|
||||
g := server.DefaultGithubRequestValidator{}
|
||||
form := url.Values{}
|
||||
form.Set("payload", `{"yo":true}`)
|
||||
buf := bytes.NewBufferString(form.Encode())
|
||||
79
server/gitlab_request_parser.go
Normal file
79
server/gitlab_request_parser.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/lkysow/go-gitlab"
|
||||
)
|
||||
|
||||
const secretHeader = "X-Gitlab-Token"
|
||||
|
||||
//go:generate pegomock generate --use-experimental-model-gen --package mocks -o mocks/mock_gitlab_request_parser.go GitlabRequestParser
|
||||
|
||||
// GitlabRequestParser parses and validates GitLab requests.
|
||||
type GitlabRequestParser interface {
|
||||
// Validate validates that the request has a token header matching secret.
|
||||
// If the secret does not match it returns an error.
|
||||
// If secret is empty it does not check the token header.
|
||||
// It then parses the request as a gitlab object depending on the header
|
||||
// provided by GitLab identifying the webhook type. If the webhook type
|
||||
// is not recognized it will return nil but will not return an error.
|
||||
// Usage:
|
||||
// event, err := GitlabRequestParser.Validate(r, secret)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// switch event := event.(type) {
|
||||
// case gitlab.MergeCommentEvent:
|
||||
// // handle
|
||||
// case gitlab.MergeEvent:
|
||||
// // handle
|
||||
// default:
|
||||
// // unsupported event
|
||||
// }
|
||||
Validate(r *http.Request, secret []byte) (interface{}, error)
|
||||
}
|
||||
|
||||
// DefaultGitlabRequestParser parses GitLab requests.
|
||||
type DefaultGitlabRequestParser struct{}
|
||||
|
||||
// Validate returns the JSON payload of the request.
|
||||
// If secret is not empty, it checks that the request was signed
|
||||
// by secret and returns an error if it was not.
|
||||
// If secret is empty, it does not check if the request was signed.
|
||||
func (d *DefaultGitlabRequestParser) Validate(r *http.Request, secret []byte) (interface{}, error) {
|
||||
const mergeEventHeader = "Merge Request Hook"
|
||||
const noteEventHeader = "Note Hook"
|
||||
|
||||
// Validate secret if specified.
|
||||
headerSecret := r.Header.Get(secretHeader)
|
||||
secretStr := string(secret)
|
||||
if len(secret) != 0 && headerSecret != secretStr {
|
||||
return nil, fmt.Errorf("header %s=%s did not match expected secret", secretHeader, headerSecret)
|
||||
}
|
||||
|
||||
// Parse request into a gitlab object based on the object type specified
|
||||
// in the gitlabHeader.
|
||||
bytes, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch r.Header.Get(gitlabHeader) {
|
||||
case mergeEventHeader:
|
||||
var m gitlab.MergeEvent
|
||||
if err := json.Unmarshal(bytes, &m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
case noteEventHeader:
|
||||
var m gitlab.MergeCommentEvent
|
||||
if err := json.Unmarshal(bytes, &m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
372
server/gitlab_request_parser_test.go
Normal file
372
server/gitlab_request_parser_test.go
Normal file
@@ -0,0 +1,372 @@
|
||||
package server_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"github.com/hootsuite/atlantis/server"
|
||||
"bytes"
|
||||
. "github.com/hootsuite/atlantis/testing"
|
||||
. "github.com/petergtz/pegomock"
|
||||
"net/http"
|
||||
"github.com/lkysow/go-gitlab"
|
||||
)
|
||||
|
||||
var parser = server.DefaultGitlabRequestParser{}
|
||||
|
||||
func TestValidate_InvalidSecret(t *testing.T) {
|
||||
t.Log("If the secret header is set and doesn't match expected an error is returned")
|
||||
RegisterMockTestingT(t)
|
||||
buf := bytes.NewBufferString("")
|
||||
req, err := http.NewRequest("POST", "http://localhost/event", buf)
|
||||
Ok(t, err)
|
||||
req.Header.Set("X-Gitlab-Token", "does-not-match")
|
||||
_, err = parser.Validate(req, []byte("secret"))
|
||||
Assert(t, err != nil , "should be an error")
|
||||
Equals(t, "header X-Gitlab-Token=does-not-match did not match expected secret", err.Error())
|
||||
}
|
||||
|
||||
func TestValidate_ValidSecret(t *testing.T) {
|
||||
t.Log("If the secret header matches then the event is returned")
|
||||
RegisterMockTestingT(t)
|
||||
buf := bytes.NewBufferString(mergeEventJSON)
|
||||
req, err := http.NewRequest("POST", "http://localhost/event", buf)
|
||||
Ok(t, err)
|
||||
req.Header.Set("X-Gitlab-Token", "secret")
|
||||
req.Header.Set("X-Gitlab-Event", "Merge Request Hook")
|
||||
b, err := parser.Validate(req, []byte("secret"))
|
||||
Ok(t, err)
|
||||
Equals(t, "Gitlab Test", b.(gitlab.MergeEvent).Project.Name)
|
||||
}
|
||||
|
||||
func TestValidate_NoSecret(t *testing.T) {
|
||||
t.Log("If there is no secret then we ignore the secret header and return the event")
|
||||
RegisterMockTestingT(t)
|
||||
buf := bytes.NewBufferString(mergeEventJSON)
|
||||
req, err := http.NewRequest("POST", "http://localhost/event", buf)
|
||||
Ok(t, err)
|
||||
req.Header.Set("X-Gitlab-Token", "random secret")
|
||||
req.Header.Set("X-Gitlab-Event", "Merge Request Hook")
|
||||
b, err := parser.Validate(req, nil)
|
||||
Ok(t, err)
|
||||
Equals(t, "Gitlab Test", b.(gitlab.MergeEvent).Project.Name)
|
||||
}
|
||||
|
||||
func TestValidate_InvalidMergeEvent(t *testing.T) {
|
||||
t.Log("If the merge event is malformed there should be an error")
|
||||
RegisterMockTestingT(t)
|
||||
buf := bytes.NewBufferString("{")
|
||||
req, err := http.NewRequest("POST", "http://localhost/event", buf)
|
||||
Ok(t, err)
|
||||
req.Header.Set("X-Gitlab-Event", "Merge Request Hook")
|
||||
_, err = parser.Validate(req, nil)
|
||||
Assert(t, err != nil , "should be an error")
|
||||
Equals(t, "unexpected end of JSON input", err.Error())
|
||||
}
|
||||
|
||||
func TestValidate_InvalidMergeCommentEvent(t *testing.T) {
|
||||
t.Log("If the merge comment event is malformed there should be an error")
|
||||
RegisterMockTestingT(t)
|
||||
buf := bytes.NewBufferString("{")
|
||||
req, err := http.NewRequest("POST", "http://localhost/event", buf)
|
||||
Ok(t, err)
|
||||
req.Header.Set("X-Gitlab-Event", "Note Hook")
|
||||
_, err = parser.Validate(req, nil)
|
||||
Assert(t, err != nil , "should be an error")
|
||||
Equals(t, "unexpected end of JSON input", err.Error())
|
||||
}
|
||||
|
||||
func TestValidate_UnrecognizedEvent(t *testing.T) {
|
||||
t.Log("If the event is not one we care about we return nil")
|
||||
RegisterMockTestingT(t)
|
||||
buf := bytes.NewBufferString("")
|
||||
req, err := http.NewRequest("POST", "http://localhost/event", buf)
|
||||
Ok(t, err)
|
||||
req.Header.Set("X-Gitlab-Event", "Random Event")
|
||||
event, err := parser.Validate(req, nil)
|
||||
Ok(t, err)
|
||||
Equals(t, nil, event)
|
||||
}
|
||||
|
||||
func TestValidate_ValidMergeEvent(t *testing.T) {
|
||||
t.Log("If the merge event is valid it should be returned")
|
||||
RegisterMockTestingT(t)
|
||||
buf := bytes.NewBufferString(mergeEventJSON)
|
||||
req, err := http.NewRequest("POST", "http://localhost/event", buf)
|
||||
Ok(t, err)
|
||||
req.Header.Set("X-Gitlab-Event", "Merge Request Hook")
|
||||
b, err := parser.Validate(req, nil)
|
||||
Ok(t, err)
|
||||
Equals(t, "Gitlab Test", b.(gitlab.MergeEvent).Project.Name)
|
||||
RegisterMockTestingT(t)
|
||||
}
|
||||
|
||||
func TestValidate_ValidMergeCommentEvent(t *testing.T) {
|
||||
t.Log("If the merge comment event is valid it should be returned")
|
||||
RegisterMockTestingT(t)
|
||||
buf := bytes.NewBufferString(mergeCommentEventJSON)
|
||||
req, err := http.NewRequest("POST", "http://localhost/event", buf)
|
||||
Ok(t, err)
|
||||
req.Header.Set("X-Gitlab-Event", "Note Hook")
|
||||
b, err := parser.Validate(req, nil)
|
||||
Ok(t, err)
|
||||
Equals(t, "Gitlab Test", b.(gitlab.MergeCommentEvent).Project.Name)
|
||||
RegisterMockTestingT(t)
|
||||
}
|
||||
|
||||
var mergeEventJSON = `{
|
||||
"object_kind": "merge_request",
|
||||
"user": {
|
||||
"name": "Administrator",
|
||||
"username": "root",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
|
||||
},
|
||||
"project": {
|
||||
"id": 1,
|
||||
"name":"Gitlab Test",
|
||||
"description":"Aut reprehenderit ut est.",
|
||||
"web_url":"http://example.com/gitlabhq/gitlab-test",
|
||||
"avatar_url":null,
|
||||
"git_ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
|
||||
"git_http_url":"https://example.com/gitlabhq/gitlab-test.git",
|
||||
"namespace":"GitlabHQ",
|
||||
"visibility_level":20,
|
||||
"path_with_namespace":"gitlabhq/gitlab-test",
|
||||
"default_branch":"master",
|
||||
"homepage":"http://example.com/gitlabhq/gitlab-test",
|
||||
"url":"https://example.com/gitlabhq/gitlab-test.git",
|
||||
"ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
|
||||
"http_url":"https://example.com/gitlabhq/gitlab-test.git"
|
||||
},
|
||||
"repository": {
|
||||
"name": "Gitlab Test",
|
||||
"url": "https://example.com/gitlabhq/gitlab-test.git",
|
||||
"description": "Aut reprehenderit ut est.",
|
||||
"homepage": "http://example.com/gitlabhq/gitlab-test"
|
||||
},
|
||||
"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":null,
|
||||
"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":null,
|
||||
"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"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"labels": [{
|
||||
"id": 206,
|
||||
"title": "API",
|
||||
"color": "#ffffff",
|
||||
"project_id": 14,
|
||||
"created_at": "2013-12-03T17:15:43Z",
|
||||
"updated_at": "2013-12-03T17:15:43Z",
|
||||
"template": false,
|
||||
"description": "API related issues",
|
||||
"type": "ProjectLabel",
|
||||
"group_id": 41
|
||||
}],
|
||||
"changes": {
|
||||
"updated_by_id": [null, 1],
|
||||
"updated_at": ["2017-09-15 16:50:55 UTC", "2017-09-15 16:52:00 UTC"],
|
||||
"labels": {
|
||||
"previous": [{
|
||||
"id": 206,
|
||||
"title": "API",
|
||||
"color": "#ffffff",
|
||||
"project_id": 14,
|
||||
"created_at": "2013-12-03T17:15:43Z",
|
||||
"updated_at": "2013-12-03T17:15:43Z",
|
||||
"template": false,
|
||||
"description": "API related issues",
|
||||
"type": "ProjectLabel",
|
||||
"group_id": 41
|
||||
}],
|
||||
"current": [{
|
||||
"id": 205,
|
||||
"title": "Platform",
|
||||
"color": "#123123",
|
||||
"project_id": 14,
|
||||
"created_at": "2013-12-03T17:15:43Z",
|
||||
"updated_at": "2013-12-03T17:15:43Z",
|
||||
"template": false,
|
||||
"description": "Platform related issues",
|
||||
"type": "ProjectLabel",
|
||||
"group_id": 41
|
||||
}]
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
var mergeCommentEventJSON = `{
|
||||
"object_kind": "note",
|
||||
"user": {
|
||||
"name": "Administrator",
|
||||
"username": "root",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
|
||||
},
|
||||
"project_id": 5,
|
||||
"project":{
|
||||
"id": 5,
|
||||
"name":"Gitlab Test",
|
||||
"description":"Aut reprehenderit ut est.",
|
||||
"web_url":"http://example.com/gitlabhq/gitlab-test",
|
||||
"avatar_url":null,
|
||||
"git_ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
|
||||
"git_http_url":"https://example.com/gitlabhq/gitlab-test.git",
|
||||
"namespace":"Gitlab Org",
|
||||
"visibility_level":10,
|
||||
"path_with_namespace":"gitlabhq/gitlab-test",
|
||||
"default_branch":"master",
|
||||
"homepage":"http://example.com/gitlabhq/gitlab-test",
|
||||
"url":"https://example.com/gitlabhq/gitlab-test.git",
|
||||
"ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
|
||||
"http_url":"https://example.com/gitlabhq/gitlab-test.git"
|
||||
},
|
||||
"repository":{
|
||||
"name": "Gitlab Test",
|
||||
"url": "http://localhost/gitlab-org/gitlab-test.git",
|
||||
"description": "Aut reprehenderit ut est.",
|
||||
"homepage": "http://example.com/gitlab-org/gitlab-test"
|
||||
},
|
||||
"object_attributes": {
|
||||
"id": 1244,
|
||||
"note": "This MR needs work.",
|
||||
"noteable_type": "MergeRequest",
|
||||
"author_id": 1,
|
||||
"created_at": "2015-05-17",
|
||||
"updated_at": "2015-05-17",
|
||||
"project_id": 5,
|
||||
"attachment": null,
|
||||
"line_code": null,
|
||||
"commit_id": "",
|
||||
"noteable_id": 7,
|
||||
"system": false,
|
||||
"st_diff": null,
|
||||
"url": "http://example.com/gitlab-org/gitlab-test/merge_requests/1#note_1244"
|
||||
},
|
||||
"merge_request": {
|
||||
"id": 7,
|
||||
"target_branch": "markdown",
|
||||
"source_branch": "master",
|
||||
"source_project_id": 5,
|
||||
"author_id": 8,
|
||||
"assignee_id": 28,
|
||||
"title": "Tempora et eos debitis quae laborum et.",
|
||||
"created_at": "2015-03-01 20:12:53 UTC",
|
||||
"updated_at": "2015-03-21 18:27:27 UTC",
|
||||
"milestone_id": 11,
|
||||
"state": "opened",
|
||||
"merge_status": "cannot_be_merged",
|
||||
"target_project_id": 5,
|
||||
"iid": 1,
|
||||
"description": "Et voluptas corrupti assumenda temporibus. Architecto cum animi eveniet amet asperiores. Vitae numquam voluptate est natus sit et ad id.",
|
||||
"position": 0,
|
||||
"source":{
|
||||
"name":"Gitlab Test",
|
||||
"description":"Aut reprehenderit ut est.",
|
||||
"web_url":"http://example.com/gitlab-org/gitlab-test",
|
||||
"avatar_url":null,
|
||||
"git_ssh_url":"git@example.com:gitlab-org/gitlab-test.git",
|
||||
"git_http_url":"https://example.com/gitlab-org/gitlab-test.git",
|
||||
"namespace":"Gitlab Org",
|
||||
"visibility_level":10,
|
||||
"path_with_namespace":"gitlab-org/gitlab-test",
|
||||
"default_branch":"master",
|
||||
"homepage":"http://example.com/gitlab-org/gitlab-test",
|
||||
"url":"https://example.com/gitlab-org/gitlab-test.git",
|
||||
"ssh_url":"git@example.com:gitlab-org/gitlab-test.git",
|
||||
"http_url":"https://example.com/gitlab-org/gitlab-test.git",
|
||||
"git_http_url":"https://example.com/gitlab-org/gitlab-test.git"
|
||||
},
|
||||
"target": {
|
||||
"name":"Gitlab Test",
|
||||
"description":"Aut reprehenderit ut est.",
|
||||
"web_url":"http://example.com/gitlabhq/gitlab-test",
|
||||
"avatar_url":null,
|
||||
"git_ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
|
||||
"git_http_url":"https://example.com/gitlabhq/gitlab-test.git",
|
||||
"namespace":"Gitlab Org",
|
||||
"visibility_level":10,
|
||||
"path_with_namespace":"gitlabhq/gitlab-test",
|
||||
"default_branch":"master",
|
||||
"homepage":"http://example.com/gitlabhq/gitlab-test",
|
||||
"url":"https://example.com/gitlabhq/gitlab-test.git",
|
||||
"ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
|
||||
"http_url":"https://example.com/gitlabhq/gitlab-test.git"
|
||||
},
|
||||
"last_commit": {
|
||||
"id": "562e173be03b8ff2efb05345d12df18815438a4b",
|
||||
"message": "Merge branch 'another-branch' into 'master'\n\nCheck in this test\n",
|
||||
"timestamp": "2002-10-02T10:00:00-05:00",
|
||||
"url": "http://example.com/gitlab-org/gitlab-test/commit/562e173be03b8ff2efb05345d12df18815438a4b",
|
||||
"author": {
|
||||
"name": "John Smith",
|
||||
"email": "john@example.com"
|
||||
}
|
||||
},
|
||||
"work_in_progress": false,
|
||||
"assignee": {
|
||||
"name": "User1",
|
||||
"username": "user1",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
|
||||
}
|
||||
}
|
||||
}`
|
||||
335
server/logging/mocks/mock_simple_logging.go
Normal file
335
server/logging/mocks/mock_simple_logging.go
Normal file
@@ -0,0 +1,335 @@
|
||||
// Automatically generated by pegomock. DO NOT EDIT!
|
||||
// Source: github.com/hootsuite/atlantis/server/logging (interfaces: SimpleLogging)
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
log "log"
|
||||
"reflect"
|
||||
|
||||
logging "github.com/hootsuite/atlantis/server/logging"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
)
|
||||
|
||||
type MockSimpleLogging struct {
|
||||
fail func(message string, callerSkip ...int)
|
||||
}
|
||||
|
||||
func NewMockSimpleLogging() *MockSimpleLogging {
|
||||
return &MockSimpleLogging{fail: pegomock.GlobalFailHandler}
|
||||
}
|
||||
|
||||
func (mock *MockSimpleLogging) Debug(format string, a ...interface{}) {
|
||||
params := []pegomock.Param{format}
|
||||
for _, param := range a {
|
||||
params = append(params, param)
|
||||
}
|
||||
pegomock.GetGenericMockFrom(mock).Invoke("Debug", params, []reflect.Type{})
|
||||
}
|
||||
|
||||
func (mock *MockSimpleLogging) Info(format string, a ...interface{}) {
|
||||
params := []pegomock.Param{format}
|
||||
for _, param := range a {
|
||||
params = append(params, param)
|
||||
}
|
||||
pegomock.GetGenericMockFrom(mock).Invoke("Info", params, []reflect.Type{})
|
||||
}
|
||||
|
||||
func (mock *MockSimpleLogging) Warn(format string, a ...interface{}) {
|
||||
params := []pegomock.Param{format}
|
||||
for _, param := range a {
|
||||
params = append(params, param)
|
||||
}
|
||||
pegomock.GetGenericMockFrom(mock).Invoke("Warn", params, []reflect.Type{})
|
||||
}
|
||||
|
||||
func (mock *MockSimpleLogging) Err(format string, a ...interface{}) {
|
||||
params := []pegomock.Param{format}
|
||||
for _, param := range a {
|
||||
params = append(params, param)
|
||||
}
|
||||
pegomock.GetGenericMockFrom(mock).Invoke("Err", params, []reflect.Type{})
|
||||
}
|
||||
|
||||
func (mock *MockSimpleLogging) Log(level logging.LogLevel, format string, a ...interface{}) {
|
||||
params := []pegomock.Param{level, format}
|
||||
for _, param := range a {
|
||||
params = append(params, param)
|
||||
}
|
||||
pegomock.GetGenericMockFrom(mock).Invoke("Log", params, []reflect.Type{})
|
||||
}
|
||||
|
||||
func (mock *MockSimpleLogging) Underlying() *log.Logger {
|
||||
params := []pegomock.Param{}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("Underlying", params, []reflect.Type{reflect.TypeOf((**log.Logger)(nil)).Elem()})
|
||||
var ret0 *log.Logger
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].(*log.Logger)
|
||||
}
|
||||
}
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mock *MockSimpleLogging) GetLevel() logging.LogLevel {
|
||||
params := []pegomock.Param{}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("GetLevel", params, []reflect.Type{reflect.TypeOf((*logging.LogLevel)(nil)).Elem()})
|
||||
var ret0 logging.LogLevel
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].(logging.LogLevel)
|
||||
}
|
||||
}
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mock *MockSimpleLogging) VerifyWasCalledOnce() *VerifierSimpleLogging {
|
||||
return &VerifierSimpleLogging{mock, pegomock.Times(1), nil}
|
||||
}
|
||||
|
||||
func (mock *MockSimpleLogging) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierSimpleLogging {
|
||||
return &VerifierSimpleLogging{mock, invocationCountMatcher, nil}
|
||||
}
|
||||
|
||||
func (mock *MockSimpleLogging) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierSimpleLogging {
|
||||
return &VerifierSimpleLogging{mock, invocationCountMatcher, inOrderContext}
|
||||
}
|
||||
|
||||
type VerifierSimpleLogging struct {
|
||||
mock *MockSimpleLogging
|
||||
invocationCountMatcher pegomock.Matcher
|
||||
inOrderContext *pegomock.InOrderContext
|
||||
}
|
||||
|
||||
func (verifier *VerifierSimpleLogging) Debug(format string, a ...interface{}) *SimpleLogging_Debug_OngoingVerification {
|
||||
params := []pegomock.Param{format}
|
||||
for _, param := range a {
|
||||
params = append(params, param)
|
||||
}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Debug", params)
|
||||
return &SimpleLogging_Debug_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type SimpleLogging_Debug_OngoingVerification struct {
|
||||
mock *MockSimpleLogging
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *SimpleLogging_Debug_OngoingVerification) GetCapturedArguments() (string, []interface{}) {
|
||||
format, a := c.GetAllCapturedArguments()
|
||||
return format[len(format)-1], a[len(a)-1]
|
||||
}
|
||||
|
||||
func (c *SimpleLogging_Debug_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 [][]interface{}) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]string, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(string)
|
||||
}
|
||||
_param1 = make([][]interface{}, len(params[1]))
|
||||
for u := range params[0] {
|
||||
_param1[u] = make([]interface{}, len(params)-1)
|
||||
for x := 1; x < len(params); x++ {
|
||||
if params[x][u] != nil {
|
||||
_param1[u][x-1] = params[x][u].(interface{})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierSimpleLogging) Info(format string, a ...interface{}) *SimpleLogging_Info_OngoingVerification {
|
||||
params := []pegomock.Param{format}
|
||||
for _, param := range a {
|
||||
params = append(params, param)
|
||||
}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Info", params)
|
||||
return &SimpleLogging_Info_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type SimpleLogging_Info_OngoingVerification struct {
|
||||
mock *MockSimpleLogging
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *SimpleLogging_Info_OngoingVerification) GetCapturedArguments() (string, []interface{}) {
|
||||
format, a := c.GetAllCapturedArguments()
|
||||
return format[len(format)-1], a[len(a)-1]
|
||||
}
|
||||
|
||||
func (c *SimpleLogging_Info_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 [][]interface{}) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]string, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(string)
|
||||
}
|
||||
_param1 = make([][]interface{}, len(params[1]))
|
||||
for u := range params[0] {
|
||||
_param1[u] = make([]interface{}, len(params)-1)
|
||||
for x := 1; x < len(params); x++ {
|
||||
if params[x][u] != nil {
|
||||
_param1[u][x-1] = params[x][u].(interface{})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierSimpleLogging) Warn(format string, a ...interface{}) *SimpleLogging_Warn_OngoingVerification {
|
||||
params := []pegomock.Param{format}
|
||||
for _, param := range a {
|
||||
params = append(params, param)
|
||||
}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Warn", params)
|
||||
return &SimpleLogging_Warn_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type SimpleLogging_Warn_OngoingVerification struct {
|
||||
mock *MockSimpleLogging
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *SimpleLogging_Warn_OngoingVerification) GetCapturedArguments() (string, []interface{}) {
|
||||
format, a := c.GetAllCapturedArguments()
|
||||
return format[len(format)-1], a[len(a)-1]
|
||||
}
|
||||
|
||||
func (c *SimpleLogging_Warn_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 [][]interface{}) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]string, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(string)
|
||||
}
|
||||
_param1 = make([][]interface{}, len(params[1]))
|
||||
for u := range params[0] {
|
||||
_param1[u] = make([]interface{}, len(params)-1)
|
||||
for x := 1; x < len(params); x++ {
|
||||
if params[x][u] != nil {
|
||||
_param1[u][x-1] = params[x][u].(interface{})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierSimpleLogging) Err(format string, a ...interface{}) *SimpleLogging_Err_OngoingVerification {
|
||||
params := []pegomock.Param{format}
|
||||
for _, param := range a {
|
||||
params = append(params, param)
|
||||
}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Err", params)
|
||||
return &SimpleLogging_Err_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type SimpleLogging_Err_OngoingVerification struct {
|
||||
mock *MockSimpleLogging
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *SimpleLogging_Err_OngoingVerification) GetCapturedArguments() (string, []interface{}) {
|
||||
format, a := c.GetAllCapturedArguments()
|
||||
return format[len(format)-1], a[len(a)-1]
|
||||
}
|
||||
|
||||
func (c *SimpleLogging_Err_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 [][]interface{}) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]string, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(string)
|
||||
}
|
||||
_param1 = make([][]interface{}, len(params[1]))
|
||||
for u := range params[0] {
|
||||
_param1[u] = make([]interface{}, len(params)-1)
|
||||
for x := 1; x < len(params); x++ {
|
||||
if params[x][u] != nil {
|
||||
_param1[u][x-1] = params[x][u].(interface{})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierSimpleLogging) Log(level logging.LogLevel, format string, a ...interface{}) *SimpleLogging_Log_OngoingVerification {
|
||||
params := []pegomock.Param{level, format}
|
||||
for _, param := range a {
|
||||
params = append(params, param)
|
||||
}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Log", params)
|
||||
return &SimpleLogging_Log_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type SimpleLogging_Log_OngoingVerification struct {
|
||||
mock *MockSimpleLogging
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *SimpleLogging_Log_OngoingVerification) GetCapturedArguments() (logging.LogLevel, string, []interface{}) {
|
||||
level, format, a := c.GetAllCapturedArguments()
|
||||
return level[len(level)-1], format[len(format)-1], a[len(a)-1]
|
||||
}
|
||||
|
||||
func (c *SimpleLogging_Log_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.LogLevel, _param1 []string, _param2 [][]interface{}) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]logging.LogLevel, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(logging.LogLevel)
|
||||
}
|
||||
_param1 = make([]string, len(params[1]))
|
||||
for u, param := range params[1] {
|
||||
_param1[u] = param.(string)
|
||||
}
|
||||
_param2 = make([][]interface{}, len(params[2]))
|
||||
for u := range params[0] {
|
||||
_param2[u] = make([]interface{}, len(params)-2)
|
||||
for x := 2; x < len(params); x++ {
|
||||
if params[x][u] != nil {
|
||||
_param2[u][x-2] = params[x][u].(interface{})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierSimpleLogging) Underlying() *SimpleLogging_Underlying_OngoingVerification {
|
||||
params := []pegomock.Param{}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Underlying", params)
|
||||
return &SimpleLogging_Underlying_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type SimpleLogging_Underlying_OngoingVerification struct {
|
||||
mock *MockSimpleLogging
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *SimpleLogging_Underlying_OngoingVerification) GetCapturedArguments() {
|
||||
}
|
||||
|
||||
func (c *SimpleLogging_Underlying_OngoingVerification) GetAllCapturedArguments() {
|
||||
}
|
||||
|
||||
func (verifier *VerifierSimpleLogging) GetLevel() *SimpleLogging_GetLevel_OngoingVerification {
|
||||
params := []pegomock.Param{}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetLevel", params)
|
||||
return &SimpleLogging_GetLevel_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type SimpleLogging_GetLevel_OngoingVerification struct {
|
||||
mock *MockSimpleLogging
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *SimpleLogging_GetLevel_OngoingVerification) GetCapturedArguments() {
|
||||
}
|
||||
|
||||
func (c *SimpleLogging_GetLevel_OngoingVerification) GetAllCapturedArguments() {
|
||||
}
|
||||
@@ -10,9 +10,23 @@ import (
|
||||
"unicode"
|
||||
)
|
||||
|
||||
//go:generate pegomock generate --use-experimental-model-gen --package mocks -o mocks/mock_simple_logging.go SimpleLogging
|
||||
|
||||
type SimpleLogging interface {
|
||||
Debug(format string, a ...interface{})
|
||||
Info(format string, a ...interface{})
|
||||
Warn(format string, a ...interface{})
|
||||
Err(format string, a ...interface{})
|
||||
Log(level LogLevel, format string, a ...interface{})
|
||||
// Underlying returns the underlying logger.
|
||||
Underlying() *log.Logger
|
||||
// GetLevel returns the current log level.
|
||||
GetLevel() LogLevel
|
||||
}
|
||||
|
||||
// SimpleLogger wraps the standard logger with leveled logging
|
||||
// and the ability to store log history for later adding it
|
||||
// to a GitHub comment.
|
||||
// to a VCS comment.
|
||||
type SimpleLogger struct {
|
||||
// Source is added as a prefix to each log entry.
|
||||
// It's useful if you want to trace a log entry back to a
|
||||
@@ -126,6 +140,14 @@ func (l *SimpleLogger) Log(level LogLevel, format string, a ...interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
func (l *SimpleLogger) Underlying() *log.Logger {
|
||||
return l.Logger
|
||||
}
|
||||
|
||||
func (l *SimpleLogger) GetLevel() LogLevel {
|
||||
return l.Level
|
||||
}
|
||||
|
||||
func (l *SimpleLogger) saveToHistory(level string, msg string) {
|
||||
l.History.WriteString(fmt.Sprintf("[%s] %s\n", level, msg))
|
||||
}
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
// Automatically generated by pegomock. DO NOT EDIT!
|
||||
// Source: github.com/hootsuite/atlantis/server (interfaces: GHRequestValidator)
|
||||
// Source: github.com/hootsuite/atlantis/server (interfaces: GithubRequestValidator)
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
http "net/http"
|
||||
"reflect"
|
||||
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
)
|
||||
|
||||
type MockGHRequestValidator struct {
|
||||
type MockGithubRequestValidator struct {
|
||||
fail func(message string, callerSkip ...int)
|
||||
}
|
||||
|
||||
func NewMockGHRequestValidator() *MockGHRequestValidator {
|
||||
return &MockGHRequestValidator{fail: pegomock.GlobalFailHandler}
|
||||
func NewMockGithubRequestValidator() *MockGithubRequestValidator {
|
||||
return &MockGithubRequestValidator{fail: pegomock.GlobalFailHandler}
|
||||
}
|
||||
|
||||
func (mock *MockGHRequestValidator) Validate(r *http.Request, secret []byte) ([]byte, error) {
|
||||
func (mock *MockGithubRequestValidator) Validate(r *http.Request, secret []byte) ([]byte, error) {
|
||||
params := []pegomock.Param{r, secret}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("Validate", params, []reflect.Type{reflect.TypeOf((*[]byte)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 []byte
|
||||
@@ -33,41 +34,41 @@ func (mock *MockGHRequestValidator) Validate(r *http.Request, secret []byte) ([]
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
func (mock *MockGHRequestValidator) VerifyWasCalledOnce() *VerifierGHRequestValidator {
|
||||
return &VerifierGHRequestValidator{mock, pegomock.Times(1), nil}
|
||||
func (mock *MockGithubRequestValidator) VerifyWasCalledOnce() *VerifierGithubRequestValidator {
|
||||
return &VerifierGithubRequestValidator{mock, pegomock.Times(1), nil}
|
||||
}
|
||||
|
||||
func (mock *MockGHRequestValidator) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierGHRequestValidator {
|
||||
return &VerifierGHRequestValidator{mock, invocationCountMatcher, nil}
|
||||
func (mock *MockGithubRequestValidator) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierGithubRequestValidator {
|
||||
return &VerifierGithubRequestValidator{mock, invocationCountMatcher, nil}
|
||||
}
|
||||
|
||||
func (mock *MockGHRequestValidator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierGHRequestValidator {
|
||||
return &VerifierGHRequestValidator{mock, invocationCountMatcher, inOrderContext}
|
||||
func (mock *MockGithubRequestValidator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierGithubRequestValidator {
|
||||
return &VerifierGithubRequestValidator{mock, invocationCountMatcher, inOrderContext}
|
||||
}
|
||||
|
||||
type VerifierGHRequestValidator struct {
|
||||
mock *MockGHRequestValidator
|
||||
type VerifierGithubRequestValidator struct {
|
||||
mock *MockGithubRequestValidator
|
||||
invocationCountMatcher pegomock.Matcher
|
||||
inOrderContext *pegomock.InOrderContext
|
||||
}
|
||||
|
||||
func (verifier *VerifierGHRequestValidator) Validate(r *http.Request, secret []byte) *GHRequestValidator_Validate_OngoingVerification {
|
||||
func (verifier *VerifierGithubRequestValidator) Validate(r *http.Request, secret []byte) *GithubRequestValidator_Validate_OngoingVerification {
|
||||
params := []pegomock.Param{r, secret}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Validate", params)
|
||||
return &GHRequestValidator_Validate_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
return &GithubRequestValidator_Validate_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type GHRequestValidator_Validate_OngoingVerification struct {
|
||||
mock *MockGHRequestValidator
|
||||
type GithubRequestValidator_Validate_OngoingVerification struct {
|
||||
mock *MockGithubRequestValidator
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *GHRequestValidator_Validate_OngoingVerification) GetCapturedArguments() (*http.Request, []byte) {
|
||||
func (c *GithubRequestValidator_Validate_OngoingVerification) GetCapturedArguments() (*http.Request, []byte) {
|
||||
r, secret := c.GetAllCapturedArguments()
|
||||
return r[len(r)-1], secret[len(secret)-1]
|
||||
}
|
||||
|
||||
func (c *GHRequestValidator_Validate_OngoingVerification) GetAllCapturedArguments() (_param0 []*http.Request, _param1 [][]byte) {
|
||||
func (c *GithubRequestValidator_Validate_OngoingVerification) GetAllCapturedArguments() (_param0 []*http.Request, _param1 [][]byte) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]*http.Request, len(params[0]))
|
||||
|
||||
83
server/mocks/mock_gitlab_request_parser.go
Normal file
83
server/mocks/mock_gitlab_request_parser.go
Normal file
@@ -0,0 +1,83 @@
|
||||
// Automatically generated by pegomock. DO NOT EDIT!
|
||||
// Source: github.com/hootsuite/atlantis/server (interfaces: GitlabRequestParser)
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
http "net/http"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type MockGitlabRequestParser struct {
|
||||
fail func(message string, callerSkip ...int)
|
||||
}
|
||||
|
||||
func NewMockGitlabRequestParser() *MockGitlabRequestParser {
|
||||
return &MockGitlabRequestParser{fail: pegomock.GlobalFailHandler}
|
||||
}
|
||||
|
||||
func (mock *MockGitlabRequestParser) Validate(r *http.Request, secret []byte) (interface{}, error) {
|
||||
params := []pegomock.Param{r, secret}
|
||||
result := pegomock.GetGenericMockFrom(mock).Invoke("Validate", params, []reflect.Type{reflect.TypeOf((*interface{})(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var ret0 interface{}
|
||||
var ret1 error
|
||||
if len(result) != 0 {
|
||||
if result[0] != nil {
|
||||
ret0 = result[0].(interface{})
|
||||
}
|
||||
if result[1] != nil {
|
||||
ret1 = result[1].(error)
|
||||
}
|
||||
}
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
func (mock *MockGitlabRequestParser) VerifyWasCalledOnce() *VerifierGitlabRequestParser {
|
||||
return &VerifierGitlabRequestParser{mock, pegomock.Times(1), nil}
|
||||
}
|
||||
|
||||
func (mock *MockGitlabRequestParser) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierGitlabRequestParser {
|
||||
return &VerifierGitlabRequestParser{mock, invocationCountMatcher, nil}
|
||||
}
|
||||
|
||||
func (mock *MockGitlabRequestParser) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierGitlabRequestParser {
|
||||
return &VerifierGitlabRequestParser{mock, invocationCountMatcher, inOrderContext}
|
||||
}
|
||||
|
||||
type VerifierGitlabRequestParser struct {
|
||||
mock *MockGitlabRequestParser
|
||||
invocationCountMatcher pegomock.Matcher
|
||||
inOrderContext *pegomock.InOrderContext
|
||||
}
|
||||
|
||||
func (verifier *VerifierGitlabRequestParser) Validate(r *http.Request, secret []byte) *GitlabRequestParser_Validate_OngoingVerification {
|
||||
params := []pegomock.Param{r, secret}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Validate", params)
|
||||
return &GitlabRequestParser_Validate_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type GitlabRequestParser_Validate_OngoingVerification struct {
|
||||
mock *MockGitlabRequestParser
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *GitlabRequestParser_Validate_OngoingVerification) GetCapturedArguments() (*http.Request, []byte) {
|
||||
r, secret := c.GetAllCapturedArguments()
|
||||
return r[len(r)-1], secret[len(secret)-1]
|
||||
}
|
||||
|
||||
func (c *GitlabRequestParser_Validate_OngoingVerification) GetAllCapturedArguments() (_param0 []*http.Request, _param1 [][]byte) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]*http.Request, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(*http.Request)
|
||||
}
|
||||
_param1 = make([][]byte, len(params[1]))
|
||||
for u, param := range params[1] {
|
||||
_param1[u] = param.([]byte)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -13,21 +13,24 @@ import (
|
||||
"github.com/elazarl/go-bindata-assetfs"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/hootsuite/atlantis/server/events"
|
||||
"github.com/hootsuite/atlantis/server/events/github"
|
||||
"github.com/hootsuite/atlantis/server/events/locking"
|
||||
"github.com/hootsuite/atlantis/server/events/locking/boltdb"
|
||||
"github.com/hootsuite/atlantis/server/events/run"
|
||||
"github.com/hootsuite/atlantis/server/events/terraform"
|
||||
"github.com/hootsuite/atlantis/server/events/vcs"
|
||||
"github.com/hootsuite/atlantis/server/logging"
|
||||
"github.com/hootsuite/atlantis/server/static"
|
||||
"github.com/lkysow/go-gitlab"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/negroni"
|
||||
"flag"
|
||||
)
|
||||
|
||||
const LockRouteName = "lock-detail"
|
||||
|
||||
// Server listens for GitHub events and runs the necessary Atlantis command
|
||||
// Server runs the Atlantis web server. It's used for webhook requests and the
|
||||
// Atlantis UI.
|
||||
type Server struct {
|
||||
Router *mux.Router
|
||||
Port int
|
||||
@@ -50,22 +53,43 @@ type Config struct {
|
||||
GithubToken string `mapstructure:"gh-token"`
|
||||
GithubUser string `mapstructure:"gh-user"`
|
||||
GithubWebHookSecret string `mapstructure:"gh-webhook-secret"`
|
||||
GitlabHostname string `mapstructure:"gitlab-hostname"`
|
||||
GitlabToken string `mapstructure:"gitlab-token"`
|
||||
GitlabUser string `mapstructure:"gitlab-user"`
|
||||
GitlabWebHookSecret string `mapstructure:"gitlab-webhook-secret"`
|
||||
LogLevel string `mapstructure:"log-level"`
|
||||
Port int `mapstructure:"port"`
|
||||
RequireApproval bool `mapstructure:"require-approval"`
|
||||
}
|
||||
|
||||
func NewServer(config Config) (*Server, error) {
|
||||
githubClient, err := github.NewClient(config.GithubHostname, config.GithubUser, config.GithubToken)
|
||||
var supportedVCSHosts []vcs.Host
|
||||
var githubClient *vcs.GithubClient
|
||||
var gitlabClient *vcs.GitlabClient
|
||||
if config.GithubUser != "" {
|
||||
supportedVCSHosts = append(supportedVCSHosts, vcs.Github)
|
||||
var err error
|
||||
githubClient, err = vcs.NewGithubClient(config.GithubHostname, config.GithubUser, config.GithubToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
githubStatus := &events.GithubStatus{Client: githubClient}
|
||||
}
|
||||
if config.GitlabUser != "" {
|
||||
supportedVCSHosts = append(supportedVCSHosts, vcs.Gitlab)
|
||||
gitlabClient = &vcs.GitlabClient{
|
||||
Client: gitlab.NewClient(nil, config.GitlabToken),
|
||||
}
|
||||
}
|
||||
vcsClient := vcs.NewDefaultClientProxy(githubClient, gitlabClient)
|
||||
commitStatusUpdater := &events.DefaultCommitStatusUpdater{Client: vcsClient}
|
||||
terraformClient, err := terraform.NewClient()
|
||||
if err != nil {
|
||||
// The flag.Lookup call is to detect if we're running in a unit test. If we
|
||||
// are, then we don't error out because we don't have/want terraform
|
||||
// installed on our CI system where the unit tests run.
|
||||
if err != nil && flag.Lookup("test.v") == nil {
|
||||
return nil, errors.Wrap(err, "initializing terraform")
|
||||
}
|
||||
githubComments := &events.GithubCommentRenderer{}
|
||||
markdownRenderer := &events.MarkdownRenderer{}
|
||||
boltdb, err := boltdb.New(config.DataDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -84,7 +108,7 @@ func NewServer(config Config) (*Server, error) {
|
||||
Terraform: terraformClient,
|
||||
}
|
||||
applyExecutor := &events.ApplyExecutor{
|
||||
Github: githubClient,
|
||||
VCSClient: vcsClient,
|
||||
Terraform: terraformClient,
|
||||
RequireApproval: config.RequireApproval,
|
||||
Run: run,
|
||||
@@ -92,17 +116,17 @@ func NewServer(config Config) (*Server, error) {
|
||||
ProjectPreExecute: projectPreExecute,
|
||||
}
|
||||
planExecutor := &events.PlanExecutor{
|
||||
Github: githubClient,
|
||||
VCSClient: vcsClient,
|
||||
Terraform: terraformClient,
|
||||
Run: run,
|
||||
Workspace: workspace,
|
||||
ProjectPreExecute: projectPreExecute,
|
||||
Locker: lockingClient,
|
||||
ModifiedProject: &events.ProjectFinder{},
|
||||
ProjectFinder: &events.ProjectFinder{},
|
||||
}
|
||||
helpExecutor := &events.HelpExecutor{}
|
||||
pullClosedExecutor := &events.PullClosedExecutor{
|
||||
Github: githubClient,
|
||||
VCSClient: vcsClient,
|
||||
Locker: lockingClient,
|
||||
Workspace: workspace,
|
||||
}
|
||||
@@ -110,6 +134,8 @@ func NewServer(config Config) (*Server, error) {
|
||||
eventParser := &events.EventParser{
|
||||
GithubUser: config.GithubUser,
|
||||
GithubToken: config.GithubToken,
|
||||
GitlabUser: config.GitlabUser,
|
||||
GitlabToken: config.GitlabToken,
|
||||
}
|
||||
commandHandler := &events.CommandHandler{
|
||||
ApplyExecutor: applyExecutor,
|
||||
@@ -117,10 +143,12 @@ func NewServer(config Config) (*Server, error) {
|
||||
HelpExecutor: helpExecutor,
|
||||
LockURLGenerator: planExecutor,
|
||||
EventParser: eventParser,
|
||||
GHClient: githubClient,
|
||||
GHStatus: githubStatus,
|
||||
VCSClient: vcsClient,
|
||||
GithubPullGetter: githubClient,
|
||||
GitlabMergeRequestGetter: gitlabClient,
|
||||
CommitStatusUpdater: commitStatusUpdater,
|
||||
EnvLocker: concurrentRunLocker,
|
||||
GHCommentRenderer: githubComments,
|
||||
MarkdownRenderer: markdownRenderer,
|
||||
Logger: logger,
|
||||
}
|
||||
eventsController := &EventsController{
|
||||
@@ -129,7 +157,10 @@ func NewServer(config Config) (*Server, error) {
|
||||
Parser: eventParser,
|
||||
Logger: logger,
|
||||
GithubWebHookSecret: []byte(config.GithubWebHookSecret),
|
||||
Validator: &GHRequestValidation{},
|
||||
GithubRequestValidator: &DefaultGithubRequestValidator{},
|
||||
GitlabRequestParser: &DefaultGitlabRequestParser{},
|
||||
GitlabWebHookSecret: []byte(config.GitlabWebHookSecret),
|
||||
SupportedVCSHosts: supportedVCSHosts,
|
||||
}
|
||||
router := mux.NewRouter()
|
||||
return &Server{
|
||||
@@ -270,7 +301,7 @@ func (s *Server) DeleteLock(w http.ResponseWriter, _ *http.Request, id string) {
|
||||
}
|
||||
|
||||
// postEvents handles POST requests to our /events endpoint. These should be
|
||||
// GitHub webhook requests.
|
||||
// VCS webhook requests.
|
||||
func (s *Server) postEvents(w http.ResponseWriter, r *http.Request) {
|
||||
s.EventsController.Post(w, r)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,16 @@ import (
|
||||
. "github.com/petergtz/pegomock"
|
||||
)
|
||||
|
||||
func TestNewServer(t *testing.T) {
|
||||
t.Log("Run through NewServer constructor")
|
||||
tmpDir, err := ioutil.TempDir("", "")
|
||||
Ok(t, err)
|
||||
_, err = server.NewServer(server.Config{
|
||||
DataDir: tmpDir,
|
||||
})
|
||||
Ok(t, err)
|
||||
}
|
||||
|
||||
func TestIndex_LockErr(t *testing.T) {
|
||||
t.Log("index should return a 503 if unable to list locks")
|
||||
RegisterMockTestingT(t)
|
||||
|
||||
24
vendor/github.com/lkysow/go-gitlab/.gitignore
generated
vendored
Normal file
24
vendor/github.com/lkysow/go-gitlab/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# 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
|
||||
5
vendor/github.com/lkysow/go-gitlab/.travis.yml
generated
vendored
Normal file
5
vendor/github.com/lkysow/go-gitlab/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
27
vendor/github.com/lkysow/go-gitlab/CHANGELOG.md
generated
vendored
Normal file
27
vendor/github.com/lkysow/go-gitlab/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
go-github CHANGELOG
|
||||
===================
|
||||
|
||||
0.6.0
|
||||
-----
|
||||
- Add support for the V4 Gitlab API. This means the older V3 API is no longer fully supported
|
||||
with this version. If you still need that version, please use the `f-api-v3` branch.
|
||||
|
||||
0.4.0
|
||||
-----
|
||||
- Add support to use [`sudo`](https://docs.gitlab.com/ce/api/README.html#sudo) for all API calls.
|
||||
- Add support for the Notification Settings API.
|
||||
- Add support for the Time Tracking API.
|
||||
- Make sure that the error response correctly outputs any returned errors.
|
||||
- And a reasonable number of smaller enhanchements and bugfixes.
|
||||
|
||||
0.3.0
|
||||
-----
|
||||
- Moved the tags related API calls to their own service, following the Gitlab API structure.
|
||||
|
||||
0.2.0
|
||||
-----
|
||||
- Convert all Option structs to use pointers for their fields.
|
||||
|
||||
0.1.0
|
||||
-----
|
||||
- Initial release.
|
||||
202
vendor/github.com/lkysow/go-gitlab/LICENSE
generated
vendored
Normal file
202
vendor/github.com/lkysow/go-gitlab/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
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.
|
||||
|
||||
129
vendor/github.com/lkysow/go-gitlab/README.md
generated
vendored
Normal file
129
vendor/github.com/lkysow/go-gitlab/README.md
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
# go-gitlab
|
||||
|
||||
A GitLab API client enabling Go programs to interact with GitLab in a simple and uniform way
|
||||
|
||||
**Documentation:** [](https://godoc.org/github.com/xanzy/go-gitlab)
|
||||
**Build Status:** [](https://travis-ci.org/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 **100%** of the existing GitLab API calls! So this
|
||||
includes all calls to the following services:
|
||||
|
||||
- [x] Branches
|
||||
- [x] Commits
|
||||
- [x] Deploy Keys
|
||||
- [x] Environments
|
||||
- [x] Groups
|
||||
- [x] Issues
|
||||
- [x] Labels
|
||||
- [x] Merge Requests
|
||||
- [x] Milestones
|
||||
- [x] Namespaces
|
||||
- [x] Notes (comments)
|
||||
- [x] Pipelines
|
||||
- [x] Project Snippets
|
||||
- [x] Projects (including setting Webhooks)
|
||||
- [x] Repositories
|
||||
- [x] Repository Files
|
||||
- [x] Services
|
||||
- [x] Session
|
||||
- [x] Settings
|
||||
- [x] System Hooks
|
||||
- [x] Users
|
||||
- [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 := gitlab.NewClient(nil, "yourtokengoeshere")
|
||||
//git.SetBaseURL("https://git.mydomain.com/api/v3")
|
||||
users, _, err := git.Users.ListUsers()
|
||||
```
|
||||
|
||||
Some API methods have optional parameters that can be passed. For example,
|
||||
to list all projects for user "svanharmelen":
|
||||
|
||||
```go
|
||||
git := gitlab.NewClient(nil)
|
||||
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 := gitlab.NewClient(nil, "yourtokengoeshere")
|
||||
|
||||
// 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.VisibilityLevel(gitlab.PublicVisibility),
|
||||
}
|
||||
project, _, err := git.Projects.CreateProject(p)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Add a new snippet
|
||||
s := &gitlab.CreateSnippetOptions{
|
||||
Title: gitlab.String("Dummy Snippet"),
|
||||
FileName: gitlab.String("snippet.go"),
|
||||
Code: gitlab.String("package main...."),
|
||||
Visibility: gitlab.VisibilityLevel(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@xanzy.io>)
|
||||
|
||||
## 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>
|
||||
240
vendor/github.com/lkysow/go-gitlab/branches.go
generated
vendored
Normal file
240
vendor/github.com/lkysow/go-gitlab/branches.go
generated
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
//
|
||||
// Copyright 2017, 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/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"`
|
||||
DevelopersCanPush bool `json:"developers_can_push"`
|
||||
DevelopersCanMerge bool `json:"developers_can_merge"`
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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 ...OptionFunc) ([]*Branch, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/repository/branches", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("GET", 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 ...OptionFunc) (*Branch, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/repository/branches/%s", url.QueryEscape(project), branch)
|
||||
|
||||
req, err := s.client.NewRequest("GET", 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 ...OptionFunc) (*Branch, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/repository/branches/%s/protect", url.QueryEscape(project), branch)
|
||||
|
||||
req, err := s.client.NewRequest("PUT", 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 ...OptionFunc) (*Branch, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/repository/branches/%s/unprotect", url.QueryEscape(project), branch)
|
||||
|
||||
req, err := s.client.NewRequest("PUT", 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 ...OptionFunc) (*Branch, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/repository/branches", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("POST", 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 ...OptionFunc) (*Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/repository/branches/%s", url.QueryEscape(project), branch)
|
||||
|
||||
req, err := s.client.NewRequest("DELETE", 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 ...OptionFunc) (*Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/repository/merged_branches", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(req, nil)
|
||||
}
|
||||
175
vendor/github.com/lkysow/go-gitlab/build_variables.go
generated
vendored
Normal file
175
vendor/github.com/lkysow/go-gitlab/build_variables.go
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// BuildVariablesService handles communication with the project variables related methods
|
||||
// of the Gitlab API
|
||||
//
|
||||
// Gitlab API Docs : https://docs.gitlab.com/ce/api/build_variables.html
|
||||
type BuildVariablesService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// BuildVariable represents a variable available for each build of the given project
|
||||
//
|
||||
// Gitlab API Docs : https://docs.gitlab.com/ce/api/build_variables.html
|
||||
type BuildVariable struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
Protected bool `json:"protected"`
|
||||
}
|
||||
|
||||
func (v BuildVariable) String() string {
|
||||
return Stringify(v)
|
||||
}
|
||||
|
||||
// ListBuildVariablesOptions are the parameters to ListBuildVariables()
|
||||
//
|
||||
// Gitlab API Docs:
|
||||
// https://docs.gitlab.com/ce/api/build_variables.html#list-project-variables
|
||||
type ListBuildVariablesOptions struct {
|
||||
ListOptions
|
||||
}
|
||||
|
||||
// ListBuildVariables gets the a list of project variables in a project
|
||||
//
|
||||
// Gitlab API Docs:
|
||||
// https://docs.gitlab.com/ce/api/build_variables.html#list-project-variables
|
||||
func (s *BuildVariablesService) ListBuildVariables(pid interface{}, opts *ListBuildVariablesOptions, options ...OptionFunc) ([]*BuildVariable, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/variables", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, opts, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var v []*BuildVariable
|
||||
resp, err := s.client.Do(req, &v)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return v, resp, err
|
||||
}
|
||||
|
||||
// GetBuildVariable gets a single project variable of a project
|
||||
//
|
||||
// Gitlab API Docs:
|
||||
// https://docs.gitlab.com/ce/api/build_variables.html#show-variable-details
|
||||
func (s *BuildVariablesService) GetBuildVariable(pid interface{}, key string, options ...OptionFunc) (*BuildVariable, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/variables/%s", url.QueryEscape(project), key)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
v := new(BuildVariable)
|
||||
resp, err := s.client.Do(req, v)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return v, resp, err
|
||||
}
|
||||
|
||||
// CreateBuildVariableOptions are the parameters to CreateBuildVariable()
|
||||
//
|
||||
// Gitlab API Docs:
|
||||
// https://docs.gitlab.com/ce/api/build_variables.html#create-variable
|
||||
type CreateBuildVariableOptions struct {
|
||||
Key *string `url:"key" json:"key"`
|
||||
Value *string `url:"value" json:"value"`
|
||||
Protected *bool `url:"protected,omitempty" json:"protected,omitempty"`
|
||||
}
|
||||
|
||||
// CreateBuildVariable creates a variable for a given project
|
||||
//
|
||||
// Gitlab API Docs:
|
||||
// https://docs.gitlab.com/ce/api/build_variables.html#create-variable
|
||||
func (s *BuildVariablesService) CreateBuildVariable(pid interface{}, opt *CreateBuildVariableOptions, options ...OptionFunc) (*BuildVariable, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/variables", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
v := new(BuildVariable)
|
||||
resp, err := s.client.Do(req, v)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return v, resp, err
|
||||
}
|
||||
|
||||
// UpdateBuildVariableOptions are the parameters to UpdateBuildVariable()
|
||||
//
|
||||
// Gitlab API Docs:
|
||||
// https://docs.gitlab.com/ce/api/build_variables.html#update-variable
|
||||
type UpdateBuildVariableOptions struct {
|
||||
Key *string `url:"key" json:"key"`
|
||||
Value *string `url:"value" json:"value"`
|
||||
Protected *bool `url:"protected,omitempty" json:"protected,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateBuildVariable updates an existing project variable
|
||||
// The variable key must exist
|
||||
//
|
||||
// Gitlab API Docs:
|
||||
// https://docs.gitlab.com/ce/api/build_variables.html#update-variable
|
||||
func (s *BuildVariablesService) UpdateBuildVariable(pid interface{}, key string, opt *UpdateBuildVariableOptions, options ...OptionFunc) (*BuildVariable, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/variables/%s", url.QueryEscape(project), key)
|
||||
|
||||
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
v := new(BuildVariable)
|
||||
resp, err := s.client.Do(req, v)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return v, resp, err
|
||||
}
|
||||
|
||||
// RemoveBuildVariable removes a project variable of a given project identified by its key
|
||||
//
|
||||
// Gitlab API Docs:
|
||||
// https://docs.gitlab.com/ce/api/build_variables.html#remove-variable
|
||||
func (s *BuildVariablesService) RemoveBuildVariable(pid interface{}, key string, options ...OptionFunc) (*Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/variables/%s", url.QueryEscape(project), key)
|
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(req, nil)
|
||||
}
|
||||
113
vendor/github.com/lkysow/go-gitlab/build_variables_test.go
generated
vendored
Normal file
113
vendor/github.com/lkysow/go-gitlab/build_variables_test.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
myKey = "MY_KEY"
|
||||
myValue = "MY_VALUE"
|
||||
myKey2 = "MY_KEY2"
|
||||
myValue2 = "MY_VALUE2"
|
||||
myNewValue = "MY_NEW_VALUE"
|
||||
)
|
||||
|
||||
func TestListBuildVariables(t *testing.T) {
|
||||
mux, server, client := setup()
|
||||
defer teardown(server)
|
||||
|
||||
mux.HandleFunc("/projects/1/variables", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "GET")
|
||||
fmt.Fprintf(w,
|
||||
`[{"key":"%s","value":"%s"},{"key":"%s","value":"%s"}]`, myKey, myValue, myKey2, myValue2)
|
||||
})
|
||||
|
||||
variables, _, err := client.BuildVariables.ListBuildVariables(1, nil)
|
||||
if err != nil {
|
||||
t.Errorf("ListBuildVariables returned error: %v", err)
|
||||
}
|
||||
|
||||
want := []*BuildVariable{{Key: myKey, Value: myValue}, {Key: myKey2, Value: myValue2}}
|
||||
if !reflect.DeepEqual(want, variables) {
|
||||
t.Errorf("ListBuildVariables returned %+v, want %+v", variables, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetBuildVariable(t *testing.T) {
|
||||
mux, server, client := setup()
|
||||
defer teardown(server)
|
||||
|
||||
mux.HandleFunc("/projects/1/variables/"+myKey, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "GET")
|
||||
fmt.Fprintf(w, `{"key":"%s","value":"%s"}`, myKey, myValue)
|
||||
})
|
||||
|
||||
variable, _, err := client.BuildVariables.GetBuildVariable(1, myKey)
|
||||
if err != nil {
|
||||
t.Errorf("GetBuildVariable returned error: %v", err)
|
||||
}
|
||||
|
||||
want := &BuildVariable{Key: myKey, Value: myValue}
|
||||
if !reflect.DeepEqual(want, variable) {
|
||||
t.Errorf("GetBuildVariable returned %+v, want %+v", variable, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateBuildVariable(t *testing.T) {
|
||||
mux, server, client := setup()
|
||||
defer teardown(server)
|
||||
|
||||
mux.HandleFunc("/projects/1/variables", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "POST")
|
||||
fmt.Fprintf(w, `{"key":"%s","value":"%s", "protected": false}`, myKey, myValue)
|
||||
})
|
||||
|
||||
opt := &CreateBuildVariableOptions{String(myKey), String(myValue), Bool(false)}
|
||||
variable, _, err := client.BuildVariables.CreateBuildVariable(1, opt)
|
||||
if err != nil {
|
||||
t.Errorf("CreateBuildVariable returned error: %v", err)
|
||||
}
|
||||
|
||||
want := &BuildVariable{Key: myKey, Value: myValue, Protected: false}
|
||||
if !reflect.DeepEqual(want, variable) {
|
||||
t.Errorf("CreateBuildVariable returned %+v, want %+v", variable, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateBuildVariable(t *testing.T) {
|
||||
mux, server, client := setup()
|
||||
defer teardown(server)
|
||||
|
||||
mux.HandleFunc("/projects/1/variables/"+myKey, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "PUT")
|
||||
fmt.Fprintf(w, `{"key":"%s","value":"%s", "protected": false}`, myKey, myNewValue)
|
||||
})
|
||||
|
||||
opt := &UpdateBuildVariableOptions{String(myKey), String(myNewValue), Bool(false)}
|
||||
variable, _, err := client.BuildVariables.UpdateBuildVariable(1, myKey, opt)
|
||||
if err != nil {
|
||||
t.Errorf("UpdateBuildVariable returned error: %v", err)
|
||||
}
|
||||
|
||||
want := &BuildVariable{Key: myKey, Value: myNewValue, Protected: false}
|
||||
if !reflect.DeepEqual(want, variable) {
|
||||
t.Errorf("UpdateBuildVariable returned %+v, want %+v", variable, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveBuildVariable(t *testing.T) {
|
||||
mux, server, client := setup()
|
||||
defer teardown(server)
|
||||
|
||||
mux.HandleFunc("/projects/1/variables/"+myKey, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "DELETE")
|
||||
})
|
||||
|
||||
_, err := client.BuildVariables.RemoveBuildVariable(1, myKey)
|
||||
if err != nil {
|
||||
t.Errorf("RemoveBuildVariable returned error: %v", err)
|
||||
}
|
||||
}
|
||||
444
vendor/github.com/lkysow/go-gitlab/commits.go
generated
vendored
Normal file
444
vendor/github.com/lkysow/go-gitlab/commits.go
generated
vendored
Normal file
@@ -0,0 +1,444 @@
|
||||
//
|
||||
// Copyright 2017, 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/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 *BuildState `json:"status"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// 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 ...OptionFunc) ([]*Commit, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/repository/commits", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("GET", 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
|
||||
}
|
||||
|
||||
// FileAction represents the available actions that can be performed on a file.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions
|
||||
type FileAction string
|
||||
|
||||
// The available file actions.
|
||||
const (
|
||||
FileCreate FileAction = "create"
|
||||
FileDelete FileAction = "delete"
|
||||
FileMove FileAction = "move"
|
||||
FileUpdate FileAction = "update"
|
||||
)
|
||||
|
||||
// CommitAction represents a single file action within a commit.
|
||||
type CommitAction struct {
|
||||
Action FileAction `url:"action" json:"action"`
|
||||
FilePath string `url:"file_path" json:"file_path"`
|
||||
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"`
|
||||
}
|
||||
|
||||
// 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 ...OptionFunc) (*Commit, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/repository/commits/%s", url.QueryEscape(project), sha)
|
||||
|
||||
req, err := s.client.NewRequest("GET", 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" json:"branch"`
|
||||
CommitMessage *string `url:"commit_message" json:"commit_message"`
|
||||
Actions []*CommitAction `url:"actions" json:"actions"`
|
||||
AuthorEmail *string `url:"author_email,omitempty" json:"author_email,omitempty"`
|
||||
AuthorName *string `url:"author_name,omitempty" json:"author_name,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 ...OptionFunc) (*Commit, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/repository/commits", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("POST", 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
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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, options ...OptionFunc) ([]*Diff, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/repository/commits/%s/diff", url.QueryEscape(project), sha)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, 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)
|
||||
}
|
||||
|
||||
// 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, options ...OptionFunc) ([]*CommitComment, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/repository/commits/%s/comments", url.QueryEscape(project), sha)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, 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 ...OptionFunc) (*CommitComment, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/repository/commits/%s/comments", url.QueryEscape(project), sha)
|
||||
|
||||
req, err := s.client.NewRequest("POST", 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 {
|
||||
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"`
|
||||
Name string `json:"name"`
|
||||
TargetURL string `json:"target_url"`
|
||||
Description string `json:"description"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
StartedAt *time.Time `json:"started_at"`
|
||||
FinishedAt *time.Time `json:"finished_at"`
|
||||
Author Author `json:"author"`
|
||||
}
|
||||
|
||||
// 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 ...OptionFunc) ([]*CommitStatus, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/repository/commits/%s/statuses", url.QueryEscape(project), sha)
|
||||
|
||||
req, err := s.client.NewRequest("GET", 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 BuildState `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"`
|
||||
}
|
||||
|
||||
// BuildState represents a GitLab build state.
|
||||
type BuildState string
|
||||
|
||||
// These constants represent all valid build states.
|
||||
const (
|
||||
Pending BuildState = "pending"
|
||||
Running BuildState = "running"
|
||||
Success BuildState = "success"
|
||||
Failed BuildState = "failed"
|
||||
Canceled BuildState = "canceled"
|
||||
)
|
||||
|
||||
// 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 ...OptionFunc) (*CommitStatus, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/statuses/%s", url.QueryEscape(project), sha)
|
||||
|
||||
req, err := s.client.NewRequest("POST", 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
|
||||
}
|
||||
|
||||
// CherryPickCommitOptions represents the available options for cherry-picking a commit.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#cherry-pick-a-commit
|
||||
type CherryPickCommitOptions struct {
|
||||
TargetBranch *string `url:"branch" json:"branch,omitempty"`
|
||||
}
|
||||
|
||||
// CherryPickCommit sherry 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 ...OptionFunc) (*Commit, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/repository/commits/%s/cherry_pick",
|
||||
url.QueryEscape(project), url.QueryEscape(sha))
|
||||
|
||||
req, err := s.client.NewRequest("POST", 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
|
||||
}
|
||||
52
vendor/github.com/lkysow/go-gitlab/commits_test.go
generated
vendored
Normal file
52
vendor/github.com/lkysow/go-gitlab/commits_test.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetCommitStatuses(t *testing.T) {
|
||||
mux, server, client := setup()
|
||||
defer teardown(server)
|
||||
|
||||
mux.HandleFunc("/projects/1/repository/commits/b0b3a907f41409829b307a28b82fdbd552ee5a27/statuses", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "GET")
|
||||
fmt.Fprint(w, `[{"id":1}]`)
|
||||
})
|
||||
|
||||
opt := &GetCommitStatusesOptions{String("master"), String("test"), String("ci/jenkins"), Bool(true)}
|
||||
statuses, _, err := client.Commits.GetCommitStatuses("1", "b0b3a907f41409829b307a28b82fdbd552ee5a27", opt)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Commits.GetCommitStatuses returned error: %v", err)
|
||||
}
|
||||
|
||||
want := []*CommitStatus{{ID: 1}}
|
||||
if !reflect.DeepEqual(want, statuses) {
|
||||
t.Errorf("Commits.GetCommitStatuses returned %+v, want %+v", statuses, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetCommitStatus(t *testing.T) {
|
||||
mux, server, client := setup()
|
||||
defer teardown(server)
|
||||
|
||||
mux.HandleFunc("/projects/1/statuses/b0b3a907f41409829b307a28b82fdbd552ee5a27", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "POST")
|
||||
fmt.Fprint(w, `{"id":1}`)
|
||||
})
|
||||
|
||||
opt := &SetCommitStatusOptions{Running, String("master"), String("ci/jenkins"), String(""), String("http://abc"), String("build")}
|
||||
status, _, err := client.Commits.SetCommitStatus("1", "b0b3a907f41409829b307a28b82fdbd552ee5a27", opt)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Commits.SetCommitStatus returned error: %v", err)
|
||||
}
|
||||
|
||||
want := &CommitStatus{ID: 1}
|
||||
if !reflect.DeepEqual(want, status) {
|
||||
t.Errorf("Commits.SetCommitStatus returned %+v, want %+v", status, want)
|
||||
}
|
||||
}
|
||||
194
vendor/github.com/lkysow/go-gitlab/deploy_keys.go
generated
vendored
Normal file
194
vendor/github.com/lkysow/go-gitlab/deploy_keys.go
generated
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
//
|
||||
// Copyright 2017, 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/url"
|
||||
"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 ...OptionFunc) ([]*DeployKey, *Response, error) {
|
||||
req, err := s.client.NewRequest("GET", "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
|
||||
}
|
||||
|
||||
// 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{}, options ...OptionFunc) ([]*DeployKey, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/deploy_keys", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, 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
|
||||
}
|
||||
|
||||
// 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 ...OptionFunc) (*DeployKey, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/deploy_keys/%d", url.QueryEscape(project), deployKey)
|
||||
|
||||
req, err := s.client.NewRequest("GET", 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 ...OptionFunc) (*DeployKey, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/deploy_keys", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("POST", 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 ...OptionFunc) (*Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/deploy_keys/%d", url.QueryEscape(project), deployKey)
|
||||
|
||||
req, err := s.client.NewRequest("DELETE", 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-deploy-key
|
||||
func (s *DeployKeysService) EnableDeployKey(pid interface{}, deployKey int, options ...OptionFunc) (*DeployKey, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/deploy_keys/%d/enable", url.QueryEscape(project), deployKey)
|
||||
|
||||
req, err := s.client.NewRequest("POST", 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
|
||||
}
|
||||
168
vendor/github.com/lkysow/go-gitlab/environments.go
generated
vendored
Normal file
168
vendor/github.com/lkysow/go-gitlab/environments.go
generated
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
//
|
||||
// Copyright 2017, 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/url"
|
||||
)
|
||||
|
||||
// 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"`
|
||||
ExternalURL string `json:"external_url"`
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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 ...OptionFunc) ([]*Environment, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/environments", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("GET", 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
|
||||
}
|
||||
|
||||
// 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 a 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 ...OptionFunc) (*Environment, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/environments", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("POST", 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 ...OptionFunc) (*Environment, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/environments/%d", url.QueryEscape(project), environment)
|
||||
|
||||
req, err := s.client.NewRequest("PUT", 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 a 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 ...OptionFunc) (*Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/environments/%d", url.QueryEscape(project), environment)
|
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(req, nil)
|
||||
}
|
||||
613
vendor/github.com/lkysow/go-gitlab/events.go
generated
vendored
Normal file
613
vendor/github.com/lkysow/go-gitlab/events.go
generated
vendored
Normal file
@@ -0,0 +1,613 @@
|
||||
//
|
||||
// Copyright 2017, 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 "time"
|
||||
|
||||
// PushEvent represents a push event.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/web_hooks/web_hooks.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"`
|
||||
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 []*Commit `json:"commits"`
|
||||
TotalCommitsCount int `json:"total_commits_count"`
|
||||
}
|
||||
|
||||
// TagEvent represents a tag event.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/web_hooks/web_hooks.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"`
|
||||
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 []*Commit `json:"commits"`
|
||||
TotalCommitsCount int `json:"total_commits_count"`
|
||||
}
|
||||
|
||||
// IssueEvent represents a issue event.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#issues-events
|
||||
type IssueEvent struct {
|
||||
ObjectKind string `json:"object_kind"`
|
||||
User *User `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"`
|
||||
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 struct {
|
||||
Name string `json:"name"`
|
||||
Username string `json:"username"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
} `json:"assignee"`
|
||||
}
|
||||
|
||||
// CommitCommentEvent represents a comment on a commit event.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/web_hooks/web_hooks.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"`
|
||||
} `json:"object_attributes"`
|
||||
Commit *Commit `json:"commit"`
|
||||
}
|
||||
|
||||
// MergeCommentEvent represents a comment on a merge event.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#comment-on-merge-request
|
||||
type MergeCommentEvent 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"`
|
||||
URL string `json:"url"`
|
||||
} `json:"object_attributes"`
|
||||
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"`
|
||||
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 struct {
|
||||
ForceRemoveSourceBranch string `json:"force_remove_source_branch"`
|
||||
} `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"`
|
||||
LastCommit struct {
|
||||
ID string `json:"id"`
|
||||
Message string `json:"message"`
|
||||
Timestamp *time.Time `json:"timestamp"`
|
||||
URL string `json:"url"`
|
||||
Author *Author `json:"author"`
|
||||
} `json:"last_commit"`
|
||||
WorkInProgress bool `json:"work_in_progress"`
|
||||
URL string `json:"url"`
|
||||
Action string `json:"action"`
|
||||
Assignee struct {
|
||||
Name string `json:"name"`
|
||||
Username string `json:"username"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
} `json:"assignee"`
|
||||
} `json:"merge_request"`
|
||||
}
|
||||
|
||||
// IssueCommentEvent represents a comment on an issue event.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/web_hooks/web_hooks.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"`
|
||||
URL string `json:"url"`
|
||||
} `json:"object_attributes"`
|
||||
Issue *Issue `json:"issue"`
|
||||
}
|
||||
|
||||
// SnippetCommentEvent represents a comment on a snippet event.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#comment-on-code-snippet
|
||||
type SnippetCommentEvent 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"`
|
||||
URL string `json:"url"`
|
||||
} `json:"object_attributes"`
|
||||
Snippet *Snippet `json:"snippet"`
|
||||
}
|
||||
|
||||
// MergeEvent represents a merge event.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#merge-request-events
|
||||
type MergeEvent struct {
|
||||
ObjectKind string `json:"object_kind"`
|
||||
User *User `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"`
|
||||
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"`
|
||||
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 struct {
|
||||
ForceRemoveSourceBranch string `json:"force_remove_source_branch"`
|
||||
} `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"`
|
||||
LastCommit struct {
|
||||
ID string `json:"id"`
|
||||
Message string `json:"message"`
|
||||
Timestamp *time.Time `json:"timestamp"`
|
||||
URL string `json:"url"`
|
||||
Author *Author `json:"author"`
|
||||
} `json:"last_commit"`
|
||||
WorkInProgress bool `json:"work_in_progress"`
|
||||
URL string `json:"url"`
|
||||
Action string `json:"action"`
|
||||
Assignee struct {
|
||||
Name string `json:"name"`
|
||||
Username string `json:"username"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
} `json:"assignee"`
|
||||
} `json:"object_attributes"`
|
||||
Repository *Repository `json:"repository"`
|
||||
Assignee struct {
|
||||
Name string `json:"name"`
|
||||
Username string `json:"username"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
} `json:"assignee"`
|
||||
}
|
||||
|
||||
// WikiPageEvent represents a wiki page event.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#wiki-page-events
|
||||
type WikiPageEvent struct {
|
||||
ObjectKind string `json:"object_kind"`
|
||||
User *User `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"`
|
||||
}
|
||||
|
||||
// PipelineEvent represents a pipeline event.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/web_hooks/web_hooks.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"`
|
||||
Status string `json:"status"`
|
||||
Stages []string `json:"stages"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
FinishedAt string `json:"finished_at"`
|
||||
Duration int `json:"duration"`
|
||||
} `json:"object_attributes"`
|
||||
User struct {
|
||||
Name string `json:"name"`
|
||||
Username string `json:"username"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
} `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"`
|
||||
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"`
|
||||
User struct {
|
||||
Name string `json:"name"`
|
||||
Username string `json:"username"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
} `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"`
|
||||
}
|
||||
|
||||
//BuildEvent represents a build event
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/web_hooks/web_hooks.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 struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
} `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 string `json:"duration"`
|
||||
StartedAt string `json:"started_at"`
|
||||
FinishedAt string `json:"finished_at"`
|
||||
} `json:"commit"`
|
||||
Repository *Repository `json:"repository"`
|
||||
}
|
||||
598
vendor/github.com/lkysow/go-gitlab/events_test.go
generated
vendored
Normal file
598
vendor/github.com/lkysow/go-gitlab/events_test.go
generated
vendored
Normal file
@@ -0,0 +1,598 @@
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPushEventUnmarshal(t *testing.T) {
|
||||
jsonObject := `{
|
||||
"object_kind": "push",
|
||||
"before": "95790bf891e76fee5e1747ab589903a6a1f80f22",
|
||||
"after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
||||
"ref": "refs/heads/master",
|
||||
"checkout_sha": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
||||
"user_id": 4,
|
||||
"user_name": "John Smith",
|
||||
"user_email": "john@example.com",
|
||||
"user_avatar": "https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80",
|
||||
"project_id": 15,
|
||||
"project":{
|
||||
"name":"Diaspora",
|
||||
"description":"",
|
||||
"web_url":"http://example.com/mike/diaspora",
|
||||
"avatar_url":null,
|
||||
"git_ssh_url":"git@example.com:mike/diaspora.git",
|
||||
"git_http_url":"http://example.com/mike/diaspora.git",
|
||||
"namespace":"Mike",
|
||||
"visibility":"public",
|
||||
"path_with_namespace":"mike/diaspora",
|
||||
"default_branch":"master",
|
||||
"homepage":"http://example.com/mike/diaspora",
|
||||
"url":"git@example.com:mike/diaspora.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/diaspora.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":"public"
|
||||
},
|
||||
"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 event *PushEvent
|
||||
err := json.Unmarshal([]byte(jsonObject), &event)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Push Event can not unmarshaled: %v\n ", err.Error())
|
||||
}
|
||||
|
||||
if event == nil {
|
||||
t.Errorf("Push Event is null")
|
||||
}
|
||||
|
||||
if event.ProjectID != 15 {
|
||||
t.Errorf("ProjectID is %v, want %v", event.ProjectID, 15)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestMergeEventUnmarshal(t *testing.T) {
|
||||
|
||||
jsonObject := `{
|
||||
"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":null,
|
||||
"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":"private",
|
||||
"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":null,
|
||||
"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":"private",
|
||||
"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"
|
||||
},
|
||||
"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 event *MergeEvent
|
||||
err := json.Unmarshal([]byte(jsonObject), &event)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Merge Event can not unmarshaled: %v\n ", err.Error())
|
||||
}
|
||||
|
||||
if event == nil {
|
||||
t.Errorf("Merge Event is null")
|
||||
}
|
||||
|
||||
if event.ObjectAttributes.ID != 99 {
|
||||
t.Errorf("ObjectAttributes.ID is %v, want %v", event.ObjectAttributes.ID, 99)
|
||||
}
|
||||
|
||||
if event.ObjectAttributes.Source.Homepage != "http://example.com/awesome_space/awesome_project" {
|
||||
t.Errorf("ObjectAttributes.Source.Homepage is %v, want %v", event.ObjectAttributes.Source.Homepage, "http://example.com/awesome_space/awesome_project")
|
||||
}
|
||||
|
||||
if event.ObjectAttributes.LastCommit.ID != "da1560886d4f094c3e6c9ef40349f7d38b5d27d7" {
|
||||
t.Errorf("ObjectAttributes.LastCommit.ID is %v, want %s", event.ObjectAttributes.LastCommit.ID, "da1560886d4f094c3e6c9ef40349f7d38b5d27d7")
|
||||
}
|
||||
if event.ObjectAttributes.Assignee.Name != "User1" {
|
||||
t.Errorf("Assignee.Name is %v, want %v", event.ObjectAttributes.ID, "User1")
|
||||
}
|
||||
|
||||
if event.ObjectAttributes.Assignee.Username != "user1" {
|
||||
t.Errorf("ObjectAttributes is %v, want %v", event.ObjectAttributes.Assignee.Username, "user1")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestPipelineEventUnmarshal(t *testing.T) {
|
||||
jsonObject := `{
|
||||
"object_kind": "pipeline",
|
||||
"object_attributes":{
|
||||
"id": 31,
|
||||
"ref": "master",
|
||||
"tag": false,
|
||||
"sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2",
|
||||
"before_sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2",
|
||||
"status": "success",
|
||||
"stages":[
|
||||
"build",
|
||||
"test",
|
||||
"deploy"
|
||||
],
|
||||
"created_at": "2016-08-12 15:23:28 UTC",
|
||||
"finished_at": "2016-08-12 15:26:29 UTC",
|
||||
"duration": 63
|
||||
},
|
||||
"user":{
|
||||
"name": "Administrator",
|
||||
"username": "root",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon"
|
||||
},
|
||||
"project":{
|
||||
"name": "Gitlab Test",
|
||||
"description": "Atque in sunt eos similique dolores voluptatem.",
|
||||
"web_url": "http://192.168.64.1:3005/gitlab-org/gitlab-test",
|
||||
"avatar_url": null,
|
||||
"git_ssh_url": "git@192.168.64.1:gitlab-org/gitlab-test.git",
|
||||
"git_http_url": "http://192.168.64.1:3005/gitlab-org/gitlab-test.git",
|
||||
"namespace": "Gitlab Org",
|
||||
"visibility": "private",
|
||||
"path_with_namespace": "gitlab-org/gitlab-test",
|
||||
"default_branch": "master"
|
||||
},
|
||||
"commit":{
|
||||
"id": "bcbb5ec396a2c0f828686f14fac9b80b780504f2",
|
||||
"message": "test\n",
|
||||
"timestamp": "2016-08-12T17:23:21+02:00",
|
||||
"url": "http://example.com/gitlab-org/gitlab-test/commit/bcbb5ec396a2c0f828686f14fac9b80b780504f2",
|
||||
"author":{
|
||||
"name": "User",
|
||||
"email": "user@gitlab.com"
|
||||
}
|
||||
},
|
||||
"builds":[
|
||||
{
|
||||
"id": 380,
|
||||
"stage": "deploy",
|
||||
"name": "production",
|
||||
"status": "skipped",
|
||||
"created_at": "2016-08-12 15:23:28 UTC",
|
||||
"started_at": null,
|
||||
"finished_at": null,
|
||||
"when": "manual",
|
||||
"manual": true,
|
||||
"user":{
|
||||
"name": "Administrator",
|
||||
"username": "root",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon"
|
||||
},
|
||||
"runner": null,
|
||||
"artifacts_file":{
|
||||
"filename": null,
|
||||
"size": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 377,
|
||||
"stage": "test",
|
||||
"name": "test-image",
|
||||
"status": "success",
|
||||
"created_at": "2016-08-12 15:23:28 UTC",
|
||||
"started_at": "2016-08-12 15:26:12 UTC",
|
||||
"finished_at": null,
|
||||
"when": "on_success",
|
||||
"manual": false,
|
||||
"user":{
|
||||
"name": "Administrator",
|
||||
"username": "root",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon"
|
||||
},
|
||||
"runner": {
|
||||
"id": 6,
|
||||
"description": "Kubernetes Runner",
|
||||
"active": true,
|
||||
"is_shared": true
|
||||
},
|
||||
"artifacts_file":{
|
||||
"filename": "artifacts.zip",
|
||||
"size": 1319148
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 378,
|
||||
"stage": "test",
|
||||
"name": "test-build",
|
||||
"status": "success",
|
||||
"created_at": "2016-08-12 15:23:28 UTC",
|
||||
"started_at": "2016-08-12 15:26:12 UTC",
|
||||
"finished_at": "2016-08-12 15:26:29 UTC",
|
||||
"when": "on_success",
|
||||
"manual": false,
|
||||
"user":{
|
||||
"name": "Administrator",
|
||||
"username": "root",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon"
|
||||
},
|
||||
"runner": null,
|
||||
"artifacts_file":{
|
||||
"filename": null,
|
||||
"size": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 376,
|
||||
"stage": "build",
|
||||
"name": "build-image",
|
||||
"status": "success",
|
||||
"created_at": "2016-08-12 15:23:28 UTC",
|
||||
"started_at": "2016-08-12 15:24:56 UTC",
|
||||
"finished_at": "2016-08-12 15:25:26 UTC",
|
||||
"when": "on_success",
|
||||
"manual": false,
|
||||
"user":{
|
||||
"name": "Administrator",
|
||||
"username": "root",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon"
|
||||
},
|
||||
"runner": null,
|
||||
"artifacts_file":{
|
||||
"filename": null,
|
||||
"size": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 379,
|
||||
"stage": "deploy",
|
||||
"name": "staging",
|
||||
"status": "created",
|
||||
"created_at": "2016-08-12 15:23:28 UTC",
|
||||
"started_at": null,
|
||||
"finished_at": null,
|
||||
"when": "on_success",
|
||||
"manual": false,
|
||||
"user":{
|
||||
"name": "Administrator",
|
||||
"username": "root",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon"
|
||||
},
|
||||
"runner": null,
|
||||
"artifacts_file":{
|
||||
"filename": null,
|
||||
"size": null
|
||||
}
|
||||
}
|
||||
]
|
||||
}`
|
||||
|
||||
var event *PipelineEvent
|
||||
err := json.Unmarshal([]byte(jsonObject), &event)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Pipeline Event can not unmarshaled: %v\n ", err.Error())
|
||||
}
|
||||
|
||||
if event == nil {
|
||||
t.Errorf("Pipeline Event is null")
|
||||
}
|
||||
|
||||
if event.ObjectAttributes.ID != 31 {
|
||||
t.Errorf("ObjectAttributes is %v, want %v", event.ObjectAttributes.ID, 1977)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestBuildEventUnmarshal(t *testing.T) {
|
||||
jsonObject := `{
|
||||
"object_kind": "build",
|
||||
"ref": "gitlab-script-trigger",
|
||||
"tag": false,
|
||||
"before_sha": "2293ada6b400935a1378653304eaf6221e0fdb8f",
|
||||
"sha": "2293ada6b400935a1378653304eaf6221e0fdb8f",
|
||||
"build_id": 1977,
|
||||
"build_name": "test",
|
||||
"build_stage": "test",
|
||||
"build_status": "created",
|
||||
"build_started_at": null,
|
||||
"build_finished_at": null,
|
||||
"build_duration": 23.265997,
|
||||
"build_allow_failure": false,
|
||||
"project_id": 380,
|
||||
"project_name": "gitlab-org/gitlab-test",
|
||||
"user": {
|
||||
"id": 3,
|
||||
"name": "User",
|
||||
"email": "user@gitlab.com"
|
||||
},
|
||||
"commit": {
|
||||
"id": 2366,
|
||||
"sha": "2293ada6b400935a1378653304eaf6221e0fdb8f",
|
||||
"message": "test\n",
|
||||
"author_name": "User",
|
||||
"author_email": "user@gitlab.com",
|
||||
"status": "created",
|
||||
"duration": null,
|
||||
"started_at": null,
|
||||
"finished_at": null
|
||||
},
|
||||
"repository": {
|
||||
"name": "gitlab_test",
|
||||
"git_ssh_url": "git@192.168.64.1:gitlab-org/gitlab-test.git",
|
||||
"description": "Atque in sunt eos similique dolores voluptatem.",
|
||||
"homepage": "http://192.168.64.1:3005/gitlab-org/gitlab-test",
|
||||
"git_ssh_url": "git@192.168.64.1:gitlab-org/gitlab-test.git",
|
||||
"git_http_url": "http://192.168.64.1:3005/gitlab-org/gitlab-test.git",
|
||||
"visibility": "private"
|
||||
}
|
||||
}`
|
||||
var event *BuildEvent
|
||||
err := json.Unmarshal([]byte(jsonObject), &event)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Build Event can not unmarshaled: %v\n ", err.Error())
|
||||
}
|
||||
|
||||
if event == nil {
|
||||
t.Errorf("Build Event is null")
|
||||
}
|
||||
|
||||
if event.BuildID != 1977 {
|
||||
t.Errorf("BuildID is %v, want %v", event.BuildID, 1977)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeEventUnmarshalFromGroup(t *testing.T) {
|
||||
|
||||
jsonObject := `{
|
||||
"object_kind": "merge_request",
|
||||
"user": {
|
||||
"name": "Administrator",
|
||||
"username": "root",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/d22738dc40839e3d95fca77ca3eac067?s=80\u0026d=identicon"
|
||||
},
|
||||
"project": {
|
||||
"name": "example-project",
|
||||
"description": "",
|
||||
"web_url": "http://example.com/exm-namespace/example-project",
|
||||
"avatar_url": null,
|
||||
"git_ssh_url": "git@example.com:exm-namespace/example-project.git",
|
||||
"git_http_url": "http://example.com/exm-namespace/example-project.git",
|
||||
"namespace": "exm-namespace",
|
||||
"visibility": "public",
|
||||
"path_with_namespace": "exm-namespace/example-project",
|
||||
"default_branch": "master",
|
||||
"homepage": "http://example.com/exm-namespace/example-project",
|
||||
"url": "git@example.com:exm-namespace/example-project.git",
|
||||
"ssh_url": "git@example.com:exm-namespace/example-project.git",
|
||||
"http_url": "http://example.com/exm-namespace/example-project.git"
|
||||
},
|
||||
"object_attributes": {
|
||||
"id": 15917,
|
||||
"target_branch ": "master ",
|
||||
"source_branch ": "source-branch-test ",
|
||||
"source_project_id ": 87,
|
||||
"author_id ": 15,
|
||||
"assignee_id ": 29,
|
||||
"title ": "source-branch-test ",
|
||||
"created_at ": "2016 - 12 - 01 13: 11: 10 UTC ",
|
||||
"updated_at ": "2016 - 12 - 01 13: 21: 20 UTC ",
|
||||
"milestone_id ": null,
|
||||
"state ": "merged ",
|
||||
"merge_status ": "can_be_merged ",
|
||||
"target_project_id ": 87,
|
||||
"iid ": 1402,
|
||||
"description ": "word doc support for e - ticket ",
|
||||
"position ": 0,
|
||||
"locked_at ": null,
|
||||
"updated_by_id ": null,
|
||||
"merge_error ": null,
|
||||
"merge_params": {
|
||||
"force_remove_source_branch": "0"
|
||||
},
|
||||
"merge_when_build_succeeds": false,
|
||||
"merge_user_id": null,
|
||||
"merge_commit_sha": "ac3ca1559bc39abf963586372eff7f8fdded646e",
|
||||
"deleted_at": null,
|
||||
"approvals_before_merge": null,
|
||||
"rebase_commit_sha": null,
|
||||
"in_progress_merge_commit_sha": null,
|
||||
"lock_version": 0,
|
||||
"time_estimate": 0,
|
||||
"source": {
|
||||
"name": "example-project",
|
||||
"description": "",
|
||||
"web_url": "http://example.com/exm-namespace/example-project",
|
||||
"avatar_url": null,
|
||||
"git_ssh_url": "git@example.com:exm-namespace/example-project.git",
|
||||
"git_http_url": "http://example.com/exm-namespace/example-project.git",
|
||||
"namespace": "exm-namespace",
|
||||
"visibility": "public",
|
||||
"path_with_namespace": "exm-namespace/example-project",
|
||||
"default_branch": "master",
|
||||
"homepage": "http://example.com/exm-namespace/example-project",
|
||||
"url": "git@example.com:exm-namespace/example-project.git",
|
||||
"ssh_url": "git@example.com:exm-namespace/example-project.git",
|
||||
"http_url": "http://example.com/exm-namespace/example-project.git"
|
||||
},
|
||||
"target": {
|
||||
"name": "example-project",
|
||||
"description": "",
|
||||
"web_url": "http://example.com/exm-namespace/example-project",
|
||||
"avatar_url": null,
|
||||
"git_ssh_url": "git@example.com:exm-namespace/example-project.git",
|
||||
"git_http_url": "http://example.com/exm-namespace/example-project.git",
|
||||
"namespace": "exm-namespace",
|
||||
"visibility": "public",
|
||||
"path_with_namespace": "exm-namespace/example-project",
|
||||
"default_branch": "master",
|
||||
"homepage": "http://example.com/exm-namespace/example-project",
|
||||
"url": "git@example.com:exm-namespace/example-project.git",
|
||||
"ssh_url": "git@example.com:exm-namespace/example-project.git",
|
||||
"http_url": "http://example.com/exm-namespace/example-project.git"
|
||||
},
|
||||
"last_commit": {
|
||||
"id": "61b6a0d35dbaf915760233b637622e383d3cc9ec",
|
||||
"message": "commit message",
|
||||
"timestamp": "2016-12-01T15:07:53+02:00",
|
||||
"url": "http://example.com/exm-namespace/example-project/commit/61b6a0d35dbaf915760233b637622e383d3cc9ec",
|
||||
"author": {
|
||||
"name": "Test User",
|
||||
"email": "test.user@mail.com"
|
||||
}
|
||||
},
|
||||
"work_in_progress": false,
|
||||
"url": "http://example.com/exm-namespace/example-project/merge_requests/1402",
|
||||
"action": "merge"
|
||||
},
|
||||
"repository": {
|
||||
"name": "example-project",
|
||||
"url": "git@example.com:exm-namespace/example-project.git",
|
||||
"description": "",
|
||||
"homepage": "http://example.com/exm-namespace/example-project"
|
||||
},
|
||||
"assignee": {
|
||||
"name": "Administrator",
|
||||
"username": "root",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/d22738dc40839e3d95fca77ca3eac067?s=80\u0026d=identicon"
|
||||
}
|
||||
}`
|
||||
|
||||
var event *MergeEvent
|
||||
err := json.Unmarshal([]byte(jsonObject), &event)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Group Merge Event can not unmarshaled: %v\n ", err.Error())
|
||||
}
|
||||
|
||||
if event == nil {
|
||||
t.Errorf("Group Merge Event is null")
|
||||
}
|
||||
|
||||
if event.ObjectKind != "merge_request" {
|
||||
t.Errorf("ObjectKind is %v, want %v", event.ObjectKind, "merge_request")
|
||||
}
|
||||
|
||||
if event.User.Username != "root" {
|
||||
t.Errorf("User.Username is %v, want %v", event.User.Username, "root")
|
||||
}
|
||||
|
||||
if event.Project.Name != "example-project" {
|
||||
t.Errorf("Project.Name is %v, want %v", event.Project.Name, "example-project")
|
||||
}
|
||||
|
||||
if event.ObjectAttributes.ID != 15917 {
|
||||
t.Errorf("ObjectAttributes.ID is %v, want %v", event.ObjectAttributes.ID, 15917)
|
||||
}
|
||||
|
||||
if event.ObjectAttributes.Source.Name != "example-project" {
|
||||
t.Errorf("ObjectAttributes.Source.Name is %v, want %v", event.ObjectAttributes.Source.Name, "example-project")
|
||||
}
|
||||
|
||||
if event.ObjectAttributes.LastCommit.Author.Email != "test.user@mail.com" {
|
||||
t.Errorf("ObjectAttributes.LastCommit.Author.Email is %v, want %v", event.ObjectAttributes.LastCommit.Author.Email, "test.user@mail.com")
|
||||
}
|
||||
|
||||
if event.Repository.Name != "example-project" {
|
||||
t.Errorf("Repository.Name is %v, want %v", event.Repository.Name, "example-project")
|
||||
}
|
||||
|
||||
if event.Assignee.Username != "root" {
|
||||
t.Errorf("Assignee.Username is %v, want %v", event.Assignee, "root")
|
||||
}
|
||||
}
|
||||
37
vendor/github.com/lkysow/go-gitlab/examples/impersonation.go
generated
vendored
Normal file
37
vendor/github.com/lkysow/go-gitlab/examples/impersonation.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/xanzy/go-gitlab"
|
||||
)
|
||||
|
||||
func impersonationExample() {
|
||||
git := gitlab.NewClient(nil, "yourtokengoeshere")
|
||||
|
||||
uid := 1
|
||||
|
||||
//list impersonation token from an user
|
||||
tokens, _, err := git.Users.GetAllImpersonationTokens(
|
||||
uid,
|
||||
&gitlab.GetAllImpersonationTokensOptions{State: gitlab.String("active")},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, token := range tokens {
|
||||
log.Println(token.Token)
|
||||
}
|
||||
|
||||
//create an impersonation token of an user
|
||||
token, _, err := git.Users.CreateImpersonationToken(
|
||||
uid,
|
||||
&gitlab.CreateImpersonationTokenOptions{Scopes: &[]string{"api"}},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
log.Println(token.Token)
|
||||
}
|
||||
32
vendor/github.com/lkysow/go-gitlab/examples/labels.go
generated
vendored
Normal file
32
vendor/github.com/lkysow/go-gitlab/examples/labels.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/xanzy/go-gitlab"
|
||||
)
|
||||
|
||||
func labelExample() {
|
||||
git := gitlab.NewClient(nil, "yourtokengoeshere")
|
||||
|
||||
// Create new label
|
||||
l := &gitlab.CreateLabelOptions{
|
||||
Name: gitlab.String("My Label"),
|
||||
Color: gitlab.String("#11FF22"),
|
||||
}
|
||||
label, _, err := git.Labels.CreateLabel("myname/myproject", l)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Printf("Created label: %s\nWith color: %s\n", label.Name, label.Color)
|
||||
|
||||
// List all labels
|
||||
labels, _, err := git.Labels.ListLabels("myname/myproject")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, label := range labels {
|
||||
log.Printf("Found label: %s", label.Name)
|
||||
}
|
||||
}
|
||||
6
vendor/github.com/lkysow/go-gitlab/examples/main.go
generated
vendored
Normal file
6
vendor/github.com/lkysow/go-gitlab/examples/main.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
// See the separate files in this directory for the examples. This file is only
|
||||
// here to provide a main() function for the `example` package, keeping Travis happy.
|
||||
}
|
||||
21
vendor/github.com/lkysow/go-gitlab/examples/pipelines.go
generated
vendored
Normal file
21
vendor/github.com/lkysow/go-gitlab/examples/pipelines.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/xanzy/go-gitlab"
|
||||
)
|
||||
|
||||
func pipelineExample() {
|
||||
git := gitlab.NewClient(nil, "yourtokengoeshere")
|
||||
git.SetBaseURL("https://gitlab.com/api/v4")
|
||||
|
||||
pipelines, _, err := git.Pipelines.ListProjectPipelines(2743054)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, pipeline := range pipelines {
|
||||
log.Printf("Found pipeline: %v", pipeline)
|
||||
}
|
||||
}
|
||||
46
vendor/github.com/lkysow/go-gitlab/examples/projects.go
generated
vendored
Normal file
46
vendor/github.com/lkysow/go-gitlab/examples/projects.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/xanzy/go-gitlab"
|
||||
)
|
||||
|
||||
func projectExample() {
|
||||
git := gitlab.NewClient(nil, "yourtokengoeshere")
|
||||
|
||||
// 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.CreateSnippetOptions{
|
||||
Title: gitlab.String("Dummy Snippet"),
|
||||
FileName: gitlab.String("snippet.go"),
|
||||
Code: gitlab.String("package main...."),
|
||||
Visibility: gitlab.Visibility(gitlab.PublicVisibility),
|
||||
}
|
||||
_, _, err = git.ProjectSnippets.CreateSnippet(project.ID, s)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// List all project snippets
|
||||
snippets, _, err := git.ProjectSnippets.ListSnippets(project.PathWithNamespace, &gitlab.ListSnippetsOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, snippet := range snippets {
|
||||
log.Printf("Found snippet: %s", snippet.Title)
|
||||
}
|
||||
}
|
||||
43
vendor/github.com/lkysow/go-gitlab/examples/repository_files.go
generated
vendored
Normal file
43
vendor/github.com/lkysow/go-gitlab/examples/repository_files.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/xanzy/go-gitlab"
|
||||
)
|
||||
|
||||
func repositoryFileExample() {
|
||||
git := gitlab.NewClient(nil, "yourtokengoeshere")
|
||||
|
||||
// Create a new repository file
|
||||
cf := &gitlab.CreateFileOptions{
|
||||
Branch: gitlab.String("master"),
|
||||
Content: gitlab.String("My file contents"),
|
||||
CommitMessage: gitlab.String("Adding a test file"),
|
||||
}
|
||||
file, _, err := git.RepositoryFiles.CreateFile("myname/myproject", "file.go", cf)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Update a repository file
|
||||
uf := &gitlab.UpdateFileOptions{
|
||||
Branch: gitlab.String("master"),
|
||||
Content: gitlab.String("My file content"),
|
||||
CommitMessage: gitlab.String("Fixing typo"),
|
||||
}
|
||||
_, _, err = git.RepositoryFiles.UpdateFile("myname/myproject", file.FilePath, uf)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
gf := &gitlab.GetFileOptions{
|
||||
Ref: gitlab.String("master"),
|
||||
}
|
||||
f, _, err := git.RepositoryFiles.GetFile("myname/myproject", file.FilePath, gf)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("File contains: %s", f.Content)
|
||||
}
|
||||
79
vendor/github.com/lkysow/go-gitlab/feature_flags.go
generated
vendored
Normal file
79
vendor/github.com/lkysow/go-gitlab/feature_flags.go
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"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 ...OptionFunc) ([]*Feature, *Response, error) {
|
||||
req, err := s.client.NewRequest("GET", "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 ...OptionFunc) (*Feature, *Response, error) {
|
||||
u := fmt.Sprintf("features/%s", url.QueryEscape(name))
|
||||
|
||||
opt := struct {
|
||||
Value interface{} `url:"value" json:"value"`
|
||||
}{
|
||||
value,
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("POST", 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
|
||||
}
|
||||
92
vendor/github.com/lkysow/go-gitlab/feature_flags_test.go
generated
vendored
Normal file
92
vendor/github.com/lkysow/go-gitlab/feature_flags_test.go
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestListFeatureFlags(t *testing.T) {
|
||||
mux, server, client := setup()
|
||||
defer teardown(server)
|
||||
|
||||
mux.HandleFunc("/features", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "GET")
|
||||
fmt.Fprint(w, `
|
||||
[
|
||||
{
|
||||
"name": "experimental_feature",
|
||||
"state": "off",
|
||||
"gates": [
|
||||
{
|
||||
"key": "boolean",
|
||||
"value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "new_library",
|
||||
"state": "on"
|
||||
}
|
||||
]
|
||||
`)
|
||||
})
|
||||
|
||||
features, _, err := client.Features.ListFeatures()
|
||||
if err != nil {
|
||||
t.Errorf("Features.ListFeatures returned error: %v", err)
|
||||
}
|
||||
|
||||
want := []*Feature{
|
||||
{Name: "experimental_feature", State: "off", Gates: []Gate{
|
||||
{Key: "boolean", Value: false},
|
||||
}},
|
||||
{Name: "new_library", State: "on"},
|
||||
}
|
||||
if !reflect.DeepEqual(want, features) {
|
||||
t.Errorf("Features.ListFeatures returned %+v, want %+v", features, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetFeatureFlag(t *testing.T) {
|
||||
mux, server, client := setup()
|
||||
defer teardown(server)
|
||||
|
||||
mux.HandleFunc("/features/new_library", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "POST")
|
||||
fmt.Fprint(w, `
|
||||
{
|
||||
"name": "new_library",
|
||||
"state": "conditional",
|
||||
"gates": [
|
||||
{
|
||||
"key": "boolean",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"key": "percentage_of_time",
|
||||
"value": 30
|
||||
}
|
||||
]
|
||||
}
|
||||
`)
|
||||
})
|
||||
|
||||
feature, _, err := client.Features.SetFeatureFlag("new_library", "30")
|
||||
if err != nil {
|
||||
t.Errorf("Features.SetFeatureFlag returned error: %v", err)
|
||||
}
|
||||
|
||||
want := &Feature{
|
||||
Name: "new_library",
|
||||
State: "conditional",
|
||||
Gates: []Gate{
|
||||
{Key: "boolean", Value: false},
|
||||
{Key: "percentage_of_time", Value: 30.0},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(want, feature) {
|
||||
t.Errorf("Features.SetFeatureFlag returned %+v, want %+v", feature, want)
|
||||
}
|
||||
}
|
||||
620
vendor/github.com/lkysow/go-gitlab/gitlab.go
generated
vendored
Normal file
620
vendor/github.com/lkysow/go-gitlab/gitlab.go
generated
vendored
Normal file
@@ -0,0 +1,620 @@
|
||||
//
|
||||
// Copyright 2017, 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"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/google/go-querystring/query"
|
||||
)
|
||||
|
||||
const (
|
||||
libraryVersion = "0.2.0"
|
||||
defaultBaseURL = "https://gitlab.com/api/v4/"
|
||||
userAgent = "go-gitlab/" + libraryVersion
|
||||
)
|
||||
|
||||
// tokenType represents a token type within GitLab.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/
|
||||
type tokenType int
|
||||
|
||||
// List of available token type
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/
|
||||
const (
|
||||
privateToken tokenType = iota
|
||||
oAuthToken
|
||||
)
|
||||
|
||||
// AccessLevelValue represents a permission level within GitLab.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/permissions/permissions.html
|
||||
type AccessLevelValue int
|
||||
|
||||
// List of available access levels
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/permissions/permissions.html
|
||||
const (
|
||||
GuestPermissions AccessLevelValue = 10
|
||||
ReporterPermissions AccessLevelValue = 20
|
||||
DeveloperPermissions AccessLevelValue = 30
|
||||
MasterPermissions AccessLevelValue = 40
|
||||
OwnerPermission AccessLevelValue = 50
|
||||
)
|
||||
|
||||
// NotificationLevelValue represents a notification level.
|
||||
type NotificationLevelValue int
|
||||
|
||||
// String implements the fmt.Stringer interface.
|
||||
func (l NotificationLevelValue) String() string {
|
||||
return notificationLevelNames[l]
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (l NotificationLevelValue) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(l.String())
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
func (l *NotificationLevelValue) UnmarshalJSON(data []byte) error {
|
||||
var raw interface{}
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch raw := raw.(type) {
|
||||
case float64:
|
||||
*l = NotificationLevelValue(raw)
|
||||
case string:
|
||||
*l = notificationLevelTypes[raw]
|
||||
default:
|
||||
return fmt.Errorf("json: cannot unmarshal %T into Go value of type %T", raw, *l)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// List of valid notification levels.
|
||||
const (
|
||||
DisabledNotificationLevel NotificationLevelValue = iota
|
||||
ParticipatingNotificationLevel
|
||||
WatchNotificationLevel
|
||||
GlobalNotificationLevel
|
||||
MentionNotificationLevel
|
||||
CustomNotificationLevel
|
||||
)
|
||||
|
||||
var notificationLevelNames = [...]string{
|
||||
"disabled",
|
||||
"participating",
|
||||
"watch",
|
||||
"global",
|
||||
"mention",
|
||||
"custom",
|
||||
}
|
||||
|
||||
var notificationLevelTypes = map[string]NotificationLevelValue{
|
||||
"disabled": DisabledNotificationLevel,
|
||||
"participating": ParticipatingNotificationLevel,
|
||||
"watch": WatchNotificationLevel,
|
||||
"global": GlobalNotificationLevel,
|
||||
"mention": MentionNotificationLevel,
|
||||
"custom": CustomNotificationLevel,
|
||||
}
|
||||
|
||||
// VisibilityValue represents a visibility level within GitLab.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/
|
||||
type VisibilityValue string
|
||||
|
||||
// List of available visibility levels
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/
|
||||
const (
|
||||
PrivateVisibility VisibilityValue = "private"
|
||||
InternalVisibility VisibilityValue = "internal"
|
||||
PublicVisibility VisibilityValue = "public"
|
||||
)
|
||||
|
||||
// A Client manages communication with the GitLab API.
|
||||
type Client struct {
|
||||
// HTTP client used to communicate with the API.
|
||||
client *http.Client
|
||||
|
||||
// Base URL for API requests. Defaults to the public GitLab API, but can be
|
||||
// set to a domain endpoint to use with aself hosted GitLab server. baseURL
|
||||
// should always be specified with a trailing slash.
|
||||
baseURL *url.URL
|
||||
|
||||
// token type used to make authenticated API calls.
|
||||
tokenType tokenType
|
||||
|
||||
// token used to make authenticated API calls.
|
||||
token string
|
||||
|
||||
// User agent used when communicating with the GitLab API.
|
||||
UserAgent string
|
||||
|
||||
// Services used for talking to different parts of the GitLab API.
|
||||
Branches *BranchesService
|
||||
BuildVariables *BuildVariablesService
|
||||
Commits *CommitsService
|
||||
DeployKeys *DeployKeysService
|
||||
Environments *EnvironmentsService
|
||||
Features *FeaturesService
|
||||
Groups *GroupsService
|
||||
GroupMembers *GroupMembersService
|
||||
Issues *IssuesService
|
||||
Jobs *JobsService
|
||||
Labels *LabelsService
|
||||
MergeRequests *MergeRequestsService
|
||||
Milestones *MilestonesService
|
||||
Namespaces *NamespacesService
|
||||
Notes *NotesService
|
||||
NotificationSettings *NotificationSettingsService
|
||||
Projects *ProjectsService
|
||||
ProjectMembers *ProjectMembersService
|
||||
ProjectSnippets *ProjectSnippetsService
|
||||
Pipelines *PipelinesService
|
||||
PipelineTriggers *PipelineTriggersService
|
||||
Repositories *RepositoriesService
|
||||
RepositoryFiles *RepositoryFilesService
|
||||
Services *ServicesService
|
||||
Session *SessionService
|
||||
Settings *SettingsService
|
||||
SystemHooks *SystemHooksService
|
||||
Tags *TagsService
|
||||
Todos *TodosService
|
||||
Users *UsersService
|
||||
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"`
|
||||
}
|
||||
|
||||
// NewClient returns a new GitLab API client. If a nil httpClient is
|
||||
// provided, http.DefaultClient will be used. To use API methods which require
|
||||
// authentication, provide a valid private token.
|
||||
func NewClient(httpClient *http.Client, token string) *Client {
|
||||
return newClient(httpClient, privateToken, token)
|
||||
}
|
||||
|
||||
// NewOAuthClient returns a new GitLab API client. If a nil httpClient is
|
||||
// provided, http.DefaultClient will be used. To use API methods which require
|
||||
// authentication, provide a valid oauth token.
|
||||
func NewOAuthClient(httpClient *http.Client, token string) *Client {
|
||||
return newClient(httpClient, oAuthToken, token)
|
||||
}
|
||||
|
||||
func newClient(httpClient *http.Client, tokenType tokenType, token string) *Client {
|
||||
if httpClient == nil {
|
||||
httpClient = http.DefaultClient
|
||||
}
|
||||
|
||||
c := &Client{client: httpClient, tokenType: tokenType, token: token, UserAgent: userAgent}
|
||||
if err := c.SetBaseURL(defaultBaseURL); err != nil {
|
||||
// Should never happen since defaultBaseURL is our constant.
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create the internal timeStats service.
|
||||
timeStats := &timeStatsService{client: c}
|
||||
|
||||
// Create all the public services.
|
||||
c.Branches = &BranchesService{client: c}
|
||||
c.BuildVariables = &BuildVariablesService{client: c}
|
||||
c.Commits = &CommitsService{client: c}
|
||||
c.DeployKeys = &DeployKeysService{client: c}
|
||||
c.Environments = &EnvironmentsService{client: c}
|
||||
c.Features = &FeaturesService{client: c}
|
||||
c.Groups = &GroupsService{client: c}
|
||||
c.GroupMembers = &GroupMembersService{client: c}
|
||||
c.Issues = &IssuesService{client: c, timeStats: timeStats}
|
||||
c.Jobs = &JobsService{client: c}
|
||||
c.Labels = &LabelsService{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.Projects = &ProjectsService{client: c}
|
||||
c.ProjectMembers = &ProjectMembersService{client: c}
|
||||
c.ProjectSnippets = &ProjectSnippetsService{client: c}
|
||||
c.Pipelines = &PipelinesService{client: c}
|
||||
c.PipelineTriggers = &PipelineTriggersService{client: c}
|
||||
c.Repositories = &RepositoriesService{client: c}
|
||||
c.RepositoryFiles = &RepositoryFilesService{client: c}
|
||||
c.Services = &ServicesService{client: c}
|
||||
c.Session = &SessionService{client: c}
|
||||
c.Settings = &SettingsService{client: c}
|
||||
c.SystemHooks = &SystemHooksService{client: c}
|
||||
c.Tags = &TagsService{client: c}
|
||||
c.Todos = &TodosService{client: c}
|
||||
c.Users = &UsersService{client: c}
|
||||
c.Version = &VersionService{client: c}
|
||||
c.Wikis = &WikisService{client: c}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// 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. urlStr
|
||||
// should always be specified with a trailing slash.
|
||||
func (c *Client) SetBaseURL(urlStr string) error {
|
||||
// Make sure the given URL end with a slash
|
||||
if !strings.HasSuffix(urlStr, "/") {
|
||||
urlStr += "/"
|
||||
}
|
||||
|
||||
var err error
|
||||
c.baseURL, err = url.Parse(urlStr)
|
||||
return err
|
||||
}
|
||||
|
||||
// NewRequest creates an API request. A relative URL path can be provided in
|
||||
// urlStr, 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 []OptionFunc) (*http.Request, error) {
|
||||
u := *c.baseURL
|
||||
// Set the encoded opaque data
|
||||
u.Opaque = c.baseURL.Path + path
|
||||
|
||||
if opt != nil {
|
||||
q, err := query.Values(opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u.RawQuery = q.Encode()
|
||||
}
|
||||
|
||||
req := &http.Request{
|
||||
Method: method,
|
||||
URL: &u,
|
||||
Proto: "HTTP/1.1",
|
||||
ProtoMajor: 1,
|
||||
ProtoMinor: 1,
|
||||
Header: make(http.Header),
|
||||
Host: u.Host,
|
||||
}
|
||||
|
||||
for _, fn := range options {
|
||||
if err := fn(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if method == "POST" || method == "PUT" {
|
||||
bodyBytes, err := json.Marshal(opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bodyReader := bytes.NewReader(bodyBytes)
|
||||
|
||||
u.RawQuery = ""
|
||||
req.Body = ioutil.NopCloser(bodyReader)
|
||||
req.ContentLength = int64(bodyReader.Len())
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
|
||||
req.Header.Set("Accept", "application/json")
|
||||
|
||||
switch c.tokenType {
|
||||
case privateToken:
|
||||
req.Header.Set("PRIVATE-TOKEN", c.token)
|
||||
case oAuthToken:
|
||||
req.Header.Set("Authorization", "Bearer "+c.token)
|
||||
}
|
||||
|
||||
if c.UserAgent != "" {
|
||||
req.Header.Set("User-Agent", c.UserAgent)
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
NextPage int
|
||||
PrevPage int
|
||||
FirstPage int
|
||||
LastPage 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
|
||||
}
|
||||
|
||||
// populatePageValues parses the HTTP Link response headers and populates the
|
||||
// various pagination link values in the Response.
|
||||
func (r *Response) populatePageValues() {
|
||||
if links, ok := r.Response.Header["Link"]; ok && len(links) > 0 {
|
||||
for _, link := range strings.Split(links[0], ",") {
|
||||
segments := strings.Split(strings.TrimSpace(link), ";")
|
||||
|
||||
// link must at least have href and rel
|
||||
if len(segments) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
// ensure href is properly formatted
|
||||
if !strings.HasPrefix(segments[0], "<") || !strings.HasSuffix(segments[0], ">") {
|
||||
continue
|
||||
}
|
||||
|
||||
// try to pull out page parameter
|
||||
url, err := url.Parse(segments[0][1 : len(segments[0])-1])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
page := url.Query().Get("page")
|
||||
if page == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, segment := range segments[1:] {
|
||||
switch strings.TrimSpace(segment) {
|
||||
case `rel="next"`:
|
||||
r.NextPage, _ = strconv.Atoi(page)
|
||||
case `rel="prev"`:
|
||||
r.PrevPage, _ = strconv.Atoi(page)
|
||||
case `rel="first"`:
|
||||
r.FirstPage, _ = strconv.Atoi(page)
|
||||
case `rel="last"`:
|
||||
r.LastPage, _ = strconv.Atoi(page)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 *http.Request, v interface{}) (*Response, error) {
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
Response *http.Response
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e *ErrorResponse) Error() string {
|
||||
path, _ := url.QueryUnescape(e.Response.Request.URL.Opaque)
|
||||
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 {
|
||||
var raw interface{}
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
errorResponse.Message = "failed to parse unknown error format"
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// OptionFunc can be passed to all API requests to make the API call as if you were
|
||||
// another user, provided your private token is from an administrator account.
|
||||
//
|
||||
// GitLab docs: https://docs.gitlab.com/ce/api/README.html#sudo
|
||||
type OptionFunc func(*http.Request) error
|
||||
|
||||
// WithSudo takes either a username or user ID and sets the SUDO request header
|
||||
func WithSudo(uid interface{}) OptionFunc {
|
||||
return func(req *http.Request) error {
|
||||
user, err := parseID(uid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("SUDO", user)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithContext runs the request with the provided context
|
||||
func WithContext(ctx context.Context) OptionFunc {
|
||||
return func(req *http.Request) error {
|
||||
*req = *req.WithContext(ctx)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Bool is a helper routine that allocates a new bool value
|
||||
// to store v and returns a pointer to it.
|
||||
func Bool(v bool) *bool {
|
||||
p := new(bool)
|
||||
*p = v
|
||||
return p
|
||||
}
|
||||
|
||||
// Int is a helper routine that allocates a new int32 value
|
||||
// to store v and returns a pointer to it, but unlike Int32
|
||||
// its argument value is an int.
|
||||
func Int(v int) *int {
|
||||
p := new(int)
|
||||
*p = v
|
||||
return p
|
||||
}
|
||||
|
||||
// String is a helper routine that allocates a new string value
|
||||
// to store v and returns a pointer to it.
|
||||
func String(v string) *string {
|
||||
p := new(string)
|
||||
*p = v
|
||||
return p
|
||||
}
|
||||
|
||||
// AccessLevel is a helper routine that allocates a new AccessLevelValue
|
||||
// to store v and returns a pointer to it.
|
||||
func AccessLevel(v AccessLevelValue) *AccessLevelValue {
|
||||
p := new(AccessLevelValue)
|
||||
*p = v
|
||||
return p
|
||||
}
|
||||
|
||||
// NotificationLevel is a helper routine that allocates a new NotificationLevelValue
|
||||
// to store v and returns a pointer to it.
|
||||
func NotificationLevel(v NotificationLevelValue) *NotificationLevelValue {
|
||||
p := new(NotificationLevelValue)
|
||||
*p = v
|
||||
return p
|
||||
}
|
||||
|
||||
// Visibility is a helper routine that allocates a new VisibilityValue
|
||||
// to store v and returns a pointer to it.
|
||||
func Visibility(v VisibilityValue) *VisibilityValue {
|
||||
p := new(VisibilityValue)
|
||||
*p = v
|
||||
return p
|
||||
}
|
||||
114
vendor/github.com/lkysow/go-gitlab/gitlab_test.go
generated
vendored
Normal file
114
vendor/github.com/lkysow/go-gitlab/gitlab_test.go
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// setup sets up a test HTTP server along with a gitlab.Client that is
|
||||
// configured to talk to that test server. Tests should register handlers on
|
||||
// mux which provide mock responses for the API method being tested.
|
||||
func setup() (*http.ServeMux, *httptest.Server, *Client) {
|
||||
// mux is the HTTP request multiplexer used with the test server.
|
||||
mux := http.NewServeMux()
|
||||
|
||||
// server is a test HTTP server used to provide mock API responses.
|
||||
server := httptest.NewServer(mux)
|
||||
|
||||
// client is the Gitlab client being tested.
|
||||
client := NewClient(nil, "")
|
||||
client.SetBaseURL(server.URL)
|
||||
|
||||
return mux, server, client
|
||||
}
|
||||
|
||||
// teardown closes the test HTTP server.
|
||||
func teardown(server *httptest.Server) {
|
||||
server.Close()
|
||||
}
|
||||
|
||||
func testURL(t *testing.T, r *http.Request, want string) {
|
||||
if got := r.RequestURI; got != want {
|
||||
t.Errorf("Request url: %+v, want %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func testMethod(t *testing.T, r *http.Request, want string) {
|
||||
if got := r.Method; got != want {
|
||||
t.Errorf("Request method: %s, want %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewClient(t *testing.T) {
|
||||
c := NewClient(nil, "")
|
||||
|
||||
if c.BaseURL().String() != defaultBaseURL {
|
||||
t.Errorf("NewClient BaseURL is %s, want %s", c.BaseURL().String(), defaultBaseURL)
|
||||
}
|
||||
if c.UserAgent != userAgent {
|
||||
t.Errorf("NewClient UserAgent is %s, want %s", c.UserAgent, userAgent)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckResponse(t *testing.T) {
|
||||
req, err := NewClient(nil, "").NewRequest("GET", "test", nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create request: %v", err)
|
||||
}
|
||||
|
||||
resp := &http.Response{
|
||||
Request: req,
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Body: ioutil.NopCloser(strings.NewReader(`
|
||||
{
|
||||
"message": {
|
||||
"prop1": [
|
||||
"message 1",
|
||||
"message 2"
|
||||
],
|
||||
"prop2":[
|
||||
"message 3"
|
||||
],
|
||||
"embed1": {
|
||||
"prop3": [
|
||||
"msg 1",
|
||||
"msg2"
|
||||
]
|
||||
},
|
||||
"embed2": {
|
||||
"prop4": [
|
||||
"some msg"
|
||||
]
|
||||
}
|
||||
},
|
||||
"error": "message 1"
|
||||
}`)),
|
||||
}
|
||||
|
||||
errResp := CheckResponse(resp)
|
||||
if errResp == nil {
|
||||
t.Fatal("Expected error response.")
|
||||
}
|
||||
|
||||
want := "GET https://gitlab.com/api/v4/test: 400 {error: message 1}, {message: {embed1: {prop3: [msg 1, msg2]}}, {embed2: {prop4: [some msg]}}, {prop1: [message 1, message 2]}, {prop2: [message 3]}}"
|
||||
|
||||
if errResp.Error() != want {
|
||||
t.Errorf("Expected error: %s, got %s", want, errResp.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestWithContext(t *testing.T) {
|
||||
ctx := context.WithValue(context.Background(), interface{}("myKey"), interface{}("myValue"))
|
||||
req, err := NewClient(nil, "").NewRequest("GET", "test", nil, []OptionFunc{WithContext(ctx)})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create request: %v", err)
|
||||
}
|
||||
|
||||
if req.Context() != ctx {
|
||||
t.Fatal("Context was not set correctly")
|
||||
}
|
||||
}
|
||||
193
vendor/github.com/lkysow/go-gitlab/group_members.go
generated
vendored
Normal file
193
vendor/github.com/lkysow/go-gitlab/group_members.go
generated
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
//
|
||||
// Copyright 2017, 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/url"
|
||||
"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
|
||||
}
|
||||
|
||||
// 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"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
State string `json:"state"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
AccessLevel AccessLevelValue `json:"access_level"`
|
||||
}
|
||||
|
||||
// ListGroupMembersOptions represents the available ListGroupMembers()
|
||||
// options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project
|
||||
type ListGroupMembersOptions struct {
|
||||
ListOptions
|
||||
}
|
||||
|
||||
// ListGroupMembers get a list of group members viewable by the authenticated
|
||||
// user.
|
||||
//
|
||||
// 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 ...OptionFunc) ([]*GroupMember, *Response, error) {
|
||||
group, err := parseID(gid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("groups/%s/members", url.QueryEscape(group))
|
||||
|
||||
req, err := s.client.NewRequest("GET", 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 ...OptionFunc) (*GroupMember, *Response, error) {
|
||||
group, err := parseID(gid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("groups/%s/members/%d", url.QueryEscape(group), user)
|
||||
|
||||
req, err := s.client.NewRequest("GET", 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
|
||||
}
|
||||
|
||||
// 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 ...OptionFunc) (*GroupMember, *Response, error) {
|
||||
group, err := parseID(gid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("groups/%s/members", url.QueryEscape(group))
|
||||
|
||||
req, err := s.client.NewRequest("POST", 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
|
||||
}
|
||||
|
||||
// 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 ...OptionFunc) (*GroupMember, *Response, error) {
|
||||
group, err := parseID(gid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("groups/%s/members/%d", url.QueryEscape(group), user)
|
||||
|
||||
req, err := s.client.NewRequest("PUT", 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 ...OptionFunc) (*Response, error) {
|
||||
group, err := parseID(gid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := fmt.Sprintf("groups/%s/members/%d", url.QueryEscape(group), user)
|
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(req, nil)
|
||||
}
|
||||
270
vendor/github.com/lkysow/go-gitlab/groups.go
generated
vendored
Normal file
270
vendor/github.com/lkysow/go-gitlab/groups.go
generated
vendored
Normal file
@@ -0,0 +1,270 @@
|
||||
//
|
||||
// Copyright 2017, 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/url"
|
||||
)
|
||||
|
||||
// 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"`
|
||||
Visibility *VisibilityValue `json:"visibility"`
|
||||
LFSEnabled bool `json:"lfs_enabled"`
|
||||
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"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
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"`
|
||||
Sort *string `url:"sort,omitempty" json:"sort,omitempty"`
|
||||
Statistics *bool `url:"statistics,omitempty" json:"statistics,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 ...OptionFunc) ([]*Group, *Response, error) {
|
||||
req, err := s.client.NewRequest("GET", "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
|
||||
}
|
||||
|
||||
// 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{}, options ...OptionFunc) (*Group, *Response, error) {
|
||||
group, err := parseID(gid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("groups/%s", url.QueryEscape(group))
|
||||
|
||||
req, err := s.client.NewRequest("GET", 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
|
||||
}
|
||||
|
||||
// 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"`
|
||||
Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"`
|
||||
LFSEnabled *bool `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"`
|
||||
RequestAccessEnabled *bool `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"`
|
||||
ParentID *int `url:"parent_id,omitempty" json:"parent_id,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 ...OptionFunc) (*Group, *Response, error) {
|
||||
req, err := s.client.NewRequest("POST", "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{}, project int, options ...OptionFunc) (*Group, *Response, error) {
|
||||
group, err := parseID(gid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("groups/%s/projects/%d", url.QueryEscape(group), project)
|
||||
|
||||
req, err := s.client.NewRequest("POST", 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 set of available options to update a Group;
|
||||
// as of today these are exactly the same available when creating a new Group.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#update-group
|
||||
type UpdateGroupOptions CreateGroupOptions
|
||||
|
||||
// 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 ...OptionFunc) (*Group, *Response, error) {
|
||||
group, err := parseID(gid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("groups/%s", url.QueryEscape(group))
|
||||
|
||||
req, err := s.client.NewRequest("PUT", 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 ...OptionFunc) (*Response, error) {
|
||||
group, err := parseID(gid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := fmt.Sprintf("groups/%s", url.QueryEscape(group))
|
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(req, 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 ...OptionFunc) ([]*Group, *Response, error) {
|
||||
var q struct {
|
||||
Search string `url:"search,omitempty" json:"search,omitempty"`
|
||||
}
|
||||
q.Search = query
|
||||
|
||||
req, err := s.client.NewRequest("GET", "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 ListGroupProjects()
|
||||
// options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/groups.html#list-a-group-s-projects
|
||||
type ListGroupProjectsOptions struct {
|
||||
ListOptions
|
||||
}
|
||||
|
||||
// ListGroupProjects get a list of group projects
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/groups.html#list-a-group-s-projects
|
||||
func (s *GroupsService) ListGroupProjects(gid interface{}, opt *ListGroupProjectsOptions, options ...OptionFunc) ([]*Project, *Response, error) {
|
||||
group, err := parseID(gid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("groups/%s/projects", url.QueryEscape(group))
|
||||
|
||||
req, err := s.client.NewRequest("GET", 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
|
||||
}
|
||||
362
vendor/github.com/lkysow/go-gitlab/issues.go
generated
vendored
Normal file
362
vendor/github.com/lkysow/go-gitlab/issues.go
generated
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
//
|
||||
// Copyright 2017, 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/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// IssuesService handles communication with the issue related methods
|
||||
// of the GitLab API.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html
|
||||
type IssuesService struct {
|
||||
client *Client
|
||||
timeStats *timeStatsService
|
||||
}
|
||||
|
||||
// Issue represents a GitLab issue.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html
|
||||
type Issue struct {
|
||||
ID int `json:"id"`
|
||||
IID int `json:"iid"`
|
||||
ProjectID int `json:"project_id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Labels []string `json:"labels"`
|
||||
Milestone *Milestone `json:"milestone"`
|
||||
Assignee struct {
|
||||
ID int `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
State string `json:"state"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
} `json:"assignee"`
|
||||
Author struct {
|
||||
ID int `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
State string `json:"state"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
} `json:"author"`
|
||||
State string `json:"state"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
Subscribed bool `json:"subscribed"`
|
||||
UserNotesCount int `json:"user_notes_count"`
|
||||
Confidential bool `json:"confidential"`
|
||||
DueDate string `json:"due_date"`
|
||||
WebURL string `json:"web_url"`
|
||||
}
|
||||
|
||||
func (i Issue) String() string {
|
||||
return Stringify(i)
|
||||
}
|
||||
|
||||
// Labels is a custom type with specific marshaling characteristics.
|
||||
type Labels []string
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (l *Labels) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(strings.Join(*l, ","))
|
||||
}
|
||||
|
||||
// ListIssuesOptions represents the available ListIssues() options.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-issues
|
||||
type ListIssuesOptions struct {
|
||||
ListOptions
|
||||
State *string `url:"state,omitempty" json:"state,omitempty"`
|
||||
Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"`
|
||||
Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"`
|
||||
Scope *string `url:"scope,omitempty" json:"scope,omitempty"`
|
||||
AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"`
|
||||
AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
|
||||
MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
|
||||
IIDs []int `url:"iids[],omitempty" json:"iids,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"`
|
||||
}
|
||||
|
||||
// ListIssues gets all issues created by authenticated user. This function
|
||||
// takes pagination parameters page and per_page to restrict the list of issues.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-issues
|
||||
func (s *IssuesService) ListIssues(opt *ListIssuesOptions, options ...OptionFunc) ([]*Issue, *Response, error) {
|
||||
req, err := s.client.NewRequest("GET", "issues", 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
|
||||
}
|
||||
|
||||
// ListGroupIssuesOptions represents the available ListGroupIssues() options.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-group-issues
|
||||
type ListGroupIssuesOptions struct {
|
||||
ListOptions
|
||||
State *string `url:"state,omitempty" json:"state,omitempty"`
|
||||
Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"`
|
||||
IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"`
|
||||
Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"`
|
||||
Scope *string `url:"scope,omitempty" json:"scope,omitempty"`
|
||||
AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"`
|
||||
AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
|
||||
MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,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"`
|
||||
}
|
||||
|
||||
// ListGroupIssues gets a list of group issues. This function accepts
|
||||
// pagination parameters page and per_page to return the list of group issues.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-group-issues
|
||||
func (s *IssuesService) ListGroupIssues(pid interface{}, opt *ListGroupIssuesOptions, options ...OptionFunc) ([]*Issue, *Response, error) {
|
||||
group, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("groups/%s/issues", url.QueryEscape(group))
|
||||
|
||||
req, err := s.client.NewRequest("GET", 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
|
||||
}
|
||||
|
||||
// ListProjectIssuesOptions represents the available ListProjectIssues() options.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-project-issues
|
||||
type ListProjectIssuesOptions struct {
|
||||
ListOptions
|
||||
IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"`
|
||||
State *string `url:"state,omitempty" json:"state,omitempty"`
|
||||
Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"`
|
||||
Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"`
|
||||
Scope *string `url:"scope,omitempty" json:"scope,omitempty"`
|
||||
AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"`
|
||||
AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
|
||||
MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,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"`
|
||||
CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
|
||||
CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
|
||||
}
|
||||
|
||||
// ListProjectIssues gets a list of project issues. This function accepts
|
||||
// pagination parameters page and per_page to return the list of project issues.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-project-issues
|
||||
func (s *IssuesService) ListProjectIssues(pid interface{}, opt *ListProjectIssuesOptions, options ...OptionFunc) ([]*Issue, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/issues", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("GET", 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
|
||||
}
|
||||
|
||||
// GetIssue gets a single project issue.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#single-issues
|
||||
func (s *IssuesService) GetIssue(pid interface{}, issue int, options ...OptionFunc) (*Issue, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/issues/%d", url.QueryEscape(project), issue)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
i := new(Issue)
|
||||
resp, err := s.client.Do(req, i)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return i, resp, err
|
||||
}
|
||||
|
||||
// CreateIssueOptions represents the available CreateIssue() options.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#new-issues
|
||||
type CreateIssueOptions struct {
|
||||
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
||||
Description *string `url:"description,omitempty" json:"description,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,comma,omitempty" json:"labels,omitempty"`
|
||||
}
|
||||
|
||||
// CreateIssue creates a new project issue.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#new-issues
|
||||
func (s *IssuesService) CreateIssue(pid interface{}, opt *CreateIssueOptions, options ...OptionFunc) (*Issue, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/issues", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
i := new(Issue)
|
||||
resp, err := s.client.Do(req, i)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return i, resp, err
|
||||
}
|
||||
|
||||
// UpdateIssueOptions represents the available UpdateIssue() options.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#edit-issues
|
||||
type UpdateIssueOptions struct {
|
||||
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
||||
Description *string `url:"description,omitempty" json:"description,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,comma,omitempty" json:"labels,omitempty"`
|
||||
StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateIssue updates an existing project issue. This function is also used
|
||||
// to mark an issue as closed.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#edit-issues
|
||||
func (s *IssuesService) UpdateIssue(pid interface{}, issue int, opt *UpdateIssueOptions, options ...OptionFunc) (*Issue, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/issues/%d", url.QueryEscape(project), issue)
|
||||
|
||||
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
i := new(Issue)
|
||||
resp, err := s.client.Do(req, i)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return i, resp, err
|
||||
}
|
||||
|
||||
// DeleteIssue deletes a single project issue.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#delete-an-issue
|
||||
func (s *IssuesService) DeleteIssue(pid interface{}, issue int, options ...OptionFunc) (*Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/issues/%d", url.QueryEscape(project), issue)
|
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(req, nil)
|
||||
}
|
||||
|
||||
// SetTimeEstimate sets the time estimate for a single project issue.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/issues.html#set-a-time-estimate-for-an-issue
|
||||
func (s *IssuesService) SetTimeEstimate(pid interface{}, issue int, opt *SetTimeEstimateOptions, options ...OptionFunc) (*TimeStats, *Response, error) {
|
||||
return s.timeStats.setTimeEstimate(pid, "issues", issue, opt, options...)
|
||||
}
|
||||
|
||||
// ResetTimeEstimate resets the time estimate for a single project issue.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/issues.html#reset-the-time-estimate-for-an-issue
|
||||
func (s *IssuesService) ResetTimeEstimate(pid interface{}, issue int, options ...OptionFunc) (*TimeStats, *Response, error) {
|
||||
return s.timeStats.resetTimeEstimate(pid, "issues", issue, options...)
|
||||
}
|
||||
|
||||
// AddSpentTime adds spent time for a single project issue.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/issues.html#add-spent-time-for-an-issue
|
||||
func (s *IssuesService) AddSpentTime(pid interface{}, issue int, opt *AddSpentTimeOptions, options ...OptionFunc) (*TimeStats, *Response, error) {
|
||||
return s.timeStats.addSpentTime(pid, "issues", issue, opt, options...)
|
||||
}
|
||||
|
||||
// ResetSpentTime resets the spent time for a single project issue.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/issues.html#reset-spent-time-for-an-issue
|
||||
func (s *IssuesService) ResetSpentTime(pid interface{}, issue int, options ...OptionFunc) (*TimeStats, *Response, error) {
|
||||
return s.timeStats.resetSpentTime(pid, "issues", issue, options...)
|
||||
}
|
||||
|
||||
// GetTimeSpent gets the spent time for a single project issue.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/issues.html#get-time-tracking-stats
|
||||
func (s *IssuesService) GetTimeSpent(pid interface{}, issue int, options ...OptionFunc) (*TimeStats, *Response, error) {
|
||||
return s.timeStats.getTimeSpent(pid, "issues", issue, options...)
|
||||
}
|
||||
349
vendor/github.com/lkysow/go-gitlab/jobs.go
generated
vendored
Normal file
349
vendor/github.com/lkysow/go-gitlab/jobs.go
generated
vendored
Normal file
@@ -0,0 +1,349 @@
|
||||
//
|
||||
// Copyright 2017, 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 (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ListJobsOptions are options for two list apis
|
||||
type ListJobsOptions struct {
|
||||
ListOptions
|
||||
Scope []BuildState `url:"scope,omitempty" json:"scope,omitempty"`
|
||||
}
|
||||
|
||||
// JobsService handles communication with the ci builds related methods
|
||||
// of the GitLab API.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/jobs.html
|
||||
type JobsService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Job represents a ci build.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/jobs.html
|
||||
type Job struct {
|
||||
Commit *Commit `json:"commit"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
ArtifactsFile struct {
|
||||
Filename string `json:"filename"`
|
||||
Size int `json:"size"`
|
||||
} `json:"artifacts_file"`
|
||||
FinishedAt *time.Time `json:"finished_at"`
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Ref string `json:"ref"`
|
||||
Runner struct {
|
||||
ID int `json:"id"`
|
||||
Description string `json:"description"`
|
||||
Active bool `json:"active"`
|
||||
IsShared bool `json:"is_shared"`
|
||||
Name string `json:"name"`
|
||||
} `json:"runner"`
|
||||
Stage string `json:"stage"`
|
||||
StartedAt *time.Time `json:"started_at"`
|
||||
Status string `json:"status"`
|
||||
Tag bool `json:"tag"`
|
||||
User *User `json:"user"`
|
||||
}
|
||||
|
||||
// ListProjectJobs gets a list of jobs in a project.
|
||||
//
|
||||
// The scope of jobs to show, one or array of: created, pending, running,
|
||||
// failed, success, canceled, skipped; showing all jobs if none provided
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/jobs.html#list-project-jobs
|
||||
func (s *JobsService) ListProjectJobs(pid interface{}, opts *ListJobsOptions, options ...OptionFunc) ([]Job, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/jobs", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, opts, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var jobs []Job
|
||||
resp, err := s.client.Do(req, &jobs)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return jobs, resp, err
|
||||
}
|
||||
|
||||
// ListPipelineJobs gets a list of jobs for specific pipeline in a
|
||||
// project. If the pipeline ID is not found, it will respond with 404.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/jobs.html#list-pipeline-jobs
|
||||
func (s *JobsService) ListPipelineJobs(pid interface{}, pipelineID int, opts *ListJobsOptions, options ...OptionFunc) ([]Job, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/pipelines/%d/jobs", project, pipelineID)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, opts, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var jobs []Job
|
||||
resp, err := s.client.Do(req, &jobs)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return jobs, resp, err
|
||||
}
|
||||
|
||||
// GetJob gets a single job of a project.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/jobs.html#get-a-single-job
|
||||
func (s *JobsService) GetJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/jobs/%d", project, jobID)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
job := new(Job)
|
||||
resp, err := s.client.Do(req, job)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return job, resp, err
|
||||
}
|
||||
|
||||
// GetJobArtifacts get jobs artifacts of a project
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/jobs.html#get-job-artifacts
|
||||
func (s *JobsService) GetJobArtifacts(pid interface{}, jobID int, options ...OptionFunc) (io.Reader, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/jobs/%d/artifacts", project, jobID)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
artifactsBuf := new(bytes.Buffer)
|
||||
resp, err := s.client.Do(req, artifactsBuf)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return artifactsBuf, resp, err
|
||||
}
|
||||
|
||||
// DownloadArtifactsFile download the artifacts file from the given
|
||||
// reference name and job provided the job finished successfully.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/jobs.html#download-the-artifacts-file
|
||||
func (s *JobsService) DownloadArtifactsFile(pid interface{}, refName string, job string, options ...OptionFunc) (io.Reader, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/jobs/artifacts/%s/download?job=%s", project, refName, job)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
artifactsBuf := new(bytes.Buffer)
|
||||
resp, err := s.client.Do(req, artifactsBuf)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return artifactsBuf, resp, err
|
||||
}
|
||||
|
||||
// GetTraceFile gets a trace of a specific job of a project
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/jobs.html#get-a-trace-file
|
||||
func (s *JobsService) GetTraceFile(pid interface{}, jobID int, options ...OptionFunc) (io.Reader, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/jobs/%d/trace", project, jobID)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
traceBuf := new(bytes.Buffer)
|
||||
resp, err := s.client.Do(req, traceBuf)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return traceBuf, resp, err
|
||||
}
|
||||
|
||||
// CancelJob cancels a single job of a project.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/jobs.html#cancel-a-job
|
||||
func (s *JobsService) CancelJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/jobs/%d/cancel", project, jobID)
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
job := new(Job)
|
||||
resp, err := s.client.Do(req, job)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return job, resp, err
|
||||
}
|
||||
|
||||
// RetryJob retries a single job of a project
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/jobs.html#retry-a-job
|
||||
func (s *JobsService) RetryJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/jobs/%d/retry", project, jobID)
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
job := new(Job)
|
||||
resp, err := s.client.Do(req, job)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return job, resp, err
|
||||
}
|
||||
|
||||
// EraseJob erases a single job of a project, removes a job
|
||||
// artifacts and a job trace.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/jobs.html#erase-a-job
|
||||
func (s *JobsService) EraseJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/jobs/%d/erase", project, jobID)
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
job := new(Job)
|
||||
resp, err := s.client.Do(req, job)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return job, resp, err
|
||||
}
|
||||
|
||||
// KeepArtifacts prevents artifacts from being deleted when
|
||||
// expiration is set.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/jobs.html#keep-artifacts
|
||||
func (s *JobsService) KeepArtifacts(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/jobs/%d/artifacts/keep", project, jobID)
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
job := new(Job)
|
||||
resp, err := s.client.Do(req, job)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return job, resp, err
|
||||
}
|
||||
|
||||
// PlayJob triggers a nanual action to start a job.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/jobs.html#play-a-job
|
||||
func (s *JobsService) PlayJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/jobs/%d/play", project, jobID)
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
job := new(Job)
|
||||
resp, err := s.client.Do(req, job)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return job, resp, err
|
||||
}
|
||||
164
vendor/github.com/lkysow/go-gitlab/labels.go
generated
vendored
Normal file
164
vendor/github.com/lkysow/go-gitlab/labels.go
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
//
|
||||
// Copyright 2017, 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/url"
|
||||
)
|
||||
|
||||
// LabelsService handles communication with the label related methods
|
||||
// of the GitLab API.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html
|
||||
type LabelsService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Label represents a GitLab label.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html
|
||||
type Label struct {
|
||||
Name string `json:"name"`
|
||||
Color string `json:"color"`
|
||||
Description string `json:"description"`
|
||||
OpenIssuesCount int `json:"open_issues_count"`
|
||||
ClosedIssuesCount int `json:"closed_issues_count"`
|
||||
OpenMergeRequestsCount int `json:"open_merge_requests_count"`
|
||||
}
|
||||
|
||||
func (l Label) String() string {
|
||||
return Stringify(l)
|
||||
}
|
||||
|
||||
// ListLabels gets all labels for given project.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels
|
||||
func (s *LabelsService) ListLabels(pid interface{}, options ...OptionFunc) ([]*Label, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var l []*Label
|
||||
resp, err := s.client.Do(req, &l)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return l, resp, err
|
||||
}
|
||||
|
||||
// CreateLabelOptions represents the available CreateLabel() options.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#create-a-new-label
|
||||
type CreateLabelOptions struct {
|
||||
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||
Color *string `url:"color,omitempty" json:"color,omitempty"`
|
||||
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// CreateLabel creates a new label for given repository with given name and
|
||||
// color.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#create-a-new-label
|
||||
func (s *LabelsService) CreateLabel(pid interface{}, opt *CreateLabelOptions, options ...OptionFunc) (*Label, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
l := new(Label)
|
||||
resp, err := s.client.Do(req, l)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return l, resp, err
|
||||
}
|
||||
|
||||
// DeleteLabelOptions represents the available DeleteLabel() options.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label
|
||||
type DeleteLabelOptions struct {
|
||||
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||
}
|
||||
|
||||
// DeleteLabel deletes a label given by its name.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label
|
||||
func (s *LabelsService) DeleteLabel(pid interface{}, opt *DeleteLabelOptions, options ...OptionFunc) (*Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(req, nil)
|
||||
}
|
||||
|
||||
// UpdateLabelOptions represents the available UpdateLabel() options.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label
|
||||
type UpdateLabelOptions struct {
|
||||
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||
NewName *string `url:"new_name,omitempty" json:"new_name,omitempty"`
|
||||
Color *string `url:"color,omitempty" json:"color,omitempty"`
|
||||
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateLabel 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/labels.html#edit-an-existing-label
|
||||
func (s *LabelsService) UpdateLabel(pid interface{}, opt *UpdateLabelOptions, options ...OptionFunc) (*Label, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
l := new(Label)
|
||||
resp, err := s.client.Do(req, l)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return l, resp, err
|
||||
}
|
||||
485
vendor/github.com/lkysow/go-gitlab/merge_requests.go
generated
vendored
Normal file
485
vendor/github.com/lkysow/go-gitlab/merge_requests.go
generated
vendored
Normal file
@@ -0,0 +1,485 @@
|
||||
//
|
||||
// Copyright 2017, 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/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
// MergeRequestsService handles communication with the merge requests related
|
||||
// methods of the GitLab API.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/merge_requests.html
|
||||
type MergeRequestsService struct {
|
||||
client *Client
|
||||
timeStats *timeStatsService
|
||||
}
|
||||
|
||||
// MergeRequest represents a GitLab merge request.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/merge_requests.html
|
||||
type MergeRequest struct {
|
||||
ID int `json:"id"`
|
||||
IID int `json:"iid"`
|
||||
ProjectID int `json:"project_id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
WorkInProgress bool `json:"work_in_progress"`
|
||||
State string `json:"state"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
TargetBranch string `json:"target_branch"`
|
||||
SourceBranch string `json:"source_branch"`
|
||||
Upvotes int `json:"upvotes"`
|
||||
Downvotes int `json:"downvotes"`
|
||||
Author struct {
|
||||
Name string `json:"name"`
|
||||
Username string `json:"username"`
|
||||
ID int `json:"id"`
|
||||
State string `json:"state"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
} `json:"author"`
|
||||
Assignee struct {
|
||||
Name string `json:"name"`
|
||||
Username string `json:"username"`
|
||||
ID int `json:"id"`
|
||||
State string `json:"state"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
} `json:"assignee"`
|
||||
SourceProjectID int `json:"source_project_id"`
|
||||
TargetProjectID int `json:"target_project_id"`
|
||||
Labels []string `json:"labels"`
|
||||
Milestone struct {
|
||||
ID int `json:"id"`
|
||||
IID int `json:"iid"`
|
||||
ProjectID int `json:"project_id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
State string `json:"state"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
DueDate string `json:"due_date"`
|
||||
} `json:"milestone"`
|
||||
MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"`
|
||||
MergeStatus string `json:"merge_status"`
|
||||
SHA string `json:"sha"`
|
||||
Subscribed bool `json:"subscribed"`
|
||||
UserNotesCount int `json:"user_notes_count"`
|
||||
SouldRemoveSourceBranch bool `json:"should_remove_source_branch"`
|
||||
ForceRemoveSourceBranch bool `json:"force_remove_source_branch"`
|
||||
Changes []struct {
|
||||
OldPath string `json:"old_path"`
|
||||
NewPath string `json:"new_path"`
|
||||
AMode string `json:"a_mode"`
|
||||
BMode string `json:"b_mode"`
|
||||
Diff string `json:"diff"`
|
||||
NewFile bool `json:"new_file"`
|
||||
RenamedFile bool `json:"renamed_file"`
|
||||
DeletedFile bool `json:"deleted_file"`
|
||||
} `json:"changes"`
|
||||
WebURL string `json:"web_url"`
|
||||
}
|
||||
|
||||
func (m MergeRequest) String() string {
|
||||
return Stringify(m)
|
||||
}
|
||||
|
||||
// MergeRequestApprovals represents GitLab merge request approvals.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ee/api/merge_requests.html#merge-request-approvals
|
||||
type MergeRequestApprovals struct {
|
||||
ID int `json:"id"`
|
||||
ProjectID int `json:"project_id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
State string `json:"state"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
MergeStatus string `json:"merge_status"`
|
||||
ApprovalsRequired int `json:"approvals_required"`
|
||||
ApprovalsMissing int `json:"approvals_missing"`
|
||||
ApprovedBy []struct {
|
||||
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"`
|
||||
} `json:"approved_by"`
|
||||
}
|
||||
|
||||
func (m MergeRequestApprovals) String() string {
|
||||
return Stringify(m)
|
||||
}
|
||||
|
||||
// ListMergeRequestsOptions represents the available ListMergeRequests()
|
||||
// options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#list-merge-requests
|
||||
type ListMergeRequestsOptions struct {
|
||||
ListOptions
|
||||
State *string `url:"state,omitempty" json:"state,omitempty"`
|
||||
OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
|
||||
Sort *string `url:"sort,omitempty" json:"sort,omitempty"`
|
||||
Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"`
|
||||
View *string `url:"view,omitempty" json:"view,omitempty"`
|
||||
Labels Labels `url:"labels,omitempty" json:"labels,omitempty"`
|
||||
CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
|
||||
CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
|
||||
Scope *string `url:"scope,omitempty" json:"scope,omitempty"`
|
||||
AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"`
|
||||
AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
|
||||
MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
|
||||
}
|
||||
|
||||
// ListMergeRequests gets all merge requests. The state
|
||||
// parameter can be used to get only merge requests with a given state (opened,
|
||||
// closed, or merged) or all of them (all). The pagination parameters page and
|
||||
// per_page can be used to restrict the list of merge requests.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#list-merge-requests
|
||||
func (s *MergeRequestsService) ListMergeRequests(opt *ListMergeRequestsOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) {
|
||||
req, err := s.client.NewRequest("GET", "merge_requests", opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var m []*MergeRequest
|
||||
resp, err := s.client.Do(req, &m)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return m, resp, err
|
||||
}
|
||||
|
||||
// ListProjectMergeRequestsOptions represents the available ListMergeRequests()
|
||||
// options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#list-project-merge-requests
|
||||
type ListProjectMergeRequestsOptions struct {
|
||||
ListOptions
|
||||
IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"`
|
||||
State *string `url:"state,omitempty" json:"state,omitempty"`
|
||||
OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
|
||||
Sort *string `url:"sort,omitempty" json:"sort,omitempty"`
|
||||
Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"`
|
||||
View *string `url:"view,omitempty" json:"view,omitempty"`
|
||||
Labels Labels `url:"labels,omitempty" json:"labels,omitempty"`
|
||||
CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
|
||||
CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
|
||||
Scope *string `url:"scope,omitempty" json:"scope,omitempty"`
|
||||
AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"`
|
||||
AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
|
||||
MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
|
||||
}
|
||||
|
||||
// ListProjectMergeRequests gets all merge requests for this project. The state
|
||||
// parameter can be used to get only merge requests with a given state (opened,
|
||||
// closed, or merged) or all of them (all). The pagination parameters page and
|
||||
// per_page can be used to restrict the list of merge requests.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#list-merge-requests
|
||||
func (s *MergeRequestsService) ListProjectMergeRequests(pid interface{}, opt *ListProjectMergeRequestsOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/merge_requests", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var m []*MergeRequest
|
||||
resp, err := s.client.Do(req, &m)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return m, resp, err
|
||||
}
|
||||
|
||||
// GetMergeRequest shows information about a single merge request.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr
|
||||
func (s *MergeRequestsService) GetMergeRequest(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequest, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/merge_requests/%d", url.QueryEscape(project), mergeRequest)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
m := new(MergeRequest)
|
||||
resp, err := s.client.Do(req, m)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return m, resp, err
|
||||
}
|
||||
|
||||
// GetMergeRequestApprovals gets information about a merge requests approvals
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ee/api/merge_requests.html#merge-request-approvals
|
||||
func (s *MergeRequestsService) GetMergeRequestApprovals(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequestApprovals, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/merge_requests/%d/approvals", url.QueryEscape(project), mergeRequest)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
a := new(MergeRequestApprovals)
|
||||
resp, err := s.client.Do(req, a)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return a, resp, err
|
||||
}
|
||||
|
||||
// GetMergeRequestCommits gets a list of merge request commits.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr-commits
|
||||
func (s *MergeRequestsService) GetMergeRequestCommits(pid interface{}, mergeRequest int, options ...OptionFunc) ([]*Commit, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/merge_requests/%d/commits", url.QueryEscape(project), mergeRequest)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, 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
|
||||
}
|
||||
|
||||
// GetMergeRequestChanges shows information about the merge request including
|
||||
// its files and changes.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr-changes
|
||||
func (s *MergeRequestsService) GetMergeRequestChanges(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequest, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/merge_requests/%d/changes", url.QueryEscape(project), mergeRequest)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
m := new(MergeRequest)
|
||||
resp, err := s.client.Do(req, m)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return m, resp, err
|
||||
}
|
||||
|
||||
// CreateMergeRequestOptions represents the available CreateMergeRequest()
|
||||
// options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#create-mr
|
||||
type CreateMergeRequestOptions struct {
|
||||
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
||||
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||
SourceBranch *string `url:"source_branch,omitempty" json:"source_branch,omitempty"`
|
||||
TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"`
|
||||
AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
|
||||
TargetProjectID *int `url:"target_project_id,omitempty" json:"target_project_id,omitempty"`
|
||||
}
|
||||
|
||||
// CreateMergeRequest creates a new merge request.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#create-mr
|
||||
func (s *MergeRequestsService) CreateMergeRequest(pid interface{}, opt *CreateMergeRequestOptions, options ...OptionFunc) (*MergeRequest, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/merge_requests", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
m := new(MergeRequest)
|
||||
resp, err := s.client.Do(req, m)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return m, resp, err
|
||||
}
|
||||
|
||||
// UpdateMergeRequestOptions represents the available UpdateMergeRequest()
|
||||
// options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#update-mr
|
||||
type UpdateMergeRequestOptions struct {
|
||||
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
||||
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||
TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"`
|
||||
AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
|
||||
Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"`
|
||||
MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"`
|
||||
StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateMergeRequest updates an existing project milestone.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#update-mr
|
||||
func (s *MergeRequestsService) UpdateMergeRequest(pid interface{}, mergeRequest int, opt *UpdateMergeRequestOptions, options ...OptionFunc) (*MergeRequest, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/merge_requests/%d", url.QueryEscape(project), mergeRequest)
|
||||
|
||||
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
m := new(MergeRequest)
|
||||
resp, err := s.client.Do(req, m)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return m, resp, err
|
||||
}
|
||||
|
||||
// AcceptMergeRequestOptions represents the available AcceptMergeRequest()
|
||||
// options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#accept-mr
|
||||
type AcceptMergeRequestOptions struct {
|
||||
MergeCommitMessage *string `url:"merge_commit_message,omitempty" json:"merge_commit_message,omitempty"`
|
||||
ShouldRemoveSourceBranch *bool `url:"should_remove_source_branch,omitempty" json:"should_remove_source_branch,omitempty"`
|
||||
MergeWhenPipelineSucceeds *bool `url:"merge_when_pipeline_succeeds,omitempty" json:"merge_when_pipeline_succeeds,omitempty"`
|
||||
Sha *string `url:"sha,omitempty" json:"sha,omitempty"`
|
||||
}
|
||||
|
||||
// AcceptMergeRequest merges changes submitted with MR using this API. If merge
|
||||
// success you get 200 OK. If it has some conflicts and can not be merged - you
|
||||
// get 405 and error message 'Branch cannot be merged'. If merge request is
|
||||
// already merged or closed - you get 405 and error message 'Method Not Allowed'
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#accept-mr
|
||||
func (s *MergeRequestsService) AcceptMergeRequest(pid interface{}, mergeRequest int, opt *AcceptMergeRequestOptions, options ...OptionFunc) (*MergeRequest, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/merge_requests/%d/merge", url.QueryEscape(project), mergeRequest)
|
||||
|
||||
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
m := new(MergeRequest)
|
||||
resp, err := s.client.Do(req, m)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return m, resp, err
|
||||
}
|
||||
|
||||
// SetTimeEstimate sets the time estimate for a single project merge request.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#set-a-time-estimate-for-a-merge-request
|
||||
func (s *MergeRequestsService) SetTimeEstimate(pid interface{}, mergeRequest int, opt *SetTimeEstimateOptions, options ...OptionFunc) (*TimeStats, *Response, error) {
|
||||
return s.timeStats.setTimeEstimate(pid, "merge_requests", mergeRequest, opt, options...)
|
||||
}
|
||||
|
||||
// ResetTimeEstimate resets the time estimate for a single project merge request.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#reset-the-time-estimate-for-a-merge-request
|
||||
func (s *MergeRequestsService) ResetTimeEstimate(pid interface{}, mergeRequest int, options ...OptionFunc) (*TimeStats, *Response, error) {
|
||||
return s.timeStats.resetTimeEstimate(pid, "merge_requests", mergeRequest, options...)
|
||||
}
|
||||
|
||||
// AddSpentTime adds spent time for a single project merge request.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#add-spent-time-for-a-merge-request
|
||||
func (s *MergeRequestsService) AddSpentTime(pid interface{}, mergeRequest int, opt *AddSpentTimeOptions, options ...OptionFunc) (*TimeStats, *Response, error) {
|
||||
return s.timeStats.addSpentTime(pid, "merge_requests", mergeRequest, opt, options...)
|
||||
}
|
||||
|
||||
// ResetSpentTime resets the spent time for a single project merge request.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#reset-spent-time-for-a-merge-request
|
||||
func (s *MergeRequestsService) ResetSpentTime(pid interface{}, mergeRequest int, options ...OptionFunc) (*TimeStats, *Response, error) {
|
||||
return s.timeStats.resetSpentTime(pid, "merge_requests", mergeRequest, options...)
|
||||
}
|
||||
|
||||
// GetTimeSpent gets the spent time for a single project merge request.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/merge_requests.html#get-time-tracking-stats
|
||||
func (s *MergeRequestsService) GetTimeSpent(pid interface{}, mergeRequest int, options ...OptionFunc) (*TimeStats, *Response, error) {
|
||||
return s.timeStats.getTimeSpent(pid, "merge_requests", mergeRequest, options...)
|
||||
}
|
||||
216
vendor/github.com/lkysow/go-gitlab/milestones.go
generated
vendored
Normal file
216
vendor/github.com/lkysow/go-gitlab/milestones.go
generated
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
//
|
||||
// Copyright 2017, 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/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
// MilestonesService handles communication with the milestone related methods
|
||||
// of the GitLab API.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/milestones.html
|
||||
type MilestonesService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Milestone represents a GitLab milestone.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/milestones.html
|
||||
type Milestone struct {
|
||||
ID int `json:"id"`
|
||||
IID int `json:"iid"`
|
||||
ProjectID int `json:"project_id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
StartDate string `json:"start_date"`
|
||||
DueDate string `json:"due_date"`
|
||||
State string `json:"state"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (m Milestone) String() string {
|
||||
return Stringify(m)
|
||||
}
|
||||
|
||||
// ListMilestonesOptions represents the available ListMilestones() options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/milestones.html#list-project-milestones
|
||||
type ListMilestonesOptions struct {
|
||||
ListOptions
|
||||
IIDs []int `url:"iids,omitempty" json:"iids,omitempty"`
|
||||
}
|
||||
|
||||
// ListMilestones returns a list of project milestones.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/milestones.html#list-project-milestones
|
||||
func (s *MilestonesService) ListMilestones(pid interface{}, opt *ListMilestonesOptions, options ...OptionFunc) ([]*Milestone, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/milestones", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var m []*Milestone
|
||||
resp, err := s.client.Do(req, &m)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return m, resp, err
|
||||
}
|
||||
|
||||
// GetMilestone gets a single project milestone.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/milestones.html#get-single-milestone
|
||||
func (s *MilestonesService) GetMilestone(pid interface{}, milestone int, options ...OptionFunc) (*Milestone, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/milestones/%d", url.QueryEscape(project), milestone)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
m := new(Milestone)
|
||||
resp, err := s.client.Do(req, m)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return m, resp, err
|
||||
}
|
||||
|
||||
// CreateMilestoneOptions represents the available CreateMilestone() options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/milestones.html#create-new-milestone
|
||||
type CreateMilestoneOptions struct {
|
||||
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
||||
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||
StartDate *string `url:"start_date,omitempty" json:"start_date,omitempty"`
|
||||
DueDate *string `url:"due_date,omitempty" json:"due_date,omitempty"`
|
||||
}
|
||||
|
||||
// CreateMilestone creates a new project milestone.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/milestones.html#create-new-milestone
|
||||
func (s *MilestonesService) CreateMilestone(pid interface{}, opt *CreateMilestoneOptions, options ...OptionFunc) (*Milestone, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/milestones", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
m := new(Milestone)
|
||||
resp, err := s.client.Do(req, m)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return m, resp, err
|
||||
}
|
||||
|
||||
// UpdateMilestoneOptions represents the available UpdateMilestone() options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/milestones.html#edit-milestone
|
||||
type UpdateMilestoneOptions struct {
|
||||
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
||||
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||
StartDate *string `url:"start_date,omitempty" json:"start_date,omitempty"`
|
||||
DueDate *string `url:"due_date,omitempty" json:"due_date,omitempty"`
|
||||
StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateMilestone updates an existing project milestone.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/milestones.html#edit-milestone
|
||||
func (s *MilestonesService) UpdateMilestone(pid interface{}, milestone int, opt *UpdateMilestoneOptions, options ...OptionFunc) (*Milestone, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/milestones/%d", url.QueryEscape(project), milestone)
|
||||
|
||||
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
m := new(Milestone)
|
||||
resp, err := s.client.Do(req, m)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return m, resp, err
|
||||
}
|
||||
|
||||
// GetMilestoneIssuesOptions represents the available GetMilestoneIssues() options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/milestones.html#get-all-issues-assigned-to-a-single-milestone
|
||||
type GetMilestoneIssuesOptions struct {
|
||||
ListOptions
|
||||
}
|
||||
|
||||
// GetMilestoneIssues gets all issues assigned to a single project milestone.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/milestones.html#get-all-issues-assigned-to-a-single-milestone
|
||||
func (s *MilestonesService) GetMilestoneIssues(pid interface{}, milestone int, opt *GetMilestoneIssuesOptions, options ...OptionFunc) ([]*Issue, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/milestones/%d/issues", url.QueryEscape(project), milestone)
|
||||
|
||||
req, err := s.client.NewRequest("GET", 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
|
||||
}
|
||||
89
vendor/github.com/lkysow/go-gitlab/namespaces.go
generated
vendored
Normal file
89
vendor/github.com/lkysow/go-gitlab/namespaces.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// Copyright 2017, 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
|
||||
|
||||
// NamespacesService handles communication with the namespace related methods
|
||||
// of the GitLab API.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html
|
||||
type NamespacesService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Namespace represents a GitLab namespace.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html
|
||||
type Namespace struct {
|
||||
ID int `json:"id"`
|
||||
Path string `json:"path"`
|
||||
Kind string `json:"kind"`
|
||||
}
|
||||
|
||||
func (n Namespace) String() string {
|
||||
return Stringify(n)
|
||||
}
|
||||
|
||||
// ListNamespacesOptions represents the available ListNamespaces() options.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html#list-namespaces
|
||||
type ListNamespacesOptions struct {
|
||||
ListOptions
|
||||
Search *string `url:"search,omitempty" json:"search,omitempty"`
|
||||
}
|
||||
|
||||
// ListNamespaces gets a list of projects accessible by the authenticated user.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html#list-namespaces
|
||||
func (s *NamespacesService) ListNamespaces(opt *ListNamespacesOptions, options ...OptionFunc) ([]*Namespace, *Response, error) {
|
||||
req, err := s.client.NewRequest("GET", "namespaces", opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var n []*Namespace
|
||||
resp, err := s.client.Do(req, &n)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return n, resp, err
|
||||
}
|
||||
|
||||
// SearchNamespace gets all namespaces that match your string in their name
|
||||
// or path.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/namespaces.html#search-for-namespace
|
||||
func (s *NamespacesService) SearchNamespace(query string, options ...OptionFunc) ([]*Namespace, *Response, error) {
|
||||
var q struct {
|
||||
Search string `url:"search,omitempty" json:"search,omitempty"`
|
||||
}
|
||||
q.Search = query
|
||||
|
||||
req, err := s.client.NewRequest("GET", "namespaces", &q, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var n []*Namespace
|
||||
resp, err := s.client.Do(req, &n)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return n, resp, err
|
||||
}
|
||||
474
vendor/github.com/lkysow/go-gitlab/notes.go
generated
vendored
Normal file
474
vendor/github.com/lkysow/go-gitlab/notes.go
generated
vendored
Normal file
@@ -0,0 +1,474 @@
|
||||
//
|
||||
// Copyright 2017, 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/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NotesService handles communication with the notes related methods
|
||||
// of the GitLab API.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/notes.html
|
||||
type NotesService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Note represents a GitLab note.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/notes.html
|
||||
type Note struct {
|
||||
ID int `json:"id"`
|
||||
Body string `json:"body"`
|
||||
Attachment string `json:"attachment"`
|
||||
Title string `json:"title"`
|
||||
FileName string `json:"file_name"`
|
||||
Author struct {
|
||||
ID int `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
State string `json:"state"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
} `json:"author"`
|
||||
System bool `json:"system"`
|
||||
ExpiresAt *time.Time `json:"expires_at"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (n Note) String() string {
|
||||
return Stringify(n)
|
||||
}
|
||||
|
||||
// ListIssueNotesOptions represents the available ListIssueNotes() options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notes.html#list-project-issue-notes
|
||||
type ListIssueNotesOptions struct {
|
||||
ListOptions
|
||||
}
|
||||
|
||||
// ListIssueNotes gets a list of all notes for a single issue.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notes.html#list-project-issue-notes
|
||||
func (s *NotesService) ListIssueNotes(pid interface{}, issue int, opt *ListIssueNotesOptions, options ...OptionFunc) ([]*Note, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/issues/%d/notes", url.QueryEscape(project), issue)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var n []*Note
|
||||
resp, err := s.client.Do(req, &n)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return n, resp, err
|
||||
}
|
||||
|
||||
// GetIssueNote returns a single note for a specific project issue.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notes.html#get-single-issue-note
|
||||
func (s *NotesService) GetIssueNote(pid interface{}, issue, note int, options ...OptionFunc) (*Note, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/issues/%d/notes/%d", url.QueryEscape(project), issue, note)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
n := new(Note)
|
||||
resp, err := s.client.Do(req, n)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return n, resp, err
|
||||
}
|
||||
|
||||
// CreateIssueNoteOptions represents the available CreateIssueNote()
|
||||
// options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notes.html#create-new-issue-note
|
||||
type CreateIssueNoteOptions struct {
|
||||
Body *string `url:"body,omitempty" json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// CreateIssueNote creates a new note to a single project issue.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notes.html#create-new-issue-note
|
||||
func (s *NotesService) CreateIssueNote(pid interface{}, issue int, opt *CreateIssueNoteOptions, options ...OptionFunc) (*Note, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/issues/%d/notes", url.QueryEscape(project), issue)
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
n := new(Note)
|
||||
resp, err := s.client.Do(req, n)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return n, resp, err
|
||||
}
|
||||
|
||||
// UpdateIssueNoteOptions represents the available UpdateIssueNote()
|
||||
// options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notes.html#modify-existing-issue-note
|
||||
type UpdateIssueNoteOptions struct {
|
||||
Body *string `url:"body,omitempty" json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateIssueNote modifies existing note of an issue.
|
||||
//
|
||||
// https://docs.gitlab.com/ce/api/notes.html#modify-existing-issue-note
|
||||
func (s *NotesService) UpdateIssueNote(pid interface{}, issue, note int, opt *UpdateIssueNoteOptions, options ...OptionFunc) (*Note, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/issues/%d/notes/%d", url.QueryEscape(project), issue, note)
|
||||
|
||||
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
n := new(Note)
|
||||
resp, err := s.client.Do(req, n)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return n, resp, err
|
||||
}
|
||||
|
||||
// DeleteIssueNote deletes an existing note of an issue.
|
||||
//
|
||||
// https://docs.gitlab.com/ce/api/notes.html#delete-an-issue-note
|
||||
func (s *NotesService) DeleteIssueNote(pid interface{}, issue, note int, options ...OptionFunc) (*Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/issues/%d/notes/%d", url.QueryEscape(project), issue, note)
|
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(req, nil)
|
||||
}
|
||||
|
||||
// ListSnippetNotes gets a list of all notes for a single snippet. Snippet
|
||||
// notes are comments users can post to a snippet.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notes.html#list-all-snippet-notes
|
||||
func (s *NotesService) ListSnippetNotes(pid interface{}, snippet int, options ...OptionFunc) ([]*Note, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/snippets/%d/notes", url.QueryEscape(project), snippet)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var n []*Note
|
||||
resp, err := s.client.Do(req, &n)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return n, resp, err
|
||||
}
|
||||
|
||||
// GetSnippetNote returns a single note for a given snippet.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notes.html#get-single-snippet-note
|
||||
func (s *NotesService) GetSnippetNote(pid interface{}, snippet, note int, options ...OptionFunc) (*Note, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/snippets/%d/notes/%d", url.QueryEscape(project), snippet, note)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
n := new(Note)
|
||||
resp, err := s.client.Do(req, n)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return n, resp, err
|
||||
}
|
||||
|
||||
// CreateSnippetNoteOptions represents the available CreateSnippetNote()
|
||||
// options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notes.html#create-new-snippet-note
|
||||
type CreateSnippetNoteOptions struct {
|
||||
Body *string `url:"body,omitempty" json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// CreateSnippetNote creates a new note for a single snippet. Snippet notes are
|
||||
// comments users can post to a snippet.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notes.html#create-new-snippet-note
|
||||
func (s *NotesService) CreateSnippetNote(pid interface{}, snippet int, opt *CreateSnippetNoteOptions, options ...OptionFunc) (*Note, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/snippets/%d/notes", url.QueryEscape(project), snippet)
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
n := new(Note)
|
||||
resp, err := s.client.Do(req, n)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return n, resp, err
|
||||
}
|
||||
|
||||
// UpdateSnippetNoteOptions represents the available UpdateSnippetNote()
|
||||
// options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notes.html#modify-existing-snippet-note
|
||||
type UpdateSnippetNoteOptions struct {
|
||||
Body *string `url:"body,omitempty" json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateSnippetNote modifies existing note of a snippet.
|
||||
//
|
||||
// https://docs.gitlab.com/ce/api/notes.html#modify-existing-snippet-note
|
||||
func (s *NotesService) UpdateSnippetNote(pid interface{}, snippet, note int, opt *UpdateSnippetNoteOptions, options ...OptionFunc) (*Note, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/snippets/%d/notes/%d", url.QueryEscape(project), snippet, note)
|
||||
|
||||
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
n := new(Note)
|
||||
resp, err := s.client.Do(req, n)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return n, resp, err
|
||||
}
|
||||
|
||||
// DeleteSnippetNote deletes an existing note of a snippet.
|
||||
//
|
||||
// https://docs.gitlab.com/ce/api/notes.html#delete-a-snippet-note
|
||||
func (s *NotesService) DeleteSnippetNote(pid interface{}, snippet, note int, options ...OptionFunc) (*Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/snippets/%d/notes/%d", url.QueryEscape(project), snippet, note)
|
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(req, nil)
|
||||
}
|
||||
|
||||
// ListMergeRequestNotes gets a list of all notes for a single merge request.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notes.html#list-all-merge-request-notes
|
||||
func (s *NotesService) ListMergeRequestNotes(pid interface{}, mergeRequest int, options ...OptionFunc) ([]*Note, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/merge_requests/%d/notes", url.QueryEscape(project), mergeRequest)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var n []*Note
|
||||
resp, err := s.client.Do(req, &n)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return n, resp, err
|
||||
}
|
||||
|
||||
// GetMergeRequestNote returns a single note for a given merge request.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notes.html#get-single-merge-request-note
|
||||
func (s *NotesService) GetMergeRequestNote(pid interface{}, mergeRequest, note int, options ...OptionFunc) (*Note, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/merge_requests/%d/notes/%d", url.QueryEscape(project), mergeRequest, note)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
n := new(Note)
|
||||
resp, err := s.client.Do(req, n)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return n, resp, err
|
||||
}
|
||||
|
||||
// CreateMergeRequestNoteOptions represents the available
|
||||
// CreateMergeRequestNote() options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notes.html#create-new-merge-request-note
|
||||
type CreateMergeRequestNoteOptions struct {
|
||||
Body *string `url:"body,omitempty" json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// CreateMergeRequestNote creates a new note for a single merge request.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notes.html#create-new-merge-request-note
|
||||
func (s *NotesService) CreateMergeRequestNote(pid interface{}, mergeRequest int, opt *CreateMergeRequestNoteOptions, options ...OptionFunc) (*Note, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/merge_requests/%d/notes", url.QueryEscape(project), mergeRequest)
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
n := new(Note)
|
||||
resp, err := s.client.Do(req, n)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return n, resp, err
|
||||
}
|
||||
|
||||
// UpdateMergeRequestNoteOptions represents the available
|
||||
// UpdateMergeRequestNote() options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notes.html#modify-existing-merge-request-note
|
||||
type UpdateMergeRequestNoteOptions struct {
|
||||
Body *string `url:"body,omitempty" json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateMergeRequestNote modifies existing note of a merge request.
|
||||
//
|
||||
// https://docs.gitlab.com/ce/api/notes.html#modify-existing-merge-request-note
|
||||
func (s *NotesService) UpdateMergeRequestNote(pid interface{}, mergeRequest, note int, opt *UpdateMergeRequestNoteOptions, options ...OptionFunc) (*Note, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf(
|
||||
"projects/%s/merge_requests/%d/notes/%d", url.QueryEscape(project), mergeRequest, note)
|
||||
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
n := new(Note)
|
||||
resp, err := s.client.Do(req, n)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return n, resp, err
|
||||
}
|
||||
|
||||
// DeleteMergeRequestNote deletes an existing note of a merge request.
|
||||
//
|
||||
// https://docs.gitlab.com/ce/api/notes.html#delete-a-merge-request-note
|
||||
func (s *NotesService) DeleteMergeRequestNote(pid interface{}, mergeRequest, note int, options ...OptionFunc) (*Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := fmt.Sprintf(
|
||||
"projects/%s/merge_requests/%d/notes/%d", url.QueryEscape(project), mergeRequest, note)
|
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(req, nil)
|
||||
}
|
||||
214
vendor/github.com/lkysow/go-gitlab/notifications.go
generated
vendored
Normal file
214
vendor/github.com/lkysow/go-gitlab/notifications.go
generated
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// NotificationSettingsService handles communication with the notification settings
|
||||
// related methods of the GitLab API.
|
||||
//
|
||||
// GitLab API docs: https://docs.gitlab.com/ce/api/notification_settings.html
|
||||
type NotificationSettingsService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// NotificationSettings represents the Gitlab notification setting.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notification_settings.html#notification-settings
|
||||
type NotificationSettings struct {
|
||||
Level NotificationLevelValue `json:"level"`
|
||||
NotificationEmail string `json:"notification_email"`
|
||||
Events *NotificationEvents `json:"events"`
|
||||
}
|
||||
|
||||
// NotificationEvents represents the available notification setting events.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notification_settings.html#notification-settings
|
||||
type NotificationEvents struct {
|
||||
CloseIssue bool `json:"close_issue"`
|
||||
CloseMergeRequest bool `json:"close_merge_request"`
|
||||
FailedPipeline bool `json:"failed_pipeline"`
|
||||
MergeMergeRequest bool `json:"merge_merge_request"`
|
||||
NewIssue bool `json:"new_issue"`
|
||||
NewMergeRequest bool `json:"new_merge_request"`
|
||||
NewNote bool `json:"new_note"`
|
||||
ReassignIssue bool `json:"reassign_issue"`
|
||||
ReassignMergeRequest bool `json:"reassign_merge_request"`
|
||||
ReopenIssue bool `json:"reopen_issue"`
|
||||
ReopenMergeRequest bool `json:"reopen_merge_request"`
|
||||
SuccessPipeline bool `json:"success_pipeline"`
|
||||
}
|
||||
|
||||
func (ns NotificationSettings) String() string {
|
||||
return Stringify(ns)
|
||||
}
|
||||
|
||||
// GetGlobalSettings returns current notification settings and email address.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notification_settings.html#global-notification-settings
|
||||
func (s *NotificationSettingsService) GetGlobalSettings(options ...OptionFunc) (*NotificationSettings, *Response, error) {
|
||||
u := "notification_settings"
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ns := new(NotificationSettings)
|
||||
resp, err := s.client.Do(req, ns)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return ns, resp, err
|
||||
}
|
||||
|
||||
// NotificationSettingsOptions represents the available options that can be passed
|
||||
// to the API when updating the notification settings.
|
||||
type NotificationSettingsOptions struct {
|
||||
Level *NotificationLevelValue `url:"level,omitempty" json:"level,omitempty"`
|
||||
NotificationEmail *string `url:"notification_email,omitempty" json:"notification_email,omitempty"`
|
||||
CloseIssue *bool `url:"close_issue,omitempty" json:"close_issue,omitempty"`
|
||||
CloseMergeRequest *bool `url:"close_merge_request,omitempty" json:"close_merge_request,omitempty"`
|
||||
FailedPipeline *bool `url:"failed_pipeline,omitempty" json:"failed_pipeline,omitempty"`
|
||||
MergeMergeRequest *bool `url:"merge_merge_request,omitempty" json:"merge_merge_request,omitempty"`
|
||||
NewIssue *bool `url:"new_issue,omitempty" json:"new_issue,omitempty"`
|
||||
NewMergeRequest *bool `url:"new_merge_request,omitempty" json:"new_merge_request,omitempty"`
|
||||
NewNote *bool `url:"new_note,omitempty" json:"new_note,omitempty"`
|
||||
ReassignIssue *bool `url:"reassign_issue,omitempty" json:"reassign_issue,omitempty"`
|
||||
ReassignMergeRequest *bool `url:"reassign_merge_request,omitempty" json:"reassign_merge_request,omitempty"`
|
||||
ReopenIssue *bool `url:"reopen_issue,omitempty" json:"reopen_issue,omitempty"`
|
||||
ReopenMergeRequest *bool `url:"reopen_merge_request,omitempty" json:"reopen_merge_request,omitempty"`
|
||||
SuccessPipeline *bool `url:"success_pipeline,omitempty" json:"success_pipeline,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateGlobalSettings updates current notification settings and email address.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notification_settings.html#update-global-notification-settings
|
||||
func (s *NotificationSettingsService) UpdateGlobalSettings(opt *NotificationSettingsOptions, options ...OptionFunc) (*NotificationSettings, *Response, error) {
|
||||
if opt.Level != nil && *opt.Level == GlobalNotificationLevel {
|
||||
return nil, nil, errors.New(
|
||||
"notification level 'global' is not valid for global notification settings")
|
||||
}
|
||||
|
||||
u := "notification_settings"
|
||||
|
||||
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ns := new(NotificationSettings)
|
||||
resp, err := s.client.Do(req, ns)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return ns, resp, err
|
||||
}
|
||||
|
||||
// GetSettingsForGroup returns current group notification settings.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notification_settings.html#group-project-level-notification-settings
|
||||
func (s *NotificationSettingsService) GetSettingsForGroup(gid interface{}, options ...OptionFunc) (*NotificationSettings, *Response, error) {
|
||||
group, err := parseID(gid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("groups/%s/notification_settings", url.QueryEscape(group))
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ns := new(NotificationSettings)
|
||||
resp, err := s.client.Do(req, ns)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return ns, resp, err
|
||||
}
|
||||
|
||||
// GetSettingsForProject returns current project notification settings.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notification_settings.html#group-project-level-notification-settings
|
||||
func (s *NotificationSettingsService) GetSettingsForProject(pid interface{}, options ...OptionFunc) (*NotificationSettings, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/notification_settings", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ns := new(NotificationSettings)
|
||||
resp, err := s.client.Do(req, ns)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return ns, resp, err
|
||||
}
|
||||
|
||||
// UpdateSettingsForGroup updates current group notification settings.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notification_settings.html#update-group-project-level-notification-settings
|
||||
func (s *NotificationSettingsService) UpdateSettingsForGroup(gid interface{}, opt *NotificationSettingsOptions, options ...OptionFunc) (*NotificationSettings, *Response, error) {
|
||||
group, err := parseID(gid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("groups/%s/notification_settings", url.QueryEscape(group))
|
||||
|
||||
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ns := new(NotificationSettings)
|
||||
resp, err := s.client.Do(req, ns)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return ns, resp, err
|
||||
}
|
||||
|
||||
// UpdateSettingsForProject updates current project notification settings.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/notification_settings.html#update-group-project-level-notification-settings
|
||||
func (s *NotificationSettingsService) UpdateSettingsForProject(pid interface{}, opt *NotificationSettingsOptions, options ...OptionFunc) (*NotificationSettings, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/notification_settings", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ns := new(NotificationSettings)
|
||||
resp, err := s.client.Do(req, ns)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return ns, resp, err
|
||||
}
|
||||
234
vendor/github.com/lkysow/go-gitlab/pipeline_triggers.go
generated
vendored
Normal file
234
vendor/github.com/lkysow/go-gitlab/pipeline_triggers.go
generated
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
// PipelineTriggersService handles Project pipeline triggers.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/pipeline_triggers.html
|
||||
type PipelineTriggersService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// PipelineTrigger represents a project pipeline trigger.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/pipeline_triggers.html#pipeline-triggers
|
||||
type PipelineTrigger struct {
|
||||
ID int `json:"id"`
|
||||
Description string `json:"description"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
DeletedAt *time.Time `json:"deleted_at"`
|
||||
LastUsed *time.Time `json:"last_used"`
|
||||
Token string `json:"token"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
Owner *User `json:"owner"`
|
||||
}
|
||||
|
||||
// ListPipelineTriggersOptions represents the available ListPipelineTriggers() options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/pipeline_triggers.html#list-project-triggers
|
||||
type ListPipelineTriggersOptions struct {
|
||||
ListOptions
|
||||
}
|
||||
|
||||
// ListPipelineTriggers gets a list of project triggers.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/pipeline_triggers.html#list-project-triggers
|
||||
func (s *PipelineTriggersService) ListPipelineTriggers(pid interface{}, opt *ListPipelineTriggersOptions, options ...OptionFunc) ([]*PipelineTrigger, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/triggers", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var pt []*PipelineTrigger
|
||||
resp, err := s.client.Do(req, &pt)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return pt, resp, err
|
||||
}
|
||||
|
||||
// GetPipelineTrigger gets a specific pipeline trigger for a project.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/pipeline_triggers.html#get-trigger-details
|
||||
func (s *PipelineTriggersService) GetPipelineTrigger(pid interface{}, trigger int, options ...OptionFunc) (*PipelineTrigger, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/triggers/%d", url.QueryEscape(project), trigger)
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
pt := new(PipelineTrigger)
|
||||
resp, err := s.client.Do(req, pt)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return pt, resp, err
|
||||
}
|
||||
|
||||
// AddPipelineTriggerOptions represents the available AddPipelineTrigger() options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/pipeline_triggers.html#create-a-project-trigger
|
||||
type AddPipelineTriggerOptions struct {
|
||||
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// AddPipelineTrigger adds a pipeline trigger to a specified project.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/pipeline_triggers.html#create-a-project-trigger
|
||||
func (s *PipelineTriggersService) AddPipelineTrigger(pid interface{}, opt *AddPipelineTriggerOptions, options ...OptionFunc) (*PipelineTrigger, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/triggers", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
pt := new(PipelineTrigger)
|
||||
resp, err := s.client.Do(req, pt)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return pt, resp, err
|
||||
}
|
||||
|
||||
// EditPipelineTriggerOptions represents the available EditPipelineTrigger() options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/pipeline_triggers.html#update-a-project-trigger
|
||||
type EditPipelineTriggerOptions struct {
|
||||
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// EditPipelineTrigger edits a trigger for a specified project.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/pipeline_triggers.html#update-a-project-trigger
|
||||
func (s *PipelineTriggersService) EditPipelineTrigger(pid interface{}, trigger int, opt *EditPipelineTriggerOptions, options ...OptionFunc) (*PipelineTrigger, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/triggers/%d", url.QueryEscape(project), trigger)
|
||||
|
||||
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
pt := new(PipelineTrigger)
|
||||
resp, err := s.client.Do(req, pt)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return pt, resp, err
|
||||
}
|
||||
|
||||
// TakeOwnershipOfPipelineTrigger sets the owner of the specified
|
||||
// pipeline trigger to the user issuing the request.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/pipeline_triggers.html#take-ownership-of-a-project-trigger
|
||||
func (s *PipelineTriggersService) TakeOwnershipOfPipelineTrigger(pid interface{}, trigger int, options ...OptionFunc) (*PipelineTrigger, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/triggers/%d/take_ownership", url.QueryEscape(project), trigger)
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
pt := new(PipelineTrigger)
|
||||
resp, err := s.client.Do(req, pt)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return pt, resp, err
|
||||
}
|
||||
|
||||
// DeletePipelineTrigger removes a trigger from a project.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/api/pipeline_triggers.html#remove-a-project-trigger
|
||||
func (s *PipelineTriggersService) DeletePipelineTrigger(pid interface{}, trigger int, options ...OptionFunc) (*Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/triggers/%d", url.QueryEscape(project), trigger)
|
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(req, nil)
|
||||
}
|
||||
|
||||
// RunPipelineTriggerOptions represents the available RunPipelineTrigger() options.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/ci/triggers/README.html#triggering-a-pipeline
|
||||
type RunPipelineTriggerOptions struct {
|
||||
Ref *string `url:"ref" json:"ref"`
|
||||
Token *string `url:"token" json:"token"`
|
||||
Variables map[string]string `url:"variables,omitempty" json:"variables,omitempty"`
|
||||
}
|
||||
|
||||
// RunPipelineTrigger starts a trigger from a project.
|
||||
//
|
||||
// GitLab API docs:
|
||||
// https://docs.gitlab.com/ce/ci/triggers/README.html#triggering-a-pipeline
|
||||
func (s *PipelineTriggersService) RunPipelineTrigger(pid interface{}, opt *RunPipelineTriggerOptions, options ...OptionFunc) (*Pipeline, *Response, error) {
|
||||
project, err := parseID(pid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("projects/%s/trigger/pipeline", url.QueryEscape(project))
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, opt, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
pt := new(Pipeline)
|
||||
resp, err := s.client.Do(req, pt)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return pt, resp, err
|
||||
}
|
||||
30
vendor/github.com/lkysow/go-gitlab/pipeline_triggers_test.go
generated
vendored
Normal file
30
vendor/github.com/lkysow/go-gitlab/pipeline_triggers_test.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRunPipeline(t *testing.T) {
|
||||
mux, server, client := setup()
|
||||
defer teardown(server)
|
||||
|
||||
mux.HandleFunc("/projects/1/trigger/pipeline", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "POST")
|
||||
fmt.Fprint(w, `{"id":1, "status":"pending"}`)
|
||||
})
|
||||
|
||||
opt := &RunPipelineTriggerOptions{Ref: String("master")}
|
||||
pipeline, _, err := client.PipelineTriggers.RunPipelineTrigger(1, opt)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("PipelineTriggers.RunPipelineTrigger returned error: %v", err)
|
||||
}
|
||||
|
||||
want := &Pipeline{ID: 1, Status: "pending"}
|
||||
if !reflect.DeepEqual(want, pipeline) {
|
||||
t.Errorf("PipelineTriggers.RunPipelineTrigger returned %+v, want %+v", pipeline, want)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user