Skip to content

Commit 34d5c8f

Browse files
authored
Add Azure Repos support (#304)
* Add Azure Repos support
1 parent 6f81024 commit 34d5c8f

File tree

22 files changed

+1112
-505
lines changed

22 files changed

+1112
-505
lines changed

cmd/digger/main.go

Lines changed: 96 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ package main
22

33
import (
44
"context"
5+
"digger/pkg/azure"
56
"digger/pkg/configuration"
67
"digger/pkg/digger"
78
"digger/pkg/gcp"
89
dg_github "digger/pkg/github"
10+
github_models "digger/pkg/github/models"
911
"digger/pkg/gitlab"
12+
"digger/pkg/locking"
1013
"digger/pkg/models"
14+
"digger/pkg/storage"
1115
"digger/pkg/usage"
1216
"digger/pkg/utils"
1317
"fmt"
@@ -17,7 +21,7 @@ import (
1721
"strings"
1822
)
1923

20-
func gitHubCI(lock utils.Lock) {
24+
func gitHubCI(lock locking.Lock) {
2125
println("Using GitHub.")
2226
githubRepositoryOwner := os.Getenv("GITHUB_REPOSITORY_OWNER")
2327
if githubRepositoryOwner != "" {
@@ -36,7 +40,7 @@ func gitHubCI(lock utils.Lock) {
3640
reportErrorAndExit(githubRepositoryOwner, "GITHUB_CONTEXT is not defined", 2)
3741
}
3842

39-
parsedGhContext, err := models.GetGitHubContext(ghContext)
43+
parsedGhContext, err := github_models.GetGitHubContext(ghContext)
4044
if err != nil {
4145
reportErrorAndExit(githubRepositoryOwner, fmt.Sprintf("Failed to parse GitHub context. %s", err), 3)
4246
}
@@ -50,7 +54,7 @@ func gitHubCI(lock utils.Lock) {
5054
}
5155
println("Digger config read successfully")
5256

53-
lock, err = utils.GetLock()
57+
lock, err = locking.GetLock()
5458
if err != nil {
5559
reportErrorAndExit(githubRepositoryOwner, fmt.Sprintf("Failed to create lock provider. %s", err), 5)
5660
}
@@ -62,23 +66,26 @@ func gitHubCI(lock utils.Lock) {
6266
repoOwner, repositoryName := splitRepositoryName[0], splitRepositoryName[1]
6367
githubPrService := dg_github.NewGitHubService(ghToken, repositoryName, repoOwner)
6468

65-
impactedProjects, requestedProject, prNumber, err := digger.ProcessGitHubEvent(ghEvent, diggerConfig, githubPrService)
69+
impactedProjects, requestedProject, prNumber, err := dg_github.ProcessGitHubEvent(ghEvent, diggerConfig, githubPrService)
6670
if err != nil {
6771
reportErrorAndExit(githubRepositoryOwner, fmt.Sprintf("Failed to process GitHub event. %s", err), 6)
6872
}
6973
logImpactedProjects(impactedProjects, prNumber)
7074
println("GitHub event processed successfully")
7175

72-
if digger.CheckIfHelpComment(ghEvent) {
76+
if dg_github.CheckIfHelpComment(ghEvent) {
7377
reply := utils.GetCommands()
74-
githubPrService.PublishComment(prNumber, reply)
78+
err := githubPrService.PublishComment(prNumber, reply)
79+
if err != nil {
80+
reportErrorAndExit(githubRepositoryOwner, "Failed to publish help command output", 1)
81+
}
7582
}
7683

7784
if len(impactedProjects) == 0 {
7885
reportErrorAndExit(githubRepositoryOwner, "No projects impacted", 0)
7986
}
8087

81-
commandsToRunPerProject, coversAllImpactedProjects, err := digger.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, diggerConfig.Workflows)
88+
commandsToRunPerProject, coversAllImpactedProjects, err := dg_github.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, diggerConfig.Workflows)
8289
if err != nil {
8390
reportErrorAndExit(githubRepositoryOwner, fmt.Sprintf("Failed to convert GitHub event to commands. %s", err), 7)
8491
}
@@ -108,7 +115,7 @@ func gitHubCI(lock utils.Lock) {
108115
}()
109116
}
110117

111-
func gitLabCI(lock utils.Lock) {
118+
func gitLabCI(lock locking.Lock) {
112119
println("Using GitLab.")
113120

114121
projectNamespace := os.Getenv("CI_PROJECT_NAMESPACE")
@@ -170,6 +177,7 @@ func gitLabCI(lock utils.Lock) {
170177
fmt.Printf("command: %s, project: %s\n", strings.Join(v.Commands, ", "), v.ProjectName)
171178
}
172179

180+
//planStorage := newPlanStorage(ghToken, repoOwner, repositoryName, prNumber)
173181
planStorage := newPlanStorage(gitlabToken, projectNamespace, projectName, *gitLabContext.MergeRequestIId)
174182

175183
allAppliesSuccess, err := gitlab.RunCommandsPerProject(commandsToRunPerProject, *gitLabContext, diggerConfig, gitlabService, lock, planStorage, currentDir)
@@ -194,6 +202,77 @@ func gitLabCI(lock utils.Lock) {
194202
}()
195203
}
196204

205+
func azureCI(lock locking.Lock) {
206+
fmt.Println("> Azure CI detected")
207+
azureContext := os.Getenv("AZURE_CONTEXT")
208+
azureToken := os.Getenv("AZURE_TOKEN")
209+
if azureToken == "" {
210+
fmt.Println("AZURE_TOKEN is empty")
211+
}
212+
parsedAzureContext, err := azure.GetAzureReposContext(azureContext)
213+
if err != nil {
214+
fmt.Printf("failed to parse Azure context. %s\n", err.Error())
215+
os.Exit(4)
216+
}
217+
218+
walker := configuration.FileSystemDirWalker{}
219+
currentDir, err := os.Getwd()
220+
if err != nil {
221+
reportErrorAndExit(parsedAzureContext.BaseUrl, fmt.Sprintf("Failed to get current dir. %s", err), 4)
222+
}
223+
fmt.Printf("main: working dir: %s \n", currentDir)
224+
225+
diggerConfig, err := configuration.NewDiggerConfig(currentDir, &walker)
226+
if err != nil {
227+
reportErrorAndExit(parsedAzureContext.BaseUrl, fmt.Sprintf("Failed to read Digger config. %s", err), 4)
228+
}
229+
fmt.Println("Digger config read successfully")
230+
231+
azureService, err := azure.NewAzureReposService(azureToken, parsedAzureContext.BaseUrl, parsedAzureContext.ProjectName, parsedAzureContext.RepositoryId)
232+
if err != nil {
233+
reportErrorAndExit(parsedAzureContext.BaseUrl, fmt.Sprintf("Failed to initialise azure service. %s", err), 5)
234+
}
235+
236+
impactedProjects, requestedProject, prNumber, err := azure.ProcessAzureReposEvent(parsedAzureContext.Event, diggerConfig, azureService)
237+
if err != nil {
238+
reportErrorAndExit(parsedAzureContext.BaseUrl, fmt.Sprintf("Failed to process Azure event. %s", err), 6)
239+
}
240+
fmt.Println("Azure event processed successfully")
241+
242+
commandsToRunPerProject, coversAllImpactedProjects, err := azure.ConvertAzureEventToCommands(parsedAzureContext, impactedProjects, requestedProject, diggerConfig.Workflows)
243+
if err != nil {
244+
reportErrorAndExit(parsedAzureContext.BaseUrl, fmt.Sprintf("Failed to convert event to command. %s", err), 7)
245+
246+
}
247+
fmt.Println(fmt.Sprintf("Azure event converted to commands successfully: %v", commandsToRunPerProject))
248+
249+
for _, v := range commandsToRunPerProject {
250+
fmt.Printf("command: %s, project: %s\n", strings.Join(v.Commands, ", "), v.ProjectName)
251+
}
252+
253+
var planStorage storage.PlanStorage
254+
255+
allAppliesSuccess, atLeastOneApply, err := digger.RunCommandsPerProject(commandsToRunPerProject, parsedAzureContext.ProjectName, parsedAzureContext.ProjectName, parsedAzureContext.EventType, prNumber, azureService, lock, planStorage, currentDir)
256+
if err != nil {
257+
reportErrorAndExit(parsedAzureContext.BaseUrl, fmt.Sprintf("Failed to run commands. %s", err), 8)
258+
}
259+
260+
if diggerConfig.AutoMerge && allAppliesSuccess && atLeastOneApply && coversAllImpactedProjects {
261+
digger.MergePullRequest(azureService, prNumber)
262+
fmt.Println("PR merged successfully")
263+
}
264+
265+
println("Commands executed successfully")
266+
267+
reportErrorAndExit(parsedAzureContext.BaseUrl, "Digger finished successfully", 0)
268+
269+
defer func() {
270+
if r := recover(); r != nil {
271+
reportErrorAndExit(parsedAzureContext.BaseUrl, fmt.Sprintf("Panic occurred. %s", r), 1)
272+
}
273+
}()
274+
}
275+
197276
/*
198277
Exit codes:
199278
0 - No errors
@@ -219,7 +298,7 @@ func main() {
219298
os.Exit(0)
220299
}
221300

222-
lock, err := utils.GetLock()
301+
lock, err := locking.GetLock()
223302
if err != nil {
224303
fmt.Printf("Failed to create lock provider. %s\n", err)
225304
os.Exit(2)
@@ -232,20 +311,22 @@ func main() {
232311
gitHubCI(lock)
233312
case digger.GitLab:
234313
gitLabCI(lock)
314+
case digger.Azure:
315+
azureCI(lock)
235316
case digger.BitBucket:
236317
case digger.None:
237318
print("No CI detected.")
238319
os.Exit(10)
239320
}
240321
}
241322

242-
func newPlanStorage(ghToken string, repoOwner string, repositoryName string, prNumber int) utils.PlanStorage {
243-
var planStorage utils.PlanStorage
323+
func newPlanStorage(ghToken string, repoOwner string, repositoryName string, prNumber int) storage.PlanStorage {
324+
var planStorage storage.PlanStorage
244325

245326
uploadDestination := strings.ToLower(os.Getenv("PLAN_UPLOAD_DESTINATION"))
246327
if uploadDestination == "github" {
247328
zipManager := utils.Zipper{}
248-
planStorage = &utils.GithubPlanStorage{
329+
planStorage = &storage.GithubPlanStorage{
249330
Client: github.NewTokenClient(context.Background(), ghToken),
250331
Owner: repoOwner,
251332
RepoName: repositoryName,
@@ -259,7 +340,7 @@ func newPlanStorage(ghToken string, repoOwner string, repositoryName string, prN
259340
reportErrorAndExit(repoOwner, fmt.Sprintf("GOOGLE_STORAGE_BUCKET is not defined"), 9)
260341
}
261342
bucket := client.Bucket(bucketName)
262-
planStorage = &utils.PlanStorageGcp{
343+
planStorage = &storage.PlanStorageGcp{
263344
Client: client,
264345
Bucket: bucket,
265346
Context: ctx,
@@ -279,7 +360,7 @@ func logImpactedProjects(projects []configuration.Project, prNumber int) {
279360
log.Print(logMessage)
280361
}
281362

282-
func logCommands(projectCommands []digger.ProjectCommand) {
363+
func logCommands(projectCommands []models.ProjectCommand) {
283364
logMessage := fmt.Sprintf("Following commands are going to be executed:\n")
284365
for _, pc := range projectCommands {
285366
logMessage += fmt.Sprintf("project: %s: commands: ", pc.ProjectName)
@@ -292,7 +373,7 @@ func logCommands(projectCommands []digger.ProjectCommand) {
292373
}
293374

294375
func reportErrorAndExit(repoOwner string, message string, exitCode int) {
295-
fmt.Printf(message)
376+
fmt.Println(message)
296377
err := usage.SendLogRecord(repoOwner, message)
297378
if err != nil {
298379
fmt.Printf("Failed to send log record. %s\n", err)

cmd/digger/main_test.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ package main
33
import (
44
"digger/pkg/configuration"
55
"digger/pkg/digger"
6-
"digger/pkg/models"
6+
"digger/pkg/github"
7+
"digger/pkg/github/models"
78
"digger/pkg/utils"
89
"fmt"
910
"testing"
@@ -863,7 +864,7 @@ var githubInvalidContextJson = `{
863864

864865
func TestGitHubNewPullRequestContext(t *testing.T) {
865866

866-
context, err := digger.GetGitHubContext(githubContextNewPullRequestJson)
867+
context, err := github.GetGitHubContext(githubContextNewPullRequestJson)
867868
assert.NoError(t, err)
868869
if err != nil {
869870
fmt.Println(err)
@@ -876,9 +877,9 @@ func TestGitHubNewPullRequestContext(t *testing.T) {
876877
prManager := &utils.MockPullRequestManager{ChangedFiles: []string{"dev/test.tf"}}
877878
planStorage := &utils.MockPlanStorage{}
878879

879-
impactedProjects, requestedProject, prNumber, err := digger.ProcessGitHubEvent(ghEvent, &diggerConfig, prManager)
880+
impactedProjects, requestedProject, prNumber, err := github.ProcessGitHubEvent(ghEvent, &diggerConfig, prManager)
880881

881-
commandsToRunPerProject, _, err := digger.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, map[string]configuration.Workflow{})
882+
commandsToRunPerProject, _, err := github.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, map[string]configuration.Workflow{})
882883
_, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, context.RepositoryOwner, context.Repository, eventName, prNumber, prManager, lock, planStorage, "")
883884

884885
assert.NoError(t, err)
@@ -899,9 +900,9 @@ func TestGitHubNewCommentContext(t *testing.T) {
899900
lock := &utils.MockLock{}
900901
prManager := &utils.MockPullRequestManager{ChangedFiles: []string{"dev/test.tf"}}
901902
planStorage := &utils.MockPlanStorage{}
902-
impactedProjects, requestedProject, prNumber, err := digger.ProcessGitHubEvent(ghEvent, &diggerConfig, prManager)
903+
impactedProjects, requestedProject, prNumber, err := github.ProcessGitHubEvent(ghEvent, &diggerConfig, prManager)
903904

904-
commandsToRunPerProject, _, err := digger.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, map[string]configuration.Workflow{})
905+
commandsToRunPerProject, _, err := github.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, map[string]configuration.Workflow{})
905906
_, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, context.RepositoryOwner, context.Repository, eventName, prNumber, prManager, lock, planStorage, "")
906907

907908
_, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, context.RepositoryOwner, context.Repository, eventName, prNumber, prManager, lock, planStorage, "")
@@ -921,7 +922,7 @@ func TestInvalidGitHubContext(t *testing.T) {
921922
}
922923

923924
func TestGitHubNewPullRequestInMultiEnvProjectContext(t *testing.T) {
924-
context, err := digger.GetGitHubContext(githubContextNewPullRequestJson)
925+
context, err := github.GetGitHubContext(githubContextNewPullRequestJson)
925926
assert.NoError(t, err)
926927
ghEvent := context.Event
927928
pullRequestNumber := 11
@@ -965,9 +966,9 @@ func TestGitHubNewPullRequestInMultiEnvProjectContext(t *testing.T) {
965966
// PullRequestManager Mock
966967
prManager := &utils.MockPullRequestManager{ChangedFiles: []string{"dev/test.tf"}}
967968
lock := &utils.MockLock{}
968-
impactedProjects, requestedProject, prNumber, err := digger.ProcessGitHubEvent(ghEvent, &diggerConfig, prManager)
969+
impactedProjects, requestedProject, prNumber, err := github.ProcessGitHubEvent(ghEvent, &diggerConfig, prManager)
969970
assert.NoError(t, err)
970-
commandsToRunPerProject, _, err := digger.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, workflows)
971+
commandsToRunPerProject, _, err := github.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, workflows)
971972
spew.Dump(lock.MapLock)
972973
assert.Equal(t, pullRequestNumber, prNumber)
973974
assert.Equal(t, 1, len(commandsToRunPerProject))

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ require (
1111
github.com/caarlos0/env/v7 v7.1.0
1212
github.com/google/go-github/v51 v51.0.0
1313
github.com/google/uuid v1.3.0
14+
github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5
1415
github.com/stretchr/testify v1.8.4
1516
github.com/xanzy/go-gitlab v0.84.0
1617
gopkg.in/yaml.v3 v3.0.1

go.sum

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ github.com/google/go-github/v51 v51.0.0/go.mod h1:kZj/rn/c1lSUbr/PFWl2hhusPV7a5X
8585
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
8686
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
8787
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
88+
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
8889
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
8990
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
9091
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -109,6 +110,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
109110
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
110111
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
111112
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
113+
github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5 h1:YH424zrwLTlyHSH/GzLMJeu5zhYVZSx5RQxGKm1h96s=
114+
github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5/go.mod h1:PoGiBqKSQK1vIfQ+yVaFcGjDySHvym6FM1cNYnwzbrY=
112115
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
113116
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
114117
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -231,10 +234,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
231234
google.golang.org/protobuf v1.29.1 h1:7QBf+IK2gx70Ap/hDsOmam3GE0v9HicjfEdAxE62UoM=
232235
google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
233236
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
234-
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
235237
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
236238
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
237-
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
238239
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
239240
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
240241
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

0 commit comments

Comments
 (0)