dbt-platform-helper 13.4.1__py3-none-any.whl → 14.1.0__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 (46) hide show
  1. dbt_platform_helper/COMMANDS.md +26 -57
  2. dbt_platform_helper/commands/config.py +9 -0
  3. dbt_platform_helper/commands/environment.py +3 -7
  4. dbt_platform_helper/commands/notify.py +24 -77
  5. dbt_platform_helper/commands/pipeline.py +6 -12
  6. dbt_platform_helper/commands/secrets.py +1 -1
  7. dbt_platform_helper/constants.py +7 -5
  8. dbt_platform_helper/domain/codebase.py +0 -5
  9. dbt_platform_helper/domain/config.py +16 -9
  10. dbt_platform_helper/domain/copilot_environment.py +3 -3
  11. dbt_platform_helper/domain/database_copy.py +1 -1
  12. dbt_platform_helper/domain/maintenance_page.py +3 -3
  13. dbt_platform_helper/domain/notify.py +64 -0
  14. dbt_platform_helper/domain/pipelines.py +20 -16
  15. dbt_platform_helper/domain/terraform_environment.py +18 -11
  16. dbt_platform_helper/domain/versioning.py +18 -78
  17. dbt_platform_helper/providers/aws/exceptions.py +1 -1
  18. dbt_platform_helper/providers/cloudformation.py +1 -1
  19. dbt_platform_helper/providers/config.py +119 -17
  20. dbt_platform_helper/providers/config_validator.py +4 -31
  21. dbt_platform_helper/providers/copilot.py +3 -3
  22. dbt_platform_helper/providers/io.py +1 -1
  23. dbt_platform_helper/providers/load_balancers.py +6 -6
  24. dbt_platform_helper/providers/platform_config_schema.py +24 -29
  25. dbt_platform_helper/providers/schema_migrations/__init__.py +0 -0
  26. dbt_platform_helper/providers/schema_migrations/schema_v0_to_v1_migration.py +43 -0
  27. dbt_platform_helper/providers/schema_migrator.py +77 -0
  28. dbt_platform_helper/providers/secrets.py +5 -5
  29. dbt_platform_helper/providers/semantic_version.py +6 -1
  30. dbt_platform_helper/providers/slack_channel_notifier.py +62 -0
  31. dbt_platform_helper/providers/terraform_manifest.py +8 -10
  32. dbt_platform_helper/providers/version.py +1 -18
  33. dbt_platform_helper/providers/version_status.py +8 -61
  34. dbt_platform_helper/providers/yaml_file.py +23 -1
  35. dbt_platform_helper/templates/environment-pipelines/main.tf +1 -1
  36. dbt_platform_helper/utils/application.py +1 -1
  37. dbt_platform_helper/utils/aws.py +3 -3
  38. dbt_platform_helper/utils/git.py +0 -15
  39. {dbt_platform_helper-13.4.1.dist-info → dbt_platform_helper-14.1.0.dist-info}/METADATA +5 -4
  40. {dbt_platform_helper-13.4.1.dist-info → dbt_platform_helper-14.1.0.dist-info}/RECORD +44 -41
  41. platform_helper.py +0 -2
  42. dbt_platform_helper/commands/version.py +0 -37
  43. dbt_platform_helper/utils/tool_versioning.py +0 -12
  44. {dbt_platform_helper-13.4.1.dist-info → dbt_platform_helper-14.1.0.dist-info}/LICENSE +0 -0
  45. {dbt_platform_helper-13.4.1.dist-info → dbt_platform_helper-14.1.0.dist-info}/WHEEL +0 -0
  46. {dbt_platform_helper-13.4.1.dist-info → dbt_platform_helper-14.1.0.dist-info}/entry_points.txt +0 -0
@@ -1,3 +1,4 @@
1
+ import os
1
2
  from collections.abc import Callable
2
3
  from os import makedirs
3
4
  from pathlib import Path
@@ -5,6 +6,7 @@ from shutil import rmtree
5
6
 
6
7
  from dbt_platform_helper.constants import CODEBASE_PIPELINES_KEY
7
8
  from dbt_platform_helper.constants import ENVIRONMENT_PIPELINES_KEY
9
+ from dbt_platform_helper.constants import PLATFORM_HELPER_VERSION_OVERRIDE_KEY
8
10
  from dbt_platform_helper.constants import SUPPORTED_AWS_PROVIDER_VERSION
9
11
  from dbt_platform_helper.constants import SUPPORTED_TERRAFORM_VERSION
