diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 76e78365..1db82c42 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -9,6 +9,15 @@ exclude: \.+.terraform\/.*$ require_serial: true +- id: opentofu-fmt + name: Terraform fmt + description: Rewrites all Terraform configuration files to a canonical format + entry: hooks/opentofu-fmt.sh + language: script + files: \.tf$ + exclude: \.+.terraform\/.*$ + require_serial: true + - id: terraform-validate name: Terraform validate description: Validates all Terraform configuration files @@ -18,6 +27,15 @@ exclude: \.+.terraform\/.*$ require_serial: true +- id: opentofu-validate + name: OpenTofu validate + description: Validates all Terraform configuration files + entry: hooks/opentofu-validate.sh + language: script + files: \.tf$ + exclude: \.+.terraform\/.*$ + require_serial: true + - id: packer-validate name: Packer validate description: Validates all Packer configuration files diff --git a/README.md b/README.md index 79d6d29a..ad36f5d2 100644 --- a/README.md +++ b/README.md @@ -5,25 +5,23 @@ This repo defines Git pre-commit hooks intended for use with [pre-commit](http://pre-commit.com/). The currently supported hooks are: -* **terraform-fmt**: Automatically run `terraform fmt` on all Terraform code (`*.tf` files). -* **terraform-validate**: Automatically run `terraform validate` on all Terraform code (`*.tf` files). -* **packer-validate**: Automatically run `packer validate` on all Packer code (`*.pkr.*` files). -* **terragrunt-hclfmt**: Automatically run `terragrunt hclfmt` on all Terragrunt configurations. -* **tflint**: Automatically run [`tflint`](https://github.com/terraform-linters/tflint) on all Terraform code (`*.tf` files). -* **shellcheck**: Run [`shellcheck`](https://www.shellcheck.net/) to lint files that contain a bash [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)). -* **gofmt**: Automatically run `gofmt` on all Golang code (`*.go` files). -* **goimports**: Automatically run `goimports` on all Golang code (`*.go` files). -* **golint**: Automatically run `golint` on all Golang code (`*.go` files). [**DEPRECATED**]: Please use `golangci-lint` below. -* **golangci-lint**: Automatically run `golangci-lint` on all Golang code (`*.go` files). -* **yapf**: Automatically run [`yapf`](https://github.com/google/yapf) on all python code (`*.py` files). -* **helmlint** Automatically run [`helm lint`](https://helm.sh/docs/helm/helm_lint/) on your Helm chart files. [See caveats here](#helm-lint-caveats). -* **markdown-link-check** Automatically run [markdown-link-check](https://github.com/tcort/markdown-link-check) on +- **terraform-fmt**: Automatically run `terraform fmt` on all Terraform code (`*.tf` files). +- **opentofu-fmt**: Automatically run `tofu fmt` on all OpenTofu code (`*.tf` files). +- **terraform-validate**: Automatically run `terraform validate` on all Terraform code (`*.tf` files). +- **opentofu-validate**: Automatically run `tofu validate` on all Terraform code (`*.tf` files). +- **packer-validate**: Automatically run `packer validate` on all Packer code (`*.pkr.*` files). +- **terragrunt-hclfmt**: Automatically run `terragrunt hclfmt` on all Terragrunt configurations. +- **tflint**: Automatically run [`tflint`](https://github.com/terraform-linters/tflint) on all Terraform code (`*.tf` files). +- **shellcheck**: Run [`shellcheck`](https://www.shellcheck.net/) to lint files that contain a bash [shebang](). +- **gofmt**: Automatically run `gofmt` on all Golang code (`*.go` files). +- **goimports**: Automatically run `goimports` on all Golang code (`*.go` files). +- **golint**: Automatically run `golint` on all Golang code (`*.go` files). [**DEPRECATED**]: Please use `golangci-lint` below. +- **golangci-lint**: Automatically run `golangci-lint` on all Golang code (`*.go` files). +- **yapf**: Automatically run [`yapf`](https://github.com/google/yapf) on all python code (`*.py` files). +- **helmlint** Automatically run [`helm lint`](https://helm.sh/docs/helm/helm_lint/) on your Helm chart files. [See caveats here](#helm-lint-caveats). +- **markdown-link-check** Automatically run [markdown-link-check](https://github.com/tcort/markdown-link-check) on markdown doc files. -* **sentinel-fmt**: Automatically run `sentinel fmt` on all Sentinel code (`*.sentinel.*` files). - - - - +- **sentinel-fmt**: Automatically run `sentinel fmt` on all Sentinel code (`*.sentinel.*` files). ## General Usage @@ -42,19 +40,30 @@ repos: - id: golint ``` -Next, have every developer:  +for OpenTofu users: + +```yaml +repos: + - repo: https://github.com/gruntwork-io/pre-commit + rev: # Get the latest from: https://github.com/gruntwork-io/pre-commit/releases + hooks: + - id: opentofu-fmt + - id: opentofu-validate + - id: tflint + - id: shellcheck + - id: gofmt + - id: golint +``` + +Next, have every developer: 1. Install [pre-commit](http://pre-commit.com/). E.g. `brew install pre-commit`. 1. Run `pre-commit install` in the repo. That’s it! Now every time you commit a code change (`.tf` file), the hooks in the `hooks:` config will execute. - - - ## Running Against All Files At Once - ### Example: Formatting all files If you'd like to format all of your code at once (rather than one file at a time), you can run: @@ -63,8 +72,6 @@ If you'd like to format all of your code at once (rather than one file at a time pre-commit run terraform-fmt --all-files ``` - - ### Example: Enforcing in CI If you'd like to enforce all your hooks, you can configure your CI build to fail if the code doesn't pass checks by @@ -79,9 +86,6 @@ pre-commit run --all-files If all the hooks pass, the last command will exit with an exit code of 0. If any of the hooks make changes (e.g., because files are not formatted), the last command will exit with a code of 1, causing the build to fail. - - - ## Helm Lint Caveats ### Detecting charts @@ -150,8 +154,8 @@ repos: ### Using the `--config` argument With the introduction of `--chdir` into tflint, the `--config` argument is now bound to whatever subdirectory you are -running the check against. For mono-repos this isn't ideal as you may have a central configuration file you'd like to -use. If this matches your use-case, you can specify the placeholder `__GIT_DIR__` value in the `--config` argument +running the check against. For mono-repos this isn't ideal as you may have a central configuration file you'd like to +use. If this matches your use-case, you can specify the placeholder `__GIT_DIR__` value in the `--config` argument that will evaluate to the root of the repository you are in. ```yaml @@ -159,9 +163,9 @@ repos: - repo: https://github.com/gruntwork-io/pre-commit rev: hooks: - - id: tflint - args: - - "--config=__GIT_DIR__/.tflint.hcl" + - id: tflint + args: + - "--config=__GIT_DIR__/.tflint.hcl" ``` #### Changing the placeholder value diff --git a/hooks/opentofu-fmt.sh b/hooks/opentofu-fmt.sh new file mode 100755 index 00000000..c0af20c8 --- /dev/null +++ b/hooks/opentofu-fmt.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +set -e + +# OSX GUI apps do not pick up environment variables the same way as Terminal apps and there are no easy solutions, +# especially as Apple changes the GUI app behavior every release (see https://stackoverflow.com/q/135688/483528). As a +# workaround to allow GitHub Desktop to work, add this (hopefully harmless) setting here. +original_path=$PATH +export PATH=$PATH:/usr/local/bin + +# Store and return last failure from fmt so this can validate every directory passed before exiting +FMT_ERROR=0 + +for file in "$@"; do + tofu fmt -diff "$file" || FMT_ERROR=$? +done + +# reset path to the original value +export PATH=$original_path + +exit ${FMT_ERROR} diff --git a/hooks/opentofu-validate.sh b/hooks/opentofu-validate.sh new file mode 100755 index 00000000..510eec7b --- /dev/null +++ b/hooks/opentofu-validate.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +set -e + +# OSX GUI apps do not pick up environment variables the same way as Terminal apps and there are no easy solutions, +# especially as Apple changes the GUI app behavior every release (see https://stackoverflow.com/q/135688/483528). As a +# workaround to allow GitHub Desktop to work, add this (hopefully harmless) setting here. +export PATH=$PATH:/usr/local/bin + +# Disable output not usually helpful when running in automation (such as guidance to run plan after init) +export TF_IN_AUTOMATION=1 + +# Store and return last failure from validate so this can validate every directory passed before exiting +VALIDATE_ERROR=0 + +for dir in $(echo "$@" | xargs -n1 dirname | sort -u | uniq); do + echo "--> Running 'openTofu validate' in directory '$dir'" + pushd "$dir" >/dev/null + tofu init -backend=false || VALIDATE_ERROR=$? + tofu validate || VALIDATE_ERROR=$? + popd >/dev/null +done + +exit ${VALIDATE_ERROR}