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

feat: New Python-based terraform_fmt hook to better support Windows #652

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
@@ -1 +1,3 @@
tests/results/*
__pycache__/
*.py[cod]
8 changes: 8 additions & 0 deletions .pre-commit-hooks.yaml
Expand Up @@ -15,6 +15,14 @@
files: (\.tf|\.tfvars)$
exclude: \.terraform/.*$

- id: terraform_fmt_py
name: Terraform fmt
description: Rewrites all Terraform configuration files to a canonical format.
entry: terraform_fmt
language: python
files: \.tf(vars)?$
exclude: \.terraform/.*$

- id: terraform_docs
name: Terraform docs
description: Inserts input and output documentation into README.md (using terraform-docs).
Expand Down
4 changes: 0 additions & 4 deletions hooks/__init__.py
@@ -1,4 +0,0 @@
print(
'`terraform_docs_replace` hook is DEPRECATED.'
'For migration instructions see https://github.com/antonbabenko/pre-commit-terraform/issues/248#issuecomment-1290829226'
)
61 changes: 61 additions & 0 deletions hooks/common.py
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's start a PR scope thread here:

How much do we want to be implemented in this PR?

1.1. Current common functional "as is"
1.2. Full common functional parity

2.1. Just terraform_fmt
2.2. All hooks fully which fully based on common functional

Choose one from 1. and 2.
The current state is 1.1. + 2.1.

Copy link
Collaborator

Choose a reason for hiding this comment

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

1.1 + 2.1 (+ each hook to be re-implemented with Python in scope of a separate PR)

ps: I don't get the difference between 1.1 and 1.2 to be honest... 🤷🏻

Copy link
Collaborator

Choose a reason for hiding this comment

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

@@ -0,0 +1,61 @@
from __future__ import annotations

import argparse
import logging
import os
from collections.abc import Sequence

logger = logging.getLogger(__name__)


def setup_logging():
logging.basicConfig(
level={
"error": logging.ERROR,
"warn": logging.WARNING,
"warning": logging.WARNING,
"info": logging.INFO,
"debug": logging.DEBUG,
}[os.environ.get("PRE_COMMIT_TERRAFORM_LOG_LEVEL", "warning").lower()]
)


def parse_env_vars(env_var_strs: list[str]) -> dict[str, str]:
ret = {}
for env_var_str in env_var_strs:
name, val = env_var_str.split("=", 1)
if val.startswith('"') and val.endswith('"'):
val = val[1:-1]
ret[name] = val
return ret


def parse_cmdline(
argv: Sequence[str] | None = None,
) -> tuple[list[str], list[str], list[str], list[str], dict[str, str]]:
parser = argparse.ArgumentParser(
add_help=False, # Allow the use of `-h` for compatiblity with Bash version of the hook
)
parser.add_argument("-a", "--args", action="append", help="Arguments")
parser.add_argument("-h", "--hook-config", action="append", help="Hook Config")
parser.add_argument("-i", "--init-args", "--tf-init-args", action="append", help="Init Args")
parser.add_argument("-e", "--envs", "--env-vars", action="append", help="Environment Variables")
parser.add_argument("FILES", nargs="*", help="Files")

parsed_args = parser.parse_args(argv)

args = parsed_args.args or []
hook_config = parsed_args.hook_config or []
files = parsed_args.FILES or []
tf_init_args = parsed_args.init_args or []
env_vars = parsed_args.envs or []

env_var_dict = parse_env_vars(env_vars)

if hook_config:
raise NotImplementedError("TODO: implement: hook_config")

if tf_init_args:
raise NotImplementedError("TODO: implement: tf_init_args")

return args, hook_config, files, tf_init_args, env_var_dict
5 changes: 5 additions & 0 deletions hooks/terraform_docs_replace.py
Expand Up @@ -3,6 +3,11 @@
import subprocess
import sys

print(
'`terraform_docs_replace` hook is DEPRECATED.'
'For migration instructions see https://github.com/antonbabenko/pre-commit-terraform/issues/248#issuecomment-1290829226'
)


def main(argv=None):
parser = argparse.ArgumentParser(
Expand Down
32 changes: 32 additions & 0 deletions hooks/terraform_fmt.py
ericfrederich marked this conversation as resolved.
Show resolved Hide resolved
@@ -0,0 +1,32 @@
from __future__ import annotations

import logging
import os
import shlex
import sys
from subprocess import PIPE, run
from typing import Sequence

from .common import parse_cmdline, setup_logging

logger = logging.getLogger(__name__)


def main(argv: Sequence[str] | None = None) -> int:
setup_logging()
logger.debug(sys.version_info)
args, hook_config, files, tf_init_args, env_vars = parse_cmdline(argv)
if os.environ.get("PRE_COMMIT_COLOR") == "never":
args.append("-no-color")
cmd = ["terraform", "fmt", *args, *files]
logger.info("calling %s", shlex.join(cmd))
logger.debug("env_vars: %r", env_vars)
logger.debug("args: %r", args)
completed_process = run(cmd, env={**os.environ, **env_vars}, text=True, stdout=PIPE)
if completed_process.stdout:
print(completed_process.stdout)
return completed_process.returncode


if __name__ == "__main__":
raise SystemExit(main())
1 change: 1 addition & 0 deletions setup.py
Expand Up @@ -28,6 +28,7 @@
entry_points={
'console_scripts': [
'terraform_docs_replace = hooks.terraform_docs_replace:main',
'terraform_fmt = hooks.terraform_fmt:main',
],
},
)