10
12
  from dbt_platform_helper.providers.config import ConfigProvider
@@ -14,9 +16,6 @@ from dbt_platform_helper.providers.io import ClickIOProvider
14
16
  from dbt_platform_helper.providers.terraform_manifest import TerraformManifestProvider
15
17
  from dbt_platform_helper.utils.application import get_application_name
16
18
  from dbt_platform_helper.utils.template import setup_templates
17
- from dbt_platform_helper.utils.tool_versioning import (
18
- get_required_terraform_platform_modules_version,
19
- )
20
19
 
21
20
 
22
21
  class Pipelines:
@@ -29,6 +28,7 @@ class Pipelines:
29
28
  get_codestar_arn: Callable[[str], str],
30
29
  io: ClickIOProvider = ClickIOProvider(),
31
30
  file_provider: FileProvider = FileProvider(),
31
+ platform_helper_version_override: str = None,
32
32
  ):
33
33
  self.config_provider = config_provider
34
34
  self.get_git_remote = get_git_remote
@@ -37,8 +37,14 @@ class Pipelines:
37
37
  self.ecr_provider = ecr_provider
38
38
  self.io = io
39
39
  self.file_provider = file_provider
40
+ self.platform_helper_version_override = platform_helper_version_override or os.environ.get(
41
+ PLATFORM_HELPER_VERSION_OVERRIDE_KEY
42
+ )
40
43
 
41
- def generate(self, cli_terraform_platform_modules_version: str, deploy_branch: str):
44
+ def generate(
45
+ self,
46
+ deploy_branch: str,
47
+ ):
42
48
  platform_config = self.config_provider.load_and_validate_platform_config()
43
49
 
44
50
  has_codebase_pipelines = CODEBASE_PIPELINES_KEY in platform_config
@@ -48,10 +54,6 @@ class Pipelines:
48
54
  self.io.warn("No pipelines defined: nothing to do.")
49
55
  return
50
56
 
51
- platform_config_terraform_modules_default_version = platform_config.get(
52
- "default_versions", {}
53
- ).get("terraform-platform-modules", "")
54
-
55
57
  app_name = get_application_name()
56
58
 
57
59
  git_repo = self.get_git_remote()
@@ -67,12 +69,14 @@ class Pipelines:
67
69
 
68
70
  self._clean_pipeline_config(copilot_pipelines_dir)
69
71
 
70
- terraform_platform_modules_version = get_required_terraform_platform_modules_version(
71
- cli_terraform_platform_modules_version,
72
- platform_config_terraform_modules_default_version,
72
+ platform_helper_version_for_template: str = platform_config.get("default_versions", {}).get(
73
+ "platform-helper"
73
74
  )
74
75
 
75
- # TODO - this whole code block/if-statement can fall away once the deploy_repository is a required key.
76
+ if self.platform_helper_version_override:
77
+ platform_helper_version_for_template = self.platform_helper_version_override
78
+
79
+ # TODO: DBTP-1965: - this whole code block/if-statement can fall away once the deploy_repository is a required key.
76
80
  deploy_repository = ""
77
81
  if "deploy_repository" in platform_config.keys():
78
82
  deploy_repository = f"{platform_config['deploy_repository']}"
@@ -95,7 +99,7 @@ class Pipelines:
95
99
  platform_config["application"],
96
100
  deploy_repository,
97
101
  account,
98
- terraform_platform_modules_version,
102
+ platform_helper_version_for_template,
99
103
  deploy_branch,
100
104
  )
101
105
 
@@ -114,7 +118,7 @@ class Pipelines:
114
118
 
115
119
  self.terraform_manifest_provider.generate_codebase_pipeline_config(
116
120
  platform_config,
117
- terraform_platform_modules_version,
121
+ platform_helper_version_for_template,
118
122
  ecrs_that_need_importing,
119
123
  deploy_repository,
120
124
  )
@@ -129,7 +133,7 @@ class Pipelines:
129
133
  application: str,
130
134
  deploy_repository: str,
131
135
  aws_account: str,
132
- terraform_platform_modules_version: str,
136
+ platform_helper_version: str,
133
137
  deploy_branch: str,
134
138
  ):
135
139
  env_pipeline_template = setup_templates().get_template("environment-pipelines/main.tf")
@@ -139,7 +143,7 @@ class Pipelines:
139
143
  "application": application,
140
144
  "deploy_repository": deploy_repository,
141
145
  "aws_account": aws_account,
