dbt-platform-helper 12.0.2__tar.gz → 12.1.0__tar.gz

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 (95) hide show
  1. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/PKG-INFO +1 -1
  2. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/COMMANDS.md +2 -4
  3. dbt_platform_helper-12.1.0/dbt_platform_helper/commands/codebase.py +145 -0
  4. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/constants.py +1 -0
  5. dbt_platform_helper-12.1.0/dbt_platform_helper/domain/codebase.py +222 -0
  6. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/domain/database_copy.py +1 -1
  7. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/exceptions.py +28 -0
  8. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/utils/application.py +1 -4
  9. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/utils/aws.py +132 -0
  10. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/utils/files.py +70 -0
  11. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/utils/git.py +13 -0
  12. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/utils/validation.py +99 -2
  13. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/pyproject.toml +1 -1
  14. dbt_platform_helper-12.0.2/dbt_platform_helper/commands/codebase.py +0 -311
  15. dbt_platform_helper-12.0.2/dbt_platform_helper/templates/env/overrides/README.md +0 -11
  16. dbt_platform_helper-12.0.2/dbt_platform_helper/templates/env/overrides/bin/override.ts +0 -9
  17. dbt_platform_helper-12.0.2/dbt_platform_helper/templates/env/overrides/log_resource_policy.json +0 -68
  18. dbt_platform_helper-12.0.2/dbt_platform_helper/templates/env/overrides/package-lock.json +0 -4307
  19. dbt_platform_helper-12.0.2/dbt_platform_helper/templates/env/overrides/package.json +0 -27
  20. dbt_platform_helper-12.0.2/dbt_platform_helper/templates/env/overrides/stack.ts +0 -51
  21. dbt_platform_helper-12.0.2/dbt_platform_helper/templates/env/overrides/tsconfig.json +0 -32
  22. dbt_platform_helper-12.0.2/dbt_platform_helper/templates/pipelines/codebase/overrides/.gitignore +0 -12
  23. dbt_platform_helper-12.0.2/dbt_platform_helper/templates/pipelines/codebase/overrides/cdk.json +0 -20
  24. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/LICENSE +0 -0
  25. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/README.md +0 -0
  26. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/__init__.py +0 -0
  27. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/addon-plans.yml +0 -0
  28. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/addons-template-map.yml +0 -0
  29. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/commands/__init__.py +0 -0
  30. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/commands/application.py +0 -0
  31. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/commands/conduit.py +0 -0
  32. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/commands/config.py +0 -0
  33. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/commands/copilot.py +0 -0
  34. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/commands/database.py +0 -0
  35. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/commands/environment.py +0 -0
  36. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/commands/generate.py +0 -0
  37. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/commands/notify.py +0 -0
  38. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/commands/pipeline.py +0 -0
  39. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/commands/secrets.py +0 -0
  40. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/commands/version.py +0 -0
  41. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/default-extensions.yml +0 -0
  42. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/domain/__init__.py +0 -0
  43. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/domain/maintenance_page.py +0 -0
  44. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/jinja2_tags.py +0 -0
  45. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/providers/load_balancers.py +0 -0
  46. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/.copilot/config.yml +0 -0
  47. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/.copilot/image_build_run.sh +0 -0
  48. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/.copilot/phases/build.sh +0 -0
  49. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/.copilot/phases/install.sh +0 -0
  50. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/.copilot/phases/post_build.sh +0 -0
  51. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/.copilot/phases/pre_build.sh +0 -0
  52. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/COMMANDS.md.jinja +0 -0
  53. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/addon-instructions.txt +0 -0
  54. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/addons/README.md +0 -0
  55. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/addons/svc/appconfig-ipfilter.yml +0 -0
  56. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/addons/svc/prometheus-policy.yml +0 -0
  57. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/addons/svc/s3-policy.yml +0 -0
  58. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/addons/svc/subscription-filter.yml +0 -0
  59. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/ci-codebuild-role-policy.json +0 -0
  60. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/create-codebuild-role.json +0 -0
  61. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/custom-codebuild-role-policy.json +0 -0
  62. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/env/manifest.yml +0 -0
  63. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/env/terraform-overrides/cfn.patches.yml +0 -0
  64. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/environment-pipelines/main.tf +0 -0
  65. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/environments/main.tf +0 -0
  66. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/pipelines/codebase/manifest.yml +0 -0
  67. {dbt_platform_helper-12.0.2/dbt_platform_helper/templates/env → dbt_platform_helper-12.1.0/dbt_platform_helper/templates/pipelines/codebase}/overrides/.gitignore +0 -0
  68. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/bin/override.ts +0 -0
  69. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/buildspec.deploy.yml +0 -0
  70. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/buildspec.image.yml +0 -0
  71. {dbt_platform_helper-12.0.2/dbt_platform_helper/templates/env → dbt_platform_helper-12.1.0/dbt_platform_helper/templates/pipelines/codebase}/overrides/cdk.json +0 -0
  72. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/package-lock.json +0 -0
  73. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/package.json +0 -0
  74. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/stack.ts +0 -0
  75. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/tsconfig.json +0 -0
  76. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/types.ts +0 -0
  77. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/pipelines/environments/buildspec.yml +0 -0
  78. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/pipelines/environments/manifest.yml +0 -0
  79. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/pipelines/environments/overrides/cfn.patches.yml +0 -0
  80. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/svc/maintenance_pages/default.html +0 -0
  81. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/svc/maintenance_pages/dmas-migration.html +0 -0
  82. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/svc/maintenance_pages/migration.html +0 -0
  83. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/svc/manifest-backend.yml +0 -0
  84. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/svc/manifest-public.yml +0 -0
  85. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/templates/svc/overrides/cfn.patches.yml +0 -0
  86. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/utils/__init__.py +0 -0
  87. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/utils/arn_parser.py +0 -0
  88. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/utils/click.py +0 -0
  89. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/utils/cloudfoundry.py +0 -0
  90. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/utils/manifests.py +0 -0
  91. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/utils/messages.py +0 -0
  92. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/utils/platform_config.py +0 -0
  93. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/utils/template.py +0 -0
  94. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/dbt_platform_helper/utils/versioning.py +0 -0
  95. {dbt_platform_helper-12.0.2 → dbt_platform_helper-12.1.0}/platform_helper.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbt-platform-helper
