dbt-platform-helper 12.4.1__py3-none-any.whl → 12.5.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of dbt-platform-helper might be problematic. Click here for more details.

Files changed (38) hide show
  1. dbt_platform_helper/COMMANDS.md +1 -6
  2. dbt_platform_helper/commands/config.py +2 -2
  3. dbt_platform_helper/commands/copilot.py +51 -30
  4. dbt_platform_helper/commands/environment.py +25 -185
  5. dbt_platform_helper/commands/pipeline.py +10 -173
  6. dbt_platform_helper/constants.py +10 -0
  7. dbt_platform_helper/domain/codebase.py +8 -4
  8. dbt_platform_helper/domain/config_validator.py +242 -0
  9. dbt_platform_helper/domain/copilot_environment.py +204 -0
  10. dbt_platform_helper/domain/database_copy.py +16 -12
  11. dbt_platform_helper/domain/maintenance_page.py +44 -20
  12. dbt_platform_helper/domain/pipelines.py +213 -0
  13. dbt_platform_helper/domain/terraform_environment.py +86 -0
  14. dbt_platform_helper/domain/test_platform_terraform_manifest_generator.py +100 -0
  15. dbt_platform_helper/jinja2_tags.py +1 -1
  16. dbt_platform_helper/providers/cache.py +14 -21
  17. dbt_platform_helper/providers/cloudformation.py +0 -1
  18. dbt_platform_helper/providers/config.py +100 -0
  19. dbt_platform_helper/providers/copilot.py +2 -0
  20. dbt_platform_helper/providers/files.py +26 -0
  21. dbt_platform_helper/providers/opensearch.py +36 -0
  22. dbt_platform_helper/providers/platform_config_schema.py +589 -527
  23. dbt_platform_helper/providers/redis.py +34 -0
  24. dbt_platform_helper/providers/vpc.py +57 -0
  25. dbt_platform_helper/providers/yaml_file.py +72 -0
  26. dbt_platform_helper/templates/addons/svc/s3-cross-account-policy.yml +67 -0
  27. dbt_platform_helper/utils/application.py +32 -34
  28. dbt_platform_helper/utils/aws.py +1 -107
  29. dbt_platform_helper/utils/files.py +8 -59
  30. dbt_platform_helper/utils/platform_config.py +0 -7
  31. dbt_platform_helper/utils/template.py +10 -0
  32. dbt_platform_helper/utils/validation.py +5 -327
  33. dbt_platform_helper/utils/versioning.py +12 -0
  34. {dbt_platform_helper-12.4.1.dist-info → dbt_platform_helper-12.5.1.dist-info}/METADATA +2 -2
  35. {dbt_platform_helper-12.4.1.dist-info → dbt_platform_helper-12.5.1.dist-info}/RECORD +38 -26
  36. {dbt_platform_helper-12.4.1.dist-info → dbt_platform_helper-12.5.1.dist-info}/WHEEL +1 -1
  37. {dbt_platform_helper-12.4.1.dist-info → dbt_platform_helper-12.5.1.dist-info}/LICENSE +0 -0
  38. {dbt_platform_helper-12.4.1.dist-info → dbt_platform_helper-12.5.1.dist-info}/entry_points.txt +0 -0
@@ -3,38 +3,62 @@ import random
3
3
  import re
4
4
  import string
5
5
  from pathlib import Path
6
+ from typing import Callable
6
7
  from typing import List
7
8
  from typing import Union
8
9
 
9
10
  import boto3
10
11
  import click
11
12
 
13
+ from dbt_platform_helper.platform_exception import PlatformException
12
14
  from dbt_platform_helper.providers.load_balancers import ListenerNotFoundException
13
15
  from dbt_platform_helper.providers.load_balancers import ListenerRuleNotFoundException
14
16
  from dbt_platform_helper.providers.load_balancers import LoadBalancerNotFoundException
15
17
  from dbt_platform_helper.providers.load_balancers import find_https_listener
18
+ from dbt_platform_helper.utils.application import Application
16
19
  from dbt_platform_helper.utils.application import Environment
17
20
  from dbt_platform_helper.utils.application import Service
18
21
  from dbt_platform_helper.utils.application import load_application
19
22
 
20
23
 