142
- "terraform_platform_modules_version": terraform_platform_modules_version,
146
+ "platform_helper_version": platform_helper_version,
143
147
  "deploy_branch": deploy_branch,
144
148
  "terraform_version": SUPPORTED_TERRAFORM_VERSION,
145
149
  "aws_provider_version": SUPPORTED_AWS_PROVIDER_VERSION,
@@ -1,9 +1,9 @@
1
+ import os
2
+
3
+ from dbt_platform_helper.constants import PLATFORM_HELPER_VERSION_OVERRIDE_KEY
1
4
  from dbt_platform_helper.platform_exception import PlatformException
2
5
  from dbt_platform_helper.providers.io import ClickIOProvider
3
6
  from dbt_platform_helper.providers.terraform_manifest import TerraformManifestProvider
4
- from dbt_platform_helper.utils.tool_versioning import (
5
- get_required_terraform_platform_modules_version,
6
- )
7
7
 
8
8
 
9
9
  class TerraformEnvironmentException(PlatformException):
@@ -20,12 +20,20 @@ class TerraformEnvironment:
20
20
  config_provider,
21
21
  manifest_provider: TerraformManifestProvider = None,
22
22
  io: ClickIOProvider = ClickIOProvider(),
23
+ platform_helper_version_override: str = None,
23
24
  ):
24
25
  self.io = io
25
26
  self.config_provider = config_provider
26
27
  self.manifest_provider = manifest_provider or TerraformManifestProvider()
28
+ self.platform_helper_version_override = platform_helper_version_override or os.environ.get(
29
+ PLATFORM_HELPER_VERSION_OVERRIDE_KEY
30
+ )
31
+
32
+ def generate(
33
+ self,
34
+ environment_name: str,
35
+ ):
27
36
 
28
- def generate(self, environment_name, terraform_platform_modules_version_override=None):
29
37
  config = self.config_provider.get_enriched_config()
30
38
 
31
39
  if environment_name not in config.get("environments").keys():
@@ -33,14 +41,13 @@ class TerraformEnvironment:
33
41
  f"cannot generate terraform for environment {environment_name}. It does not exist in your configuration"
34
42
  )
35
43
 
