diff --git a/command/013_config_upgrade.go b/command/013_config_upgrade.go index b7f0da6be..286f063d3 100644 --- a/command/013_config_upgrade.go +++ b/command/013_config_upgrade.go @@ -247,8 +247,9 @@ func (c *ZeroThirteenUpgradeCommand) Run(args []string) int { return 1 } - // Default output filename is "providers.tf" - filename := path.Join(dir, "providers.tf") + // Default output filename is "versions.tf", which is also where the + // 0.12upgrade command added the required_version constraint. + filename := path.Join(dir, "versions.tf") // Special case: if we only have one file with a required providers // block, output to that file instead. @@ -322,14 +323,22 @@ func (c *ZeroThirteenUpgradeCommand) Run(args []string) int { var first *hclwrite.Block var rest []*hclwrite.Block + // First terraform block in the first file. Declared at this scope so + // that it can be used to write the version constraint later, if this + // is the "versions.tf" file. + var tfBlock *hclwrite.Block + if len(requiredProviderBlocks) > 0 { // If we already have one or more required provider blocks, we'll rewrite // the first one, and remove the rest. first, rest = requiredProviderBlocks[0], requiredProviderBlocks[1:] + + // Set the terraform block here for later use to update the + // required version constraint. + tfBlock = parentBlocks[first] } else { // Otherwise, find or a create a terraform block, and add a new // empty required providers block to it. - var tfBlock *hclwrite.Block for _, rootBlock := range root.Blocks() { if rootBlock.Type() == "terraform" { tfBlock = rootBlock @@ -404,6 +413,14 @@ func (c *ZeroThirteenUpgradeCommand) Run(args []string) int { } } + // If this is the "versions.tf" file, add a new version constraint to + // the first terraform block. If this isn't the "versions.tf" file, + // we'll update that file separately. + versionsFilename := path.Join(dir, "versions.tf") + if filename == versionsFilename { + tfBlock.Body().SetAttributeValue("required_version", cty.StringVal(">= 0.13")) + } + // Remove the rest of the blocks (and the parent block, if it's empty) for _, rpBlock := range rest { tfBlock := parentBlocks[rpBlock] @@ -440,6 +457,84 @@ func (c *ZeroThirteenUpgradeCommand) Run(args []string) int { return 1 } + // If the file we just updated was not a "versions.tf" file, add or + // update that file to set the required version constraint in the first + // terraform block. + if filename != versionsFilename { + var file *hclwrite.File + + // If the versions file doesn't exist, just create a new empty file + if _, err := os.Stat(versionsFilename); os.IsNotExist(err) { + file = hclwrite.NewEmptyFile() + } else if err != nil { + diags = diags.Append(tfdiags.Sourceless( + tfdiags.Error, + "Unable to read configuration file", + fmt.Sprintf("Error when reading configuration file %q: %s", versionsFilename, err), + )) + c.showDiagnostics(diags) + return 1 + } else { + // Versions file already exists, so load and parse it + config, err := ioutil.ReadFile(versionsFilename) + if err != nil { + diags = diags.Append(tfdiags.Sourceless( + tfdiags.Error, + "Unable to read configuration file", + fmt.Sprintf("Error when reading configuration file %q: %s", versionsFilename, err), + )) + c.showDiagnostics(diags) + return 1 + } + var parseDiags hcl.Diagnostics + file, parseDiags = hclwrite.ParseConfig(config, filename, hcl.InitialPos) + diags = diags.Append(parseDiags) + } + + if diags.HasErrors() { + c.showDiagnostics(diags) + return 1 + } + + // Find or create a terraform block + root := file.Body() + var tfBlock *hclwrite.Block + for _, rootBlock := range root.Blocks() { + if rootBlock.Type() == "terraform" { + tfBlock = rootBlock + break + } + } + if tfBlock == nil { + tfBlock = root.AppendNewBlock("terraform", nil) + } + + // Set the required version attribute + tfBlock.Body().SetAttributeValue("required_version", cty.StringVal(">= 0.13")) + + // Write the config back to the file + f, err := os.OpenFile(versionsFilename, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + diags = diags.Append(tfdiags.Sourceless( + tfdiags.Error, + "Unable to open configuration file for writing", + fmt.Sprintf("Error when reading configuration file %q: %s", filename, err), + )) + c.showDiagnostics(diags) + return 1 + } + _, err = file.WriteTo(f) + if err != nil { + diags = diags.Append(tfdiags.Sourceless( + tfdiags.Error, + "Unable to rewrite configuration file", + fmt.Sprintf("Error when rewriting configuration file %q: %s", filename, err), + )) + c.showDiagnostics(diags) + return 1 + } + } + // After successfully writing the new configuration, remove all other // required provider blocks from remaining configuration files. for _, path := range rewritePaths { @@ -600,8 +695,8 @@ func (c *ZeroThirteenUpgradeCommand) Help() string { helpText := ` Usage: terraform 0.13upgrade [module-dir] - Generates a "providers.tf" configuration file which includes source - configuration for every non-default provider. + Updates module configuration files to add provider source attributes and + merge multiple required_providers blocks into one. ` return strings.TrimSpace(helpText) } diff --git a/command/013_config_upgrade_test.go b/command/013_config_upgrade_test.go index b35b464cb..2bc472fe1 100644 --- a/command/013_config_upgrade_test.go +++ b/command/013_config_upgrade_test.go @@ -93,7 +93,7 @@ func TestZeroThirteenUpgrade_success(t *testing.T) { "preserves comments": "013upgrade-preserves-comments", "multiple blocks": "013upgrade-multiple-blocks", "multiple files": "013upgrade-multiple-files", - "existing providers.tf": "013upgrade-existing-providers-tf", + "existing versions.tf": "013upgrade-existing-versions-tf", "skipped files": "013upgrade-skipped-files", } for name, testPath := range testCases { diff --git a/command/testdata/013upgrade-existing-providers-tf/input/providers.tf b/command/testdata/013upgrade-existing-providers-tf/input/providers.tf deleted file mode 100644 index 04203320a..000000000 --- a/command/testdata/013upgrade-existing-providers-tf/input/providers.tf +++ /dev/null @@ -1,3 +0,0 @@ -# This is a file called providers.tf which does not originally have a -# required_providers block. -resource foo_resource a {} diff --git a/command/testdata/013upgrade-existing-providers-tf/expected/main.tf b/command/testdata/013upgrade-existing-versions-tf/expected/main.tf similarity index 100% rename from command/testdata/013upgrade-existing-providers-tf/expected/main.tf rename to command/testdata/013upgrade-existing-versions-tf/expected/main.tf diff --git a/command/testdata/013upgrade-existing-providers-tf/expected/providers.tf b/command/testdata/013upgrade-existing-versions-tf/expected/versions.tf similarity index 71% rename from command/testdata/013upgrade-existing-providers-tf/expected/providers.tf rename to command/testdata/013upgrade-existing-versions-tf/expected/versions.tf index 8394c756e..22c14e5c2 100644 --- a/command/testdata/013upgrade-existing-providers-tf/expected/providers.tf +++ b/command/testdata/013upgrade-existing-versions-tf/expected/versions.tf @@ -1,7 +1,9 @@ -# This is a file called providers.tf which does not originally have a +# This is a file called versions.tf which does not originally have a # required_providers block. resource foo_resource a {} + terraform { + required_version = ">= 0.13" required_providers { bar = { source = "hashicorp/bar" diff --git a/command/testdata/013upgrade-existing-providers-tf/input/main.tf b/command/testdata/013upgrade-existing-versions-tf/input/main.tf similarity index 100% rename from command/testdata/013upgrade-existing-providers-tf/input/main.tf rename to command/testdata/013upgrade-existing-versions-tf/input/main.tf diff --git a/command/testdata/013upgrade-existing-versions-tf/input/versions.tf b/command/testdata/013upgrade-existing-versions-tf/input/versions.tf new file mode 100644 index 000000000..c4ab732da --- /dev/null +++ b/command/testdata/013upgrade-existing-versions-tf/input/versions.tf @@ -0,0 +1,7 @@ +# This is a file called versions.tf which does not originally have a +# required_providers block. +resource foo_resource a {} + +terraform { + required_version = ">= 0.12" +} diff --git a/command/testdata/013upgrade-explicit-providers/expected/versions.tf b/command/testdata/013upgrade-explicit-providers/expected/versions.tf new file mode 100644 index 000000000..6b6318def --- /dev/null +++ b/command/testdata/013upgrade-explicit-providers/expected/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13" +} diff --git a/command/testdata/013upgrade-file-exists/expected/providers.tf b/command/testdata/013upgrade-file-exists/expected/versions.tf similarity index 84% rename from command/testdata/013upgrade-file-exists/expected/providers.tf rename to command/testdata/013upgrade-file-exists/expected/versions.tf index f0f674de4..973e28c11 100644 --- a/command/testdata/013upgrade-file-exists/expected/providers.tf +++ b/command/testdata/013upgrade-file-exists/expected/versions.tf @@ -9,4 +9,5 @@ terraform { source = "hashicorp/foo" } } + required_version = ">= 0.13" } diff --git a/command/testdata/013upgrade-file-exists/input/providers.tf b/command/testdata/013upgrade-file-exists/input/versions.tf similarity index 100% rename from command/testdata/013upgrade-file-exists/input/providers.tf rename to command/testdata/013upgrade-file-exists/input/versions.tf diff --git a/command/testdata/013upgrade-implicit-not-found/expected/providers.tf b/command/testdata/013upgrade-implicit-not-found/expected/versions.tf similarity index 93% rename from command/testdata/013upgrade-implicit-not-found/expected/providers.tf rename to command/testdata/013upgrade-implicit-not-found/expected/versions.tf index d076393f4..795fe47ef 100644 --- a/command/testdata/013upgrade-implicit-not-found/expected/providers.tf +++ b/command/testdata/013upgrade-implicit-not-found/expected/versions.tf @@ -13,4 +13,5 @@ terraform { # https://www.terraform.io/docs/configuration/providers.html#provider-source } } + required_version = ">= 0.13" } diff --git a/command/testdata/013upgrade-implicit-providers/expected/providers.tf b/command/testdata/013upgrade-implicit-providers/expected/versions.tf similarity index 86% rename from command/testdata/013upgrade-implicit-providers/expected/providers.tf rename to command/testdata/013upgrade-implicit-providers/expected/versions.tf index 9b2a488e5..1bfef1799 100644 --- a/command/testdata/013upgrade-implicit-providers/expected/providers.tf +++ b/command/testdata/013upgrade-implicit-providers/expected/versions.tf @@ -10,4 +10,5 @@ terraform { source = "hashicorp/foo" } } + required_version = ">= 0.13" } diff --git a/command/testdata/013upgrade-multiple-blocks/expected/providers.tf b/command/testdata/013upgrade-multiple-blocks/expected/versions.tf similarity index 89% rename from command/testdata/013upgrade-multiple-blocks/expected/providers.tf rename to command/testdata/013upgrade-multiple-blocks/expected/versions.tf index 195b21389..bcfd89046 100644 --- a/command/testdata/013upgrade-multiple-blocks/expected/providers.tf +++ b/command/testdata/013upgrade-multiple-blocks/expected/versions.tf @@ -12,4 +12,5 @@ terraform { version = "0.5" } } + required_version = ">= 0.13" } diff --git a/command/testdata/013upgrade-multiple-files/expected/providers.tf b/command/testdata/013upgrade-multiple-files/expected/versions.tf similarity index 93% rename from command/testdata/013upgrade-multiple-files/expected/providers.tf rename to command/testdata/013upgrade-multiple-files/expected/versions.tf index b46e7180d..5604764ef 100644 --- a/command/testdata/013upgrade-multiple-files/expected/providers.tf +++ b/command/testdata/013upgrade-multiple-files/expected/versions.tf @@ -13,4 +13,5 @@ terraform { version = "1.0.0" } } + required_version = ">= 0.13" } diff --git a/command/testdata/013upgrade-multiple-files/input/providers.tf b/command/testdata/013upgrade-multiple-files/input/versions.tf similarity index 100% rename from command/testdata/013upgrade-multiple-files/input/providers.tf rename to command/testdata/013upgrade-multiple-files/input/versions.tf diff --git a/command/testdata/013upgrade-preserves-comments/expected/versions.tf b/command/testdata/013upgrade-preserves-comments/expected/versions.tf new file mode 100644 index 000000000..6b6318def --- /dev/null +++ b/command/testdata/013upgrade-preserves-comments/expected/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13" +} diff --git a/command/testdata/013upgrade-provider-not-found/expected/versions.tf b/command/testdata/013upgrade-provider-not-found/expected/versions.tf new file mode 100644 index 000000000..6b6318def --- /dev/null +++ b/command/testdata/013upgrade-provider-not-found/expected/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13" +} diff --git a/command/testdata/013upgrade-providers-with-source/expected/versions.tf b/command/testdata/013upgrade-providers-with-source/expected/versions.tf new file mode 100644 index 000000000..6b6318def --- /dev/null +++ b/command/testdata/013upgrade-providers-with-source/expected/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13" +} diff --git a/command/testdata/013upgrade-skipped-files/expected/versions.tf b/command/testdata/013upgrade-skipped-files/expected/versions.tf new file mode 100644 index 000000000..6b6318def --- /dev/null +++ b/command/testdata/013upgrade-skipped-files/expected/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13" +} diff --git a/command/testdata/013upgrade-submodule/expected-module/module/providers.tf b/command/testdata/013upgrade-submodule/expected-module/module/versions.tf similarity index 74% rename from command/testdata/013upgrade-submodule/expected-module/module/providers.tf rename to command/testdata/013upgrade-submodule/expected-module/module/versions.tf index 3af569d04..999c94807 100644 --- a/command/testdata/013upgrade-submodule/expected-module/module/providers.tf +++ b/command/testdata/013upgrade-submodule/expected-module/module/versions.tf @@ -4,4 +4,5 @@ terraform { source = "hashicorp/foo" } } + required_version = ">= 0.13" } diff --git a/command/testdata/013upgrade-submodule/expected/versions.tf b/command/testdata/013upgrade-submodule/expected/versions.tf new file mode 100644 index 000000000..6b6318def --- /dev/null +++ b/command/testdata/013upgrade-submodule/expected/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13" +}