mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-07-29 15:58:24 +00:00
continue azure devops support
This commit is contained in:
@@ -98,7 +98,7 @@
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/benmatselby/go-azuredevops/azuredevops"
|
||||
name = "github.com/benmatselby/go-azuredevops"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/go-test/deep"
|
||||
|
||||
@@ -75,7 +75,7 @@ const (
|
||||
TFETokenFlag = "tfe-token"
|
||||
|
||||
// Flag defaults.
|
||||
DefaultADHostname = "linkconsulting.visualstudio.com"
|
||||
DefaultADHostname = "visualstudio.com"
|
||||
DefaultCheckoutStrategy = "branch"
|
||||
DefaultBitbucketBaseURL = bitbucketcloud.BaseURL
|
||||
DefaultDataDir = "~/.atlantis"
|
||||
|
||||
@@ -380,8 +380,8 @@ func TestExecute_Defaults(t *testing.T) {
|
||||
Equals(t, "bitbucket-token", passedConfig.BitbucketToken)
|
||||
Equals(t, "bitbucket-user", passedConfig.BitbucketUser)
|
||||
Equals(t, "https://dev.azure.org", passedConfig.ADBaseURL)
|
||||
Equals(t, "azuredevops-token", passedConfig.AzuredevopsToken)
|
||||
Equals(t, "azuredevops-user", passedConfig.AzuredevopsUser)
|
||||
Equals(t, "azuredevops-token", passedConfig.AzureDevopsToken)
|
||||
Equals(t, "azuredevops-user", passedConfig.AzureDevopsUser)
|
||||
Equals(t, "", passedConfig.BitbucketWebhookSecret)
|
||||
Equals(t, "info", passedConfig.LogLevel)
|
||||
Equals(t, 4141, passedConfig.Port)
|
||||
|
||||
@@ -65,9 +65,10 @@ type CommentBuilder interface {
|
||||
|
||||
// CommentParser implements CommentParsing
|
||||
type CommentParser struct {
|
||||
GithubUser string
|
||||
GitlabUser string
|
||||
BitbucketUser string
|
||||
GithubUser string
|
||||
GitlabUser string
|
||||
BitbucketUser string
|
||||
AzureDevopsUser string
|
||||
}
|
||||
|
||||
// CommentParseResult describes the result of parsing a comment as a command.
|
||||
@@ -125,6 +126,8 @@ func (e *CommentParser) Parse(comment string, vcsHost models.VCSHostType) Commen
|
||||
vcsUser = e.GitlabUser
|
||||
case models.BitbucketCloud, models.BitbucketServer:
|
||||
vcsUser = e.BitbucketUser
|
||||
case models.AzureDevops:
|
||||
vcsUser = e.AzureDevopsUser
|
||||
}
|
||||
executableNames := []string{"run", atlantisExecutable, "@" + vcsUser}
|
||||
if !e.stringInSlice(args[0], executableNames) {
|
||||
|
||||
@@ -644,9 +644,10 @@ func TestBuildPlanApplyComment(t *testing.T) {
|
||||
|
||||
func TestParse_VCSUsername(t *testing.T) {
|
||||
cp := events.CommentParser{
|
||||
GithubUser: "gh",
|
||||
GitlabUser: "gl",
|
||||
BitbucketUser: "bb",
|
||||
GithubUser: "gh",
|
||||
GitlabUser: "gl",
|
||||
BitbucketUser: "bb",
|
||||
AzureDevopsUser: "ad",
|
||||
}
|
||||
cases := []struct {
|
||||
vcs models.VCSHostType
|
||||
@@ -668,6 +669,10 @@ func TestParse_VCSUsername(t *testing.T) {
|
||||
vcs: models.BitbucketCloud,
|
||||
user: "bb",
|
||||
},
|
||||
{
|
||||
vcs: models.AzureDevops,
|
||||
user: "ad",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
|
||||
@@ -245,6 +245,8 @@ type EventParser struct {
|
||||
BitbucketUser string
|
||||
BitbucketToken string
|
||||
BitbucketServerURL string
|
||||
AzureDevopsUser string
|
||||
AzureDevopsToken string
|
||||
}
|
||||
|
||||
// GetBitbucketCloudPullEventType returns the type of the pull request
|
||||
|
||||
@@ -38,6 +38,8 @@ var parser = events.EventParser{
|
||||
BitbucketUser: "bitbucket-user",
|
||||
BitbucketToken: "bitbucket-token",
|
||||
BitbucketServerURL: "http://mycorp.com:7490",
|
||||
AzureDevopsUser: "azuredevops-user",
|
||||
AzureDevopsToken: "azuredevops-token",
|
||||
}
|
||||
|
||||
func TestParseGithubRepo(t *testing.T) {
|
||||
|
||||
@@ -282,7 +282,6 @@ func (h VCSHostType) String() string {
|
||||
return "BitbucketCloud"
|
||||
case BitbucketServer:
|
||||
return "BitbucketServer"
|
||||
}
|
||||
case AzureDevops:
|
||||
return "AzureDevops"
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
// APIs.
|
||||
package azuredevops
|
||||
|
||||
const BaseURL = "https://dev.azure.com"
|
||||
const BaseURL = "https://visualstudio.com"
|
||||
|
||||
@@ -197,7 +197,7 @@ func (b *Client) prepRequest(method string, path string, body io.Reader) (*http.
|
||||
}
|
||||
// Add this header to disable CSRF checks.
|
||||
// See https://confluence.atlassian.com/cloudkb/xsrf-check-failed-when-calling-cloud-apis-826874382.html
|
||||
req.Header.Add("X-Atlassian-Token", "no-check")
|
||||
//req.Header.Add("X-Atlassian-Token", "no-check")
|
||||
return req, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/runatlantis/atlantis/server/events/models"
|
||||
"github.com/runatlantis/atlantis/server/events/vcs/azuredevops"
|
||||
. "github.com/runatlantis/atlantis/testing"
|
||||
)
|
||||
|
||||
@@ -28,7 +29,7 @@ func TestClient_GetModifiedFilesPagination(t *testing.T) {
|
||||
"type": "commit_file",
|
||||
"links": {
|
||||
"self": {
|
||||
"href": "https://dev.azure.com/2.0/repositories/bitbucket/geordi/src/e1749643d655d7c7014001a6c0f58abaf42ad850/setup.py"
|
||||
"href": "https://visualstudio.com/org/2.0/repositories/bitbucket/geordi/src/e1749643d655d7c7014001a6c0f58abaf42ad850/setup.py"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -37,7 +38,7 @@ func TestClient_GetModifiedFilesPagination(t *testing.T) {
|
||||
"type": "commit_file",
|
||||
"links": {
|
||||
"self": {
|
||||
"href": "https://dev.azure.com/2.0/repositories/bitbucket/geordi/src/d222fa235229c55dad20b190b0b571adf737d5a6/setup.py"
|
||||
"href": "https://visualstudio.com/org/2.0/repositories/bitbucket/geordi/src/d222fa235229c55dad20b190b0b571adf737d5a6/setup.py"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +70,7 @@ func TestClient_GetModifiedFilesPagination(t *testing.T) {
|
||||
defer testServer.Close()
|
||||
|
||||
serverURL = testServer.URL
|
||||
client := bitbucketcloud.NewClient(http.DefaultClient, "user", "pass", "runatlantis.io")
|
||||
client := azuredevops.NewClient(http.DefaultClient, "user", "pass", "runatlantis.io")
|
||||
client.BaseURL = testServer.URL
|
||||
|
||||
files, err := client.GetModifiedFiles(models.Repo{
|
||||
@@ -79,8 +80,8 @@ func TestClient_GetModifiedFilesPagination(t *testing.T) {
|
||||
CloneURL: "",
|
||||
SanitizedCloneURL: "",
|
||||
VCSHost: models.VCSHost{
|
||||
Type: models.BitbucketCloud,
|
||||
Hostname: "dev.azure.com",
|
||||
Type: models.AzureDevops,
|
||||
Hostname: "visualstudio.com",
|
||||
},
|
||||
}, models.PullRequest{
|
||||
Num: 1,
|
||||
@@ -105,7 +106,7 @@ func TestClient_GetModifiedFilesOldNil(t *testing.T) {
|
||||
"type": "commit_file",
|
||||
"links": {
|
||||
"self": {
|
||||
"href": "https://dev.azure.com/2.0/repositories/lkysow/atlantis-example/src/1ed8205eec00dab4f1c0a8c486a4492c98c51f8e/main.tf"
|
||||
"href": "https://visualstudio.com/2.0/repositories/lkysow/atlantis-example/src/1ed8205eec00dab4f1c0a8c486a4492c98c51f8e/main.tf"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -130,7 +131,7 @@ func TestClient_GetModifiedFilesOldNil(t *testing.T) {
|
||||
}))
|
||||
defer testServer.Close()
|
||||
|
||||
client := bitbucketcloud.NewClient(http.DefaultClient, "user", "pass", "runatlantis.io")
|
||||
client := azuredevops.NewClient(http.DefaultClient, "user", "pass", "runatlantis.io")
|
||||
client.BaseURL = testServer.URL
|
||||
|
||||
files, err := client.GetModifiedFiles(models.Repo{
|
||||
@@ -140,8 +141,8 @@ func TestClient_GetModifiedFilesOldNil(t *testing.T) {
|
||||
CloneURL: "",
|
||||
SanitizedCloneURL: "",
|
||||
VCSHost: models.VCSHost{
|
||||
Type: models.BitbucketCloud,
|
||||
Hostname: "dev.azure.com",
|
||||
Type: models.AzureDevops,
|
||||
Hostname: "visualstudio.com",
|
||||
},
|
||||
}, models.PullRequest{
|
||||
Num: 1,
|
||||
@@ -196,10 +197,10 @@ func TestClient_PullIsApproved(t *testing.T) {
|
||||
}))
|
||||
defer testServer.Close()
|
||||
|
||||
client := bitbucketcloud.NewClient(http.DefaultClient, "user", "pass", "runatlantis.io")
|
||||
client := azuredevops.NewClient(http.DefaultClient, "user", "pass", "runatlantis.io")
|
||||
client.BaseURL = testServer.URL
|
||||
|
||||
repo, err := models.NewRepo(models.BitbucketServer, "owner/repo", "https://dev.azure.com/owner/repo.git", "user", "token")
|
||||
repo, err := models.NewRepo(models.AzureDevops, "owner/repo", "https://visualstudio.com/owner/repo.git", "user", "token")
|
||||
Ok(t, err)
|
||||
approved, err := client.PullIsApproved(repo, models.PullRequest{
|
||||
Num: 1,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package azuredevops
|
||||
|
||||
const (
|
||||
PullCreatedHeader = "pullrequest:created"
|
||||
PullUpdatedHeader = "pullrequest:updated"
|
||||
PullFulfilledHeader = "pullrequest:fulfilled"
|
||||
PullCreatedHeader = "git.pullrequest.created"
|
||||
PullUpdatedHeader = "git.pullrequest.updated"
|
||||
PullFulfilledHeader = "git.pullrequest.merged"
|
||||
PullRejectedHeader = "pullrequest:rejected"
|
||||
PullCommentCreatedHeader = "pullrequest:comment_created"
|
||||
PullCommentCreatedHeader = "workitem.commented"
|
||||
)
|
||||
|
||||
type CommentEvent struct {
|
||||
|
||||
@@ -47,7 +47,7 @@ func NewClientProxy(githubClient Client, gitlabClient Client, bitbucketCloudClie
|
||||
models.Gitlab: gitlabClient,
|
||||
models.BitbucketCloud: bitbucketCloudClient,
|
||||
models.BitbucketServer: bitbucketServerClient,
|
||||
models.AzureDevops: azuredevopsClient
|
||||
models.AzureDevops: azuredevopsClient,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
|
||||
const githubHeader = "X-Github-Event"
|
||||
const gitlabHeader = "X-Gitlab-Event"
|
||||
const azuredevopsHeader = "X-AzureDevops-Event"
|
||||
|
||||
// bitbucketEventTypeHeader is the same in both cloud and server.
|
||||
const bitbucketEventTypeHeader = "X-Event-Key"
|
||||
@@ -69,6 +70,10 @@ type EventsController struct {
|
||||
// UI that identifies this call as coming from Bitbucket. If empty, no
|
||||
// request validation is done.
|
||||
BitbucketWebhookSecret []byte
|
||||
// AzureDevopsWebhookSecret is the secret added to this webhook via the Azure
|
||||
// Devops UI that identifies this call as coming from Bitbucket. If empty, no
|
||||
// request validation is done.
|
||||
AzureDevopsWebhookSecret []byte
|
||||
}
|
||||
|
||||
// Post handles POST webhook requests.
|
||||
@@ -108,6 +113,14 @@ func (e *EventsController) Post(w http.ResponseWriter, r *http.Request) {
|
||||
e.Logger.Debug("handling Bitbucket Server post")
|
||||
e.handleBitbucketServerPost(w, r)
|
||||
return
|
||||
} else if r.Header.Get(azuredevopsHeader) != "" {
|
||||
if !e.supportsHost(models.AzureDevops) {
|
||||
e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request since not configured to support AzureDevops")
|
||||
return
|
||||
}
|
||||
e.Logger.Debug("handling AzureDevops post")
|
||||
e.handleAzureDevopsPost(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request")
|
||||
@@ -195,6 +208,44 @@ func (e *EventsController) handleBitbucketServerPost(w http.ResponseWriter, r *h
|
||||
}
|
||||
}
|
||||
|
||||
func (e *EventsController) handleAzureDevopsPost(w http.ResponseWriter, r *http.Request) {}
|
||||
|
||||
/*func (e *EventsController) handleAzureDevopsPost(w http.ResponseWriter, r *http.Request) {
|
||||
eventType := r.Header.Get(azuredevopsEventTypeHeader)
|
||||
reqID := r.Header.Get(azuredevopsRequestIDHeader)
|
||||
sig := r.Header.Get(azuredevopsSignatureHeader)
|
||||
defer r.Body.Close() // nolint: errcheck
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
e.respond(w, logging.Error, http.StatusBadRequest, "Unable to read body: %s %s=%s", err, azuredevopsRequestIDHeader, reqID)
|
||||
return
|
||||
}
|
||||
if eventType == azuredevops.DiagnosticsPingHeader {
|
||||
// Specially handle the diagnostics:ping event because Bitbucket Server
|
||||
// doesn't send the signature with this event for some reason.
|
||||
e.respond(w, logging.Info, http.StatusOK, "Successfully received %s event %s=%s", eventType, azuredevopsRequestIDHeader, reqID)
|
||||
return
|
||||
}
|
||||
if len(e.AzureDevopsWebhookSecret) > 0 {
|
||||
if err := azuredevops.ValidateSignature(body, sig, e.AzureDevopsWebhookSecret); err != nil {
|
||||
e.respond(w, logging.Warn, http.StatusBadRequest, errors.Wrap(err, "request did not pass validation").Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
switch eventType {
|
||||
case azuredevops.PullCreatedHeader, azuredevops.PullMergedHeader, azuredevops.PullDeclinedHeader, azuredevops.PullDeletedHeader:
|
||||
e.Logger.Debug("handling as pull request state changed event")
|
||||
e.handleBitbucketServerPullRequestEvent(w, eventType, body, reqID)
|
||||
return
|
||||
case azuredevops.PullCommentCreatedHeader:
|
||||
e.Logger.Debug("handling as comment created event")
|
||||
e.HandleBitbucketServerCommentEvent(w, body, reqID)
|
||||
return
|
||||
default:
|
||||
e.respond(w, logging.Debug, http.StatusOK, "Ignoring unsupported event type %s %s=%s", eventType, bitbucketServerRequestIDHeader, reqID)
|
||||
}
|
||||
}*/
|
||||
|
||||
// HandleGithubCommentEvent handles comment events from GitHub where Atlantis
|
||||
// commands can come from. It's exported to make testing easier.
|
||||
func (e *EventsController) HandleGithubCommentEvent(w http.ResponseWriter, event *github.IssueCommentEvent, githubReqID string) {
|
||||
|
||||
@@ -235,11 +235,14 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
|
||||
BitbucketUser: userConfig.BitbucketUser,
|
||||
BitbucketToken: userConfig.BitbucketToken,
|
||||
BitbucketServerURL: userConfig.BitbucketBaseURL,
|
||||
AzureDevopsUser: userConfig.AzureDevopsUser,
|
||||
AzureDevopsToken: userConfig.AzureDevopsToken,
|
||||
}
|
||||
commentParser := &events.CommentParser{
|
||||
GithubUser: userConfig.GithubUser,
|
||||
GitlabUser: userConfig.GitlabUser,
|
||||
BitbucketUser: userConfig.BitbucketUser,
|
||||
GithubUser: userConfig.GithubUser,
|
||||
GitlabUser: userConfig.GitlabUser,
|
||||
BitbucketUser: userConfig.BitbucketUser,
|
||||
AzureDevopsUser: userConfig.AzureDevopsUser,
|
||||
}
|
||||
defaultTfVersion := terraformClient.DefaultVersion()
|
||||
pendingPlanFinder := &events.DefaultPendingPlanFinder{}
|
||||
@@ -324,6 +327,7 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
|
||||
SupportedVCSHosts: supportedVCSHosts,
|
||||
VCSClient: vcsClient,
|
||||
BitbucketWebhookSecret: []byte(userConfig.BitbucketWebhookSecret),
|
||||
AzureDevopsWebhookSecret: []byte(userConfig.AzureDevopsWebhookSecret),
|
||||
}
|
||||
return &Server{
|
||||
AtlantisVersion: config.AtlantisVersion,
|
||||
|
||||
@@ -6,29 +6,34 @@ import "github.com/runatlantis/atlantis/server/logging"
|
||||
// The mapstructure tags correspond to flags in cmd/server.go and are used when
|
||||
// the config is parsed from a YAML file.
|
||||
type UserConfig struct {
|
||||
AllowForkPRs bool `mapstructure:"allow-fork-prs"`
|
||||
AllowRepoConfig bool `mapstructure:"allow-repo-config"`
|
||||
AtlantisURL string `mapstructure:"atlantis-url"`
|
||||
Automerge bool `mapstructure:"automerge"`
|
||||
BitbucketBaseURL string `mapstructure:"bitbucket-base-url"`
|
||||
BitbucketToken string `mapstructure:"bitbucket-token"`
|
||||
BitbucketUser string `mapstructure:"bitbucket-user"`
|
||||
BitbucketWebhookSecret string `mapstructure:"bitbucket-webhook-secret"`
|
||||
CheckoutStrategy string `mapstructure:"checkout-strategy"`
|
||||
DataDir string `mapstructure:"data-dir"`
|
||||
GithubHostname string `mapstructure:"gh-hostname"`
|
||||
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"`
|
||||
RepoConfig string `mapstructure:"repo-config"`
|
||||
RepoConfigJSON string `mapstructure:"repo-config-json"`
|
||||
RepoWhitelist string `mapstructure:"repo-whitelist"`
|
||||
AllowForkPRs bool `mapstructure:"allow-fork-prs"`
|
||||
AllowRepoConfig bool `mapstructure:"allow-repo-config"`
|
||||
AtlantisURL string `mapstructure:"atlantis-url"`
|
||||
Automerge bool `mapstructure:"automerge"`
|
||||
AzureDevopsBaseURL string `mapstructure:"azuredevops-base-url"`
|
||||
AzureDevopsHostname string `mapstructure:"azuredevops-hostname"`
|
||||
AzureDevopsToken string `mapstructure:"azuredevops-token"`
|
||||
AzureDevopsUser string `mapstructure:"azuredevops-user"`
|
||||
AzureDevopsWebhookSecret string `mapstructure:"azuredevops-webhook-secret"`
|
||||
BitbucketBaseURL string `mapstructure:"bitbucket-base-url"`
|
||||
BitbucketToken string `mapstructure:"bitbucket-token"`
|
||||
BitbucketUser string `mapstructure:"bitbucket-user"`
|
||||
BitbucketWebhookSecret string `mapstructure:"bitbucket-webhook-secret"`
|
||||
CheckoutStrategy string `mapstructure:"checkout-strategy"`
|
||||
DataDir string `mapstructure:"data-dir"`
|
||||
GithubHostname string `mapstructure:"gh-hostname"`
|
||||
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"`
|
||||
RepoConfig string `mapstructure:"repo-config"`
|
||||
RepoConfigJSON string `mapstructure:"repo-config-json"`
|
||||
RepoWhitelist string `mapstructure:"repo-whitelist"`
|
||||
// RequireApproval is whether to require pull request approval before
|
||||
// allowing terraform apply's to be run.
|
||||
RequireApproval bool `mapstructure:"require-approval"`
|
||||
|
||||
Reference in New Issue
Block a user