From bec44ce39e81482edd602d7d4e7e6354f0aba4e8 Mon Sep 17 00:00:00 2001 From: Ross Strickland Date: Wed, 24 Apr 2024 21:43:49 -0600 Subject: [PATCH] add depends_on; fix execution_order_group 0. (#320) * add depends_on; fix execution_order_group 0. --- README.md | 3 +- cmd/config.go | 5 +- cmd/generate.go | 46 ++++++++++++----- cmd/generate_test.go | 21 ++++++++ cmd/golden/withDependsOn.yaml | 45 +++++++++++++++++ cmd/golden/withExecutionOrderGroups.yaml | 1 + .../withExecutionOrderGroupsAndDependsOn.yaml | 49 +++++++++++++++++++ main.go | 2 +- out | 49 +++++++++++++++++++ 9 files changed, 205 insertions(+), 16 deletions(-) create mode 100644 cmd/golden/withDependsOn.yaml create mode 100644 cmd/golden/withExecutionOrderGroupsAndDependsOn.yaml create mode 100644 out diff --git a/README.md b/README.md index 2142fcb4..aa34a429 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Then, make sure `terragrunt-atlantis-config` is present on your Atlantis server. ```hcl variable "terragrunt_atlantis_config_version" { - default = "1.17.9" + default = "1.18.0" } build { @@ -132,6 +132,7 @@ One way to customize the behavior of this module is through CLI flag values pass | `--filter` | Path or glob expression to the directory you want scope down the config for. Default is all files in root | "" | | `--num-executors` | Number of executors used for parallel generation of projects. Default is 15 | 15 | | `--execution-order-groups` | Computes execution_order_group for projects | false | +| `--depends-on` | Computes depends_on for projects. Project names are required. | false | ## Project generation 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 c3e75810..a603a500 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -817,7 +817,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] @@ -829,9 +829,10 @@ 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)) + depPath := filepath.ToSlash(filepath.Dir(filepath.Join(project.Dir, dep))) if depPath == project.Dir { // skip dependency on oneself continue @@ -842,12 +843,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 } @@ -860,12 +869,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 @@ -914,13 +925,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() { @@ -954,6 +973,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 48722497..fe6cf912 100644 --- a/cmd/generate_test.go +++ b/cmd/generate_test.go @@ -44,6 +44,8 @@ func resetForRun() error { createHclProjectChilds = false createHclProjectExternalChilds = true useProjectMarkers = false + executionOrderGroups = false + dependsOn = false return nil } @@ -639,3 +641,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 diff --git a/main.go b/main.go index 0161bb5b..b5fab3ab 100644 --- a/main.go +++ b/main.go @@ -5,7 +5,7 @@ import "github.com/transcend-io/terragrunt-atlantis-config/cmd" // This variable is set at build time using -ldflags parameters. // But we still set a default here for those using plain `go get` downloads // For more info, see: http://stackoverflow.com/a/11355611/483528 -var VERSION string = "1.17.9" +var VERSION string = "1.18.0" func main() { cmd.Execute(VERSION) diff --git a/out b/out new file mode 100644 index 00000000..f9ca39aa --- /dev/null +++ b/out @@ -0,0 +1,49 @@ +automerge: false +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 + dir: depender_on_depender + execution_order_group: 2 + name: depender_on_depender +version: 3