Repository: diggerhq/digger
Pull request #314 (2023-06-05 14:41:49)

move workflow initialization to one place


Patch:
diff --git a/cmd/digger/main.go b/cmd/digger/main.go
index b5b6e761..8e452d2a 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)
 	}
@@ -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/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..73239eb4 100644
--- a/pkg/gitlab/gitlab.go
+++ b/pkg/gitlab/gitlab.go
@@ -250,9 +250,8 @@ 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)
 			}
 
 			commandsPerProject = append(commandsPerProject, models.ProjectCommand{
@@ -270,7 +269,7 @@ func ConvertGitLabEventToCommands(event GitLabEvent, gitLabContext *GitLabContex
 		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)
 			}
 			commandsPerProject = append(commandsPerProject, models.ProjectCommand{
 				ProjectName:      project.Name,
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)