diff --git a/internal/command/e2etest/providers_mirror_test.go b/internal/command/e2etest/providers_mirror_test.go index ed331718a6..12552882c9 100644 --- a/internal/command/e2etest/providers_mirror_test.go +++ b/internal/command/e2etest/providers_mirror_test.go @@ -19,78 +19,97 @@ import ( // interacts directly with Terraform Registry and the full details of that are // tricky to mock. Such a mock is _possible_, but we're using e2etest as a // compromise for now to keep these tests relatively simple. - func TestTerraformProvidersMirror(t *testing.T) { - testTerraformProvidersMirror(t, "terraform-providers-mirror", "") -} - -func TestTerraformProvidersMirrorWithLockFile(t *testing.T) { - testTerraformProvidersMirror(t, "terraform-providers-mirror-with-lock-file", "") -} - -func TestTerraformProvidersMirrorWithBrokenLockFile(t *testing.T) { - testTerraformProvidersMirror(t, "terraform-providers-mirror-with-broken-lock-file", "Inconsistent dependency lock file") -} - -func testTerraformProvidersMirror(t *testing.T, fixture string, errMsg string) { // This test reaches out to releases.hashicorp.com to download the // template and null providers, so it can only run if network access is // allowed. skipIfCannotAccessNetwork(t) - outputDir := t.TempDir() - t.Logf("creating mirror directory in %s", outputDir) + for _, test := range []struct { + name string + args []string + err string + }{ + { + name: "terraform-providers-mirror", + args: []string{"-platform=linux_amd64", "-platform=windows_386"}, + }, + { + name: "terraform-providers-mirror-with-lock-file", + args: []string{"-platform=linux_amd64", "-platform=windows_386"}, + }, + { + // should ignore lock file + name: "terraform-providers-mirror-with-broken-lock-file", + args: []string{"-platform=linux_amd64", "-platform=windows_386", "-lock-file=false"}, + }, + { + name: "terraform-providers-mirror-with-broken-lock-file", + args: []string{"-platform=linux_amd64", "-platform=windows_386", "-lock-file=true"}, + err: "Inconsistent dependency lock file", + }, + } { + t.Run(test.name, func(t *testing.T) { + outputDir := t.TempDir() + t.Logf("creating mirror directory in %s", outputDir) - fixturePath := filepath.Join("testdata", fixture) - tf := e2e.NewBinary(t, terraformBin, fixturePath) + fixturePath := filepath.Join("testdata", test.name) + tf := e2e.NewBinary(t, terraformBin, fixturePath) - stdout, stderr, err := tf.Run("providers", "mirror", "-platform=linux_amd64", "-platform=windows_386", outputDir) - if errMsg != "" { - if !strings.Contains(stderr, errMsg) { - t.Fatalf("expected error %q, got %q\n", errMsg, stderr) - } - return - } + args := []string{"providers", "mirror"} + args = append(args, test.args...) + args = append(args, outputDir) - if err != nil { - t.Fatalf("unexpected error: %s\nstdout:\n%s\nstderr:\n%s", err, stdout, stderr) - } + stdout, stderr, err := tf.Run(args...) + if test.err != "" { + if !strings.Contains(stderr, test.err) { + t.Fatalf("expected error %q, got %q\n", test.err, stderr) + } + return + } - // The test fixture includes exact version constraints for the two - // providers it depends on so that the following should remain stable. - // In the (unlikely) event that these particular versions of these - // providers are removed from the registry, this test will start to fail. - want := []string{ - "registry.terraform.io/hashicorp/null/2.1.0.json", - "registry.terraform.io/hashicorp/null/index.json", - "registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip", - "registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_windows_386.zip", - "registry.terraform.io/hashicorp/template/2.1.1.json", - "registry.terraform.io/hashicorp/template/index.json", - "registry.terraform.io/hashicorp/template/terraform-provider-template_2.1.1_linux_amd64.zip", - "registry.terraform.io/hashicorp/template/terraform-provider-template_2.1.1_windows_386.zip", - } - var got []string - walkErr := filepath.Walk(outputDir, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if info.IsDir() { - return nil // we only care about leaf files for this test - } - relPath, err := filepath.Rel(outputDir, path) - if err != nil { - return err - } - got = append(got, filepath.ToSlash(relPath)) - return nil - }) - if walkErr != nil { - t.Fatal(walkErr) - } - sort.Strings(got) + if err != nil { + t.Fatalf("unexpected error: %s\nstdout:\n%s\nstderr:\n%s", err, stdout, stderr) + } + + // The test fixture includes exact version constraints for the two + // providers it depends on so that the following should remain stable. + // In the (unlikely) event that these particular versions of these + // providers are removed from the registry, this test will start to fail. + want := []string{ + "registry.terraform.io/hashicorp/null/2.1.0.json", + "registry.terraform.io/hashicorp/null/index.json", + "registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip", + "registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_windows_386.zip", + "registry.terraform.io/hashicorp/template/2.1.1.json", + "registry.terraform.io/hashicorp/template/index.json", + "registry.terraform.io/hashicorp/template/terraform-provider-template_2.1.1_linux_amd64.zip", + "registry.terraform.io/hashicorp/template/terraform-provider-template_2.1.1_windows_386.zip", + } + var got []string + walkErr := filepath.Walk(outputDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil // we only care about leaf files for this test + } + relPath, err := filepath.Rel(outputDir, path) + if err != nil { + return err + } + got = append(got, filepath.ToSlash(relPath)) + return nil + }) + if walkErr != nil { + t.Fatal(walkErr) + } + sort.Strings(got) + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected files in result\n%s", diff) + } - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("unexpected files in result\n%s", diff) + }) } } diff --git a/internal/command/e2etest/testdata/terraform-providers-mirror-with-broken-lock-file/terraform-providers-mirror.tf b/internal/command/e2etest/testdata/terraform-providers-mirror-with-broken-lock-file/terraform-providers-mirror.tf index 1598a27835..4b31e03012 100644 --- a/internal/command/e2etest/testdata/terraform-providers-mirror-with-broken-lock-file/terraform-providers-mirror.tf +++ b/internal/command/e2etest/testdata/terraform-providers-mirror-with-broken-lock-file/terraform-providers-mirror.tf @@ -1,7 +1,7 @@ terraform { required_providers { - template = { source = "hashicorp/template" } - null = { source = "hashicorp/null" } + template = { version = "2.1.1" } + null = { source = "hashicorp/null", version = "2.1.0" } terraform = { source = "terraform.io/builtin/terraform" } } } diff --git a/internal/command/providers_mirror.go b/internal/command/providers_mirror.go index 87143a8851..ec2904eda1 100644 --- a/internal/command/providers_mirror.go +++ b/internal/command/providers_mirror.go @@ -34,8 +34,13 @@ func (c *ProvidersMirrorCommand) Synopsis() string { func (c *ProvidersMirrorCommand) Run(args []string) int { args = c.Meta.process(args) cmdFlags := c.Meta.defaultFlagSet("providers mirror") + var optPlatforms arguments.FlagStringSlice cmdFlags.Var(&optPlatforms, "platform", "target platform") + + var optLockFile bool + cmdFlags.BoolVar(&optLockFile, "lock-file", true, "use lock file") + cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } if err := cmdFlags.Parse(args); err != nil { c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error())) @@ -89,7 +94,7 @@ func (c *ProvidersMirrorCommand) Run(args []string) int { diags = diags.Append(lockedDepsDiags) // If lock file is present, validate it against configuration - if !lockedDeps.Empty() { + if !lockedDeps.Empty() && optLockFile { if errs := config.VerifyDependencySelections(lockedDeps); len(errs) > 0 { diags = diags.Append(tfdiags.Sourceless( tfdiags.Error, @@ -161,7 +166,7 @@ func (c *ProvidersMirrorCommand) Run(args []string) int { continue } selected := candidates.Newest() - if !lockedDeps.Empty() { + if !lockedDeps.Empty() && optLockFile { selected = lockedDeps.Provider(provider).Version() c.Ui.Output(fmt.Sprintf(" - Selected v%s to match dependency lock file", selected.String())) } else if len(constraintsStr) > 0 {