36
- platform_config_terraform_modules_default_version = config.get("default_versions", {}).get(
37
- "terraform-platform-modules", ""
38
- )
39
- terraform_platform_modules_version = get_required_terraform_platform_modules_version(
40
- terraform_platform_modules_version_override,
41
- platform_config_terraform_modules_default_version,
44
+ platform_helper_version_for_template: str = config.get("default_versions", {}).get(
45
+ "platform-helper"
42
46
  )
43
47
 
48
+ if self.platform_helper_version_override:
49
+ platform_helper_version_for_template = self.platform_helper_version_override
50
+
44
51
  self.manifest_provider.generate_environment_config(
45
- config, environment_name, terraform_platform_modules_version
52
+ config, environment_name, platform_helper_version_for_template
46
53
  )
@@ -12,14 +12,11 @@ from dbt_platform_helper.providers.semantic_version import (
12
12
  from dbt_platform_helper.providers.semantic_version import SemanticVersion
13
13
  from dbt_platform_helper.providers.version import AWSCLIInstalledVersionProvider
14
14
  from dbt_platform_helper.providers.version import CopilotInstalledVersionProvider
15
- from dbt_platform_helper.providers.version import DeprecatedVersionFileVersionProvider
16
15
  from dbt_platform_helper.providers.version import GithubLatestVersionProvider
17
16
  from dbt_platform_helper.providers.version import InstalledVersionProvider
18
17
  from dbt_platform_helper.providers.version import PyPiLatestVersionProvider
19
18
  from dbt_platform_helper.providers.version import VersionProvider
20
- from dbt_platform_helper.providers.version_status import PlatformHelperVersionStatus
21
19
  from dbt_platform_helper.providers.version_status import VersionStatus
22
- from dbt_platform_helper.providers.yaml_file import YamlFileProvider
23
20
 
24
21
 
25
22
  def running_as_installed_package():
@@ -31,24 +28,20 @@ def skip_version_checks():
31
28
 
32
29
 
33
30
  class PlatformHelperVersionNotFoundException(PlatformException):
34
- def __init__(self):
35
- super().__init__(f"""Platform helper version could not be resolved.""")
31
+ def __init__(self, message=None):
32
+ super().__init__(message or "Platform helper version could not be resolved.")
36
33
 
37
34
 
38
35
  class PlatformHelperVersioning:
39
36
  def __init__(
40
37
  self,
41
38
  io: ClickIOProvider = ClickIOProvider(),
42
- version_file_version_provider: DeprecatedVersionFileVersionProvider = DeprecatedVersionFileVersionProvider(
43
- YamlFileProvider
44
- ),
45
39
  config_provider: ConfigProvider = ConfigProvider(),
46
40
  latest_version_provider: VersionProvider = PyPiLatestVersionProvider,
47
41
  installed_version_provider: InstalledVersionProvider = InstalledVersionProvider(),
48
42
  skip_versioning_checks: bool = None,
49
43
  ):
50
44
  self.io = io
51
- self.version_file_version_provider = version_file_version_provider
52
45
  self.config_provider = config_provider
53
46
  self.latest_version_provider = latest_version_provider
54
47
  self.installed_version_provider = installed_version_provider
@@ -56,10 +49,9 @@ class PlatformHelperVersioning:
56
49
  skip_versioning_checks if skip_versioning_checks is not None else skip_version_checks()
57
50
  )
58
51
 
59
- def get_required_version(self, pipeline=None):
60
- version_status = self._get_version_status()
61
- self.io.process_messages(version_status.validate())
62
- required_version = self._resolve_required_version(pipeline, version_status)
52
+ def get_required_version(self):
53
+ platform_config = self.config_provider.load_and_validate_platform_config()
54
+ required_version = platform_config.get("default_versions", {}).get("platform-helper")
63
55
  self.io.info(required_version)
64
56
  return required_version
65
57
 
@@ -68,25 +60,24 @@ class PlatformHelperVersioning:
68
60
  if self.skip_versioning_checks:
69
61
  return
70
62
 
71
- version_status = self._get_version_status()
72
- self.io.process_messages(version_status.validate())
63
+ version_status = self.get_version_status()
64
+ required_version = self.get_required_version()
73
65
 
74
- required_version = SemanticVersion.from_string(
75
- self._resolve_required_version(version_status=version_status)
76
- )
66
+ if SemanticVersion.is_semantic_version(required_version):
67
+ required_version_semver = SemanticVersion.from_string(required_version)
77
68
 
78
- if not version_status.installed == required_version:
79
- message = (
80
- f"WARNING: You are running platform-helper v{version_status.installed} against "
81
- f"v{required_version} specified for the project."
82
- )
83
- self.io.warn(message)
69
+ if not version_status.installed == required_version_semver:
70
+ message = (
71
+ f"WARNING: You are running platform-helper v{version_status.installed} against "
72
+ f"v{required_version_semver} specified for the project."
73
+ )
74
+ self.io.warn(message)
84
75
 
85
76
  def check_if_needs_update(self):
86
77
  if self.skip_versioning_checks:
87
78
  return
88
79
 
89
- version_status = self._get_version_status(include_project_versions=False)
80
+ version_status = self.get_version_status()
90
81
 
91
82
  message = (
92
83
  f"You are running platform-helper v{version_status.installed}, upgrade to "
@@ -101,65 +92,14 @@ class PlatformHelperVersioning:
101
92
  except IncompatibleMinorVersionException:
102
93
  self.io.warn(message)
103
94
 
104
- def _get_version_status(
105
- self,
106
- include_project_versions: bool = True,
107
- ) -> PlatformHelperVersionStatus:
95
+ def get_version_status(self) -> VersionStatus:
108
96
  locally_installed_version = self.installed_version_provider.get_semantic_version(
109
97
  "dbt-platform-helper"
110
98
  )
111
99
 
112
100
  latest_release = self.latest_version_provider.get_semantic_version("dbt-platform-helper")
113
101
 
114
- if not include_project_versions:
115
- return PlatformHelperVersionStatus(
116
- installed=locally_installed_version,
117
- latest=latest_release,
118
- )
119
-
120
- platform_config_default, pipeline_overrides = None, {}
121
-
122
- platform_config = self.config_provider.load_unvalidated_config_file()
123
-
124
- if platform_config:
125
- platform_config_default = SemanticVersion.from_string(
126
- platform_config.get("default_versions", {}).get("platform-helper")
127
- )
128
-
129
- pipeline_overrides = {
130
- name: pipeline.get("versions", {}).get("platform-helper")
131
- for name, pipeline in platform_config.get("environment_pipelines", {}).items()
132
- if pipeline.get("versions", {}).get("platform-helper")
133
- }
134
- out = PlatformHelperVersionStatus(
135
- installed=locally_installed_version,
136
- latest=latest_release,
137
- deprecated_version_file=self.version_file_version_provider.get_semantic_version(),
138
- platform_config_default=platform_config_default,
139
- pipeline_overrides=pipeline_overrides,
140
- )
141
-
142
- return out
143
-
144
- def _resolve_required_version(
145
- self, pipeline: str = None, version_status: PlatformHelperVersionStatus = None
146
- ) -> str:
147
- pipeline_version = version_status.pipeline_overrides.get(pipeline)
148
- version_precedence = [
149
- pipeline_version,
150
- version_status.platform_config_default,
151
- version_status.deprecated_version_file,
152
- ]
153
- non_null_version_precedence = [
154
- f"{v}" if isinstance(v, SemanticVersion) else v for v in version_precedence if v
155
- ]
156
-
157
- out = non_null_version_precedence[0] if non_null_version_precedence else None
158
-
159
- if not out:
160
- raise PlatformHelperVersionNotFoundException
161
-
162
- return out
102
+ return VersionStatus(installed=locally_installed_version, latest=latest_release)
163
103
 
164
104
 
165
105
  class AWSVersioning:
@@ -29,7 +29,7 @@ class LogGroupNotFoundException(AWSException):
29
29
  super().__init__(f"""No log group called "{log_group_name}".""")
30
30
 
31
31
 
32
- # Todo: This should probably be in the AWS Copilot provider, but was causing circular import when we tried it pre refactoring the utils/aws.py
32
+ # TODO: DBTP-1976: This should probably be in the AWS Copilot provider, but was causing circular import when we tried it pre refactoring the utils/aws.py
33
33
  class CopilotCodebaseNotFoundException(PlatformException):
34
34
  def __init__(self, codebase: str):
35
35
  super().__init__(
@@ -8,7 +8,7 @@ from dbt_platform_helper.platform_exception import PlatformException
8
8
 
9
9
 
10
10
  class CloudFormation:
11
- # TODO add handling for optional client parameters to handle case of calling boto API with None
11
+ # TODO: DBTP-1966: add handling for optional client parameters to handle case of calling boto API with None
12
12
  def __init__(self, cloudformation_client, iam_client=None, ssm_client=None):
13
13
  self.cloudformation_client = cloudformation_client
14
14
  self.iam_client = iam_client
@@ -1,41 +1,59 @@
1
1
  from copy import deepcopy
2
+ from datetime import datetime
2
3
  from pathlib import Path
3
4
 
4
5
  from schema import SchemaError
5
6
 
7
+ from dbt_platform_helper.constants import FIRST_UPGRADABLE_PLATFORM_HELPER_MAJOR_VERSION
6
8
  from dbt_platform_helper.constants import PLATFORM_CONFIG_FILE
9
+ from dbt_platform_helper.constants import PLATFORM_CONFIG_SCHEMA_VERSION
10
+ from dbt_platform_helper.constants import PLATFORM_HELPER_PACKAGE_NAME
7
11
  from dbt_platform_helper.providers.config_validator import ConfigValidator
8
12
  from dbt_platform_helper.providers.config_validator import ConfigValidatorError
9
13
  from dbt_platform_helper.providers.io import ClickIOProvider
10
14
  from dbt_platform_helper.providers.platform_config_schema import PlatformConfigSchema
15
+ from dbt_platform_helper.providers.semantic_version import SemanticVersion
16
+ from dbt_platform_helper.providers.version import InstalledVersionProvider
11
17
  from dbt_platform_helper.providers.yaml_file import FileNotFoundException
12
18
  from dbt_platform_helper.providers.yaml_file import FileProviderException
13
19
  from dbt_platform_helper.providers.yaml_file import YamlFileProvider
14
20
 
21
+ SCHEMA_VERSION_MESSAGE = """Installed version: platform-helper: {installed_platform_helper_version} (schema version: {installed_schema_version})
22
+ 'platform-config.yml' version: platform-helper: {config_platform_helper_version} (schema version: {config_schema_version})"""
23
+ PLEASE_UPGRADE_TO_V13_MESSAGE = """Please ensure that you have already upgraded to platform-helper 13, following the instructions in https://platform.readme.trade.gov.uk/reference/upgrading-platform-helper/.
24
+
25
+ Then upgrade platform-helper to version {installed_platform_helper_version} and run 'platform-helper config migrate' to upgrade the configuration to the current schema version."""
26
+
15
27
 
16
28
  class ConfigProvider:
17
29
  def __init__(
18
30
  self,
19
- config_validator: ConfigValidator = None,
20
- file_provider: YamlFileProvider = None,
21
- io: ClickIOProvider = None,
31
+ config_validator: ConfigValidator = ConfigValidator(),
32
+ file_provider: YamlFileProvider = YamlFileProvider,
33
+ io: ClickIOProvider = ClickIOProvider(),
34
+ schema_version_for_installed_platform_helper: int = PLATFORM_CONFIG_SCHEMA_VERSION,
35
+ installed_version_provider: InstalledVersionProvider = InstalledVersionProvider,
22
36
  ):
23
37
  self.config = {}
24
- self.validator = config_validator or ConfigValidator()
25
- self.io = io or ClickIOProvider()
26
- self.file_provider = file_provider or YamlFileProvider
27
-
28
- # TODO refactor so that apply_environment_defaults isn't set, discarded and set again
38
+ self.validator = config_validator
39
+ self.io = io
40
+ self.file_provider = file_provider
41
+ self.schema_version_for_installed_platform_helper = (
42
+ schema_version_for_installed_platform_helper
43
+ )
44
+ self.installed_version_provider = installed_version_provider
45
+
46
+ # TODO: DBTP-1964: refactor so that apply_environment_defaults isn't set, discarded and set again
29
47
  def get_enriched_config(self):
30
48
  return self.apply_environment_defaults(self.load_and_validate_platform_config())
31
49
 
32
50
  def _validate_platform_config(self):
33
51
  PlatformConfigSchema.schema().validate(self.config)
34
-
35
- # TODO= logically this isn't validation but loading + parsing, to move.
52
+ # TODO: DBTP-1964: = logically this isn't validation but loading + parsing, to move.
36
53
  # also, we apply defaults but discard that data. Should we just apply
37
54
  # defaults to config returned by load_and_validate
38
55
  enriched_config = ConfigProvider.apply_environment_defaults(self.config)
56
+
39
57
  try:
40
58
  self.validator.run_validations(enriched_config)
41
59
  except ConfigValidatorError as exc:
@@ -51,6 +69,8 @@ class ConfigProvider:
51
69
  except FileProviderException as e:
52
70
  self.io.abort_with_error(f"Error loading configuration from {path}: {e}")
53
71
 
72
+ self._validate_schema_version()
73
+
54
74
  try:
55
75
  self._validate_platform_config()
56
76
  except SchemaError as e:
@@ -58,13 +78,90 @@ class ConfigProvider:
58
78
 
59
79
  return self.config
60
80
 
81
+ def _abort_due_to_schema_version_error(self, config_description: str, action_required: str):
82
+ self.io.abort_with_error(
83
+ "\n".join(
84
+ [
85
+ config_description,
86
+ "",
87
+ action_required,
88
+ ]
89
+ )
90
+ )
91
+
92
+ def _validate_schema_version(self):
93
+ config_schema_version = self.config.get("schema_version")
94
+ config_platform_helper_version = self.config.get("default_versions", {}).get(
95
+ "platform-helper", ""
96
+ )
97
+ header = SCHEMA_VERSION_MESSAGE.format(
98
+ installed_platform_helper_version=self._installed_platform_helper_version(),
99
+ installed_schema_version=self.schema_version_for_installed_platform_helper,
100
+ config_platform_helper_version=(
101
+ config_platform_helper_version if config_platform_helper_version else "N/A"
102
+ ),
103
+ config_schema_version=(config_schema_version if config_schema_version else "N/A"),
104
+ )
105
+
106
+ if config_schema_version:
107
+ self._handle_schema_version_mismatch(config_schema_version, header)
108
+ else:
109
+ self._handle_missing_schema_version(config_platform_helper_version, header)
110
+
111
+ def _handle_schema_version_mismatch(self, platform_config_schema_version: int, header: str):
112
+ platform_config_schema_version_is_old = (
113
+ platform_config_schema_version < self.schema_version_for_installed_platform_helper
114
+ )
115
+ installed_platform_helper_is_old = (
116
+ platform_config_schema_version > self.schema_version_for_installed_platform_helper
117
+ )
118
+
119
+ if platform_config_schema_version_is_old:
120
+ self._abort_due_to_schema_version_error(
121
+ header,
122
+ "Please upgrade your platform-config.yml by running 'platform-helper config migrate'.",
123
+ )
124
+ elif installed_platform_helper_is_old:
125
+ self._abort_due_to_schema_version_error(
126
+ header,
127
+ f"Please update your platform-helper to a version that supports schema_version: {platform_config_schema_version}.",
128
+ )
129
+ # else the schema_version is the correct one so continue.
130
+
131
+ def _handle_missing_schema_version(self, config_platform_helper_version: str, header: str):
132
+ config_p_h_version_semver = SemanticVersion.from_string(config_platform_helper_version)
133
+ major_version = config_p_h_version_semver and config_p_h_version_semver.major
134
+ platform_config_is_old_but_supported_by_migrations = (
135
+ major_version and major_version == FIRST_UPGRADABLE_PLATFORM_HELPER_MAJOR_VERSION
136
+ )
137
+ platform_config_is_old = (
138
+ major_version and major_version < FIRST_UPGRADABLE_PLATFORM_HELPER_MAJOR_VERSION
139
+ )
140
+ platform_config_is_really_old = not major_version
141
+ installed_platform_helper_version = self._installed_platform_helper_version()
142
+
143
+ if platform_config_is_old_but_supported_by_migrations:
144
+ self._abort_due_to_schema_version_error(
145
+ header,
146
+ f"Please upgrade your platform-config.yml to be compatible with {installed_platform_helper_version} by running: 'platform-helper config migrate'.",
147
+ )
148
+ elif platform_config_is_old or platform_config_is_really_old:
149
+ self._abort_due_to_schema_version_error(
150
+ header,
151
+ PLEASE_UPGRADE_TO_V13_MESSAGE.format(
152
+ installed_platform_helper_version=installed_platform_helper_version,
153
+ ),
154
+ )
155
+ # if major_version and major_version > FIRST_UPGRADABLE_PLATFORM_HELPER_MAJOR_VERSION then
156
+ # the platform-config.yml is malformed and so should progress to validation if appropriate.
157
+
61
158
  def load_unvalidated_config_file(self, path=PLATFORM_CONFIG_FILE):
62
159
  try:
63
160
  return self.file_provider.load(path)
64
161
  except FileProviderException:
65
162
  return {}
66
163
 
67
- # TODO remove function and push logic to where this is called.
164
+ # TODO: DBTP-1888: remove function and push logic to where this is called.
68
165
  # removed usage from config domain, code is very generic and doesn't require the overhead of a function
69
166
  def config_file_check(self, path=PLATFORM_CONFIG_FILE):
70
167
  if not Path(path).exists():
@@ -86,17 +183,12 @@ class ConfigProvider:
86
183
  name: data if data else {} for name, data in environments.items() if name != "*"
87
184
  }
88
185
 
89
- default_versions = config.get("default_versions", {})
186
+ config.get("default_versions", {})
90
187
 
91
188
  def combine_env_data(data):
92
189
  return {
93
190
  **env_defaults,
94
191
  **data,
95
- "versions": {
96
- **default_versions,
97
- **env_defaults.get("versions", {}),
98
- **data.get("versions", {}),
99
- },
100
192
  }
101
193
 
102
194
  defaulted_envs = {
@@ -107,3 +199,13 @@ class ConfigProvider:
107
199
  enriched_config["environments"] = defaulted_envs
108
200
 
109
201
  return enriched_config
202
+
203
+ def write_platform_config(self, new_platform_config):
204
+ current_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
205
+ message = f"# Generated by platform-helper {self._installed_platform_helper_version()} / {current_date}.\n\n"
206
+ self.file_provider.write(PLATFORM_CONFIG_FILE, new_platform_config, message)
207
+
208
+ def _installed_platform_helper_version(self) -> str:
209
+ return str(
210
+ self.installed_version_provider.get_semantic_version(PLATFORM_HELPER_PACKAGE_NAME)
211
+ )
@@ -89,16 +89,16 @@ class ConfigValidator:
89
89
  return self._validate_extension_supported_versions(
90
90
  config=config,
91
91
  aws_provider=Redis(self._get_client("elasticache")),
92
- extension_type="redis", # TODO this is information which can live in the RedisProvider
93
- version_key="engine", # TODO this is information which can live in the RedisProvider
92
+ extension_type="redis", # TODO: DBTP-1888: this is information which can live in the RedisProvider
93
+ version_key="engine", # TODO: DBTP-1888: this is information which can live in the RedisProvider
94
94
  )
95
95
 
96
96
  def validate_supported_opensearch_versions(self, config):
97
97
  return self._validate_extension_supported_versions(
98
98
  config=config,
99
99
  aws_provider=Opensearch(self._get_client("opensearch")),
100
- extension_type="opensearch", # TODO this is information which can live in the OpensearchProvider
101
- version_key="engine", # TODO this is information which can live in the OpensearchProvider
100
+ extension_type="opensearch", # TODO: DBTP-1888: this is information which can live in the OpensearchProvider
101
+ version_key="engine", # TODO: DBTP-1888: this is information which can live in the OpensearchProvider
102
102
  )
103
103
 
104
104
  def validate_environment_pipelines(self, config):
@@ -180,21 +180,6 @@ class ConfigValidator:
180
180
  from_env = section["from"]
181
181
  to_env = section["to"]
182
182
 
183
- from_account = (
184
- config.get("environments", {})
185
- .get(from_env, {})
186
- .get("accounts", {})
187
- .get("deploy", {})
188
- .get("id")
189
- )
190
- to_account = (
191
- config.get("environments", {})
192
- .get(to_env, {})
193
- .get("accounts", {})
194
- .get("deploy", {})
195
- .get("id")
196
- )
197
-
198
183
  if from_env == to_env:
199
184
  errors.append(
200
185
  f"database_copy 'to' and 'from' cannot be the same environment in extension '{extension_name}'."
@@ -215,18 +200,6 @@ class ConfigValidator:
215
200
  f"database_copy 'to' parameter must be a valid environment ({all_envs_string}) but was '{to_env}' in extension '{extension_name}'."
216
201
  )
217
202
 
218
- # TODO - The from_account and to_account properties are deprecated and will be removed when terraform-platform-modules is merged with platform-tools
219
- if from_account != to_account:
220
- if "from_account" in section and section["from_account"] != from_account:
221
- errors.append(
222
- f"Incorrect value for 'from_account' for environment '{from_env}'"
223
- )
224
-
225
- if "to_account" in section and section["to_account"] != to_account:
226
- errors.append(
227
- f"Incorrect value for 'to_account' for environment '{to_env}'"
228
- )
229
-
230
203
  if errors:
231
204
  raise ConfigValidatorError("\n".join(errors))
232
205
 
@@ -53,7 +53,7 @@ def create_addon_client_task(
53
53
  # We cannot check for botocore.errorfactory.NoSuchEntityException as botocore generates that class on the fly as part of errorfactory.
54
54
  # factory. Checking the error code is the recommended way of handling these exceptions.
55
55
  if ex.response.get("Error", {}).get("Code", None) != "NoSuchEntity":
56
- # TODO When we are refactoring this, raise an exception to be caught at the command layer
56
+ # TODO: DBTP-1946: When we are refactoring this, raise an exception to be caught at the command layer
57
57
  abort_with_error(
58
58
  f"cannot obtain Role {role_name}: {ex.response.get('Error', {}).get('Message', '')}"
59
59
  )
@@ -132,7 +132,7 @@ def connect_to_addon_client_task(
132
132
  tries = 0
133
133
  while tries < 15 and not running:
134
134
  tries += 1
135
- # Todo: Use from ECS provider when we refactor this
135
+ # TODO: DBTP-1946: Use from ECS provider when we refactor this
136
136
  if get_ecs_task_arns(ecs_client, cluster_arn, task_name):
137
137
  subprocess.call(
138
138
  "copilot task exec "
@@ -154,7 +154,7 @@ def _normalise_secret_name(addon_name: str) -> str:
154
154
 
155
155
 
156
156
  def _get_secrets_provider(application: Application, env: str) -> Secrets:
157
- # Todo: We instantiate the secrets provider here to avoid rabbit holing, but something better probably possible when we are refactoring this area
157
+ # TODO: DBTP-1946: We instantiate the secrets provider here to avoid rabbit holing, but something better probably possible when we are refactoring this area
158
158
  return Secrets(
159
159
  application.environments[env].session.client("ssm"),
160
160
  application.environments[env].session.client("secretsmanager"),
@@ -29,7 +29,7 @@ class ClickIOProvider:
29
29
  click.secho(f"Error: {message}", err=True, fg="red")
30
30
  exit(1)
31
31
 
32
- # TODO messages will be a ValidationMessages class rather than a free-rein dictionary
32
+ # TODO: DBTP-1979: messages will be a ValidationMessages class rather than a free-rein dictionary
33
33
  def process_messages(self, messages: dict):
34
34
  if not messages:
35
35
  return