Merge pull request #32695 from hashicorp/radditude/init-config-warning

keep errors friendly when init encounters syntax problems
This commit is contained in:
CJ Horton 2023-02-21 16:09:05 -08:00 committed by GitHub
commit 3c54e42080
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 128 additions and 6 deletions

View File

@ -244,14 +244,28 @@ func (c *InitCommand) Run(args []string) int {
return 1
}
// If the core version is OK, show any underlying config errors uncovered when initializing
// the backend.
diags = diags.Append(backDiags)
if backDiags.HasErrors() {
c.showDiagnostics(diags)
return 1
// If we pass the core version check, we want to show any errors from initializing the backend next,
// which will include syntax errors from loading the configuration. However, there's a special case
// where we are unable to load the backend from configuration or state _and_ the configuration has
// errors. In that case, we want to show a slightly friendlier error message for newcomers.
showBackendDiags := back != nil || rootModEarly.Backend != nil || rootModEarly.CloudConfig != nil
if showBackendDiags {
diags = diags.Append(backDiags)
if backDiags.HasErrors() {
c.showDiagnostics(diags)
return 1
}
} else {
diags = diags.Append(earlyConfDiags)
if earlyConfDiags.HasErrors() {
c.Ui.Error(strings.TrimSpace(errInitConfigError))
c.showDiagnostics(diags)
return 1
}
}
// If everything is ok with the core version check and backend initialization,
// show other errors from loading the full configuration tree.
diags = diags.Append(confDiags)
if confDiags.HasErrors() {
c.Ui.Error(strings.TrimSpace(errInitConfigError))

View File

@ -18,6 +18,7 @@ import (
"github.com/zclconf/go-cty/cty"
"github.com/hashicorp/go-version"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/configs"
"github.com/hashicorp/terraform/internal/configs/configschema"
@ -2620,6 +2621,96 @@ func TestInit_invalidBuiltInProviders(t *testing.T) {
}
}
func TestInit_invalidSyntaxNoBackend(t *testing.T) {
td := t.TempDir()
testCopyDir(t, testFixturePath("init-syntax-invalid-no-backend"), td)
defer testChdir(t, td)()
ui := cli.NewMockUi()
view, _ := testView(t)
m := Meta{
Ui: ui,
View: view,
}
c := &InitCommand{
Meta: m,
}
if code := c.Run(nil); code == 0 {
t.Fatalf("succeeded, but was expecting error\nstdout:\n%s\nstderr:\n%s", ui.OutputWriter, ui.ErrorWriter)
}
errStr := ui.ErrorWriter.String()
if subStr := "There are some problems with the configuration, described below"; !strings.Contains(errStr, subStr) {
t.Errorf("Error output should include preamble\nwant substr: %s\ngot:\n%s", subStr, errStr)
}
if subStr := "Error: Unsupported block type"; !strings.Contains(errStr, subStr) {
t.Errorf("Error output should mention the syntax problem\nwant substr: %s\ngot:\n%s", subStr, errStr)
}
}
func TestInit_invalidSyntaxWithBackend(t *testing.T) {
td := t.TempDir()
testCopyDir(t, testFixturePath("init-syntax-invalid-with-backend"), td)
defer testChdir(t, td)()
ui := cli.NewMockUi()
view, _ := testView(t)
m := Meta{
Ui: ui,
View: view,
}
c := &InitCommand{
Meta: m,
}
if code := c.Run(nil); code == 0 {
t.Fatalf("succeeded, but was expecting error\nstdout:\n%s\nstderr:\n%s", ui.OutputWriter, ui.ErrorWriter)
}
errStr := ui.ErrorWriter.String()
if subStr := "There are some problems with the configuration, described below"; !strings.Contains(errStr, subStr) {
t.Errorf("Error output should include preamble\nwant substr: %s\ngot:\n%s", subStr, errStr)
}
if subStr := "Error: Unsupported block type"; !strings.Contains(errStr, subStr) {
t.Errorf("Error output should mention the syntax problem\nwant substr: %s\ngot:\n%s", subStr, errStr)
}
}
func TestInit_invalidSyntaxInvalidBackend(t *testing.T) {
td := t.TempDir()
testCopyDir(t, testFixturePath("init-syntax-invalid-backend-invalid"), td)
defer testChdir(t, td)()
ui := cli.NewMockUi()
view, _ := testView(t)
m := Meta{
Ui: ui,
View: view,
}
c := &InitCommand{
Meta: m,
}
if code := c.Run(nil); code == 0 {
t.Fatalf("succeeded, but was expecting error\nstdout:\n%s\nstderr:\n%s", ui.OutputWriter, ui.ErrorWriter)
}
errStr := ui.ErrorWriter.String()
if subStr := "There are some problems with the configuration, described below"; strings.Contains(errStr, subStr) {
t.Errorf("Error output should not include preamble\nwant substr: %s\ngot:\n%s", subStr, errStr)
}
if subStr := "Error: Unsupported block type"; strings.Contains(errStr, subStr) {
t.Errorf("Error output should not mention syntax errors\nwant substr: %s\ngot:\n%s", subStr, errStr)
}
if subStr := "Error: Unsupported backend type"; !strings.Contains(errStr, subStr) {
t.Errorf("Error output should mention the invalid backend\nwant substr: %s\ngot:\n%s", subStr, errStr)
}
}
// newMockProviderSource is a helper to succinctly construct a mock provider
// source that contains a set of packages matching the given provider versions
// that are available for installation (from temporary local files).

View File

@ -0,0 +1,7 @@
terraform {
backend "nonexistent" {}
}
bad_block {
}

View File

@ -0,0 +1,3 @@
bad_block {
}

View File

@ -0,0 +1,7 @@
terraform {
backend "local" {}
}
bad_block {
}