21
- class MaintenancePageProvider:
22
- def activate(self, app, env, svc, template, vpc):
23
- application = load_application(app)
24
- application_environment = get_app_environment(app, env)
24
+ class MaintenancePageException(PlatformException):
25
+ pass
26
+
27
+
28
+ class LoadBalancedWebServiceNotFoundException(MaintenancePageException):
29
+ pass
30
+
31
+
32
+ class MaintenancePage:
33
+ def __init__(
34
+ self,
35
+ user_prompt_callback: Callable[[str], bool] = click.confirm,
36
+ echo: Callable[[str], str] = click.secho,
37
+ ):
38
+ self.user_prompt_callback = user_prompt_callback
39
+ self.echo = echo
25
40
 
41
+ def _get_deployed_load_balanced_web_services(self, app: Application, svc: str):
26
42
  if "*" in svc:
27
- services = [
28
- s for s in application.services.values() if s.kind == "Load Balanced Web Service"
29
- ]
43
+ services = [s for s in app.services.values() if s.kind == "Load Balanced Web Service"]
30
44
  else:
31
- all_services = [get_app_service(app, s) for s in list(svc)]
45
+ all_services = [get_app_service(app.name, s) for s in list(svc)]
32
46
  services = [s for s in all_services if s.kind == "Load Balanced Web Service"]
33
-
34
47
  if not services:
35
- click.secho(f"No services deployed yet to {app} environment {env}", fg="red")
48
+ raise LoadBalancedWebServiceNotFoundException
49
+ return services
50
+
51
+ def activate(self, app, env, svc, template, vpc):
52
+ try:
53
+ services = self._get_deployed_load_balanced_web_services(load_application(app), svc)
54
+ except LoadBalancedWebServiceNotFoundException:
55
+ # TODO DBTP-1643 - this bit of logic does not depend on env, so env shouldn't really be in the exception
56
+ # message
57
+ # Exception should be propagated to command and caught there.
58
+ self.echo(f"No services deployed yet to {app} environment {env}", fg="red")
36
59
  raise click.Abort
37
60
 
61
+ application_environment = get_app_environment(app, env)
38
62
  try:
39
63
  https_listener = find_https_listener(application_environment.session, app, env)
40
64
  current_maintenance_page = get_maintenance_page(
@@ -42,7 +66,7 @@ class MaintenancePageProvider:
42
66
  )
43
67
  remove_current_maintenance_page = False
44
68
  if current_maintenance_page:
