Skip to content

Commit 4bbedb4

Browse files
authored
Drop Terragrunt support and modernize Python codebase (#89)
* Refactor: remove Terragrunt support Strip out all Terragrunt-specific logic, arguments, and classes (e.g., TerragruntTest). Remove Terragrunt test fixtures and associated test files (test_tg_all.py). Clean up test_args.py to remove Terragrunt argument tests. Update README.md to remove the Terragrunt documentation. Going forward, this library will only support Terraform and OpenTofu. * Refactor: Python modernization - Remove legacy Python 2 future imports. - Migrate string formatting to f-strings via flynt. - Replace os.path usage with pathlib.Path. - Add comprehensive type hinting to TerraformTest and related methods. * Refactor: parse_args mapping Replaced long list of if/elif statements with declarative mappings (bool_flags, inverse_bool_flags, kv_flags) to simplify adding new flags and reduce cyclomatic complexity. * Chore: configure and apply yapf formatting Add .style.yapf using google style to match the Cloud Foundation Fabric repository. Apply yapf formatting across all python files. * Chore: update CI to use yapf for linting Replace autopep8 with yapf in the GitHub Actions linting workflow and DEV-REQUIREMENTS.txt to enforce the new Google-style formatting rules defined in .style.yapf. * Fix: format setup.py with yapf
1 parent 897f228 commit 4bbedb4

26 files changed

Lines changed: 291 additions & 502 deletions

.github/workflows/linting.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,5 @@ jobs:
4747
- name: Check python formatting
4848
id: lint
4949
run: |
50-
echo '[pep8]' > pep8
51-
echo 'indent-size = 2' >> pep8
52-
autopep8 --diff --global-config pep8 --recursive --exit-code \
50+
yapf --diff --recursive --parallel \
5351
*.py test

.style.yapf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[style]
2+
based_on_style=google
3+
indent_width=2
4+
split_before_named_assigns=false

DEV-REQUIREMENTS.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
autopep8>=2.0
1+
yapf>=0.40
22
pytest>=7.2

README.md

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -46,38 +46,6 @@ def test_modules(plan):
4646
assert res['values']['location'] == plan.variables['gcs_location']
4747
```
4848

49-
## Terragrunt support
50-
51-
Support for Terragrunt actually follows the same principle of the thin `TerraformTest` wrapper.
52-
53-
Please see the following example for how to use it:
54-
55-
```python
56-
import pytest
57-
import tftest
58-
59-
60-
@pytest.fixture
61-
def run_all_apply_out(fixtures_dir):
62-
# notice for run-all, you need to specify when TerragruntTest is constructed
63-
tg = tftest.TerragruntTest('tg_apply_all', fixtures_dir, tg_run_all=True)
64-
# the rest is very similar to how you use TerraformTest
65-
tg.setup()
66-
# to use --terragrunt-<option>, pass in tg_<option in snake case>
67-
tg.apply(output=False, tg_non_interactive=True)
68-
yield tg.output()
69-
tg.destroy(auto_approve=True, tg_non_interactive=True)
70-
71-
72-
def test_run_all_apply(run_all_apply_out):
73-
triggers = [o["triggers"] for o in run_all_apply_out]
74-
assert [{'name': 'foo', 'template': 'sample template foo'}] in triggers
75-
assert [{'name': 'bar', 'template': 'sample template bar'}] in triggers
76-
assert [{'name': 'one', 'template': 'sample template one'},
77-
{'name': 'two', 'template': 'sample template two'}] in triggers
78-
assert len(run_all_apply_out) == 3
79-
```
80-
8149
## Caching
8250

8351
The `TerraformTest` `setup`, `init`, `plan`, `apply`, `output` and `destroy` methods have the ability to cache it's associate output to a local `.tftest-cache` directory. For subsequent calls of the method, the cached value can be returned instead of calling the actual underlying `terraform` command. Using the cache value can be significantly faster than running the Terraform command again especially if the command is time-intensive.

setup.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@
1616

1717
from tftest import __version__
1818

19-
2019
with open("README.md", "r") as fh:
2120
long_description = fh.read()
2221

23-
2422
setuptools.setup(
2523
name="tftest",
2624
version=__version__,

test/fixtures/plan_no_resource_changes/terragrunt.hcl

Lines changed: 0 additions & 3 deletions
This file was deleted.

test/fixtures/tg_apply_all/bar/terragrunt.hcl

Lines changed: 0 additions & 11 deletions
This file was deleted.

test/fixtures/tg_apply_all/foo/terragrunt.hcl

Lines changed: 0 additions & 11 deletions
This file was deleted.

test/fixtures/tg_apply_all/terragrunt.hcl

Lines changed: 0 additions & 11 deletions
This file was deleted.

test/test_args.py

Lines changed: 124 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -11,51 +11,128 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
1514
"Test the function for mapping Terraform arguments."
1615
import pytest
1716

1817
import tftest
1918

20-
2119
ARGS_TESTS = (
22-
({'auto_approve': True}, ['-auto-approve']),
23-
({'auto_approve': False}, []),
24-
({'backend': True}, []),
25-
({'backend': None}, []),
26-
({'backend': False}, ['-backend=false']),
27-
({'color': True}, []),
28-
({'color': False}, ['-no-color']),
29-
({'color': False, 'input': False}, ['-no-color', '-input=false']),
30-
({'force_copy': True}, ['-force-copy']),
31-
({'force_copy': None}, []),
32-
({'force_copy': False}, []),
33-
({'input': True}, []),
34-
({'input': False}, ['-input=false']),
35-
({'json_format': True}, ['-json']),
36-
({'json_format': False}, []),
37-
({'lock': True}, []),
38-
({'lock': False}, ['-lock=false']),
39-
({'plugin_dir': ''}, []),
40-
({'plugin_dir': 'abc'}, ['-plugin-dir', 'abc']),
41-
({'refresh': True}, []),
42-
({'refresh': None}, []),
43-
({'refresh': False}, ['-refresh=false']),
44-
({'upgrade': True}, ['-upgrade']),
45-
({'upgrade': False}, []),
46-
({'tf_var_file': None}, []),
47-
({'tf_var_file': 'foo.tfvar'}, ['-var-file=foo.tfvar']),
48-
({'tf_var_file': ['foo.tfvar', 'bar.tfvar']}, [
49-
'-var-file=foo.tfvar', '-var-file=bar.tfvar']),
50-
({'tf_vars': {'text': 'text'}}, ['-var', 'text=text']),
51-
({'tf_vars': {'number': 0}}, ['-var', 'number=0']),
52-
({'tf_vars': {'bool': False}}, ['-var', 'bool=False']),
53-
({'tf_vars': {'dict': {'text': 'text'}}},
54-
['-var', 'dict={"text": "text"}']),
55-
({'tf_vars': {'list': ['item1', 'item2']}},
56-
['-var', 'list=["item1", "item2"]']),
57-
({'tf_vars': {'dict': {'list': ['item1', 'item2']}}},
58-
['-var', 'dict={"list": ["item1", "item2"]}']),
20+
({
21+
'auto_approve': True
22+
}, ['-auto-approve']),
23+
({
24+
'auto_approve': False
25+
}, []),
26+
({
27+
'backend': True
28+
}, []),
29+
({
30+
'backend': None
31+
}, []),
32+
({
33+
'backend': False
34+
}, ['-backend=false']),
35+
({
36+
'color': True
37+
}, []),
38+
({
39+
'color': False
40+
}, ['-no-color']),
41+
({
42+
'color': False,
43+
'input': False
44+
}, ['-no-color', '-input=false']),
45+
({
46+
'force_copy': True
47+
}, ['-force-copy']),
48+
({
49+
'force_copy': None
50+
}, []),
51+
({
52+
'force_copy': False
53+
}, []),
54+
({
55+
'input': True
56+
}, []),
57+
({
58+
'input': False
59+
}, ['-input=false']),
60+
({
61+
'json_format': True
62+
}, ['-json']),
63+
({
64+
'json_format': False
65+
}, []),
66+
({
67+
'lock': True
68+
}, []),
69+
({
70+
'lock': False
71+
}, ['-lock=false']),
72+
({
73+
'plugin_dir': ''
74+
}, []),
75+
({
76+
'plugin_dir': 'abc'
77+
}, ['-plugin-dir', 'abc']),
78+
({
79+
'refresh': True
80+
}, []),
81+
({
82+
'refresh': None
83+
}, []),
84+
({
85+
'refresh': False
86+
}, ['-refresh=false']),
87+
({
88+
'upgrade': True
89+
}, ['-upgrade']),
90+
({
91+
'upgrade': False
92+
}, []),
93+
({
94+
'tf_var_file': None
95+
}, []),
96+
({
97+
'tf_var_file': 'foo.tfvar'
98+
}, ['-var-file=foo.tfvar']),
99+
({
100+
'tf_var_file': ['foo.tfvar', 'bar.tfvar']
101+
}, ['-var-file=foo.tfvar', '-var-file=bar.tfvar']),
102+
({
103+
'tf_vars': {
104+
'text': 'text'
105+
}
106+
}, ['-var', 'text=text']),
107+
({
108+
'tf_vars': {
109+
'number': 0
110+
}
111+
}, ['-var', 'number=0']),
112+
({
113+
'tf_vars': {
114+
'bool': False
115+
}
116+
}, ['-var', 'bool=False']),
117+
({
118+
'tf_vars': {
119+
'dict': {
120+
'text': 'text'
121+
}
122+
}
123+
}, ['-var', 'dict={"text": "text"}']),
124+
({
125+
'tf_vars': {
126+
'list': ['item1', 'item2']
127+
}
128+
}, ['-var', 'list=["item1", "item2"]']),
129+
({
130+
'tf_vars': {
131+
'dict': {
132+
'list': ['item1', 'item2']
133+
}
134+
}
135+
}, ['-var', 'dict={"list": ["item1", "item2"]}']),
59136
)
60137

61138

@@ -65,56 +142,15 @@ def test_args(kwargs, expected):
65142
assert tftest.parse_args(**kwargs) == expected
66143

67144

68-
TERRAGRUNT_ARGS_TESTCASES = [
69-
({"tg_config": "Obama"}, ['--terragrunt-config', 'Obama']),
70-
({"tg_tfpath": "Barrack"}, ['--terragrunt-tfpath', 'Barrack']),
71-
({"tg_no_auto_init": True}, ['--terragrunt-no-auto-init']),
72-
({"tg_no_auto_init": False}, []),
73-
({"tg_no_auto_retry": True}, ['--terragrunt-no-auto-retry']),
74-
({"tg_no_auto_retry": False}, []),
75-
({"tg_non_interactive": True}, ['--terragrunt-non-interactive']),
76-
({"tg_non_interactive": False}, []),
77-
({"tg_working_dir": "George"}, ['--terragrunt-working-dir', 'George']),
78-
({"tg_download_dir": "Bush"}, ['--terragrunt-download-dir', 'Bush']),
79-
({"tg_source": "Clinton"}, ['--terragrunt-source', 'Clinton']),
80-
({"tg_source_update": True}, ['--terragrunt-source-update']),
81-
({"tg_source_update": False}, []),
82-
({"tg_iam_role": "Bill"}, ['--terragrunt-iam-role', 'Bill']),
83-
({"tg_ignore_dependency_errors": True}, [
84-
'--terragrunt-ignore-dependency-errors']),
85-
({"tg_ignore_dependency_errors": False}, []),
86-
({"tg_ignore_dependency_order": True}, [
87-
'--terragrunt-ignore-dependency-order']),
88-
({"tg_ignore_dependency_order": False}, []),
89-
({"tg_ignore_external_dependencies": "dont care what is here"},
90-
['--terragrunt-ignore-external-dependencies']),
91-
({"tg_include_external_dependencies": True}, [
92-
'--terragrunt-include-external-dependencies']),
93-
({"tg_include_external_dependencies": False}, []),
94-
({"tg_parallelism": 20}, ['--terragrunt-parallelism 20']),
95-
({"tg_exclude_dir": "Ronald"}, ['--terragrunt-exclude-dir', 'Ronald']),
96-
({"tg_include_dir": "Reagan"}, ['--terragrunt-include-dir', 'Reagan']),
97-
({"tg_check": True}, ['--terragrunt-check']),
98-
({"tg_check": False}, []),
99-
({"tg_hclfmt_file": "Biden"}, ['--terragrunt-hclfmt-file', 'Biden']),
100-
({"tg_override_attr": {"Iron": "Man", "Captain": "America"}},
101-
['--terragrunt-override-attr=Iron=Man', '--terragrunt-override-attr=Captain=America']),
102-
({"tg_debug": True}, ['--terragrunt-debug']),
103-
({"tg_debug": False}, []),
104-
105-
]
106-
107-
108-
@pytest.mark.parametrize("kwargs, expected", TERRAGRUNT_ARGS_TESTCASES)
109-
def test_terragrunt_args(kwargs, expected):
110-
assert tftest.parse_args(**kwargs) == expected
111-
112-
113145
def test_var_args():
114-
assert sorted(tftest.parse_args(init_vars={'a': 1, 'b': '["2"]'})) == sorted(
115-
["-backend-config=a=1", '-backend-config=b=["2"]'])
116-
assert sorted(tftest.parse_args(tf_vars={'a': 1, 'b': '["2"]'})) == sorted(
117-
['-var', 'b=["2"]', '-var', 'a=1'])
146+
assert sorted(tftest.parse_args(init_vars={
147+
'a': 1,
148+
'b': '["2"]'
149+
})) == sorted(["-backend-config=a=1", '-backend-config=b=["2"]'])
150+
assert sorted(tftest.parse_args(tf_vars={
151+
'a': 1,
152+
'b': '["2"]'
153+
})) == sorted(['-var', 'b=["2"]', '-var', 'a=1'])
118154

119155

120156
def test_targets():

0 commit comments

Comments
 (0)