Skip to content

Commit

Permalink
Add --chdir option (#1612)
Browse files Browse the repository at this point in the history
* Add --chdir option

* Make the values file path relative to the changed directory

* Load config file in the changed directory
  • Loading branch information
wata727 authored Dec 12, 2022
1 parent 51b71ab commit 3a5be74
Show file tree
Hide file tree
Showing 33 changed files with 1,132 additions and 116 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,13 @@ Application Options:
--var-file=FILE Terraform variable file name
--var='foo=bar' Set a Terraform variable
--module Inspect modules
--chdir=DIR Switch to a different working directory before running inspection
--force Return zero exit status even if issues found
--color Enable colorized output
--no-color Disable colorized output
Help Options:
-h, --help Show this help message
```

See [User Guide](docs/user-guide) for details.
Expand Down
2 changes: 1 addition & 1 deletion cmd/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func (cli *CLI) Run(args []string) int {
case opts.Init:
return cli.init(opts)
case opts.Langserver:
return cli.startLanguageServer(opts.Config, opts.toConfig())
return cli.startLanguageServer(opts)
case opts.ActAsBundledPlugin:
return cli.actAsBundledPlugin()
default:
Expand Down
5 changes: 5 additions & 0 deletions cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import (
)

func (cli *CLI) init(opts Options) int {
if opts.Chdir != "" {
fmt.Fprintf(cli.errStream, "Cannot use --chdir with --init\n")
return ExitCodeError
}

cfg, err := tflint.LoadConfig(afero.Afero{Fs: afero.NewOsFs()}, opts.Config)
if err != nil {
cli.formatter.Print(tflint.Issues{}, fmt.Errorf("Failed to load TFLint config; %w", err), map[string][]byte{})
Expand Down
28 changes: 24 additions & 4 deletions cmd/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"fmt"
"os"
"strings"

"github.com/hashicorp/hcl/v2"
Expand All @@ -15,6 +16,25 @@ import (
)

func (cli *CLI) inspect(opts Options, dir string, filterFiles []string) int {
// Switch to a different working directory
originalWd, err := os.Getwd()
if err != nil {
cli.formatter.Print(tflint.Issues{}, fmt.Errorf("Failed to determine current working directory; %w", err), map[string][]byte{})
return ExitCodeError
}
if opts.Chdir != "" {
if dir != "." {
cli.formatter.Print(tflint.Issues{}, fmt.Errorf("Cannot use --chdir and directory argument at the same time"), map[string][]byte{})
return ExitCodeError
}

err := os.Chdir(opts.Chdir)
if err != nil {
cli.formatter.Print(tflint.Issues{}, fmt.Errorf("Failed to switch to a different working directory; %w", err), map[string][]byte{})
return ExitCodeError
}
}

// Setup config
cfg, err := tflint.LoadConfig(afero.Afero{Fs: afero.NewOsFs()}, opts.Config)
if err != nil {
Expand All @@ -32,14 +52,14 @@ func (cli *CLI) inspect(opts Options, dir string, filterFiles []string) int {
cli.formatter.Format = cfg.Format

// Setup loader
cli.loader, err = terraform.NewLoader(afero.Afero{Fs: afero.NewOsFs()})
cli.loader, err = terraform.NewLoader(afero.Afero{Fs: afero.NewOsFs()}, originalWd)
if err != nil {
cli.formatter.Print(tflint.Issues{}, fmt.Errorf("Failed to prepare loading; %w", err), map[string][]byte{})
return ExitCodeError
}

// Setup runners
runners, appErr := cli.setupRunners(opts, cfg, dir)
runners, appErr := cli.setupRunners(opts, cfg, originalWd, dir)
if appErr != nil {
cli.formatter.Print(tflint.Issues{}, appErr, cli.loader.Sources())
return ExitCodeError
Expand Down Expand Up @@ -129,7 +149,7 @@ func (cli *CLI) inspect(opts Options, dir string, filterFiles []string) int {
return ExitCodeOK
}

func (cli *CLI) setupRunners(opts Options, cfg *tflint.Config, dir string) ([]*tflint.Runner, error) {
func (cli *CLI) setupRunners(opts Options, cfg *tflint.Config, originalWd string, dir string) ([]*tflint.Runner, error) {
configs, diags := cli.loader.LoadConfig(dir, cfg.Module)
if diags.HasErrors() {
return []*tflint.Runner{}, fmt.Errorf("Failed to load configurations; %w", diags)
Expand Down Expand Up @@ -162,7 +182,7 @@ func (cli *CLI) setupRunners(opts Options, cfg *tflint.Config, dir string) ([]*t
}
variables = append(variables, cliVars)

runner, err := tflint.NewRunner(cfg, annotations, configs, variables...)
runner, err := tflint.NewRunner(originalWd, cfg, annotations, configs, variables...)
if err != nil {
return []*tflint.Runner{}, fmt.Errorf("Failed to initialize a runner; %w", err)
}
Expand Down
11 changes: 9 additions & 2 deletions cmd/langserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,22 @@ package cmd

import (
"context"
"fmt"
"log"
"os"

"github.com/sourcegraph/jsonrpc2"
"github.com/terraform-linters/tflint/langserver"
"github.com/terraform-linters/tflint/tflint"
)

func (cli *CLI) startLanguageServer(configPath string, cliConfig *tflint.Config) int {
func (cli *CLI) startLanguageServer(opts Options) int {
if opts.Chdir != "" {
fmt.Fprintf(cli.errStream, "Cannot use --chdir with --langserver\n")
return ExitCodeError
}
configPath := opts.Config
cliConfig := opts.toConfig()

log.Println("Starting language server...")

handler, plugin, err := langserver.NewHandler(configPath, cliConfig)
Expand Down
1 change: 1 addition & 0 deletions cmd/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Options struct {
Varfiles []string `long:"var-file" description:"Terraform variable file name" value-name:"FILE"`
Variables []string `long:"var" description:"Set a Terraform variable" value-name:"'foo=bar'"`
Module bool `long:"module" description:"Inspect modules"`
Chdir string `long:"chdir" description:"Switch to a different working directory before running inspection" value-name:"DIR"`
Force bool `long:"force" description:"Return zero exit status even if issues found"`
Color bool `long:"color" description:"Enable colorized output"`
NoColor bool `long:"no-color" description:"Disable colorized output"`
Expand Down
5 changes: 5 additions & 0 deletions cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import (
)

func (cli *CLI) printVersion(opts Options) int {
if opts.Chdir != "" {
fmt.Fprintf(cli.errStream, "Cannot use --chdir with --version\n")
return ExitCodeError
}

fmt.Fprintf(cli.outStream, "TFLint version %s\n", tflint.Version)

// Load configuration files to print plugin versions
Expand Down
14 changes: 14 additions & 0 deletions integrationtest/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,20 @@ func TestIntegration(t *testing.T) {
status: cmd.ExitCodeError,
stderr: fmt.Sprintf("Failed to load `%s`: Multiple files in different directories are not allowed", filepath.Join("subdir", "main.tf")),
},
{
name: "--chdir",
command: "./tflint --chdir subdir",
dir: "multiple_files",
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",
status: cmd.ExitCodeError,
stderr: "Cannot use --chdir and directory argument at the same time",
},
}

dir, _ := os.Getwd()
Expand Down
3 changes: 3 additions & 0 deletions integrationtest/cli/multiple_files/subdir/.tflint.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
plugin "testing" {
enabled = true
}
4 changes: 0 additions & 4 deletions integrationtest/inspection/bad-config/.tflint.hcl
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
plugin "testing" {
enabled = true
}

plugin "aws" {
enabled = false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"Modules":[{"Key":"","Source":"","Dir":"."},{"Key":"aws_instance","Source":"./module","Dir":"module"}]}
11 changes: 11 additions & 0 deletions integrationtest/inspection/chdir/dir/.tflint.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
plugin "testing" {
enabled = true
}

plugin "terraform" {
enabled = false
}

config {
varfile = ["from_config.tfvars"]
}
1 change: 1 addition & 0 deletions integrationtest/inspection/chdir/dir/dir.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
file_in_dir
1 change: 1 addition & 0 deletions integrationtest/inspection/chdir/dir/from_cli.tfvars
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from_cli="from_cli"
1 change: 1 addition & 0 deletions integrationtest/inspection/chdir/dir/from_config.tfvars
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from_config="from_config"
21 changes: 21 additions & 0 deletions integrationtest/inspection/chdir/dir/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
variable "from_config" {
default = "default"
}

variable "from_cli" {
default = "default"
}

variable "from_auto" {
default = "default"
}

variable "from_auto_default" {
default = "default"
}

module "aws_instance" {
source = "./module"

instance_type = "${var.from_config}-${var.from_cli}-${var.from_auto}-${var.from_auto_default}-${file("dir.txt")}-${file("${path.cwd}/root.txt")}"
}
5 changes: 5 additions & 0 deletions integrationtest/inspection/chdir/dir/module/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
variable "instance_type" {}

resource "aws_instance" "main" {
instance_type = var.instance_type
}
1 change: 1 addition & 0 deletions integrationtest/inspection/chdir/dir/subdir.auto.tfvars
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from_auto="from_auto"
1 change: 1 addition & 0 deletions integrationtest/inspection/chdir/dir/terraform.tfvars
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from_auto_default="from_auto_default"
48 changes: 48 additions & 0 deletions integrationtest/inspection/chdir/result.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"issues": [
{
"rule": {
"name": "aws_instance_example_type",
"severity": "error",
"link": ""
},
"message": "instance type is from_config-from_cli-from_auto-from_auto_default-file_in_dir-file_in_root",
"range": {
"filename": "dir/main.tf",
"start": {
"line": 20,
"column": 19
},
"end": {
"line": 20,
"column": 148
}
},
"callers": [
{
"filename": "dir/main.tf",
"start": {
"line": 20,
"column": 19
},
"end": {
"line": 20,
"column": 148
}
},
{
"filename": "dir/module/main.tf",
"start": {
"line": 4,
"column": 19
},
"end": {
"line": 4,
"column": 36
}
}
]
}
],
"errors": []
}
48 changes: 48 additions & 0 deletions integrationtest/inspection/chdir/result_windows.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"issues": [
{
"rule": {
"name": "aws_instance_example_type",
"severity": "error",
"link": ""
},
"message": "instance type is from_config-from_cli-from_auto-from_auto_default-file_in_dir-file_in_root",
"range": {
"filename": "dir\\main.tf",
"start": {
"line": 20,
"column": 19
},
"end": {
"line": 20,
"column": 148
}
},
"callers": [
{
"filename": "dir\\main.tf",
"start": {
"line": 20,
"column": 19
},
"end": {
"line": 20,
"column": 148
}
},
{
"filename": "dir\\module\\main.tf",
"start": {
"line": 4,
"column": 19
},
"end": {
"line": 4,
"column": 36
}
}
]
}
],
"errors": []
}
1 change: 1 addition & 0 deletions integrationtest/inspection/chdir/root.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
file_in_root
18 changes: 11 additions & 7 deletions integrationtest/inspection/inspection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,11 @@ func TestIntegration(t *testing.T) {
Command: "tflint --module --format json",
Dir: "expand",
},
{
Name: "chdir",
Command: "tflint --chdir dir --module --var-file from_cli.tfvars --format json",
Dir: "chdir",
},
}

// Disable the bundled plugin because the `os.Executable()` is go(1) in the tests
Expand All @@ -225,6 +230,11 @@ func TestIntegration(t *testing.T) {
t.Fatal(err)
}

resultFile := "result.json"
if runtime.GOOS == "windows" && IsWindowsResultExist() {
resultFile = "result_windows.json"
}

if tc.Env != nil {
for k, v := range tc.Env {
t.Setenv(k, v)
Expand All @@ -237,13 +247,7 @@ func TestIntegration(t *testing.T) {

cli.Run(args)

var b []byte
var err error
if runtime.GOOS == "windows" && IsWindowsResultExist() {
b, err = os.ReadFile(filepath.Join(testDir, "result_windows.json"))
} else {
b, err = os.ReadFile(filepath.Join(testDir, "result.json"))
}
b, err := os.ReadFile(filepath.Join(testDir, resultFile))
if err != nil {
t.Fatal(err)
}
Expand Down
4 changes: 2 additions & 2 deletions langserver/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ func (h *handler) chdir(dir string) error {
func (h *handler) inspect() (map[string][]lsp.Diagnostic, error) {
ret := map[string][]lsp.Diagnostic{}

loader, err := terraform.NewLoader(afero.Afero{Fs: h.fs})
loader, err := terraform.NewLoader(afero.Afero{Fs: h.fs}, h.rootDir)
if err != nil {
return ret, fmt.Errorf("Failed to prepare loading: %w", err)
}
Expand Down Expand Up @@ -177,7 +177,7 @@ func (h *handler) inspect() (map[string][]lsp.Diagnostic, error) {
}
variables = append(variables, cliVars)

runner, err := tflint.NewRunner(h.config, annotations, configs, variables...)
runner, err := tflint.NewRunner(h.rootDir, h.config, annotations, configs, variables...)
if err != nil {
return ret, fmt.Errorf("Failed to initialize a runner: %w", err)
}
Expand Down
Loading

0 comments on commit 3a5be74

Please sign in to comment.