diff --git a/README.md b/README.md index fac045ae5..b39066b79 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ ### Step 1 -On MacOSX install the pre-commit package +On MacOSX install the `pre-commit` and `awk` (required for Terraform 0.12) package ```bash -brew install pre-commit +brew install pre-commit awk ``` For other operating systems check the [official documentation](http://pre-commit.com/#install) @@ -21,10 +21,10 @@ Step into the repository you want to have the pre-commit hooks installed and run ```bash cat < .pre-commit-config.yaml - repo: git://github.com/antonbabenko/pre-commit-terraform - rev: v1.12.0 + rev: v1.13.0 hooks: - id: terraform_fmt - # - id: terraform_docs # terraform-docs is not working with Terraform 0.12 yet (read note in README) + - id: terraform_docs EOF ``` @@ -73,7 +73,7 @@ Check the [source file](https://github.com/antonbabenko/pre-commit-terraform/blo 1. It is possible to pass additional arguments to shell scripts when using `terraform_docs` and `terraform_docs_without_aggregate_type_defaults`. Send pull-request with the new hook if there is something missing. -1. `terraform-docs` is not working with Terraform 0.12 yet (see [issue #62](https://github.com/segmentio/terraform-docs/issues/62)), so remember to disable `terraform_docs`, `terraform_docs_replace` and `terraform_docs_without_aggregate_type_defaults` hooks in your `.pre-commit-config.yaml` +1. `terraform-docs` works with Terraform 0.12 but support is hackish (it requires `awk` to be installed) and may contain bugs. You can follow the native support of Terraform 0.12 in `terraform-docs` in [issue #62](https://github.com/segmentio/terraform-docs/issues/62). ## Notes for developers diff --git a/terraform_docs.sh b/terraform_docs.sh index 1bd79627a..191a4a2bd 100755 --- a/terraform_docs.sh +++ b/terraform_docs.sh @@ -25,12 +25,25 @@ main() { esac done - terraform_docs "$args" "$files" + local hack_terraform_docs=$(terraform version | head -1 | grep -c 0.12) + + if [[ "$hack_terraform_docs" == "1" ]]; then + which awk 2>&1 >/dev/null || ( echo "awk is required for terraform-docs hack to work with Terraform 0.12"; exit 1) + + TMP_AWK_FILE="$(mktemp --tmpdir terraform-docs-XXXXXXXXXX.awk)" + terraform_docs_awk $TMP_AWK_FILE + terraform_docs "$TMP_AWK_FILE" "$args" "$files" + rm -f "$TMP_AWK_FILE" + else + terraform_docs "0" "$args" "$files" + fi + } terraform_docs() { - readonly args="$1" - readonly files="$2" + readonly terraform_docs_awk_file="$1" + readonly args="$2" + readonly files="$3" declare -a paths declare -a tfvars_files @@ -62,7 +75,14 @@ terraform_docs() { continue fi + if [[ "$terraform_docs_awk_file" == "0" ]]; then terraform-docs $args md ./ > "$tmp_file" + else + TMP_FILE="$(mktemp --tmpdir terraform-docs-XXXXXXXXXX.tf)" + awk -f "$terraform_docs_awk_file" ./*.tf > "$TMP_FILE" + terraform-docs $args md "$TMP_FILE" > "$tmp_file" + rm -f "$TMP_FILE" + fi # Replace content between markers with the placeholder - https://stackoverflow.com/questions/1212799/how-do-i-extract-lines-between-two-line-delimiters-in-perl#1212834 perl -i -ne 'if (/BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK/../END OF PRE-COMMIT-TERRAFORM DOCS HOOK/) { print $_ if /BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK/; print "I_WANT_TO_BE_REPLACED\n$_" if /END OF PRE-COMMIT-TERRAFORM DOCS HOOK/;} else { print $_ }' "$text_file" @@ -76,6 +96,93 @@ terraform_docs() { done } +terraform_docs_awk() { + readonly output_file=$1 + + cat <<"EOF" > $output_file +# This script converts Terraform 0.12 variables/outputs to something suitable for `terraform-docs` +# As of terraform-docs v0.6.0, HCL2 is not supported. This script is a *dirty hack* to get around it. +# https://github.com/segmentio/terraform-docs/ +# https://github.com/segmentio/terraform-docs/issues/62 + +{ + if ( /\{/ ) { + braceCnt++ + } + + if ( /\}/ ) { + braceCnt-- + } + + # [START] variable or output block started + if ($0 ~ /(variable|output) "(.*?)"/) { + # [CLOSE] "default" block + if (blockDefCnt > 0) { + blockDefCnt = 0 + } + blockCnt++ + print $0 + } + + # [START] multiline default statement started + if (blockCnt > 0) { + if ($1 == "default") { + print $0 + if ($NF ~ /[\[\(\{]/) { + blockDefCnt++ + blockDefStart=1 + } + } + } + + # [PRINT] single line "description" + if (blockDefCnt == 0) { + if ($1 == "description") { + # [CLOSE] "default" block + if (blockDefCnt > 0) { + blockDefCnt = 0 + } + print $0 + } + } + + # [PRINT] single line "type" + if (blockCnt > 0) { + if ($1 == "type" ) { + # [CLOSE] "default" block + if (blockDefCnt > 0) { + blockDefCnt = 0 + } + type=$3 + if (type ~ "object") { + print " type = \"object\"" + } else { + print " type = \"" $3 "\"" + } + } + } + + # [CLOSE] variable/output block + if (blockCnt > 0) { + if (braceCnt == 0 && blockCnt > 0) { + blockCnt-- + print $0 + } + } + + # [PRINT] Multiline "default" statement + if (blockCnt > 0 && blockDefCnt > 0) { + if (blockDefStart == 1) { + blockDefStart = 0 + } else { + print $0 + } + } +} +EOF + +} + getopt() { # pure-getopt, a drop-in replacement for GNU getopt in pure Bash. # version 1.4.3