Repository: diggerhq/digger
Pull request #315 (2023-06-05 15:18:06)

Refactor gitlab path to make use of shared functionality


Patch:
diff --git a/cmd/digger/main.go b/cmd/digger/main.go
index b5b6e761..05a6ca11 100644
--- a/cmd/digger/main.go
+++ b/cmd/digger/main.go
@@ -48,7 +48,7 @@ func gitHubCI(lock locking.Lock) {
 
 	walker := configuration.FileSystemDirWalker{}
 
-	diggerConfig, err := configuration.NewDiggerConfig("./", &walker)
+	diggerConfig, err := configuration.LoadDiggerConfig("./", &walker)
 	if err != nil {
 		reportErrorAndExit(githubRepositoryOwner, fmt.Sprintf("Failed to read Digger config. %s", err), 4)
 	}
@@ -132,7 +132,7 @@ func gitLabCI(lock locking.Lock) {
 	}
 	fmt.Printf("main: working dir: %s \n", currentDir)
 
-	diggerConfig, err := configuration.NewDiggerConfig(currentDir, &walker)
+	diggerConfig, err := configuration.LoadDiggerConfig(currentDir, &walker)
 	if err != nil {
 		reportErrorAndExit(projectNamespace, fmt.Sprintf("Failed to read Digger config. %s", err), 4)
 	}
@@ -158,14 +158,14 @@ func gitLabCI(lock locking.Lock) {
 
 	gitlabEvent := gitlab.GitLabEvent{EventType: gitLabContext.EventType}
 
-	impactedProjects, err := gitlab.ProcessGitLabEvent(gitLabContext, diggerConfig, gitlabService)
+	impactedProjects, requestedProject, err := gitlab.ProcessGitLabEvent(gitLabContext, diggerConfig, gitlabService)
 	if err != nil {
 		fmt.Printf("failed to process GitLab event, %v", err)
 		os.Exit(6)
 	}
 	println("GitLab event processed successfully")
 
-	commandsToRunPerProject, err := gitlab.ConvertGitLabEventToCommands(gitlabEvent, gitLabContext, impactedProjects, diggerConfig.Workflows)
+	commandsToRunPerProject, coversAllImpactedProjects, err := gitlab.ConvertGitLabEventToCommands(gitlabEvent, gitLabContext, impactedProjects, requestedProject, diggerConfig.Workflows)
 	if err != nil {
 		fmt.Printf("failed to convert event to command, %v", err)
 		os.Exit(7)
@@ -180,13 +180,13 @@ func gitLabCI(lock locking.Lock) {
 	//planStorage := newPlanStorage(ghToken, repoOwner, repositoryName, prNumber)
 	planStorage := newPlanStorage(gitlabToken, projectNamespace, projectName, *gitLabContext.MergeRequestIId)
 
-	allAppliesSuccess, err := gitlab.RunCommandsPerProject(commandsToRunPerProject, *gitLabContext, diggerConfig, 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)
 	}
 
-	if diggerConfig.AutoMerge && allAppliesSuccess {
+	if diggerConfig.AutoMerge && atLeastOneApply && allAppliesSuccess && coversAllImpactedProjects {
 		digger.MergePullRequest(gitlabService, *gitLabContext.MergeRequestIId)
 		println("Merge request changes has been applied successfully")
 	}
@@ -222,7 +222,7 @@ func azureCI(lock locking.Lock) {
 	}
 	fmt.Printf("main: working dir: %s \n", currentDir)
 
-	diggerConfig, err := configuration.NewDiggerConfig(currentDir, &walker)
+	diggerConfig, err := configuration.LoadDiggerConfig(currentDir, &walker)
 	if err != nil {
 		reportErrorAndExit(parsedAzureContext.BaseUrl, fmt.Sprintf("Failed to read Digger config. %s", err), 4)
 	}
diff --git a/go.mod b/go.mod
index 8264f313..07f2cc19 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,7 @@ require (
 	cloud.google.com/go/storage v1.30.1
 	github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0
 	github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.0.1
-	github.com/aws/aws-sdk-go v1.44.275
+	github.com/aws/aws-sdk-go v1.44.276
 	github.com/bmatcuk/doublestar/v4 v4.6.0
 	github.com/caarlos0/env/v7 v7.1.0
 	github.com/google/go-github/v51 v51.0.0
diff --git a/go.sum b/go.sum
index 421ad001..1e23ff1c 100644
--- a/go.sum
+++ b/go.sum
@@ -33,6 +33,8 @@ github.com/aws/aws-sdk-go v1.44.274 h1:vfreSv19e/9Ka9YytOzgzJasrRZfX7dnttLlbh8NK
 github.com/aws/aws-sdk-go v1.44.274/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
 github.com/aws/aws-sdk-go v1.44.275 h1:VqRULgqrigvQLll4e4hXuc568EQAtZQ6jmBzLlQHzSI=
 github.com/aws/aws-sdk-go v1.44.275/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
+github.com/aws/aws-sdk-go v1.44.276 h1:ywPlx9C5Yc482dUgAZ9bHpQ6onVvJvYE9FJWsNDCEy0=
+github.com/aws/aws-sdk-go v1.44.276/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
 github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc=
 github.com/bmatcuk/doublestar/v4 v4.6.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
 github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
diff --git a/pkg/azure/azure.go b/pkg/azure/azure.go
index 09157fe8..66d4115e 100644
--- a/pkg/azure/azure.go
+++ b/pkg/azure/azure.go
@@ -347,7 +347,7 @@ func ConvertAzureEventToCommands(parseAzureContext Azure, impactedProjects []con
 		for _, project := range impactedProjects {
 			workflow, ok := workflows[project.Workflow]
 			if !ok {
-				workflow = *configuration.DefaultWorkflow()
+				return nil, false, fmt.Errorf("failed to find workflow config '%s' for project '%s'", project.Workflow, project.Name)
 			}
 
 			stateEnvVars, commandEnvVars := configuration.CollectEnvVars(workflow.EnvVars)
@@ -369,7 +369,7 @@ func ConvertAzureEventToCommands(parseAzureContext Azure, impactedProjects []con
 		for _, project := range impactedProjects {
 			workflow, ok := workflows[project.Workflow]
 			if !ok {
-				workflow = *configuration.DefaultWorkflow()
+				return nil, false, fmt.Errorf("failed to find workflow config '%s' for project '%s'", project.Workflow, project.Name)
 			}
 
 			stateEnvVars, commandEnvVars := configuration.CollectEnvVars(workflow.EnvVars)
@@ -392,7 +392,7 @@ func ConvertAzureEventToCommands(parseAzureContext Azure, impactedProjects []con
 			for _, project := range impactedProjects {
 				workflow, ok := workflows[project.Workflow]
 				if !ok {
-					workflow = *configuration.DefaultWorkflow()
+					return nil, false, fmt.Errorf("failed to find workflow config '%s' for project '%s'", project.Workflow, project.Name)
 				}
 				stateEnvVars, commandEnvVars := configuration.CollectEnvVars(workflow.EnvVars)
 
@@ -442,7 +442,7 @@ func ConvertAzureEventToCommands(parseAzureContext Azure, impactedProjects []con
 					}
 					workflow, ok := workflows[project.Workflow]
 					if !ok {
-						workflow = *configuration.DefaultWorkflow()
+						return nil, false, fmt.Errorf("failed to find workflow config '%s' for project '%s'", project.Workflow, project.Name)
 					}
 					stateEnvVars, commandEnvVars := configuration.CollectEnvVars(workflow.EnvVars)
 
diff --git a/pkg/configuration/digger_config.go b/pkg/configuration/digger_config.go
index e74f2878..14235e04 100644
--- a/pkg/configuration/digger_config.go
+++ b/pkg/configuration/digger_config.go
@@ -195,7 +195,6 @@ func (s *Step) extract(stepMap map[string]interface{}, action string) {
 	}
 }
 
-// duplicate copied from digger.go
 func defaultWorkflow() *Workflow {
 	return &Workflow{
 		Configuration: &WorkflowConfiguration{
@@ -228,18 +227,37 @@ func defaultWorkflow() *Workflow {
 
 func ConvertDiggerYamlToConfig(diggerYaml *DiggerConfigYaml, workingDir string, walker DirWalker) (*DiggerConfig, error) {
 	var diggerConfig DiggerConfig
+	const defaultWorkflowName = "default"
 
 	diggerConfig.AutoMerge = diggerYaml.AutoMerge
 
+	// if workflow block is not specified in yaml we create a default one, and add it to every project
 	if diggerYaml.Workflows != nil {
 		diggerConfig.Workflows = diggerYaml.Workflows
 	} else {
 		workflow := *defaultWorkflow()
 		diggerConfig.Workflows = make(map[string]Workflow)
-		diggerConfig.Workflows["default"] = workflow
+		diggerConfig.Workflows[defaultWorkflowName] = workflow
 	}
 
 	diggerConfig.Projects = diggerYaml.Projects
+
+	// update project's workflow if needed
+	for _, project := range diggerConfig.Projects {
+		if project.Workflow == "" {
+			project.Workflow = defaultWorkflowName
+		}
+	}
+
+	// check for project name duplicates
+	projectNames := make(map[string]bool)
+	for _, project := range diggerConfig.Projects {
+		if projectNames[project.Name] {
+			return nil, fmt.Errorf("project name '%s' is duplicated", project.Name)
+		}
+		projectNames[project.Name] = true
+	}
+
 	diggerConfig.CollectUsageData = diggerYaml.CollectUsageData
 
 	if diggerYaml.GenerateProjectsConfig != nil {
@@ -261,25 +279,16 @@ func ConvertDiggerYamlToConfig(diggerYaml *DiggerConfigYaml, workingDir string,
 				return nil, err
 			}
 			if includeMatch && !excludeMatch {
-				project := Project{Name: filepath.Base(dir), Dir: filepath.Join(workingDir, dir)}
+				// generate a new project using default workflow
+				project := Project{Name: filepath.Base(dir), Dir: filepath.Join(workingDir, dir), Workflow: defaultWorkflowName}
 				diggerConfig.Projects = append(diggerConfig.Projects, project)
 			}
 		}
 	}
-
-	projectNames := make(map[string]bool)
-
-	for _, project := range diggerConfig.Projects {
-		if projectNames[project.Name] {
-			return nil, fmt.Errorf("project name '%s' is duplicated", project.Name)
-		}
-		projectNames[project.Name] = true
-	}
-
 	return &diggerConfig, nil
 }
 
-func NewDiggerConfig(workingDir string, walker DirWalker) (*DiggerConfig, error) {
+func LoadDiggerConfig(workingDir string, walker DirWalker) (*DiggerConfig, error) {
 	config := &DiggerConfigYaml{}
 	fileName, err := retrieveConfigFile(workingDir)
 	if err != nil {
@@ -342,6 +351,13 @@ func NewDiggerConfig(workingDir string, walker DirWalker) (*DiggerConfig, error)
 	if err != nil {
 		return nil, err
 	}
+
+	for _, p := range c.Projects {
+		_, ok := c.Workflows[p.Workflow]
+		if !ok {
+			return nil, fmt.Errorf("failed to find workflow config '%s' for project '%s'", p.Workflow, p.Name)
+		}
+	}
 	return c, nil
 }
 
@@ -413,20 +429,6 @@ func (c *DiggerConfig) GetWorkflow(workflowName string) *Workflow {
 
 }
 
-func (c *DiggerConfig) GetWorkflowConfiguration(projectName string) WorkflowConfiguration {
-	project := c.GetProject(projectName)
-	workflows := c.Workflows
-	if project == nil {
-		return WorkflowConfiguration{}
-	}
-	workflow, ok := workflows[project.Workflow]
-
-	if !ok {
-		return WorkflowConfiguration{}
-	}
-	return *workflow.Configuration
-}
-
 type File struct {
 	Filename string
 }
@@ -489,33 +491,3 @@ func CollectEnvVars(envs EnvVars) (map[string]string, map[string]string) {
 	}
 	return stateEnvVars, commandEnvVars
 }
-
-func DefaultWorkflow() *Workflow {
-	return &Workflow{
-		Configuration: &WorkflowConfiguration{
-			OnCommitToDefault:   []string{"digger unlock"},
-			OnPullRequestPushed: []string{"digger plan"},
-			OnPullRequestClosed: []string{"digger unlock"},
-		},
-		Plan: &Stage{
-			Steps: []Step{
-				{
-					Action: "init", ExtraArgs: []string{},
-				},
-				{
-					Action: "plan", ExtraArgs: []string{},
-				},
-			},
-		},
-		Apply: &Stage{
-			Steps: []Step{
-				{
-					Action: "init", ExtraArgs: []string{},
-				},
-				{
-					Action: "apply", ExtraArgs: []string{},
-				},
-			},
-		},
-	}
-}
diff --git a/pkg/github/github.go b/pkg/github/github.go
index fb4ff1e6..cffcd991 100644
--- a/pkg/github/github.go
+++ b/pkg/github/github.go
@@ -141,7 +141,7 @@ func ConvertGithubEventToCommands(event models.Event, impactedProjects []configu
 		for _, project := range impactedProjects {
 			workflow, ok := workflows[project.Workflow]
 			if !ok {
-				workflow = *configuration.DefaultWorkflow()
+				return nil, false, fmt.Errorf("failed to find workflow config '%s' for project '%s'", project.Workflow, project.Name)
 			}
 
 			stateEnvVars, commandEnvVars := configuration.CollectEnvVars(workflow.EnvVars)
@@ -207,7 +207,7 @@ func ConvertGithubEventToCommands(event models.Event, impactedProjects []configu
 				for _, project := range runForProjects {
 					workflow, ok := workflows[project.Workflow]
 					if !ok {
-						workflow = *configuration.DefaultWorkflow()
+						return nil, false, fmt.Errorf("failed to find workflow config '%s' for project '%s'", project.Workflow, project.Name)
 					}
 
 					stateEnvVars, commandEnvVars := configuration.CollectEnvVars(workflow.EnvVars)
diff --git a/pkg/gitlab/gitlab.go b/pkg/gitlab/gitlab.go
index f9e3b5be..b2c6a9a4 100644
--- a/pkg/gitlab/gitlab.go
+++ b/pkg/gitlab/gitlab.go
@@ -1,19 +1,13 @@
 package gitlab
 
 import (
-	"digger/pkg/ci"
 	"digger/pkg/configuration"
-	"digger/pkg/digger"
-	"digger/pkg/locking"
 	"digger/pkg/models"
-	"digger/pkg/storage"
-	"digger/pkg/terraform"
-	"digger/pkg/usage"
+	"digger/pkg/utils"
 	"fmt"
 	"github.com/caarlos0/env/v7"
 	go_gitlab "github.com/xanzy/go-gitlab"
 	"log"
-	"path"
 	"strings"
 )
 
@@ -88,28 +82,40 @@ func NewGitLabService(token string, gitLabContext *GitLabContext) (*GitLabServic
 	}, nil
 }
 
-func ProcessGitLabEvent(gitlabContext *GitLabContext, diggerConfig *configuration.DiggerConfig, service *GitLabService) ([]configuration.Project, error) {
+func ProcessGitLabEvent(gitlabContext *GitLabContext, diggerConfig *configuration.DiggerConfig, service *GitLabService) ([]configuration.Project, *configuration.Project, error) {
 	var impactedProjects []configuration.Project
 
 	if gitlabContext.MergeRequestIId == nil {
-		return nil, fmt.Errorf("value for 'Merge Request ID' parameter is not found")
+		return nil, nil, fmt.Errorf("value for 'Merge Request ID' parameter is not found")
 	}
 
 	mergeRequestId := gitlabContext.MergeRequestIId
 	changedFiles, err := service.GetChangedFiles(*mergeRequestId)
 
 	if err != nil {
-		return nil, fmt.Errorf("could not get changed files")
+		return nil, nil, fmt.Errorf("could not get changed files")
 	}
 
 	impactedProjects = diggerConfig.GetModifiedProjects(changedFiles)
 
-	fmt.Println("Impacted projects:")
-	for _, v := range impactedProjects {
-		fmt.Printf("%s\n", v.Name)
-	}
+	switch gitlabContext.EventType {
+	case MergeRequestComment:
+		requestedProject := utils.ParseProjectName(gitlabContext.DiggerCommand)
+
+		if requestedProject == "" {
+			return impactedProjects, nil, nil
+		}
+
+		for _, project := range impactedProjects {
+			if project.Name == requestedProject {
+				return impactedProjects, &project, nil
+			}
+		}
+		return nil, nil, fmt.Errorf("requested project not found in modified projects")
+	default:
+		return impactedProjects, nil, nil
 
-	return impactedProjects, nil
+	}
 }
 
 type GitLabService struct {
@@ -242,7 +248,7 @@ const (
 	MergeRequestComment = GitLabEventType("merge_request_commented")
 )
 
-func ConvertGitLabEventToCommands(event GitLabEvent, gitLabContext *GitLabContext, impactedProjects []configuration.Project, workflows map[string]configuration.Workflow) ([]models.ProjectCommand, error) {
+func ConvertGitLabEventToCommands(event GitLabEvent, gitLabContext *GitLabContext, impactedProjects []configuration.Project, requestedProject *configuration.Project, workflows map[string]configuration.Workflow) ([]models.ProjectCommand, bool, error) {
 	commandsPerProject := make([]models.ProjectCommand, 0)
 
 	fmt.Printf("ConvertGitLabEventToCommands, event.EventType: %s\n", event.EventType)
@@ -250,11 +256,11 @@ func ConvertGitLabEventToCommands(event GitLabEvent, gitLabContext *GitLabContex
 	case MergeRequestOpened, MergeRequestReopened, MergeRequestUpdated:
 		for _, project := range impactedProjects {
 			workflow, ok := workflows[project.Workflow]
-
 			if !ok {
-				workflow = workflows["default"]
+				return nil, 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{
 				ProjectName:      project.Name,
 				ProjectDir:       project.Dir,
@@ -263,15 +269,18 @@ func ConvertGitLabEventToCommands(event GitLabEvent, gitLabContext *GitLabContex
 				Commands:         workflow.Configuration.OnPullRequestPushed,
 				ApplyStage:       workflow.Apply,
 				PlanStage:        workflow.Plan,
+				CommandEnvVars:   commandEnvVars,
+				StateEnvVars:     stateEnvVars,
 			})
 		}
-		return commandsPerProject, nil
+		return commandsPerProject, true, nil
 	case MergeRequestClosed, MergeRequestMerged:
 		for _, project := range impactedProjects {
 			workflow, ok := workflows[project.Workflow]
 			if !ok {
-				workflow = workflows["default"]
+				return nil, 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{
 				ProjectName:      project.Name,
 				ProjectDir:       project.Dir,
@@ -280,134 +289,60 @@ func ConvertGitLabEventToCommands(event GitLabEvent, gitLabContext *GitLabContex
 				Commands:         workflow.Configuration.OnPullRequestClosed,
 				ApplyStage:       workflow.Apply,
 				PlanStage:        workflow.Plan,
+				CommandEnvVars:   commandEnvVars,
+				StateEnvVars:     stateEnvVars,
 			})
 		}
-		return commandsPerProject, nil
+		return commandsPerProject, true, nil
 	case MergeRequestComment:
 		supportedCommands := []string{"digger plan", "digger apply", "digger unlock", "digger lock"}
 
+		coversAllImpactedProjects := true
+
+		runForProjects := impactedProjects
+
+		if requestedProject != nil {
+			if len(impactedProjects) > 1 {
+				coversAllImpactedProjects = false
+				runForProjects = []configuration.Project{*requestedProject}
+			} else if len(impactedProjects) == 1 && impactedProjects[0].Name != requestedProject.Name {
+				return commandsPerProject, false, fmt.Errorf("requested project %v is not impacted by this PR", requestedProject.Name)
+			}
+		}
+
 		for _, command := range supportedCommands {
 			if strings.Contains(gitLabContext.DiggerCommand, command) {
-				for _, project := range impactedProjects {
+				for _, project := range runForProjects {
+					workflow, ok := workflows[project.Workflow]
+					if !ok {
+						workflow = workflows["default"]
+					}
 					workspace := project.Workspace
-					//workspaceOverride, err := parseWorkspace(gitLabContext.DiggerCommand)
-					//if err != nil {
-					//	return []digger.ProjectCommand{}, err
-					//}
-					//if workspaceOverride != "" {
-					//	workspace = workspaceOverride
-					//}
+					workspaceOverride, err := utils.ParseWorkspace(gitLabContext.DiggerCommand)
+					if err != nil {
+						return []models.ProjectCommand{}, false, err
+					}
+					if workspaceOverride != "" {
+						workspace = workspaceOverride
+					}
+					stateEnvVars, commandEnvVars := configuration.CollectEnvVars(workflow.EnvVars)
 					commandsPerProject = append(commandsPerProject, models.ProjectCommand{
 						ProjectName:      project.Name,
 						ProjectDir:       project.Dir,
 						ProjectWorkspace: workspace,
 						Terragrunt:       project.Terragrunt,
 						Commands:         []string{command},
+						ApplyStage:       workflow.Apply,
+						PlanStage:        workflow.Plan,
+						CommandEnvVars:   commandEnvVars,
+						StateEnvVars:     stateEnvVars,
 					})
 				}
 			}
 		}
-		return commandsPerProject, nil
+		return commandsPerProject, coversAllImpactedProjects, nil
 
 	default:
-		return []models.ProjectCommand{}, fmt.Errorf("unsupported GitLab event type: %v", event)
-	}
-	return nil, nil
-}
-
-func RunCommandsPerProject(commandsPerProject []models.ProjectCommand, gitLabContext GitLabContext, diggerConfig *configuration.DiggerConfig, service ci.CIService, lock locking.Lock, planStorage storage.PlanStorage, workingDir string) (bool, error) {
-
-	allAppliesSuccess := true
-	appliesPerProject := make(map[string]bool)
-	for _, projectCommands := range commandsPerProject {
-		appliesPerProject[projectCommands.ProjectName] = false
-		for _, command := range projectCommands.Commands {
-			projectLock := &locking.ProjectLockImpl{
-				InternalLock: lock,
-				CIService:    service,
-				ProjectName:  projectCommands.ProjectName,
-				RepoName:     gitLabContext.ProjectName,
-				RepoOwner:    gitLabContext.ProjectNamespace,
-			}
-
-			var terraformExecutor terraform.TerraformExecutor
-			projectPath := path.Join(workingDir, projectCommands.ProjectDir)
-			if projectCommands.Terragrunt {
-				terraformExecutor = terraform.Terragrunt{WorkingDir: path.Join(workingDir, projectCommands.ProjectDir)}
-			} else {
-				terraformExecutor = terraform.Terraform{WorkingDir: path.Join(workingDir, projectCommands.ProjectDir), Workspace: projectCommands.ProjectWorkspace}
-			}
-			commandRunner := digger.CommandRunner{}
-
-			diggerExecutor := digger.DiggerExecutor{
-				gitLabContext.ProjectNamespace,
-				gitLabContext.ProjectName,
-				projectCommands.ProjectName,
-				projectPath,
-				projectCommands.StateEnvVars,
-				projectCommands.CommandEnvVars,
-				projectCommands.ApplyStage,
-				projectCommands.PlanStage,
-				commandRunner,
-				terraformExecutor,
-				service,
-				projectLock,
-				planStorage,
-			}
-
-			repoOwner := gitLabContext.ProjectNamespace
-			repoName := gitLabContext.ProjectName
-			prNumber := *gitLabContext.MergeRequestIId
-			eventName := ""
-			switch command {
-			case "digger plan":
-				usage.SendUsageRecord(repoOwner, eventName, "plan")
-				service.SetStatus(prNumber, "pending", projectCommands.ProjectName+"/plan")
-				planPerformed, err := diggerExecutor.Plan(prNumber)
-				if err != nil {
-					log.Printf("Failed to run digger plan command. %v", err)
-					service.SetStatus(prNumber, "failure", projectCommands.ProjectName+"/plan")
-
-					return false, fmt.Errorf("failed to run digger plan command. %v", err)
-				} else if !planPerformed {
-					service.SetStatus(prNumber, "pending", projectCommands.ProjectName+"/plan")
-				} else {
-					service.SetStatus(prNumber, "success", projectCommands.ProjectName+"/plan")
-				}
-			case "digger apply":
-				usage.SendUsageRecord(repoName, eventName, "apply")
-				service.SetStatus(prNumber, "pending", projectCommands.ProjectName+"/apply")
-				applyPerformed, err := diggerExecutor.Apply(prNumber)
-				if err != nil {
-					log.Printf("Failed to run digger apply command. %v", err)
-					service.SetStatus(prNumber, "failure", projectCommands.ProjectName+"/apply")
-					return false, fmt.Errorf("failed to run digger apply command. %v", err)
-				} else if !applyPerformed {
-					service.SetStatus(prNumber, "pending", projectCommands.ProjectName+"/apply")
-				} else {
-					service.SetStatus(prNumber, "success", projectCommands.ProjectName+"/apply")
-					appliesPerProject[projectCommands.ProjectName] = true
-				}
-			case "digger unlock":
-				usage.SendUsageRecord(repoOwner, eventName, "unlock")
-				err := diggerExecutor.Unlock(prNumber)
-				if err != nil {
-					return false, fmt.Errorf("failed to unlock project. %v", err)
-				}
-			case "digger lock":
-				usage.SendUsageRecord(repoOwner, eventName, "lock")
-				err := diggerExecutor.Lock(prNumber)
-				if err != nil {
-					return false, fmt.Errorf("failed to lock project. %v", err)
-				}
-			}
-		}
-	}
-
-	for _, success := range appliesPerProject {
-		if !success {
-			allAppliesSuccess = false
-		}
+		return []models.ProjectCommand{}, false, fmt.Errorf("unsupported GitLab event type: %v", event)
 	}
-	return allAppliesSuccess, nil
 }
diff --git a/pkg/usage/usage.go b/pkg/usage/usage.go
index dba316d8..c6d4c105 100644
--- a/pkg/usage/usage.go
+++ b/pkg/usage/usage.go
@@ -77,7 +77,7 @@ func init() {
 		fmt.Printf("Failed to get current dir. %s", err)
 	}
 	walker := configuration.FileSystemDirWalker{}
-	config, err := configuration.NewDiggerConfig(currentDir, &walker)
+	config, err := configuration.LoadDiggerConfig(currentDir, &walker)
 	if err != nil {
 		return
 	}


Test patch:
diff --git a/pkg/configuration/digger_config_test.go b/pkg/configuration/digger_config_test.go
index 3044fd96..9dd42af6 100644
--- a/pkg/configuration/digger_config_test.go
+++ b/pkg/configuration/digger_config_test.go
@@ -26,7 +26,7 @@ func setUp() (string, func()) {
 }
 
 func TestDiggerConfigFileDoesNotExist(t *testing.T) {
-	dg, err := NewDiggerConfig("", &FileSystemDirWalker{})
+	dg, err := LoadDiggerConfig("", &FileSystemDirWalker{})
 	assert.NoError(t, err, "expected error to be not nil")
 	assert.Equal(t, dg.Projects[0].Name, "default", "expected default project to have name 'default'")
 	assert.Equal(t, dg.Projects[0].Dir, ".", "expected default project dir to be '.'")
@@ -46,7 +46,7 @@ func TestDiggerConfigWhenMultipleConfigExist(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	dg, err := NewDiggerConfig(tempDir, &FileSystemDirWalker{})
+	dg, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{})
 	assert.Error(t, err, "expected error to be returned")
 	assert.ErrorContains(t, err, ErrDiggerConfigConflict.Error(), "expected error to match target error")
 	assert.Nil(t, dg, "expected diggerConfig to be nil")
@@ -66,12 +66,33 @@ projects:
 	deleteFile := createFile(path.Join(tempDir, "digger.yaml"), diggerCfg)
 	defer deleteFile()
 
-	dg, err := NewDiggerConfig(tempDir, &FileSystemDirWalker{})
+	dg, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{})
 	assert.NoError(t, err, "expected error to be nil")
 	assert.NotNil(t, dg, "expected digger config to be not nil")
 	assert.Equal(t, "path/to/module/test", dg.GetDirectory("prod"))
 }
 
+func TestDiggerConfigDefaultWorkflow(t *testing.T) {
+	tempDir, teardown := setUp()
+	defer teardown()
+
+	diggerCfg := `
+projects:
+- name: prod
+  branch: /main/
+  dir: path/to/module/test
+`
+	deleteFile := createFile(path.Join(tempDir, "digger.yaml"), diggerCfg)
+	defer deleteFile()
+
+	dg, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{})
+	assert.NoError(t, err, "expected error to be nil")
+	assert.NotNil(t, dg, "expected digger config to be not nil")
+	assert.Equal(t, "default", dg.Projects[0].Workflow)
+	_, ok := dg.Workflows["default"]
+	assert.True(t, ok)
+}
+
 func TestDiggerConfigWhenOnlyYmlExists(t *testing.T) {
 	tempDir, teardown := setUp()
 	defer teardown()
@@ -86,7 +107,7 @@ projects:
 	deleteFile := createFile(path.Join(tempDir, "digger.yml"), diggerCfg)
 	defer deleteFile()
 
-	dg, err := NewDiggerConfig(tempDir, &FileSystemDirWalker{})
+	dg, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{})
 	assert.NoError(t, err, "expected error to be nil")
 	assert.NotNil(t, dg, "expected digger config to be not nil")
 	assert.Equal(t, "path/to/module", dg.GetDirectory("dev"))
@@ -111,7 +132,7 @@ workflows:
 	deleteFile := createFile(path.Join(tempDir, "digger.yaml"), diggerCfg)
 	defer deleteFile()
 
-	dg, err := NewDiggerConfig(tempDir, &FileSystemDirWalker{})
+	dg, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{})
 	assert.NoError(t, err, "expected error to be nil")
 	assert.Equal(t, Step{Action: "run", Value: "echo \"hello\"", Shell: ""}, dg.Workflows["myworkflow"].Plan.Steps[0], "parsed struct does not match expected struct")
 }
@@ -156,7 +177,7 @@ workflows:
 	deleteFile := createFile(path.Join(tempDir, "digger.yaml"), diggerCfg)
 	defer deleteFile()
 
-	dg, err := NewDiggerConfig(tempDir, &FileSystemDirWalker{})
+	dg, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{})
 	assert.NoError(t, err, "expected error to be nil")
 	assert.Equal(t, []EnvVarConfig{
 		{Name: "TF_VAR_state", Value: "s3://mybucket/terraform.tfstate"},
@@ -186,7 +207,7 @@ workflows:
 	deleteFile := createFile(path.Join(tempDir, "digger.yaml"), diggerCfg)
 	defer deleteFile()
 
-	dg, err := NewDiggerConfig(tempDir, &FileSystemDirWalker{})
+	dg, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{})
 	assert.NoError(t, err, "expected error to be nil")
 	assert.Equal(t, Step{Action: "init", ExtraArgs: nil, Shell: ""}, dg.Workflows["default"].Plan.Steps[0], "parsed struct does not match expected struct")
 	assert.Equal(t, Step{Action: "plan", ExtraArgs: []string{"-var-file=terraform.tfvars"}, Shell: ""}, dg.Workflows["default"].Plan.Steps[1], "parsed struct does not match expected struct")
@@ -212,7 +233,7 @@ generate_projects:
 	walker.Files = append(walker.Files, "dev/project")
 	walker.Files = append(walker.Files, "testtt")
 
-	dg, err := NewDiggerConfig(tempDir, walker)
+	dg, err := LoadDiggerConfig(tempDir, walker)
 	assert.NoError(t, err, "expected error to be nil")
 	assert.NotNil(t, dg, "expected digger config to be not nil")
 	assert.Equal(t, "test1", dg.Projects[0].Name)
@@ -242,7 +263,7 @@ generate_projects:
 	walker.Files = append(walker.Files, "dev/project")
 	walker.Files = append(walker.Files, "testtt")
 
-	dg, err := NewDiggerConfig(tempDir, walker)
+	dg, err := LoadDiggerConfig(tempDir, walker)
 	assert.NoError(t, err, "expected error to be nil")
 	assert.NotNil(t, dg, "expected digger config to be not nil")
 	assert.Equal(t, "test1", dg.Projects[0].Name)
@@ -271,7 +292,7 @@ generate_projects:
 	walker.Files = append(walker.Files, "dev/project")
 	walker.Files = append(walker.Files, "testtt")
 
-	dg, err := NewDiggerConfig(tempDir, walker)
+	dg, err := LoadDiggerConfig(tempDir, walker)
 	assert.NoError(t, err, "expected error to be nil")
 	assert.NotNil(t, dg, "expected digger config to be not nil")
 	assert.Equal(t, "dev", dg.Projects[0].Name)
@@ -288,7 +309,7 @@ func TestMissingProjectsReturnsError(t *testing.T) {
 	defer deleteFile()
 	walker := &MockDirWalker{}
 
-	_, err := NewDiggerConfig(tempDir, walker)
+	_, err := LoadDiggerConfig(tempDir, walker)
 	assert.ErrorContains(t, err, "no projects configuration found")
 }
 
diff --git a/pkg/integration/integration_test.go b/pkg/integration/integration_test.go
index 9acb364d..d1f11977 100644
--- a/pkg/integration/integration_test.go
+++ b/pkg/integration/integration_test.go
@@ -352,7 +352,7 @@ func TestHappyPath(t *testing.T) {
 	terraform.CreateValidTerraformTestFile(dir)
 	terraform.CreateSingleEnvDiggerYmlFile(dir)
 
-	diggerConfig, err := configuration.NewDiggerConfig(dir, &configuration.FileSystemDirWalker{})
+	diggerConfig, err := configuration.LoadDiggerConfig(dir, &configuration.FileSystemDirWalker{})
 	assert.NoError(t, err)
 
 	lock, err := locking.GetLock()
@@ -496,7 +496,7 @@ func TestMultiEnvHappyPath(t *testing.T) {
 	terraform.CreateValidTerraformTestFile(dir)
 	terraform.CreateMultiEnvDiggerYmlFile(dir)
 
-	diggerConfig, err := configuration.NewDiggerConfig(dir, &configuration.FileSystemDirWalker{})
+	diggerConfig, err := configuration.LoadDiggerConfig(dir, &configuration.FileSystemDirWalker{})
 	assert.NoError(t, err)
 
 	sess, err := session.NewSessionWithOptions(session.Options{
@@ -713,7 +713,7 @@ workflows:
 	terraform.CreateValidTerraformTestFile(dir)
 	terraform.CreateCustomDiggerYmlFile(dir, diggerCfg)
 
-	diggerConfig, err := configuration.NewDiggerConfig(dir, &configuration.FileSystemDirWalker{})
+	diggerConfig, err := configuration.LoadDiggerConfig(dir, &configuration.FileSystemDirWalker{})
 	assert.NoError(t, err)
 
 	assert.NotNil(t, diggerConfig.Workflows)