diff --git a/cmd/config.go b/cmd/config.go index ca2ea9ef..142d5c10 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -54,7 +54,10 @@ type AtlantisProject struct { ApplyRequirements *[]string `json:"apply_requirements,omitempty"` // Atlantis use ExecutionOrderGroup for sort projects before applying/planning - ExecutionOrderGroup int `json:"execution_order_group,omitempty"` + ExecutionOrderGroup *int `json:"execution_order_group,omitempty"` + + // Atlantis uses DependsOn to define dependencies between projects + DependsOn []string `json:"depends_on,omitempty"` } // Autoplan settings for which plans affect other plans diff --git a/cmd/generate.go b/cmd/generate.go index 997e3eda..e1e7b1d0 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -813,7 +813,7 @@ func main(cmd *cobra.Command, args []string) error { // Sort the projects in config by Dir sort.Slice(config.Projects, func(i, j int) bool { return config.Projects[i].Dir < config.Projects[j].Dir }) - if executionOrderGroups { + if executionOrderGroups || dependsOn { projectsMap := make(map[string]*AtlantisProject, len(config.Projects)) for i := range config.Projects { projectsMap[config.Projects[i].Dir] = &config.Projects[i] @@ -825,6 +825,7 @@ func main(cmd *cobra.Command, args []string) error { hasChanges = false for _, project := range config.Projects { executionOrderGroup := 0 + dependsOnList := []string{} // choose order group based on dependencies for _, dep := range project.Autoplan.WhenModified { depPath := filepath.Dir(filepath.Join(project.Dir, dep)) @@ -838,12 +839,20 @@ func main(cmd *cobra.Command, args []string) error { // skip not project dependencies continue } - if depProject.ExecutionOrderGroup+1 > executionOrderGroup { - executionOrderGroup = depProject.ExecutionOrderGroup + 1 + if depProject.ExecutionOrderGroup != nil { + if *depProject.ExecutionOrderGroup+1 > executionOrderGroup { + executionOrderGroup = *depProject.ExecutionOrderGroup + 1 + } } + dependsOnList = append(dependsOnList, depProject.Name) } - if projectsMap[project.Dir].ExecutionOrderGroup != executionOrderGroup { - projectsMap[project.Dir].ExecutionOrderGroup = executionOrderGroup + if projectsMap[project.Dir].ExecutionOrderGroup == nil || *projectsMap[project.Dir].ExecutionOrderGroup != executionOrderGroup { + if executionOrderGroups { + projectsMap[project.Dir].ExecutionOrderGroup = &executionOrderGroup + } + if dependsOn { + projectsMap[project.Dir].DependsOn = dependsOnList + } // repeat the main cycle when changed some project hasChanges = true } @@ -856,12 +865,14 @@ func main(cmd *cobra.Command, args []string) error { } // Sort by execution_order_group - sort.Slice(config.Projects, func(i, j int) bool { - if config.Projects[i].ExecutionOrderGroup == config.Projects[j].ExecutionOrderGroup { - return config.Projects[i].Dir < config.Projects[j].Dir - } - return config.Projects[i].ExecutionOrderGroup < config.Projects[j].ExecutionOrderGroup - }) + if executionOrderGroups { + sort.Slice(config.Projects, func(i, j int) bool { + if *config.Projects[i].ExecutionOrderGroup == *config.Projects[j].ExecutionOrderGroup { + return config.Projects[i].Dir < config.Projects[j].Dir + } + return *config.Projects[i].ExecutionOrderGroup < *config.Projects[j].ExecutionOrderGroup + }) + } } // Convert config to YAML string @@ -910,13 +921,21 @@ var createHclProjectChilds bool var createHclProjectExternalChilds bool var useProjectMarkers bool var executionOrderGroups bool +var dependsOn bool // generateCmd represents the generate command var generateCmd = &cobra.Command{ Use: "generate", Short: "Makes atlantis config", Long: `Logs Yaml representing Atlantis config to stderr`, - RunE: main, + // Test is needed to confirm that if --depends on is set, --create-project-name is also set. + PreRun: func(cmd *cobra.Command, args []string) { + dependsOn, _ := cmd.Flags().GetBool("depends-on") + if dependsOn { + cmd.MarkFlagRequired("create-project-name") + } + }, + RunE: main, } func init() { @@ -950,6 +969,7 @@ func init() { generateCmd.PersistentFlags().BoolVar(&createHclProjectExternalChilds, "create-hcl-project-external-childs", true, "Creates Atlantis projects for terragrunt child modules outside the directories containing the HCL files defined in --project-hcl-files") generateCmd.PersistentFlags().BoolVar(&useProjectMarkers, "use-project-markers", false, "Creates Atlantis projects only for project hcl files with locals: atlantis_project = true") generateCmd.PersistentFlags().BoolVar(&executionOrderGroups, "execution-order-groups", false, "Computes execution_order_groups for projects") + generateCmd.PersistentFlags().BoolVar(&dependsOn, "depends-on", false, "Computes depends_on for projects. Requires --create-project-name.") } // Runs a set of arguments, returning the output diff --git a/cmd/generate_test.go b/cmd/generate_test.go index b7be3846..42ac5442 100644 --- a/cmd/generate_test.go +++ b/cmd/generate_test.go @@ -43,6 +43,8 @@ func resetForRun() error { createHclProjectChilds = false createHclProjectExternalChilds = true useProjectMarkers = false + executionOrderGroups = false + dependsOn = false return nil } @@ -623,3 +625,22 @@ func TestWithExecutionOrderGroups(t *testing.T) { "--execution-order-groups", }) } + +func TestWithExecutionOrderGroupsAndDependsOn(t *testing.T) { + runTest(t, filepath.Join("golden", "withExecutionOrderGroupsAndDependsOn.yaml"), []string{ + "--root", + filepath.Join("..", "test_examples", "chained_dependencies"), + "--execution-order-groups", + "--depends-on", + "--create-project-name", + }) +} + +func TestWithDependsOn(t *testing.T) { + runTest(t, filepath.Join("golden", "withDependsOn.yaml"), []string{ + "--root", + filepath.Join("..", "test_examples", "chained_dependencies"), + "--depends-on", + "--create-project-name", + }) +} diff --git a/cmd/golden/withDependsOn.yaml b/cmd/golden/withDependsOn.yaml new file mode 100644 index 00000000..329a9fcd --- /dev/null +++ b/cmd/golden/withDependsOn.yaml @@ -0,0 +1,45 @@ +parallel_apply: true +parallel_plan: true +projects: +- autoplan: + enabled: false + when_modified: + - '*.hcl' + - '*.tf*' + dir: dependency + name: dependency +- autoplan: + enabled: false + when_modified: + - '*.hcl' + - '*.tf*' + - ../dependency/terragrunt.hcl + depends_on: + - dependency + dir: depender + name: depender +- autoplan: + enabled: false + when_modified: + - '*.hcl' + - '*.tf*' + - ../depender/terragrunt.hcl + - ../dependency/terragrunt.hcl + - nested/terragrunt.hcl + depends_on: + - depender + - dependency + - depender_on_depender_nested + dir: depender_on_depender + name: depender_on_depender +- autoplan: + enabled: false + when_modified: + - '*.hcl' + - '*.tf*' + - ../../dependency/terragrunt.hcl + depends_on: + - dependency + dir: depender_on_depender/nested + name: depender_on_depender_nested +version: 3 diff --git a/cmd/golden/withExecutionOrderGroups.yaml b/cmd/golden/withExecutionOrderGroups.yaml index a98ce795..c45bd1ca 100644 --- a/cmd/golden/withExecutionOrderGroups.yaml +++ b/cmd/golden/withExecutionOrderGroups.yaml @@ -8,6 +8,7 @@ projects: - '*.hcl' - '*.tf*' dir: dependency + execution_order_group: 0 - autoplan: enabled: false when_modified: diff --git a/cmd/golden/withExecutionOrderGroupsAndDependsOn.yaml b/cmd/golden/withExecutionOrderGroupsAndDependsOn.yaml new file mode 100644 index 00000000..d61520ae --- /dev/null +++ b/cmd/golden/withExecutionOrderGroupsAndDependsOn.yaml @@ -0,0 +1,49 @@ +parallel_apply: true +parallel_plan: true +projects: +- autoplan: + enabled: false + when_modified: + - '*.hcl' + - '*.tf*' + dir: dependency + execution_order_group: 0 + name: dependency +- autoplan: + enabled: false + when_modified: + - '*.hcl' + - '*.tf*' + - ../dependency/terragrunt.hcl + depends_on: + - dependency + dir: depender + execution_order_group: 1 + name: depender +- autoplan: + enabled: false + when_modified: + - '*.hcl' + - '*.tf*' + - ../../dependency/terragrunt.hcl + depends_on: + - dependency + dir: depender_on_depender/nested + execution_order_group: 1 + name: depender_on_depender_nested +- autoplan: + enabled: false + when_modified: + - '*.hcl' + - '*.tf*' + - ../depender/terragrunt.hcl + - ../dependency/terragrunt.hcl + - nested/terragrunt.hcl + depends_on: + - depender + - dependency + - depender_on_depender_nested + dir: depender_on_depender + execution_order_group: 2 + name: depender_on_depender +version: 3