diff --git a/cmd/cli.go b/cmd/cli.go index 952cfebf2..74e881287 100644 --- a/cmd/cli.go +++ b/cmd/cli.go @@ -88,11 +88,6 @@ func (cli *CLI) Run(args []string) int { cli.formatter.Print(tflint.Issues{}, fmt.Errorf("Failed to parse CLI options; %w", err), map[string][]byte{}) return ExitCodeError } - dir, filterFiles, err := processArgs(args[1:]) - if err != nil { - cli.formatter.Print(tflint.Issues{}, fmt.Errorf("Failed to parse CLI arguments; %w", err), map[string][]byte{}) - return ExitCodeError - } switch { case opts.Version: @@ -104,51 +99,8 @@ func (cli *CLI) Run(args []string) int { case opts.ActAsBundledPlugin: return cli.actAsBundledPlugin() default: - return cli.inspect(opts, dir, filterFiles) - } -} - -func processArgs(args []string) (string, []string, error) { - if len(args) == 0 { - return ".", []string{}, nil + return cli.inspect(opts, args) } - - var dir string - filterFiles := []string{} - - for _, file := range args { - fileInfo, err := os.Stat(file) - if err != nil { - if os.IsNotExist(err) { - return dir, filterFiles, fmt.Errorf("Failed to load `%s`: File not found", file) - } - return dir, filterFiles, fmt.Errorf("Failed to load `%s`: %s", file, err) - } - - if fileInfo.IsDir() { - dir = file - if len(args) != 1 { - return dir, filterFiles, fmt.Errorf("Failed to load `%s`: Multiple arguments are not allowed when passing a directory", file) - } - return dir, filterFiles, nil - } - - if !strings.HasSuffix(file, ".tf") && !strings.HasSuffix(file, ".tf.json") { - return dir, filterFiles, fmt.Errorf("Failed to load `%s`: File is not a target of Terraform", file) - } - - fileDir := filepath.Dir(file) - if dir == "" { - dir = fileDir - filterFiles = append(filterFiles, file) - } else if fileDir == dir { - filterFiles = append(filterFiles, file) - } else { - return dir, filterFiles, fmt.Errorf("Failed to load `%s`: Multiple files in different directories are not allowed", file) - } - } - - return dir, filterFiles, nil } func unknownOptionHandler(option string, arg flags.SplitArgument, args []string) ([]string, error) { diff --git a/cmd/inspect.go b/cmd/inspect.go index 2db265cb9..6ea187f3c 100644 --- a/cmd/inspect.go +++ b/cmd/inspect.go @@ -2,6 +2,8 @@ package cmd import ( "fmt" + "os" + "path/filepath" "strings" "github.com/hashicorp/hcl/v2" @@ -14,19 +16,10 @@ import ( "google.golang.org/grpc/status" ) -func (cli *CLI) inspect(opts Options, targetDir string, filterFiles []string) int { +func (cli *CLI) inspect(opts Options, args []string) int { // Respect the "--format" flag until a config is loaded cli.formatter.Format = opts.Format - if opts.Chdir != "" && targetDir != "." { - cli.formatter.Print(tflint.Issues{}, fmt.Errorf("Cannot use --chdir and directory argument at the same time"), map[string][]byte{}) - return ExitCodeError - } - if opts.Recursive && (targetDir != "." || len(filterFiles) > 0) { - cli.formatter.Print(tflint.Issues{}, fmt.Errorf("Cannot use --recursive and arguments at the same time"), map[string][]byte{}) - return ExitCodeError - } - workingDirs, err := findWorkingDirs(opts) if err != nil { cli.formatter.Print(tflint.Issues{}, fmt.Errorf("Failed to find workspaces; %w", err), map[string][]byte{}) @@ -37,6 +30,23 @@ func (cli *CLI) inspect(opts Options, targetDir string, filterFiles []string) in for _, wd := range workingDirs { err := cli.withinChangedDir(wd, func() error { + // Parse directory/file arguments after changing the working directory + targetDir, filterFiles, err := processArgs(args[1:]) + if err != nil { + return fmt.Errorf("Failed to parse CLI arguments; %w", err) + } + + if opts.Chdir != "" && targetDir != "." { + return fmt.Errorf("Cannot use --chdir and directory argument at the same time") + } + if opts.Recursive && (targetDir != "." || len(filterFiles) > 0) { + return fmt.Errorf("Cannot use --recursive and arguments at the same time") + } + + // Join with the working directory to create the fullpath + for i, file := range filterFiles { + filterFiles[i] = filepath.Join(wd, file) + } moduleIssues, err := cli.inspectModule(opts, targetDir, filterFiles) if err != nil { return err @@ -73,6 +83,49 @@ func (cli *CLI) inspect(opts Options, targetDir string, filterFiles []string) in return ExitCodeOK } +func processArgs(args []string) (string, []string, error) { + if len(args) == 0 { + return ".", []string{}, nil + } + + var dir string + filterFiles := []string{} + + for _, file := range args { + fileInfo, err := os.Stat(file) + if err != nil { + if os.IsNotExist(err) { + return dir, filterFiles, fmt.Errorf("Failed to load `%s`: File not found", file) + } + return dir, filterFiles, fmt.Errorf("Failed to load `%s`: %s", file, err) + } + + if fileInfo.IsDir() { + dir = file + if len(args) != 1 { + return dir, filterFiles, fmt.Errorf("Failed to load `%s`: Multiple arguments are not allowed when passing a directory", file) + } + return dir, filterFiles, nil + } + + if !strings.HasSuffix(file, ".tf") && !strings.HasSuffix(file, ".tf.json") { + return dir, filterFiles, fmt.Errorf("Failed to load `%s`: File is not a target of Terraform", file) + } + + fileDir := filepath.Dir(file) + if dir == "" { + dir = fileDir + filterFiles = append(filterFiles, file) + } else if fileDir == dir { + filterFiles = append(filterFiles, file) + } else { + return dir, filterFiles, fmt.Errorf("Failed to load `%s`: Multiple files in different directories are not allowed", file) + } + } + + return dir, filterFiles, nil +} + func (cli *CLI) inspectModule(opts Options, dir string, filterFiles []string) (tflint.Issues, error) { issues := tflint.Issues{} var err error diff --git a/integrationtest/cli/chdir/main.tf b/integrationtest/cli/chdir/main.tf new file mode 100644 index 000000000..b73b98751 --- /dev/null +++ b/integrationtest/cli/chdir/main.tf @@ -0,0 +1,3 @@ +resource "aws_instance" "main" { + instance_type = "t2.micro" +} diff --git a/integrationtest/cli/chdir/subdir/.tflint.hcl b/integrationtest/cli/chdir/subdir/.tflint.hcl new file mode 100644 index 000000000..e19f589dd --- /dev/null +++ b/integrationtest/cli/chdir/subdir/.tflint.hcl @@ -0,0 +1,3 @@ +plugin "testing" { + enabled = true +} diff --git a/integrationtest/cli/chdir/subdir/main.tf b/integrationtest/cli/chdir/subdir/main.tf new file mode 100644 index 000000000..95a956c68 --- /dev/null +++ b/integrationtest/cli/chdir/subdir/main.tf @@ -0,0 +1,3 @@ +resource "aws_instance" "main" { + instance_type = "m5.2xlarge" +} diff --git a/integrationtest/cli/chdir/subdir/nested/main.tf b/integrationtest/cli/chdir/subdir/nested/main.tf new file mode 100644 index 000000000..832d5642c --- /dev/null +++ b/integrationtest/cli/chdir/subdir/nested/main.tf @@ -0,0 +1,3 @@ +resource "aws_instance" "main" { + instance_type = "t2.nano" +} diff --git a/integrationtest/cli/cli_test.go b/integrationtest/cli/cli_test.go index 87ea8f8f0..8553de764 100644 --- a/integrationtest/cli/cli_test.go +++ b/integrationtest/cli/cli_test.go @@ -276,22 +276,43 @@ func TestIntegration(t *testing.T) { }, { name: "--chdir", - command: "./tflint --chdir subdir", - dir: "multiple_files", + command: "./tflint --chdir=subdir", + dir: "chdir", + status: cmd.ExitCodeIssuesFound, + stdout: fmt.Sprintf("%s (aws_instance_example_type)", color.New(color.Bold).Sprint("instance type is m5.2xlarge")), + }, + { + name: "--chdir and file argument", + command: "./tflint --chdir=subdir main.tf", + dir: "chdir", status: cmd.ExitCodeIssuesFound, stdout: fmt.Sprintf("%s (aws_instance_example_type)", color.New(color.Bold).Sprint("instance type is m5.2xlarge")), }, { name: "--chdir and directory argument", - command: "./tflint --chdir subdir ../", - dir: "multiple_files", + command: "./tflint --chdir=subdir ../", + dir: "chdir", status: cmd.ExitCodeError, stderr: "Cannot use --chdir and directory argument at the same time", }, { - name: "--recursive and arguments", + name: "--chdir and file under the directory argument", + command: fmt.Sprintf("./tflint --chdir=subdir %s", filepath.Join("nested", "main.tf")), + dir: "chdir", + status: cmd.ExitCodeError, + stderr: "Cannot use --chdir and directory argument at the same time", + }, + { + name: "--recursive and file argument", + command: "./tflint --recursive main.tf", + dir: "chdir", + status: cmd.ExitCodeError, + stderr: "Cannot use --recursive and arguments at the same time", + }, + { + name: "--recursive and directory argument", command: "./tflint --recursive subdir", - dir: "multiple_files", + dir: "chdir", status: cmd.ExitCodeError, stderr: "Cannot use --recursive and arguments at the same time", },