Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add error for missing variable #57

Merged
merged 2 commits into from
Aug 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions tfexec/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,13 @@ func (tf *Terraform) runTerraformCmd(cmd *exec.Cmd) error {

stdout := tf.stdout
if cmd.Stdout != nil {
stdout = io.MultiWriter(cmd.Stdout, stdout)
stdout = io.MultiWriter(stdout, cmd.Stdout)
}
cmd.Stdout = stdout

stderr := io.MultiWriter(&errBuf, tf.stderr)
if cmd.Stderr != nil {
stderr = io.MultiWriter(cmd.Stderr, stderr)
stderr = io.MultiWriter(stderr, cmd.Stderr)
}
cmd.Stderr = stderr

Expand Down
46 changes: 36 additions & 10 deletions tfexec/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@ import (
"fmt"
"os/exec"
"regexp"
"strings"
)

var (
// The "Required variable not set:" case is for 0.11
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved these out here so that the bad regexp panic happens at init time, and not at error parse time.

missingVarErrRegexp = regexp.MustCompile(`Error: No value for required variable|Error: Required variable not set:`)
missingVarNameRegexp = regexp.MustCompile(`The root module input variable "(.+)" is not set, and has no default|Error: Required variable not set: (.+)`)

usageRegexp = regexp.MustCompile(`Too many command line arguments|^Usage: .*Options:.*|Error: Invalid -\d+ option`)

// "Could not load plugin" is present in 0.13
noInitErrRegexp = regexp.MustCompile(`Error: Could not satisfy plugin requirements|Error: Could not load plugin`)

noConfigErrRegexp = regexp.MustCompile(`Error: No configuration files`)
)

func parseError(err error, stderr string) error {
Expand All @@ -13,16 +27,22 @@ func parseError(err error, stderr string) error {
}

switch {
// case ErrTerraformNotFound.regexp.MatchString(stderr):
// return ErrTerraformNotFound
case regexp.MustCompile(usageRegexp).MatchString(stderr):
case missingVarErrRegexp.MatchString(stderr):
name := ""
names := missingVarNameRegexp.FindStringSubmatch(stderr)
for i := 1; i < len(names); i++ {
name = strings.TrimSpace(names[i])
if name != "" {
break
}
}

return &ErrMissingVar{name}
case usageRegexp.MatchString(stderr):
return &ErrCLIUsage{stderr: stderr}
case regexp.MustCompile(`Error: Could not satisfy plugin requirements`).MatchString(stderr):
return &ErrNoInit{stderr: stderr}
case regexp.MustCompile(`Error: Could not load plugin`).MatchString(stderr):
// this string is present in 0.13
case noInitErrRegexp.MatchString(stderr):
return &ErrNoInit{stderr: stderr}
case regexp.MustCompile(`Error: No configuration files`).MatchString(stderr):
case noConfigErrRegexp.MatchString(stderr):
return &ErrNoConfig{stderr: stderr}
default:
return errors.New(stderr)
Expand Down Expand Up @@ -77,8 +97,6 @@ type ErrCLIUsage struct {
stderr string
}

var usageRegexp = `Too many command line arguments|^Usage: .*Options:.*|Error: Invalid -\d+ option`

func (e *ErrCLIUsage) Error() string {
return e.stderr
}
Expand All @@ -92,3 +110,11 @@ type ErrManualEnvVar struct {
func (err *ErrManualEnvVar) Error() string {
return fmt.Sprintf("manual setting of env var %q detected", err.name)
}

type ErrMissingVar struct {
VariableName string
}

func (err *ErrMissingVar) Error() string {
return fmt.Sprintf("variable %q was required but not supplied", err.VariableName)
}
27 changes: 27 additions & 0 deletions tfexec/internal/e2etest/errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,30 @@ func TestUnparsedError(t *testing.T) {
}
})
}

func TestMissingVar(t *testing.T) {
runTest(t, "var", func(t *testing.T, tfv *version.Version, tf *tfexec.Terraform) {
err := tf.Init(context.Background())
if err != nil {
t.Fatalf("err during init: %s", err)
}

err = tf.Plan(context.Background())
if err == nil {
t.Fatalf("expected error running Plan, none returned")
}
var e *tfexec.ErrMissingVar
if !errors.As(err, &e) {
t.Fatalf("expected ErrMissingVar, got %T, %s", err, err)
}

if e.VariableName != "no_default" {
t.Fatalf("expected missing no_default, got %q", e.VariableName)
}

err = tf.Plan(context.Background(), tfexec.Var("no_default=foo"))
if err != nil {
t.Fatalf("expected no error, got %s", err)
}
})
}
6 changes: 6 additions & 0 deletions tfexec/internal/e2etest/testdata/var/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
variable "default" {
default = "foo"
}

variable "no_default" {
}
3 changes: 2 additions & 1 deletion tfexec/internal/e2etest/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"

"github.com/hashicorp/go-version"
Expand Down Expand Up @@ -62,7 +63,7 @@ func runTestVersions(t *testing.T, versions []string, fixtureName string, cb fun
}
}

var stdouterr bytes.Buffer
var stdouterr strings.Builder
tf.SetStdout(&stdouterr)
tf.SetStderr(&stdouterr)

Expand Down