45
- remove_current_maintenance_page = click.confirm(
69
+ remove_current_maintenance_page = self.user_prompt_callback(
46
70
  f"There is currently a '{current_maintenance_page}' maintenance page for the {env} "
47
71
  f"environment in {app}.\nWould you like to replace it with a '{template}' "
48
72
  f"maintenance page?"
@@ -50,7 +74,7 @@ class MaintenancePageProvider:
50
74
  if not remove_current_maintenance_page:
51
75
  raise click.Abort
52
76
 
53
- if remove_current_maintenance_page or click.confirm(
77
+ if remove_current_maintenance_page or self.user_prompt_callback(
54
78
  f"You are about to enable the '{template}' maintenance page for the {env} "
55
79
  f"environment in {app}.\nWould you like to continue?"
56
80
  ):
@@ -68,7 +92,7 @@ class MaintenancePageProvider:
68
92
  allowed_ips,
69
93
  template,
70
94
  )
71
- click.secho(
95
+ self.echo(
72
96
  f"Maintenance page '{template}' added for environment {env} in application {app}",
73
97
  fg="green",
74
98
  )
@@ -76,13 +100,13 @@ class MaintenancePageProvider:
76
100
  raise click.Abort
77
101
 
78
102
  except LoadBalancerNotFoundException:
79
- click.secho(
103
+ self.echo(
80
104
  f"No load balancer found for environment {env} in the application {app}.", fg="red"
81
105
  )
82
106
  raise click.Abort
83
107
 
84
108
  except ListenerNotFoundException:
85
- click.secho(
109
+ self.echo(
86
110
  f"No HTTPS listener found for environment {env} in the application {app}.", fg="red"
87
111
  )
88
112
  raise click.Abort
@@ -96,28 +120,28 @@ class MaintenancePageProvider:
96
120
  application_environment.session, https_listener
97
121
  )
98
122
  if not current_maintenance_page:
99
- click.secho("There is no current maintenance page to remove", fg="red")
123
+ self.echo("There is no current maintenance page to remove", fg="red")
100
124
  raise click.Abort
101
125
 
102
- if not click.confirm(
126
+ if not self.user_prompt_callback(
103
127
  f"There is currently a '{current_maintenance_page}' maintenance page, "
104
128
  f"would you like to remove it?"
105
129
  ):
106
130
  raise click.Abort
107
131
 
108
132
  remove_maintenance_page(application_environment.session, https_listener)
109
- click.secho(
133
+ self.echo(
110
134
  f"Maintenance page removed from environment {env} in application {app}", fg="green"
111
135
  )
112
136
 
113
137
  except LoadBalancerNotFoundException:
114
- click.secho(
138
+ self.echo(
115
139
  f"No load balancer found for environment {env} in the application {app}.", fg="red"
116
140
  )
117
141
  raise click.Abort
118
142
 
119
143
  except ListenerNotFoundException:
120
- click.secho(
144
+ self.echo(
121
145
  f"No HTTPS listener found for environment {env} in the application {app}.", fg="red"
122
146
  )
123
147
  raise click.Abort
@@ -0,0 +1,213 @@
1
+ from collections.abc import Callable
2
+ from os import makedirs
3
+ from pathlib import Path
4
+ from shutil import rmtree
5
+
6
+ from dbt_platform_helper.constants import CODEBASE_PIPELINES_KEY
7
+ from dbt_platform_helper.constants import ENVIRONMENT_PIPELINES_KEY
8
+ from dbt_platform_helper.constants import ENVIRONMENTS_KEY
9
+ from dbt_platform_helper.providers.config import ConfigProvider
10
+ from dbt_platform_helper.providers.files import FileProvider
11
+ from dbt_platform_helper.utils.application import get_application_name
12
+ from dbt_platform_helper.utils.aws import get_account_details
13
+ from dbt_platform_helper.utils.aws import get_public_repository_arn
14
+ from dbt_platform_helper.utils.files import generate_override_files_from_template
15
+ from dbt_platform_helper.utils.template import setup_templates
16
+ from dbt_platform_helper.utils.versioning import (
17
+ get_required_terraform_platform_modules_version,
18
+ )
19
+
20
+
21
+ class Pipelines:
22
+ def __init__(
23
+ self,
24
+ config_provider: ConfigProvider,
25
+ echo: Callable[[str], str],
26
+ abort: Callable[[str], None],
27
+ get_git_remote: Callable[[], str],
28
+ get_codestar_arn: Callable[[str], str],
29
+ ):
30
+ self.config_provider = config_provider
31
+ self.echo = echo
32
+ self.abort = abort
33
+ self.get_git_remote = get_git_remote
34
+ self.get_codestar_arn = get_codestar_arn
35
+
36
+ def generate(self, terraform_platform_modules_version, deploy_branch):
37
+ pipeline_config = self.config_provider.load_and_validate_platform_config()
38
+
39
+ has_codebase_pipelines = CODEBASE_PIPELINES_KEY in pipeline_config
40
+ has_environment_pipelines = ENVIRONMENT_PIPELINES_KEY in pipeline_config
41
+
42
+ if not (has_codebase_pipelines or has_environment_pipelines):
43
+ self.echo("No pipelines defined: nothing to do.", err=True, fg="yellow")
44
+ return
45
+
46
+ platform_config_terraform_modules_default_version = pipeline_config.get(
47
+ "default_versions", {}
48
+ ).get("terraform-platform-modules", "")
49
+
50
+ templates = setup_templates()
51
+ app_name = get_application_name()
52
+
53
+ git_repo = self.get_git_remote()
54
+ if not git_repo:
55
+ self.abort("The current directory is not a git repository")
56
+
57
+ codestar_connection_arn = self.get_codestar_arn(app_name)
58
+ if codestar_connection_arn is None:
59
+ self.abort(f'There is no CodeStar Connection named "{app_name}" to use')
60
+
61
+ base_path = Path(".")
62
+ copilot_pipelines_dir = base_path / f"copilot/pipelines"
63
+
64
+ self._clean_pipeline_config(copilot_pipelines_dir)
65
+
66
+ if has_environment_pipelines:
67
+ environment_pipelines = pipeline_config[ENVIRONMENT_PIPELINES_KEY]
68
+
69
+ for config in environment_pipelines.values():
70
+ aws_account = config.get("account")
71
+ self._generate_terraform_environment_pipeline_manifest(
72
+ pipeline_config["application"],
73
+ aws_account,
74
+ terraform_platform_modules_version,
75
+ platform_config_terraform_modules_default_version,
76
+ deploy_branch,
77
+ )
78
+
79
+ if has_codebase_pipelines:
80
+ account_id, _ = get_account_details()
81
+
82
+ for codebase in pipeline_config[CODEBASE_PIPELINES_KEY]:
83
+ self._generate_codebase_pipeline(
84
+ account_id,
85
+ app_name,
86
+ codestar_connection_arn,
87
+ git_repo,
88
+ codebase,
89
+ base_path,
90
+ copilot_pipelines_dir,
91
+ templates,
92
+ )
93
+
94
+ def _clean_pipeline_config(self, pipelines_dir):
95
+ if pipelines_dir.exists():
96
+ self.echo("Deleting copilot/pipelines directory.")
97
+ rmtree(pipelines_dir)
98
+
99
+ def _generate_codebase_pipeline(
100
+ self,
101
+ account_id,
102
+ app_name,
103
+ codestar_connection_arn,
104
+ git_repo,
105
+ codebase,
106
+ base_path,
107
+ pipelines_dir,
108
+ templates,
109
+ ):
110
+ makedirs(pipelines_dir / codebase["name"] / "overrides", exist_ok=True)
111
+ environments = []
112
+ for pipelines in codebase["pipelines"]:
113
+ environments += pipelines[ENVIRONMENTS_KEY]
114
+
115
+ additional_ecr = codebase.get("additional_ecr_repository", None)
116
+ add_public_perms = additional_ecr and additional_ecr.startswith("public.ecr.aws")
117
+ additional_ecr_arn = get_public_repository_arn(additional_ecr) if add_public_perms else None
118
+
119
+ template_data = {
120
+ "account_id": account_id,
121
+ "app_name": app_name,
122
+ "deploy_repo": git_repo,
123
+ "codebase": codebase,
124
+ ENVIRONMENTS_KEY: environments,
125
+ "codestar_connection_arn": codestar_connection_arn,
126
+ "codestar_connection_id": codestar_connection_arn.split("/")[-1],
127
+ "additional_ecr_arn": additional_ecr_arn,
128
+ }
129
+
130
+ self._create_file_from_template(
131
+ base_path,
132
+ f"{codebase['name']}/manifest.yml",
133
+ pipelines_dir,
134
+ template_data,
135
+ templates,
136
+ "codebase/manifest.yml",
137
+ )
138
+
139
+ overrides_path = Path(__file__).parent.parent.joinpath(
140
+ "templates/pipelines/codebase/overrides"
141
+ )
142
+ generate_override_files_from_template(
143
+ base_path, overrides_path, pipelines_dir / codebase["name"] / "overrides", template_data
144
+ )
145
+
146
+ def _create_file_from_template(
147
+ self, base_path, file_name, pipelines_dir, template_data, templates, template_name=None
148
+ ):
149
+ contents = templates.get_template(
150
+ f"pipelines/{file_name if template_name is None else template_name}"
151
+ ).render(template_data)
152
+ message = FileProvider.mkfile(
153
+ base_path, pipelines_dir / file_name, contents, overwrite=True
154
+ )
155
+ self.echo(message)
156
+
157
+ def _generate_terraform_environment_pipeline_manifest(
158
+ self,
159
+ application,
160
+ aws_account,
161
+ cli_terraform_platform_modules_version,
162
+ platform_config_terraform_modules_default_version,
163
+ deploy_branch,
164
+ ):
165
+ env_pipeline_template = setup_templates().get_template("environment-pipelines/main.tf")
166
+
167
+ terraform_platform_modules_version = get_required_terraform_platform_modules_version(
168
+ cli_terraform_platform_modules_version,
169
+ platform_config_terraform_modules_default_version,
170
+ )
171
+
172
+ contents = env_pipeline_template.render(
173
+ {
174
+ "application": application,
175
+ "aws_account": aws_account,
176
+ "terraform_platform_modules_version": terraform_platform_modules_version,
177
+ "deploy_branch": deploy_branch,
178
+ }
179
+ )
180
+
181
+ dir_path = f"terraform/environment-pipelines/{aws_account}"
182
+ makedirs(dir_path, exist_ok=True)
183
+
184
+ self.echo(FileProvider.mkfile(".", f"{dir_path}/main.tf", contents, overwrite=True))
185
+
186
+ def generate_terraform_codebase_pipeline_manifest(
187
+ self,
188
+ application,
189
+ aws_account,
190
+ cli_terraform_platform_modules_version,
191
+ platform_config_terraform_modules_default_version,
192
+ deploy_branch,
193
+ ):
194
+ env_pipeline_template = setup_templates().get_template("codebase-pipelines/main.tf")
195
+
196
+ terraform_platform_modules_version = get_required_terraform_platform_modules_version(
197
+ cli_terraform_platform_modules_version,
198
+ platform_config_terraform_modules_default_version,
199
+ )
200
+
201
+ contents = env_pipeline_template.render(
202
+ {
203
+ "application": application,
204
+ "aws_account": aws_account,
205
+ "terraform_platform_modules_version": terraform_platform_modules_version,
206
+ "deploy_branch": deploy_branch,
207
+ }
208
+ )
209
+
210
+ dir_path = f"terraform/environment-pipelines/{aws_account}"
211
+ makedirs(dir_path, exist_ok=True)
212
+
213
+ self.echo(FileProvider.mkfile(".", f"{dir_path}/main.tf", contents, overwrite=True))
@@ -0,0 +1,86 @@
1
+ import click
2
+
3
+ from dbt_platform_helper.constants import DEFAULT_TERRAFORM_PLATFORM_MODULES_VERSION
4
+ from dbt_platform_helper.platform_exception import PlatformException
5
+ from dbt_platform_helper.providers.files import FileProvider
6
+ from dbt_platform_helper.utils.template import setup_templates
7
+
8
+
9
+ class PlatformTerraformManifestGenerator:
10
+ def __init__(self, file_provider):
11
+ self.file_provider = file_provider
12
+ self.manifest_template = setup_templates().get_template("environments/main.tf")
13
+
14
+ def generate_manifest(
15
+ self,
16
+ environment_name: str,
17
+ application_name: str,
18
+ environment_config: dict,
19
+ terraform_platform_modules_version_override: str = None,
20
+ ):
21
+ terraform_platform_modules_version = (
22
+ terraform_platform_modules_version_override
23
+ or environment_config.get("versions", {}).get(
24
+ "terraform-platform-modules", DEFAULT_TERRAFORM_PLATFORM_MODULES_VERSION
25
+ )
26
+ )
27
+
28
+ return self.manifest_template.render(
29
+ {
30
+ "application": application_name,
31
+ "environment": environment_name,
32
+ "config": environment_config,
33
+ "terraform_platform_modules_version": terraform_platform_modules_version,
34
+ }
35
+ )
36
+
37
+ def write_manifest(self, environment_name: str, manifest_content: str):
38
+ return self.file_provider.mkfile(
39
+ ".",
40
+ f"terraform/environments/{environment_name}/main.tf",
41
+ manifest_content,
42
+ overwrite=True,
43
+ )
44
+
45
+
46
+ class TerraformEnvironmentException(PlatformException):
47
+ pass
48
+
49
+
50
+ class EnvironmentNotFoundException(TerraformEnvironmentException):
51
+ pass
52
+
53
+
54
+ class TerraformEnvironment:
55
+ def __init__(
56
+ self,
57
+ config_provider,
58
+ manifest_generator: PlatformTerraformManifestGenerator = None,
59
+ echo_fn=click.echo,
60
+ ):
61
+ self.echo = echo_fn
62
+ self.config_provider = config_provider
63
+ self.manifest_generator = manifest_generator or PlatformTerraformManifestGenerator(
64
+ FileProvider()
65
+ )
66
+
67
+ def generate(self, environment_name, terraform_platform_modules_version_override=None):
68
+ config = self.config_provider.get_enriched_config()
69
+
70
+ if environment_name not in config.get("environments").keys():
71
+ raise EnvironmentNotFoundException(
72
+ f"Error: cannot generate terraform for environment {environment_name}. It does not exist in your configuration"
73
+ )
74
+
75
+ manifest = self.manifest_generator.generate_manifest(
76
+ environment_name=environment_name,
77
+ application_name=config["application"],
78
+ environment_config=config["environments"][environment_name],
79
+ terraform_platform_modules_version_override=terraform_platform_modules_version_override,
80
+ )
81
+
82
+ self.echo(
83
+ self.manifest_generator.write_manifest(
84
+ environment_name=environment_name, manifest_content=manifest
85
+ )
86
+ )
@@ -0,0 +1,100 @@
1
+ from unittest.mock import Mock
2
+
3
+ from dbt_platform_helper.constants import DEFAULT_TERRAFORM_PLATFORM_MODULES_VERSION
4
+ from dbt_platform_helper.domain.terraform_environment import (
5
+ PlatformTerraformManifestGenerator,
6
+ )
7
+ from dbt_platform_helper.providers.files import FileProvider
8
+
9
+
10
+ class TestPlatformTerraformManifestGenerator:
11
+
12
+ def test_generator_generates_expected_manifest_content_with_version_override(self):
13
+ test_environment_config = {
14
+ "vpc": "vpc3",
15
+ "accounts": {
16
+ "deploy": {"name": "non-prod-acc", "id": "1122334455"},
17
+ "dns": {"name": "non-prod-dns-acc", "id": "6677889900"},
18
+ },
19
+ "versions": {"terraform-platform-modules": 3},
20
+ }
21
+ expected_header = "# WARNING: This is an autogenerated file, not for manual editing."
22
+ expected_modules = "git::https://github.com/uktrade/terraform-platform-modules.git//extensions?depth=1&ref=123456"
23
+ expected_moved_block = (
24
+ "moved {\n from = module.extensions-tf\n to = module.extensions\n}\n"
25
+ )
26
+
27
+ result = PlatformTerraformManifestGenerator(Mock()).generate_manifest(
28
+ "test", "test-app", test_environment_config, 123456
29
+ )
30
+
31
+ assert expected_header in result
32
+ assert expected_modules in result
33
+ assert expected_moved_block in result
34
+ assert 'environment = "test"' in result
35
+ assert 'application = "test-app"' in result
36
+ assert 'vpc_name = "vpc3"'
37
+
38
+ def test_generator_generates_expected_manifest_content_with_tpm_version_set_in_config(self):
39
+ test_environment_config = {
40
+ "vpc": "vpc3",
41
+ "accounts": {
42
+ "deploy": {"name": "non-prod-acc", "id": "1122334455"},
43
+ "dns": {"name": "non-prod-dns-acc", "id": "6677889900"},
44
+ },
45
+ "versions": {"terraform-platform-modules": 3},
46
+ }
47
+ expected_header = "# WARNING: This is an autogenerated file, not for manual editing."
48
+ expected_modules = "git::https://github.com/uktrade/terraform-platform-modules.git//extensions?depth=1&ref=3"
49
+ expected_moved_block = (
50
+ "moved {\n from = module.extensions-tf\n to = module.extensions\n}\n"
51
+ )
52
+
53
+ result = PlatformTerraformManifestGenerator(Mock()).generate_manifest(
54
+ "test", "test-app", test_environment_config
55
+ )
56
+
57
+ assert expected_header in result
58
+ assert expected_modules in result
59
+ assert expected_moved_block in result
60
+ assert 'environment = "test"' in result
61
+ assert 'application = "test-app"' in result
62
+ assert 'vpc_name = "vpc3"'
63
+
64
+ def test_generator_generates_expected_manifest_content_with_default_version(self):
65
+ test_environment_config = {
66
+ "vpc": "vpc3",
67
+ "accounts": {
68
+ "deploy": {"name": "non-prod-acc", "id": "1122334455"},
69
+ "dns": {"name": "non-prod-dns-acc", "id": "6677889900"},
70
+ },
71
+ }
72
+ expected_header = "# WARNING: This is an autogenerated file, not for manual editing."
73
+ expected_modules = f"git::https://github.com/uktrade/terraform-platform-modules.git//extensions?depth=1&ref={DEFAULT_TERRAFORM_PLATFORM_MODULES_VERSION}"
74
+ expected_moved_block = (
75
+ "moved {\n from = module.extensions-tf\n to = module.extensions\n}\n"
76
+ )
77
+
78
+ result = PlatformTerraformManifestGenerator(Mock()).generate_manifest(
79
+ "test", "test-app", test_environment_config
80
+ )
81
+
82
+ assert expected_header in result
83
+ assert expected_modules in result
84
+ assert expected_moved_block in result
85
+ assert 'environment = "test"' in result
86
+ assert 'application = "test-app"' in result
87
+ assert 'vpc_name = "vpc3"'
88
+
89
+ def test_generator_write_manifest_makes_the_expected_manifest_file(self):
90
+ mock_file_provider = Mock(spec=FileProvider)
91
+ PlatformTerraformManifestGenerator(mock_file_provider).write_manifest(
92
+ "test-environment", "test-manifest-content"
93
+ )
94
+
95
+ mock_file_provider.mkfile.assert_called_once_with(
96
+ ".",
97
+ f"terraform/environments/test-environment/main.tf",
98
+ "test-manifest-content",
99
+ overwrite=True,
100
+ )
@@ -17,4 +17,4 @@ class ExtraHeaderTag(StandaloneTag):
17
17
  tags = {"extra_header"}
18
18
 
19
19
  def render(self):
20
- return f"WARNING: This is an autogenerated file, not for manual editing."
20
+ return "WARNING: This is an autogenerated file, not for manual editing."
@@ -1,17 +1,20 @@
1
1
  import os
2
2
  from datetime import datetime
3
- from pathlib import Path
4
3
 
5
- import yaml
4
+ from dbt_platform_helper.providers.yaml_file import YamlFileProvider
6
5
 
7
6
 
8
7
  class CacheProvider:
9
- def __init__(self):
8
+ def __init__(
9
+ self,
10
+ file_provider: YamlFileProvider = None,
11
+ ):
10
12
  self._cache_file = ".platform-helper-config-cache.yml"
13
+ self.file_provider = file_provider or YamlFileProvider
11
14
 
12
15
  def read_supported_versions_from_cache(self, resource_name):
13
16
 
14
- platform_helper_config = self.__read_file_as_yaml(self._cache_file)
17
+ platform_helper_config = self.file_provider.load(self._cache_file)
15
18
 
16
19
  return platform_helper_config.get(resource_name).get("versions")
17
20
 
@@ -20,7 +23,7 @@ class CacheProvider:
20
23
  platform_helper_config = {}
21
24
 
22
25
  if self.__cache_exists():
23
- platform_helper_config = self.__read_file_as_yaml(self._cache_file)
26
+ platform_helper_config = self.file_provider.load(self._cache_file)
24
27
 
25
28
  cache_dict = {
26
29
  resource_name: {
@@ -31,7 +34,11 @@ class CacheProvider:
31
34
 
32
35
  platform_helper_config.update(cache_dict)
33
36
 
34
- self.__write_cache(platform_helper_config)
37
+ self.file_provider.write(
38
+ self._cache_file,
39
+ platform_helper_config,
40
+ "# [!] This file is autogenerated via the platform-helper. Do not edit.\n",
41
+ )
35
42
 
36
43
  def cache_refresh_required(self, resource_name) -> bool:
37
44
  """
@@ -47,7 +54,7 @@ class CacheProvider:
47
54
  if not self.__cache_exists():
48
55
  return True
49
56
 
50
- platform_helper_config = self.__read_file_as_yaml(self._cache_file)
57
+ platform_helper_config = self.file_provider.load(self._cache_file)
51
58
 
52
59
  if platform_helper_config.get(resource_name):
53
60
  return self.__check_if_cached_datetime_is_greater_than_interval(
@@ -65,19 +72,5 @@ class CacheProvider:
65
72
 
66
73
  return delta.days > interval_in_days
67
74
 
68
- # TODO - same applies here as below
69
- @staticmethod
70
- def __read_file_as_yaml(file_name):
71
-
72
- return yaml.safe_load(Path(file_name).read_text())
73
-
74
- # TODO - temp fix to the unit test coverage issue, plan is to seperate out any yaml interaction methods into a seperate 'yaml' provider
75
- # should be done under a different sub-task which will need to loop back to this provider as part of that work to use the yaml provider instead
76
- def __write_cache(self, contents):
77
-
78
- with open(self._cache_file, "w") as file:
79
- file.write("# [!] This file is autogenerated via the platform-helper. Do not edit.\n")
80
- yaml.dump(contents, file)
81
-
82
75
  def __cache_exists(self):
83
76
  return os.path.exists(self._cache_file)
@@ -93,7 +93,6 @@ class CloudFormation:
93
93
  )
94
94
 
95
95
  params = []
96
- # TODO Currently not covered by tests - see https://uktrade.atlassian.net/browse/DBTP-1582
97
96
  if "Parameters" in template_yml:
98
97
  for param in template_yml["Parameters"]:
99
98
  params.append({"ParameterKey": param, "UsePreviousValue": True})