diff --git a/command/apply.go b/command/apply.go index 36b66f677b..6fb47f5249 100644 --- a/command/apply.go +++ b/command/apply.go @@ -134,7 +134,7 @@ func (c *ApplyCommand) Run(args []string) int { // Applying changes with dev overrides in effect could make it impossible // to switch back to a release version if the schema isn't compatible, // so we'll warn about it. - diags = diags.Append(c.providerDevOverrideWarnings()) + diags = diags.Append(c.providerDevOverrideRuntimeWarnings()) // Before we delegate to the backend, we'll print any warning diagnostics // we've accumulated here, since the backend will start fresh with its own diff --git a/command/e2etest/provider_dev_test.go b/command/e2etest/provider_dev_test.go index 723591dbeb..43bb435069 100644 --- a/command/e2etest/provider_dev_test.go +++ b/command/e2etest/provider_dev_test.go @@ -61,7 +61,8 @@ func TestProviderDevOverrides(t *testing.T) { // dev overrides are always ready to use and don't need any special action // to "install" them. This test is mimicking the a happy path of going // directly from "go build" to validate/plan/apply without interacting - // with any registries, mirrors, lock files, etc. + // with any registries, mirrors, lock files, etc. To verify "terraform + // init" does actually show a warning, that behavior is tested at the end. stdout, stderr, err = tf.Run("validate") if err != nil { t.Fatalf("unexpected error: %s\n%s", err, stderr) @@ -73,4 +74,15 @@ func TestProviderDevOverrides(t *testing.T) { if got, want := stdout, `Provider development overrides are in effect`; !strings.Contains(got, want) { t.Errorf("stdout doesn't include the warning about development overrides\nwant: %s\n%s", want, got) } + + stdout, stderr, err = tf.Run("init") + if err == nil { + t.Fatal("expected error: Failed to query available provider packages") + } + if got, want := stdout, `Provider development overrides are in effect`; !strings.Contains(got, want) { + t.Errorf("stdout doesn't include the warning about development overrides\nwant: %s\n%s", want, got) + } + if got, want := stderr, `Failed to query available provider packages`; !strings.Contains(got, want) { + t.Errorf("stderr doesn't include the error about listing unavailable development provider\nwant: %s\n%s", want, got) + } } diff --git a/command/init.go b/command/init.go index 85d38b4359..96ead754f3 100644 --- a/command/init.go +++ b/command/init.go @@ -423,6 +423,12 @@ the backend configuration is present and valid. // Load the complete module tree, and fetch any missing providers. // This method outputs its own Ui. func (c *InitCommand) getProviders(config *configs.Config, state *states.State, upgrade bool, pluginDirs []string) (output, abort bool, diags tfdiags.Diagnostics) { + // Dev overrides cause the result of "terraform init" to be irrelevant for + // any overridden providers, so we'll warn about it to avoid later + // confusion when Terraform ends up using a different provider than the + // lock file called for. + diags = diags.Append(c.providerDevOverrideInitWarnings()) + // First we'll collect all the provider dependencies we can see in the // configuration and the state. reqs, hclDiags := config.ProviderRequirements() @@ -754,12 +760,6 @@ func (c *InitCommand) getProviders(config *configs.Config, state *states.State, } ctx = evts.OnContext(ctx) - // Dev overrides cause the result of "terraform init" to be irrelevant for - // any overridden providers, so we'll warn about it to avoid later - // confusion when Terraform ends up using a different provider than the - // lock file called for. - diags = diags.Append(c.providerDevOverrideWarnings()) - mode := providercache.InstallNewProvidersOnly if upgrade { mode = providercache.InstallUpgrades diff --git a/command/meta_providers.go b/command/meta_providers.go index ee351843a6..289492e826 100644 --- a/command/meta_providers.go +++ b/command/meta_providers.go @@ -177,8 +177,35 @@ func (m *Meta) providerInstallSource() getproviders.Source { return m.ProviderSource } -// providerDevOverrideWarnings returns a diagnostics that contains at least -// one warning if and only if there is at least one provider development +// providerDevOverrideInitWarnings returns a diagnostics that contains at +// least one warning if and only if there is at least one provider development +// override in effect. If not, the result is always empty. The result never +// contains error diagnostics. +// +// The init command can use this to include a warning that the results +// may differ from what's expected due to the development overrides. For +// other commands, providerDevOverrideRuntimeWarnings should be used. +func (m *Meta) providerDevOverrideInitWarnings() tfdiags.Diagnostics { + if len(m.ProviderDevOverrides) == 0 { + return nil + } + var detailMsg strings.Builder + detailMsg.WriteString("The following provider development overrides are set in the CLI configuration:\n") + for addr, path := range m.ProviderDevOverrides { + detailMsg.WriteString(fmt.Sprintf(" - %s in %s\n", addr.ForDisplay(), path)) + } + detailMsg.WriteString("\nSkip terraform init when using provider development overrides. It is not necessary and may error unexpectedly.") + return tfdiags.Diagnostics{ + tfdiags.Sourceless( + tfdiags.Warning, + "Provider development overrides are in effect", + detailMsg.String(), + ), + } +} + +// providerDevOverrideRuntimeWarnings returns a diagnostics that contains at +// least one warning if and only if there is at least one provider development // override in effect. If not, the result is always empty. The result never // contains error diagnostics. // @@ -187,7 +214,10 @@ func (m *Meta) providerInstallSource() getproviders.Source { // not necessary to bother the user with this warning on every command, but // it's helpful to return it on commands that have externally-visible side // effects and on commands that are used to verify conformance to schemas. -func (m *Meta) providerDevOverrideWarnings() tfdiags.Diagnostics { +// +// See providerDevOverrideInitWarnings for warnings specific to the init +// command. +func (m *Meta) providerDevOverrideRuntimeWarnings() tfdiags.Diagnostics { if len(m.ProviderDevOverrides) == 0 { return nil } diff --git a/command/validate.go b/command/validate.go index 6519a5db9b..687bbb8c8d 100644 --- a/command/validate.go +++ b/command/validate.go @@ -81,7 +81,7 @@ func (c *ValidateCommand) Run(args []string) int { // not be valid for a stable release, so we'll warn about that in case // the user is trying to use "terraform validate" as a sort of pre-flight // check before submitting a change. - diags = diags.Append(c.providerDevOverrideWarnings()) + diags = diags.Append(c.providerDevOverrideRuntimeWarnings()) return c.showResults(diags, jsonOutput) }