3
- Version: 12.0.2
3
+ Version: 12.1.0
4
4
  Summary: Set of tools to help transfer applications/services from GOV.UK PaaS to DBT PaaS augmenting AWS Copilot.
5
5
  License: MIT
6
6
  Author: Department for Business and Trade Platform Team
@@ -222,7 +222,7 @@ platform-helper codebase build --app <application> --codebase <codebase>
222
222
  - `--app <text>`
223
223
  - AWS application name
224
224
  - `--codebase <text>`
225
- - The codebase name as specified in the pipelines.yml file
225
+ - The codebase name as specified in the platform-config.yml file
226
226
  - `--commit <text>`
227
227
  - GitHub commit hash
228
228
  - `--help <boolean>` _Defaults to False._
@@ -232,8 +232,6 @@ platform-helper codebase build --app <application> --codebase <codebase>
232
232
 
233
233
  [↩ Parent](#platform-helper-codebase)
234
234
 
235
- Trigger a CodePipeline pipeline based deployment.
236
-
237
235
  ## Usage
238
236
 
239
237
  ```
@@ -248,7 +246,7 @@ platform-helper codebase deploy --app <application> --env <environment> --codeba
248
246
  - `--env <text>`
249
247
  - AWS Copilot environment
250
248
  - `--codebase <text>`
251
- - The codebase name as specified in the pipelines.yml file
249
+ - The codebase name as specified in the platform-config.yml file
252
250
  - `--commit <text>`
253
251
  - GitHub commit hash
254
252
  - `--help <boolean>` _Defaults to False._
@@ -0,0 +1,145 @@
1
+ import json
2
+ import os
3
+
4
+ import click
5
+
6
+ from dbt_platform_helper.domain.codebase import Codebase
7
+ from dbt_platform_helper.exceptions import ApplicationDeploymentNotTriggered
8
+ from dbt_platform_helper.exceptions import ApplicationEnvironmentNotFoundError
9
+ from dbt_platform_helper.exceptions import ApplicationNotFoundError
10
+ from dbt_platform_helper.exceptions import CopilotCodebaseNotFoundError
11
+ from dbt_platform_helper.exceptions import ImageNotFoundError
12
+ from dbt_platform_helper.exceptions import NoCopilotCodebasesFoundError
13
+ from dbt_platform_helper.exceptions import NotInCodeBaseRepositoryError
14
+ from dbt_platform_helper.utils.click import ClickDocOptGroup
15
+ from dbt_platform_helper.utils.git import CommitNotFoundError
16
+ from dbt_platform_helper.utils.versioning import (
17
+ check_platform_helper_version_needs_update,
18
+ )
19
+
20
+
21
+ @click.group(chain=True, cls=ClickDocOptGroup)
22
+ def codebase():
23
+ """Codebase commands."""
24
+ check_platform_helper_version_needs_update()
25
+
26
+
27
+ @codebase.command()
28
+ def prepare():
29
+ """Sets up an application codebase for use within a DBT platform project."""
30
+ try:
31
+ Codebase().prepare()
32
+ except NotInCodeBaseRepositoryError:
33
+ # TODO print error attached to exception
34
+ click.secho(
35
+ "You are in the deploy repository; make sure you are in the application codebase repository.",
36
+ fg="red",
37
+ )
38
+ raise click.Abort
39
+
40
+
41
+ @codebase.command()
42
+ @click.option("--app", help="AWS application name", required=True)
43
+ @click.option(
44
+ "--with-images",
45
+ help="List up to the last 10 images tagged for this codebase",
46
+ default=False,
47
+ is_flag=True,
48
+ )
49
+ def list(app, with_images):
50
+ """List available codebases for the application."""
51
+ try:
52
+ Codebase().list(app, with_images)
53
+ except NoCopilotCodebasesFoundError:
54
+ click.secho(
55
+ f"""No codebases found for application "{app}""",
56
+ fg="red",
57
+ )
58
+ raise click.Abort
59
+ except ApplicationNotFoundError:
60
+ click.secho(
61
+ f"""The account "{os.environ.get("AWS_PROFILE")}" does not contain the application "{app}"; ensure you have set the environment variable "AWS_PROFILE" correctly.""",
62
+ fg="red",
63
+ )
64
+ raise click.Abort
65
+
66
+
67
+ @codebase.command()
68
+ @click.option("--app", help="AWS application name", required=True)
69
+ @click.option(
70
+ "--codebase",
71
+ help="The codebase name as specified in the platform-config.yml file",
72
+ required=True,
73
+ )
74
+ @click.option("--commit", help="GitHub commit hash", required=True)
75
+ def build(app, codebase, commit):
76
+ """Trigger a CodePipeline pipeline based build."""
77
+ try:
78
+ Codebase().build(app, codebase, commit)
79
+ except ApplicationNotFoundError:
80
+ click.secho(
81
+ f"""The account "{os.environ.get("AWS_PROFILE")}" does not contain the application "{app}"; ensure you have set the environment variable "AWS_PROFILE" correctly.""",
82
+ fg="red",
83
+ )
84
+ raise click.Abort
85
+ except CommitNotFoundError:
86
+ click.secho(
87
+ f'The commit hash "{commit}" either does not exist or you need to run `git fetch`.',
88
+ fg="red",
89
+ )
90
+ raise click.Abort
91
+ except ApplicationDeploymentNotTriggered:
92
+ click.secho(
93
+ f"Your build for {codebase} was not triggered.",
94
+ fg="red",
95
+ )
96
+ raise click.Abort
97
+
98
+
99
+ @codebase.command()
100
+ @click.option("--app", help="AWS application name", required=True)
101
+ @click.option("--env", help="AWS Copilot environment", required=True)
102
+ @click.option(
103
+ "--codebase",
104
+ help="The codebase name as specified in the platform-config.yml file",
105
+ required=True,
106
+ )
107
+ @click.option("--commit", help="GitHub commit hash", required=True)
108
+ def deploy(app, env, codebase, commit):
109
+ try:
110
+ Codebase().deploy(app, env, codebase, commit)
111
+ except ApplicationNotFoundError:
112
+ click.secho(
113
+ f"""The account "{os.environ.get("AWS_PROFILE")}" does not contain the application "{app}"; ensure you have set the environment variable "AWS_PROFILE" correctly.""",
114
+ fg="red",
115
+ )
116
+ raise click.Abort
117
+ except ApplicationEnvironmentNotFoundError:
118
+ click.secho(
119
+ f"""The environment "{env}" either does not exist or has not been deployed.""",
120
+ fg="red",
121
+ )
122
+ raise click.Abort
123
+ # TODO: don't hide json decode error
124
+ except (
125
+ CopilotCodebaseNotFoundError,
126
+ json.JSONDecodeError,
127
+ ):
128
+ click.secho(
129
+ f"""The codebase "{codebase}" either does not exist or has not been deployed.""",
130
+ fg="red",
131
+ )
132
+ raise click.Abort
133
+ except ImageNotFoundError:
134
+ click.secho(
135
+ f'The commit hash "{commit}" has not been built into an image, try the '
136
+ "`platform-helper codebase build` command first.",
137
+ fg="red",
138
+ )
139
+ raise click.Abort
140
+ except ApplicationDeploymentNotTriggered:
141
+ click.secho(
142
+ f"Your deployment for {codebase} was not triggered.",
143
+ fg="red",
144
+ )
145
+ raise click.Abort
@@ -3,3 +3,4 @@ PLATFORM_HELPER_VERSION_FILE = ".platform-helper-version"
3
3
  CODEBASE_PIPELINES_KEY = "codebase_pipelines"
4
4
  ENVIRONMENTS_KEY = "environments"
5
5
  DEFAULT_TERRAFORM_PLATFORM_MODULES_VERSION = "5"
6
+ PLATFORM_HELPER_CACHE_FILE = ".platform-helper-config-cache.yml"
@@ -0,0 +1,222 @@
1
+ import json
2
+ import stat
3
+ import subprocess
4
+ from collections.abc import Callable
5
+ from pathlib import Path
6
+
7
+ import click
8
+ import requests
9
+ import yaml
10
+ from boto3 import Session
11
+
12
+ from dbt_platform_helper.exceptions import ApplicationDeploymentNotTriggered
13
+ from dbt_platform_helper.exceptions import ApplicationEnvironmentNotFoundError
14
+ from dbt_platform_helper.exceptions import NoCopilotCodebasesFoundError
15
+ from dbt_platform_helper.exceptions import NotInCodeBaseRepositoryError
16
+ from dbt_platform_helper.utils.application import Application
17
+ from dbt_platform_helper.utils.application import load_application
18
+ from dbt_platform_helper.utils.aws import check_codebase_exists
19
+ from dbt_platform_helper.utils.aws import check_image_exists
20
+ from dbt_platform_helper.utils.aws import get_aws_session_or_abort
21
+ from dbt_platform_helper.utils.aws import get_build_url_from_arn
22
+ from dbt_platform_helper.utils.aws import list_latest_images
23
+ from dbt_platform_helper.utils.aws import start_build_extraction
24
+ from dbt_platform_helper.utils.files import mkfile
25
+ from dbt_platform_helper.utils.git import check_if_commit_exists
26
+ from dbt_platform_helper.utils.template import setup_templates
27
+
28
+
29
+ class Codebase:
30
+ def __init__(
31
+ self,
32
+ input_fn: Callable[[str], str] = click.prompt,
33
+ echo_fn: Callable[[str], str] = click.secho,
34
+ confirm_fn: Callable[[str], bool] = click.confirm,
35
+ load_application_fn: Callable[[str], Application] = load_application,
36
+ get_aws_session_or_abort_fn: Callable[[str], Session] = get_aws_session_or_abort,
37
+ check_codebase_exists_fn: Callable[[str], str] = check_codebase_exists,
38
+ check_image_exists_fn: Callable[[str], str] = check_image_exists,
39
+ get_build_url_from_arn_fn: Callable[[str], str] = get_build_url_from_arn,
40
+ list_latest_images_fn: Callable[[str], str] = list_latest_images,
41
+ start_build_extraction_fn: Callable[[str], str] = start_build_extraction,
42
+ check_if_commit_exists_fn: Callable[[str], str] = check_if_commit_exists,
43
+ subprocess: Callable[[str], str] = subprocess.run,
44
+ ):
45
+ self.input_fn = input_fn
46
+ self.echo_fn = echo_fn
47
+ self.confirm_fn = confirm_fn
48
+ self.load_application_fn = load_application_fn
49
+ self.get_aws_session_or_abort_fn = get_aws_session_or_abort_fn
50
+ self.check_codebase_exists_fn = check_codebase_exists_fn
51
+ self.check_image_exists_fn = check_image_exists_fn
52
+ self.get_build_url_from_arn_fn = get_build_url_from_arn_fn
53
+ self.list_latest_images_fn = list_latest_images_fn
54
+ self.start_build_extraction_fn = start_build_extraction_fn
55
+ self.check_if_commit_exists_fn = check_if_commit_exists_fn
56
+ self.subprocess = subprocess
57
+
58
+ def prepare(self):
59
+ """Sets up an application codebase for use within a DBT platform
60
+ project."""
61
+ templates = setup_templates()
62
+
63
+ repository = (
64
+ self.subprocess(["git", "remote", "get-url", "origin"], capture_output=True, text=True)
65
+ .stdout.split("/")[-1]
66
+ .strip()
67
+ .removesuffix(".git")
68
+ )
69
+ if repository.endswith("-deploy") or Path("./copilot").exists():
70
+ raise NotInCodeBaseRepositoryError
71
+
72
+ builder_configuration_url = "https://raw.githubusercontent.com/uktrade/ci-image-builder/main/image_builder/configuration/builder_configuration.yml"
73
+ builder_configuration_response = requests.get(builder_configuration_url)
74
+ builder_configuration_content = yaml.safe_load(
75
+ builder_configuration_response.content.decode("utf-8")
76
+ )
77
+ builder_versions = next(
78
+ (
79
+ item
80
+ for item in builder_configuration_content["builders"]
81
+ if item["name"] == "paketobuildpacks/builder-jammy-base"
82
+ ),
83
+ None,
84
+ )
85
+ builder_version = max(x["version"] for x in builder_versions["versions"])
86
+ builder_version = min(builder_version, "0.4.240")
87
+
88
+ Path("./.copilot/phases").mkdir(parents=True, exist_ok=True)
89
+ image_build_run_contents = templates.get_template(f".copilot/image_build_run.sh").render()
90
+
91
+ config_contents = templates.get_template(f".copilot/config.yml").render(
92
+ repository=repository, builder_version=builder_version
93
+ )
94
+ self.echo_fn(
95
+ mkfile(
96
+ Path("."), ".copilot/image_build_run.sh", image_build_run_contents, overwrite=True
97
+ )
98
+ )
99
+
100
+ image_build_run_file = Path(".copilot/image_build_run.sh")
101
+ image_build_run_file.chmod(image_build_run_file.stat().st_mode | stat.S_IEXEC)
102
+
103
+ self.echo_fn(mkfile(Path("."), ".copilot/config.yml", config_contents, overwrite=True))
104
+
105
+ for phase in ["build", "install", "post_build", "pre_build"]:
106
+ phase_contents = templates.get_template(f".copilot/phases/{phase}.sh").render()
107
+
108
+ self.echo_fn(
109
+ mkfile(Path("./.copilot"), f"phases/{phase}.sh", phase_contents, overwrite=True)
110
+ )
111
+
112
+ def build(self, app: str, codebase: str, commit: str):
113
+ """Trigger a CodePipeline pipeline based build."""
114
+ session = self.get_aws_session_or_abort_fn()
115
+ self.load_application_fn(app, default_session=session)
116
+
117
+ self.check_if_commit_exists_fn(commit)
118
+
119
+ codebuild_client = session.client("codebuild")
120
+ build_url = self.__start_build_with_confirmation(
121
+ self.confirm_fn,
122
+ codebuild_client,
123
+ self.get_build_url_from_arn_fn,
124
+ f'You are about to build "{app}" for "{codebase}" with commit "{commit}". Do you want to continue?',
125
+ {
126
+ "projectName": f"codebuild-{app}-{codebase}",
127
+ "artifactsOverride": {"type": "NO_ARTIFACTS"},
128
+ "sourceVersion": commit,
129
+ },
130
+ )
131
+
132
+ if build_url:
133
+ return self.echo_fn(
134
+ f"Your build has been triggered. Check your build progress in the AWS Console: {build_url}"
135
+ )
136
+
137
+ raise ApplicationDeploymentNotTriggered()
138
+
139
+ def deploy(self, app, env, codebase, commit):
140
+ """Trigger a CodePipeline pipeline based deployment."""
141
+ session = self.get_aws_session_or_abort_fn()
142
+
143
+ application = self.load_application_fn(app, default_session=session)
144
+ if not application.environments.get(env):
145
+ raise ApplicationEnvironmentNotFoundError()
146
+
147
+ json.loads(self.check_codebase_exists_fn(session, application, codebase))
148
+
149
+ self.check_image_exists_fn(session, application, codebase, commit)
150
+
151
+ codebuild_client = session.client("codebuild")
152
+ build_url = self.__start_build_with_confirmation(
153
+ self.confirm_fn,
154
+ codebuild_client,
155
+ self.get_build_url_from_arn_fn,
156
+ f'You are about to deploy "{app}" for "{codebase}" with commit "{commit}" to the "{env}" environment. Do you want to continue?',
157
+ {
158
+ "projectName": f"pipeline-{application.name}-{codebase}-BuildProject",
159
+ "artifactsOverride": {"type": "NO_ARTIFACTS"},
160
+ "sourceTypeOverride": "NO_SOURCE",
161
+ "environmentVariablesOverride": [
162
+ {"name": "COPILOT_ENVIRONMENT", "value": env},
163
+ {"name": "IMAGE_TAG", "value": f"commit-{commit}"},
164
+ ],
165
+ },
166
+ )
167
+
168
+ if build_url:
169
+ return self.echo_fn(
170
+ "Your deployment has been triggered. Check your build progress in the AWS Console: "
171
+ f"{build_url}",
172
+ )
173
+
174
+ raise ApplicationDeploymentNotTriggered()
175
+
176
+ def list(self, app: str, with_images: bool):
177
+ """List available codebases for the application."""
178
+ session = self.get_aws_session_or_abort_fn()
179
+ application = self.load_application_fn(app, session)
180
+ ssm_client = session.client("ssm")
181
+ ecr_client = session.client("ecr")
182
+ codebases = self.__get_codebases(application, ssm_client)
183
+
184
+ self.echo_fn("The following codebases are available:")
185
+
186
+ for codebase in codebases:
187
+ self.echo_fn(f"- {codebase['name']} (https://github.com/{codebase['repository']})")
188
+ if with_images:
189
+ self.list_latest_images_fn(
190
+ ecr_client,
191
+ f"{application.name}/{codebase['name']}",
192
+ codebase["repository"],
193
+ self.echo_fn,
194
+ )
195
+
196
+ self.echo_fn("")
197
+
198
+ # TODO return empty list without exception
199
+ def __get_codebases(self, application, ssm_client):
200
+ parameters = ssm_client.get_parameters_by_path(
201
+ Path=f"/copilot/applications/{application.name}/codebases",
202
+ Recursive=True,
203
+ )["Parameters"]
204
+
205
+ codebases = [json.loads(p["Value"]) for p in parameters]
206
+
207
+ if not codebases:
208
+ raise NoCopilotCodebasesFoundError
209
+ return codebases
210
+
211
+ def __start_build_with_confirmation(
212
+ self,
213
+ confirm_fn,
214
+ codebuild_client,
215
+ get_build_url_from_arn_fn,
216
+ confirmation_message,
217
+ build_options,
218
+ ):
219
+ if confirm_fn(confirmation_message):
220
+ build_arn = self.start_build_extraction_fn(codebuild_client, build_options)
221
+ return get_build_url_from_arn_fn(build_arn)
222
+ return None
@@ -8,9 +8,9 @@ from boto3 import Session
8
8
 
9
9
  from dbt_platform_helper.constants import PLATFORM_CONFIG_FILE
10
10
  from dbt_platform_helper.domain.maintenance_page import MaintenancePageProvider
11
+ from dbt_platform_helper.exceptions import ApplicationNotFoundError
11
12
  from dbt_platform_helper.exceptions import AWSException
12
13
  from dbt_platform_helper.utils.application import Application
13
- from dbt_platform_helper.utils.application import ApplicationNotFoundError
14
14
  from dbt_platform_helper.utils.application import load_application
15
15
  from dbt_platform_helper.utils.aws import Vpc
16
16
  from dbt_platform_helper.utils.aws import get_connection_string
@@ -18,3 +18,31 @@ class IncompatibleMinorVersion(ValidationException):
18
18
  super().__init__()
19
19
  self.app_version = app_version
20
20
  self.check_version = check_version
21
+
22
+
23
+ class CopilotCodebaseNotFoundError(Exception):
24
+ pass
25
+
26
+
27
+ class NotInCodeBaseRepositoryError(Exception):
28
+ pass
29
+
30
+
31
+ class NoCopilotCodebasesFoundError(Exception):
32
+ pass
33
+
34
+
35
+ class ImageNotFoundError(Exception):
36
+ pass
37
+
38
+
39
+ class ApplicationDeploymentNotTriggered(Exception):
40
+ pass
41
+
42
+
43
+ class ApplicationNotFoundError(Exception):
44
+ pass
45
+
46
+
47
+ class ApplicationEnvironmentNotFoundError(Exception):
48
+ pass
@@ -8,6 +8,7 @@ import yaml
8
8
  from boto3 import Session
9
9
  from yaml.parser import ParserError
10
10
 
11
+ from dbt_platform_helper.exceptions import ApplicationNotFoundError
11
12
  from dbt_platform_helper.utils.aws import get_aws_session_or_abort
12
13
  from dbt_platform_helper.utils.aws import get_profile_name_from_account_id
13
14
  from dbt_platform_helper.utils.aws import get_ssm_secrets
@@ -67,10 +68,6 @@ class Application:
67
68
  return str(self) == str(other)
68
69
 
69
70
 
70
- class ApplicationNotFoundError(Exception):
71
- pass
72
-
73
-
74
71
  def load_application(app: str = None, default_session: Session = None) -> Application:
75
72
  application = Application(app if app else get_application_name())
76
73
  current_session = default_session if default_session else get_aws_session_or_abort()
@@ -13,7 +13,12 @@ import yaml
13
13
  from boto3 import Session
14
14
 
15
15
  from dbt_platform_helper.exceptions import AWSException
16
+ from dbt_platform_helper.exceptions import CopilotCodebaseNotFoundError
17
+ from dbt_platform_helper.exceptions import ImageNotFoundError
16
18
  from dbt_platform_helper.exceptions import ValidationException
19
+ from dbt_platform_helper.utils.files import cache_refresh_required
20
+ from dbt_platform_helper.utils.files import read_supported_versions_from_cache
21
+ from dbt_platform_helper.utils.files import write_to_cache
17
22
 
18
23
  SSM_BASE_PATH = "/copilot/{app}/{env}/secrets/"
19
24
  SSM_PATH = "/copilot/{app}/{env}/secrets/{name}"
@@ -351,6 +356,59 @@ def get_postgres_connection_data_updated_with_master_secret(session, parameter_n
351
356
  return parameter_data
352
357
 
353
358
 
359
+ def get_supported_redis_versions():
360
+
361
+ if cache_refresh_required("redis"):
362
+
363
+ supported_versions = []
364
+
365
+ session = get_aws_session_or_abort()
366
+ elasticache_client = session.client("elasticache")
367
+
368
+ supported_versions_response = elasticache_client.describe_cache_engine_versions(
369
+ Engine="redis"
370
+ )
371
+
372
+ supported_versions = [
373
+ version["EngineVersion"]
374
+ for version in supported_versions_response["CacheEngineVersions"]
375
+ ]
376
+
377
+ write_to_cache("redis", supported_versions)
378
+
379
+ return supported_versions
380
+
381
+ else:
382
+ return read_supported_versions_from_cache("redis")
383
+
384
+
385
+ def get_supported_opensearch_versions():
386
+
387
+ if cache_refresh_required("opensearch"):
388
+
389
+ supported_versions = []
390
+
391
+ session = get_aws_session_or_abort()
392
+ opensearch_client = session.client("opensearch")
393
+
394
+ response = opensearch_client.list_versions()
395
+ all_versions = response["Versions"]
396
+
397
+ opensearch_versions = [
398
+ version for version in all_versions if not version.startswith("Elasticsearch_")
399
+ ]
400
+ supported_versions = [
401
+ version.removeprefix("OpenSearch_") for version in opensearch_versions
402
+ ]
403
+
404
+ write_to_cache("opensearch", supported_versions)
405
+
406
+ return supported_versions
407
+
408
+ else:
409
+ return read_supported_versions_from_cache("opensearch")
410
+
411
+
354
412
  def get_connection_string(
355
413
  session: Session,
356
414
  app: str,
@@ -420,3 +478,77 @@ def get_vpc_info_by_name(session: Session, app: str, env: str, vpc_name: str) ->
420
478
  raise AWSException(f"No matching security groups found in vpc '{vpc_name}'")
421
479
 
422
480
  return Vpc(subnets, sec_groups)
481
+
482
+
483
+ def start_build_extraction(codebuild_client, build_options):
484
+ response = codebuild_client.start_build(**build_options)
485
+ return response["build"]["arn"]
486
+
487
+
488
+ def check_codebase_exists(session: Session, application, codebase: str):
489
+ try:
490
+ ssm_client = session.client("ssm")
491
+ ssm_client.get_parameter(
492
+ Name=f"/copilot/applications/{application.name}/codebases/{codebase}"
493
+ )["Parameter"]["Value"]
494
+ except (
495
+ KeyError,
496
+ ValueError,
497
+ ssm_client.exceptions.ParameterNotFound,
498
+ ):
499
+ raise CopilotCodebaseNotFoundError
500
+
501
+
502
+ def check_image_exists(session, application, codebase, commit):
503
+ ecr_client = session.client("ecr")
504
+ try:
505
+ ecr_client.describe_images(
506
+ repositoryName=f"{application.name}/{codebase}",
507
+ imageIds=[{"imageTag": f"commit-{commit}"}],
508
+ )
509
+ except (
510
+ ecr_client.exceptions.RepositoryNotFoundException,
511
+ ecr_client.exceptions.ImageNotFoundException,
512
+ ):
513
+ raise ImageNotFoundError
514
+
515
+
516
+ def get_build_url_from_arn(build_arn: str) -> str:
517
+ _, _, _, region, account_id, project_name, build_id = build_arn.split(":")
518
+ project_name = project_name.removeprefix("build/")
519
+ return (
520
+ f"https://eu-west-2.console.aws.amazon.com/codesuite/codebuild/{account_id}/projects/"
521
+ f"{project_name}/build/{project_name}%3A{build_id}"
522
+ )
523
+
524
+
525
+ def list_latest_images(ecr_client, ecr_repository_name, codebase_repository, echo_fn):
526
+ paginator = ecr_client.get_paginator("describe_images")
527
+ describe_images_response_iterator = paginator.paginate(
528
+ repositoryName=ecr_repository_name,
529
+ filter={"tagStatus": "TAGGED"},
530
+ )
531
+ images = []
532
+ for page in describe_images_response_iterator:
533
+ images += page["imageDetails"]
534
+
535
+ sorted_images = sorted(
536
+ images,
537
+ key=lambda i: i["imagePushedAt"],
538
+ reverse=True,
539
+ )
540
+
541
+ MAX_RESULTS = 20
542
+
543
+ for image in sorted_images[:MAX_RESULTS]:
544
+ try:
545
+ commit_tag = next(t for t in image["imageTags"] if t.startswith("commit-"))
546
+ if not commit_tag:
547
+ continue
548
+
549
+ commit_hash = commit_tag.replace("commit-", "")
550
+ echo_fn(
551
+ f" - https://github.com/{codebase_repository}/commit/{commit_hash} - published: {image['imagePushedAt']}"
552
+ )
553
+ except StopIteration:
554
+ continue