Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 27 additions & 25 deletions cmd/digger/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,40 +23,40 @@ import (

func gitHubCI(lock locking.Lock) {
println("Using GitHub.")
githubRepositoryOwner := os.Getenv("GITHUB_REPOSITORY_OWNER")
if githubRepositoryOwner != "" {
usage.SendUsageRecord(githubRepositoryOwner, "log", "initialize")
githubActor := os.Getenv("GITHUB_ACTOR")
if githubActor != "" {
usage.SendUsageRecord(githubActor, "log", "initialize")
} else {
usage.SendUsageRecord("", "log", "non github initialisation")
}

ghToken := os.Getenv("GITHUB_TOKEN")
if ghToken == "" {
reportErrorAndExit(githubRepositoryOwner, "GITHUB_TOKEN is not defined", 1)
reportErrorAndExit(githubActor, "GITHUB_TOKEN is not defined", 1)
}

ghContext := os.Getenv("GITHUB_CONTEXT")
if ghContext == "" {
reportErrorAndExit(githubRepositoryOwner, "GITHUB_CONTEXT is not defined", 2)
reportErrorAndExit(githubActor, "GITHUB_CONTEXT is not defined", 2)
}

parsedGhContext, err := github_models.GetGitHubContext(ghContext)
if err != nil {
reportErrorAndExit(githubRepositoryOwner, fmt.Sprintf("Failed to parse GitHub context. %s", err), 3)
reportErrorAndExit(githubActor, fmt.Sprintf("Failed to parse GitHub context. %s", err), 3)
}
println("GitHub context parsed successfully")

walker := configuration.FileSystemDirWalker{}

diggerConfig, err := configuration.LoadDiggerConfig("./", &walker)
if err != nil {
reportErrorAndExit(githubRepositoryOwner, fmt.Sprintf("Failed to read Digger config. %s", err), 4)
reportErrorAndExit(githubActor, fmt.Sprintf("Failed to read Digger config. %s", err), 4)
}
println("Digger config read successfully")

lock, err = locking.GetLock()
if err != nil {
reportErrorAndExit(githubRepositoryOwner, fmt.Sprintf("Failed to create lock provider. %s", err), 5)
reportErrorAndExit(githubActor, fmt.Sprintf("Failed to create lock provider. %s", err), 5)
}
println("Lock provider has been created successfully")

Expand All @@ -68,7 +68,7 @@ func gitHubCI(lock locking.Lock) {

impactedProjects, requestedProject, prNumber, err := dg_github.ProcessGitHubEvent(ghEvent, diggerConfig, githubPrService)
if err != nil {
reportErrorAndExit(githubRepositoryOwner, fmt.Sprintf("Failed to process GitHub event. %s", err), 6)
reportErrorAndExit(githubActor, fmt.Sprintf("Failed to process GitHub event. %s", err), 6)
}
logImpactedProjects(impactedProjects, prNumber)
println("GitHub event processed successfully")
Expand All @@ -77,26 +77,26 @@ func gitHubCI(lock locking.Lock) {
reply := utils.GetCommands()
err := githubPrService.PublishComment(prNumber, reply)
if err != nil {
reportErrorAndExit(githubRepositoryOwner, "Failed to publish help command output", 1)
reportErrorAndExit(githubActor, "Failed to publish help command output", 1)
}
}

if len(impactedProjects) == 0 {
reportErrorAndExit(githubRepositoryOwner, "No projects impacted", 0)
reportErrorAndExit(githubActor, "No projects impacted", 0)
}

commandsToRunPerProject, coversAllImpactedProjects, err := dg_github.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, diggerConfig.Workflows)
if err != nil {
reportErrorAndExit(githubRepositoryOwner, fmt.Sprintf("Failed to convert GitHub event to commands. %s", err), 7)
reportErrorAndExit(githubActor, fmt.Sprintf("Failed to convert GitHub event to commands. %s", err), 7)
}
println("GitHub event converted to commands successfully")
logCommands(commandsToRunPerProject)

planStorage := newPlanStorage(ghToken, repoOwner, repositoryName, prNumber)
planStorage := newPlanStorage(ghToken, repoOwner, repositoryName, githubActor, prNumber)

allAppliesSuccessful, atLeastOneApply, err := digger.RunCommandsPerProject(commandsToRunPerProject, repoOwner, repositoryName, eventName, prNumber, githubPrService, lock, planStorage, "")
allAppliesSuccessful, atLeastOneApply, err := digger.RunCommandsPerProject(commandsToRunPerProject, parsedGhContext.Repository, githubActor, eventName, prNumber, githubPrService, lock, planStorage, "")
if err != nil {
reportErrorAndExit(githubRepositoryOwner, fmt.Sprintf("Failed to run commands. %s", err), 8)
reportErrorAndExit(githubActor, fmt.Sprintf("Failed to run commands. %s", err), 8)
}

if diggerConfig.AutoMerge && allAppliesSuccessful && atLeastOneApply && coversAllImpactedProjects {
Expand All @@ -106,11 +106,11 @@ func gitHubCI(lock locking.Lock) {

println("Commands executed successfully")

reportErrorAndExit(githubRepositoryOwner, "Digger finished successfully", 0)
reportErrorAndExit(githubActor, "Digger finished successfully", 0)

defer func() {
if r := recover(); r != nil {
reportErrorAndExit(githubRepositoryOwner, fmt.Sprintf("Panic occurred. %s", r), 1)
reportErrorAndExit(githubActor, fmt.Sprintf("Panic occurred. %s", r), 1)
}
}()
}
Expand Down Expand Up @@ -177,10 +177,11 @@ func gitLabCI(lock locking.Lock) {
fmt.Printf("command: %s, project: %s\n", strings.Join(v.Commands, ", "), v.ProjectName)
}

//planStorage := newPlanStorage(ghToken, repoOwner, repositoryName, prNumber)
planStorage := newPlanStorage(gitlabToken, projectNamespace, projectName, *gitLabContext.MergeRequestIId)
diggerProjectNamespace := gitLabContext.ProjectNamespace + "/" + gitLabContext.ProjectName
planStorage := newPlanStorage("", "", "", gitLabContext.GitlabUserName, *gitLabContext.MergeRequestIId)

allAppliesSuccess, atLeastOneApply, err := digger.RunCommandsPerProject(commandsToRunPerProject, diggerProjectNamespace, gitLabContext.GitlabUserName, gitLabContext.EventType.String(), *gitLabContext.MergeRequestIId, gitlabService, lock, planStorage, currentDir)

allAppliesSuccess, atLeastOneApply, err := digger.RunCommandsPerProject(commandsToRunPerProject, gitLabContext.ProjectNamespace, gitLabContext.ProjectName, gitLabContext.EventType.String(), *gitLabContext.MergeRequestIId, gitlabService, lock, planStorage, currentDir)
if err != nil {
fmt.Printf("failed to execute command, %v", err)
os.Exit(8)
Expand Down Expand Up @@ -251,8 +252,9 @@ func azureCI(lock locking.Lock) {
}

var planStorage storage.PlanStorage
diggerProjectNamespace := parsedAzureContext.BaseUrl + "/" + parsedAzureContext.ProjectName

allAppliesSuccess, atLeastOneApply, err := digger.RunCommandsPerProject(commandsToRunPerProject, parsedAzureContext.ProjectName, parsedAzureContext.ProjectName, parsedAzureContext.EventType, prNumber, azureService, lock, planStorage, currentDir)
allAppliesSuccess, atLeastOneApply, err := digger.RunCommandsPerProject(commandsToRunPerProject, diggerProjectNamespace, parsedAzureContext.BaseUrl, parsedAzureContext.EventType, prNumber, azureService, lock, planStorage, currentDir)
if err != nil {
reportErrorAndExit(parsedAzureContext.BaseUrl, fmt.Sprintf("Failed to run commands. %s", err), 8)
}
Expand Down Expand Up @@ -320,24 +322,24 @@ func main() {
}
}

func newPlanStorage(ghToken string, repoOwner string, repositoryName string, prNumber int) storage.PlanStorage {
func newPlanStorage(ghToken string, ghRepoOwner string, ghRepositoryName string, requestedBy string, prNumber int) storage.PlanStorage {
var planStorage storage.PlanStorage

uploadDestination := strings.ToLower(os.Getenv("PLAN_UPLOAD_DESTINATION"))
if uploadDestination == "github" {
zipManager := utils.Zipper{}
planStorage = &storage.GithubPlanStorage{
Client: github.NewTokenClient(context.Background(), ghToken),
Owner: repoOwner,
RepoName: repositoryName,
Owner: ghRepoOwner,
RepoName: ghRepositoryName,
PullRequestNumber: prNumber,
ZipManager: zipManager,
}
} else if uploadDestination == "gcp" {
ctx, client := gcp.GetGoogleStorageClient()
bucketName := strings.ToLower(os.Getenv("GOOGLE_STORAGE_BUCKET"))
if bucketName == "" {
reportErrorAndExit(repoOwner, fmt.Sprintf("GOOGLE_STORAGE_BUCKET is not defined"), 9)
reportErrorAndExit(requestedBy, fmt.Sprintf("GOOGLE_STORAGE_BUCKET is not defined"), 9)
}
bucket := client.Bucket(bucketName)
planStorage = &storage.PlanStorageGcp{
Expand Down
29 changes: 13 additions & 16 deletions pkg/digger/digger.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,15 @@ import (
"time"
)

func RunCommandsPerProject(commandsPerProject []models.ProjectCommand, repoOwner string, repoName string, eventName string, prNumber int, ciService ci.CIService, lock locking.Lock, planStorage storage.PlanStorage, workingDir string) (bool, bool, error) {
func RunCommandsPerProject(commandsPerProject []models.ProjectCommand, projectNamespace string, requestedBy string, eventName string, prNumber int, ciService ci.CIService, lock locking.Lock, planStorage storage.PlanStorage, workingDir string) (bool, bool, error) {
appliesPerProject := make(map[string]bool)
for _, projectCommands := range commandsPerProject {
for _, command := range projectCommands.Commands {
projectLock := &locking.ProjectLockImpl{
InternalLock: lock,
CIService: ciService,
ProjectName: projectCommands.ProjectName,
RepoName: repoName,
RepoOwner: repoOwner,
InternalLock: lock,
CIService: ciService,
ProjectName: projectCommands.ProjectName,
ProjectNamespace: projectNamespace,
}

var terraformExecutor terraform.TerraformExecutor
Expand All @@ -44,8 +43,7 @@ func RunCommandsPerProject(commandsPerProject []models.ProjectCommand, repoOwner

commandRunner := CommandRunner{}
diggerExecutor := DiggerExecutor{
repoOwner,
repoName,
projectNamespace,
projectCommands.ProjectName,
projectPath,
projectCommands.StateEnvVars,
Expand All @@ -60,7 +58,7 @@ func RunCommandsPerProject(commandsPerProject []models.ProjectCommand, repoOwner
}
switch command {
case "digger plan":
usage.SendUsageRecord(repoOwner, eventName, "plan")
usage.SendUsageRecord(requestedBy, eventName, "plan")
ciService.SetStatus(prNumber, "pending", projectCommands.ProjectName+"/plan")
planPerformed, err := diggerExecutor.Plan(prNumber)
if err != nil {
Expand All @@ -72,7 +70,7 @@ func RunCommandsPerProject(commandsPerProject []models.ProjectCommand, repoOwner
}
case "digger apply":
appliesPerProject[projectCommands.ProjectName] = false
usage.SendUsageRecord(repoName, eventName, "apply")
usage.SendUsageRecord(requestedBy, eventName, "apply")
ciService.SetStatus(prNumber, "pending", projectCommands.ProjectName+"/apply")
applyPerformed, err := diggerExecutor.Apply(prNumber)
if err != nil {
Expand All @@ -84,13 +82,13 @@ func RunCommandsPerProject(commandsPerProject []models.ProjectCommand, repoOwner
appliesPerProject[projectCommands.ProjectName] = true
}
case "digger unlock":
usage.SendUsageRecord(repoOwner, eventName, "unlock")
usage.SendUsageRecord(requestedBy, eventName, "unlock")
err := diggerExecutor.Unlock(prNumber)
if err != nil {
return false, false, fmt.Errorf("failed to unlock project. %v", err)
}
case "digger lock":
usage.SendUsageRecord(repoOwner, eventName, "lock")
usage.SendUsageRecord(requestedBy, eventName, "lock")
err := diggerExecutor.Lock(prNumber)
if err != nil {
return false, false, fmt.Errorf("failed to lock project. %v", err)
Expand Down Expand Up @@ -140,8 +138,7 @@ func MergePullRequest(githubPrService ci.CIService, prNumber int) {
}

type DiggerExecutor struct {
RepoOwner string
RepoName string
ProjectNamespace string
ProjectName string
ProjectPath string
StateEnvVars map[string]string
Expand Down Expand Up @@ -201,15 +198,15 @@ func (c CommandRunner) Run(workingDir string, shell string, commands []string) (
}

func (d DiggerExecutor) planFileName() string {
return d.RepoName + "#" + d.ProjectName + ".tfplan"
return d.ProjectNamespace + "#" + d.ProjectName + ".tfplan"
}

func (d DiggerExecutor) localPlanFilePath() string {
return path.Join(d.ProjectPath, d.planFileName())
}

func (d DiggerExecutor) storedPlanFilePath() string {
return path.Join(d.RepoOwner, d.planFileName())
return path.Join(d.ProjectNamespace, d.planFileName())
}

func (d DiggerExecutor) Plan(prNumber int) (bool, error) {
Expand Down
5 changes: 3 additions & 2 deletions pkg/gitlab/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type GitLabContext struct {
ProjectNamespaceId *int `env:"CI_PROJECT_NAMESPACE_ID"`
OpenMergeRequests []string `env:"CI_OPEN_MERGE_REQUESTS"`
Token string `env:"GITLAB_TOKEN"`
GitlabUserName string `env:"GITLAB_USER_NAME"`
DiggerCommand string `env:"DIGGER_COMMAND"`
DiscussionID string `env:"DISCUSSION_ID"`
IsMeargeable bool `env:"IS_MERGEABLE"`
Expand Down Expand Up @@ -257,7 +258,7 @@ func ConvertGitLabEventToCommands(event GitLabEvent, gitLabContext *GitLabContex
for _, project := range impactedProjects {
workflow, ok := workflows[project.Workflow]
if !ok {
return nil, fmt.Errorf("failed to find workflow config '%s' for project '%s'", project.Workflow, project.Name)
return nil, true, fmt.Errorf("failed to find workflow config '%s' for project '%s'", project.Workflow, project.Name)
}

stateEnvVars, commandEnvVars := configuration.CollectEnvVars(workflow.EnvVars)
Expand All @@ -278,7 +279,7 @@ func ConvertGitLabEventToCommands(event GitLabEvent, gitLabContext *GitLabContex
for _, project := range impactedProjects {
workflow, ok := workflows[project.Workflow]
if !ok {
return nil, fmt.Errorf("failed to find workflow config '%s' for project '%s'", project.Workflow, project.Name)
return nil, true, fmt.Errorf("failed to find workflow config '%s' for project '%s'", project.Workflow, project.Name)
}
stateEnvVars, commandEnvVars := configuration.CollectEnvVars(workflow.EnvVars)
commandsPerProject = append(commandsPerProject, models.ProjectCommand{
Expand Down
Loading