diff --git a/docs/getting-started.md b/docs/getting-started.md index 94d86508..cf57b167 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -4,7 +4,7 @@ The GitOps CLI provides several commands which can be used to perform typical op ``` usage: gitopscli [-h] - {deploy,sync-apps,add-pr-comment,create-preview,delete-preview,version} + {deploy,sync-apps,add-pr-comment,create-preview,create-pr-preview,delete-preview,delete-pr-preview,version} ... GitOps CLI @@ -13,13 +13,15 @@ options: -h, --help show this help message and exit commands: - {deploy,sync-apps,add-pr-comment,create-preview,delete-preview,version} + {deploy,sync-apps,add-pr-comment,create-preview,create-pr-preview,delete-preview,delete-pr-preview,version} deploy Trigger a new deployment by changing YAML values sync-apps Synchronize applications (= every directory) from apps config repository to apps root config add-pr-comment Create a comment on the pull request create-preview Create a preview environment + create-pr-preview Create a preview environment for a pull request delete-preview Delete a preview environment + delete-pr-preview Delete a preview environment for a pull request version Show the GitOps CLI version information ``` diff --git a/docs/includes/preview-configuration.md b/docs/includes/preview-configuration.md index 1f6c9bff..ae8fdaab 100644 --- a/docs/includes/preview-configuration.md +++ b/docs/includes/preview-configuration.md @@ -1,7 +1,11 @@ ## Configuration ### Preview Templates -You have to provide a folder with the deployment configuration templates for every application you want to use this command for. By default it is assumed that this folder is located in your *deployment config repository* under the top-level folder `.preview-templates`. For example `.preview-templates/app-xy` for your app `app-xy`. The `create-preview` command simply copies this directory to the root of your *deployment config repository* and replaces e.g. image tag and route host which are specific to this preview. +You have to provide a folder with the deployment configuration templates for every application you want to use this command for. + +By default it is assumed that this folder is located in your *deployment config repository* under the top-level folder `.preview-templates`. For example `.preview-templates/app-xy` for your app `app-xy`. The `create-preview` command simply copies this directory to your *deployment config repository* and replaces e.g. image tag and route host which are specific to this preview. + +By default previews are created in the repository root. If `previewConfig.target.path` is set, previews are created below that path instead. ``` deployment-config-repo/ @@ -44,6 +48,7 @@ previewConfig: target: organisation: deployments repository: deployment-config-repo +# path: custom/${APPLICATION_NAME} # optional (defaults to repo's root directory) # branch: master # optional (defaults to repo's default branch) # namespace: ${APPLICATION_NAME}-${PREVIEW_ID_HASH}-preview' # optional (default: '${APPLICATION_NAME}-${PREVIEW_ID}-${PREVIEW_ID_HASH_SHORT}-preview', # Invalid characters in PREVIEW_ID will be replaced. PREVIEW_ID will be diff --git a/gitopscli/commands/create_preview.py b/gitopscli/commands/create_preview.py index 3b4c0b2e..d607cd4e 100644 --- a/gitopscli/commands/create_preview.py +++ b/gitopscli/commands/create_preview.py @@ -128,12 +128,13 @@ def __create_preview_from_template_if_not_existing( gitops_config: GitOpsConfig, ) -> bool: preview_namespace = gitops_config.get_preview_namespace(self.__args.preview_id) - full_preview_folder_path = target_git_repo.get_full_file_path(preview_namespace) + preview_folder_path = gitops_config.get_preview_folder_path(self.__args.preview_id) + full_preview_folder_path = target_git_repo.get_full_file_path(preview_folder_path) preview_env_already_exist = Path(full_preview_folder_path).is_dir() if preview_env_already_exist: - logging.info("Use existing folder for preview: %s", preview_namespace) + logging.info("Use existing folder for preview: %s (path: %s)", preview_namespace, preview_folder_path) return False - logging.info("Create new folder for preview: %s", preview_namespace) + logging.info("Create new folder for preview: %s (path: %s)", preview_namespace, preview_folder_path) full_preview_template_folder_path = template_git_repo.get_full_file_path(gitops_config.preview_template_path) if not Path(full_preview_template_folder_path).is_dir(): raise GitOpsException(f"The preview template folder does not exist: {gitops_config.preview_template_path}") @@ -143,7 +144,7 @@ def __create_preview_from_template_if_not_existing( def __replace_values(self, git_repo: GitRepo, gitops_config: GitOpsConfig) -> bool: preview_id = self.__args.preview_id - preview_folder_name = gitops_config.get_preview_namespace(self.__args.preview_id) + preview_folder_path = gitops_config.get_preview_folder_path(self.__args.preview_id) context = GitOpsConfig.Replacement.PreviewContext(gitops_config, preview_id, self.__args.git_hash) any_value_replaced = False for file, replacements in gitops_config.replacements.items(): @@ -151,7 +152,7 @@ def __replace_values(self, git_repo: GitRepo, gitops_config: GitOpsConfig) -> bo replacement_value = replacement.get_value(context) value_replaced = self.__update_yaml_file( git_repo, - f"{preview_folder_name}/{file}", + f"{preview_folder_path}/{file}", replacement.path, replacement_value, ) diff --git a/gitopscli/commands/delete_preview.py b/gitopscli/commands/delete_preview.py index 4b1deee0..cc390b26 100644 --- a/gitopscli/commands/delete_preview.py +++ b/gitopscli/commands/delete_preview.py @@ -38,9 +38,10 @@ def execute(self) -> None: preview_target_git_repo.clone(gitops_config.preview_target_branch) preview_namespace = gitops_config.get_preview_namespace(preview_id) - logging.info("Preview folder name: %s", preview_namespace) + preview_folder_path = gitops_config.get_preview_folder_path(preview_id) + logging.info("Preview folder name: %s (path: %s)", preview_namespace, preview_folder_path) - preview_folder_exists = self.__delete_folder_if_exists(preview_target_git_repo, preview_namespace) + preview_folder_exists = self.__delete_folder_if_exists(preview_target_git_repo, preview_folder_path) if not preview_folder_exists: if self.__args.expect_preview_exists: raise GitOpsException(f"There was no preview with name: {preview_namespace}") diff --git a/gitopscli/gitops_config.py b/gitopscli/gitops_config.py index 0f30c61a..0e002050 100644 --- a/gitopscli/gitops_config.py +++ b/gitopscli/gitops_config.py @@ -69,6 +69,7 @@ def get_value(self, context: PreviewContext) -> str: preview_target_branch: str | None preview_target_namespace_template: str preview_target_max_namespace_length: int + preview_target_path_template: str replacements: dict[str, list[Replacement]] @@ -76,6 +77,10 @@ def get_value(self, context: PreviewContext) -> str: def preview_template_path(self) -> str: return self.preview_template_path_template.replace("${APPLICATION_NAME}", self.application_name) + @property + def preview_target_path(self) -> str: + return self.preview_target_path_template.replace("${APPLICATION_NAME}", self.application_name) + def __post_init__(self) -> None: assert isinstance(self.application_name, str), "application_name of wrong type!" assert isinstance(self.preview_host_template, str), "preview_host_template of wrong type!" @@ -106,6 +111,8 @@ def __post_init__(self) -> None: int, ), "preview_target_max_namespace_length of wrong type!" assert self.preview_target_max_namespace_length >= 1, "preview_target_max_namespace_length is < 1!" + assert isinstance(self.preview_target_path_template, str), "preview_target_path_template of wrong type!" + self.__assert_variables(self.preview_target_path_template, {"APPLICATION_NAME"}) assert isinstance(self.replacements, dict), "replacements of wrong type!" for file, replacements in self.replacements.items(): assert isinstance(file, str), f"replacement file '{file}' of wrong type!" @@ -120,6 +127,12 @@ def get_preview_host(self, preview_id: str) -> str: preview_host = preview_host.replace("${PREVIEW_ID}", self.__sanitize(preview_id)) return preview_host.replace("${PREVIEW_NAMESPACE}", self.get_preview_namespace(preview_id)) + def get_preview_folder_path(self, preview_id: str) -> str: + preview_namespace = self.get_preview_namespace(preview_id) + if self.preview_target_path: + return f"{self.preview_target_path}/{preview_namespace}" + return preview_namespace + def get_preview_namespace(self, preview_id: str) -> str: preview_namespace = self.preview_target_namespace_template preview_namespace = preview_namespace.replace("${APPLICATION_NAME}", self.application_name) @@ -325,6 +338,7 @@ def __parse_v0(self) -> GitOpsConfig: preview_target_branch=None, # use default branch preview_target_namespace_template="${APPLICATION_NAME}-${PREVIEW_ID_HASH}-preview", preview_target_max_namespace_length=63, + preview_target_path_template="", replacements=replacements, ) @@ -364,6 +378,9 @@ def add_var_dollar(template: str) -> str: ), ), preview_target_max_namespace_length=63, + preview_target_path_template=add_var_dollar( + self.__get_string_value_or_default("previewConfig.target.path", ""), + ), replacements=replacements, ) @@ -439,5 +456,9 @@ def __parse_v2(self) -> GitOpsConfig: "${APPLICATION_NAME}-${PREVIEW_ID}-${PREVIEW_ID_HASH_SHORT}-preview", ), preview_target_max_namespace_length=preview_target_max_namespace_length, + preview_target_path_template=self.__get_string_value_or_default( + "previewConfig.target.path", + "", + ), replacements=replacements, ) diff --git a/tests/commands/test_create_preview.py b/tests/commands/test_create_preview.py index 06c5ad4f..30a2dd89 100644 --- a/tests/commands/test_create_preview.py +++ b/tests/commands/test_create_preview.py @@ -78,6 +78,7 @@ def setUp(self): preview_target_branch=None, preview_target_namespace_template="my-app-${PREVIEW_ID_HASH}-preview", preview_target_max_namespace_length=50, + preview_target_path_template="", replacements={ "Chart.yaml": [GitOpsConfig.Replacement(path="name", value_template="${PREVIEW_NAMESPACE}")], "values.yaml": [ @@ -165,7 +166,9 @@ def test_create_new_preview(self): call.GitRepo.get_full_file_path("my-app-685912d3-preview"), call.Path("/tmp/target-repo/my-app-685912d3-preview"), call.Path.is_dir(), - call.logging.info("Create new folder for preview: %s", "my-app-685912d3-preview"), + call.logging.info( + "Create new folder for preview: %s (path: %s)", "my-app-685912d3-preview", "my-app-685912d3-preview" + ), call.GitRepo.get_full_file_path(".preview-templates/my-app"), call.Path("/tmp/template-repo/.preview-templates/my-app"), call.Path.is_dir(), @@ -231,6 +234,7 @@ def test_create_new_preview_from_same_template_target_repo(self): preview_target_branch=gitops_config.preview_target_branch, preview_target_namespace_template=gitops_config.preview_target_namespace_template, preview_target_max_namespace_length=gitops_config.preview_target_max_namespace_length, + preview_target_path_template=gitops_config.preview_target_path_template, replacements=gitops_config.replacements, ) @@ -270,7 +274,9 @@ def test_create_new_preview_from_same_template_target_repo(self): call.GitRepo.get_full_file_path("my-app-685912d3-preview"), call.Path("/tmp/target-repo/my-app-685912d3-preview"), call.Path.is_dir(), - call.logging.info("Create new folder for preview: %s", "my-app-685912d3-preview"), + call.logging.info( + "Create new folder for preview: %s (path: %s)", "my-app-685912d3-preview", "my-app-685912d3-preview" + ), call.GitRepo.get_full_file_path(".preview-templates/my-app"), call.Path("/tmp/target-repo/.preview-templates/my-app"), call.Path.is_dir(), @@ -347,7 +353,9 @@ def test_update_existing_preview(self): call.GitRepo.get_full_file_path("my-app-685912d3-preview"), call.Path("/tmp/target-repo/my-app-685912d3-preview"), call.Path.is_dir(), - call.logging.info("Use existing folder for preview: %s", "my-app-685912d3-preview"), + call.logging.info( + "Use existing folder for preview: %s (path: %s)", "my-app-685912d3-preview", "my-app-685912d3-preview" + ), call.GitRepo.get_full_file_path("my-app-685912d3-preview/Chart.yaml"), call.update_yaml_file( "/tmp/target-repo/my-app-685912d3-preview/Chart.yaml", "name", "my-app-685912d3-preview" @@ -419,7 +427,9 @@ def test_preview_already_up_to_date(self): call.GitRepo.get_full_file_path("my-app-685912d3-preview"), call.Path("/tmp/target-repo/my-app-685912d3-preview"), call.Path.is_dir(), - call.logging.info("Use existing folder for preview: %s", "my-app-685912d3-preview"), + call.logging.info( + "Use existing folder for preview: %s (path: %s)", "my-app-685912d3-preview", "my-app-685912d3-preview" + ), call.GitRepo.get_full_file_path("my-app-685912d3-preview/Chart.yaml"), call.update_yaml_file( "/tmp/target-repo/my-app-685912d3-preview/Chart.yaml", "name", "my-app-685912d3-preview" @@ -471,7 +481,9 @@ def test_create_preview_for_unknown_template(self): call.GitRepo.get_full_file_path("my-app-685912d3-preview"), call.Path("/tmp/target-repo/my-app-685912d3-preview"), call.Path.is_dir(), - call.logging.info("Create new folder for preview: %s", "my-app-685912d3-preview"), + call.logging.info( + "Create new folder for preview: %s (path: %s)", "my-app-685912d3-preview", "my-app-685912d3-preview" + ), call.GitRepo.get_full_file_path(".preview-templates/my-app"), call.Path("/tmp/template-repo/.preview-templates/my-app"), call.Path.is_dir(), @@ -498,7 +510,9 @@ def test_create_preview_values_yaml_not_found(self): call.GitRepo.get_full_file_path("my-app-685912d3-preview"), call.Path("/tmp/target-repo/my-app-685912d3-preview"), call.Path.is_dir(), - call.logging.info("Use existing folder for preview: %s", "my-app-685912d3-preview"), + call.logging.info( + "Use existing folder for preview: %s (path: %s)", "my-app-685912d3-preview", "my-app-685912d3-preview" + ), call.GitRepo.get_full_file_path("my-app-685912d3-preview/Chart.yaml"), call.update_yaml_file( "/tmp/target-repo/my-app-685912d3-preview/Chart.yaml", "name", "my-app-685912d3-preview" @@ -526,7 +540,9 @@ def test_create_preview_values_yaml_parse_error(self): call.GitRepo.get_full_file_path("my-app-685912d3-preview"), call.Path("/tmp/target-repo/my-app-685912d3-preview"), call.Path.is_dir(), - call.logging.info("Use existing folder for preview: %s", "my-app-685912d3-preview"), + call.logging.info( + "Use existing folder for preview: %s (path: %s)", "my-app-685912d3-preview", "my-app-685912d3-preview" + ), call.GitRepo.get_full_file_path("my-app-685912d3-preview/Chart.yaml"), call.update_yaml_file( "/tmp/target-repo/my-app-685912d3-preview/Chart.yaml", "name", "my-app-685912d3-preview" @@ -554,7 +570,9 @@ def test_create_preview_with_invalid_replacement_path(self): call.GitRepo.get_full_file_path("my-app-685912d3-preview"), call.Path("/tmp/target-repo/my-app-685912d3-preview"), call.Path.is_dir(), - call.logging.info("Use existing folder for preview: %s", "my-app-685912d3-preview"), + call.logging.info( + "Use existing folder for preview: %s (path: %s)", "my-app-685912d3-preview", "my-app-685912d3-preview" + ), call.GitRepo.get_full_file_path("my-app-685912d3-preview/Chart.yaml"), call.update_yaml_file( "/tmp/target-repo/my-app-685912d3-preview/Chart.yaml", "name", "my-app-685912d3-preview" @@ -587,7 +605,9 @@ def test_create_new_preview_invalid_chart_template(self): call.GitRepo.get_full_file_path("my-app-685912d3-preview"), call.Path("/tmp/target-repo/my-app-685912d3-preview"), call.Path.is_dir(), - call.logging.info("Create new folder for preview: %s", "my-app-685912d3-preview"), + call.logging.info( + "Create new folder for preview: %s (path: %s)", "my-app-685912d3-preview", "my-app-685912d3-preview" + ), call.GitRepo.get_full_file_path(".preview-templates/my-app"), call.Path("/tmp/template-repo/.preview-templates/my-app"), call.Path.is_dir(), @@ -600,3 +620,50 @@ def test_create_new_preview_invalid_chart_template(self): "/tmp/target-repo/my-app-685912d3-preview/Chart.yaml", "name", "my-app-685912d3-preview" ), ] + + def test_create_new_preview_with_target_path(self): + gitops_config: GitOpsConfig = self.load_gitops_config_mock.return_value + self.load_gitops_config_mock.return_value = GitOpsConfig( + api_version=gitops_config.api_version, + application_name=gitops_config.application_name, + messages_created_template=gitops_config.messages_created_template, + messages_updated_template=gitops_config.messages_updated_template, + messages_uptodate_template=gitops_config.messages_uptodate_template, + preview_host_template=gitops_config.preview_host_template, + preview_template_organisation=gitops_config.preview_template_organisation, + preview_template_repository=gitops_config.preview_template_repository, + preview_template_path_template=gitops_config.preview_template_path_template, + preview_template_branch=gitops_config.preview_template_branch, + preview_target_organisation=gitops_config.preview_target_organisation, + preview_target_repository=gitops_config.preview_target_repository, + preview_target_branch=gitops_config.preview_target_branch, + preview_target_namespace_template=gitops_config.preview_target_namespace_template, + preview_target_max_namespace_length=gitops_config.preview_target_max_namespace_length, + preview_target_path_template="preview-envs/${APPLICATION_NAME}", + replacements=gitops_config.replacements, + ) + + self.path_mock.is_dir.side_effect = [ + False, # /tmp/target-repo/preview-envs/my-app/my-app-685912d3-preview, doesn't exist yet -> create + True, # /tmp/template-repo/.preview-templates/my-app + ] + + deployment_created_callback = Mock(return_value=None) + + command = CreatePreviewCommand(ARGS) + command.register_callbacks( + deployment_already_up_to_date_callback=lambda _: self.fail("should not be called"), + deployment_updated_callback=lambda _: self.fail("should not be called"), + deployment_created_callback=deployment_created_callback, + ) + command.execute() + + deployment_created_callback.assert_called_once_with("created template 685912d3") + self.target_git_repo_mock.get_full_file_path.assert_any_call("preview-envs/my-app/my-app-685912d3-preview") + self.target_git_repo_mock.get_full_file_path.assert_any_call( + "preview-envs/my-app/my-app-685912d3-preview/Chart.yaml" + ) + self.shutil_mock.copytree.assert_called_once_with( + "/tmp/template-repo/.preview-templates/my-app", + "/tmp/target-repo/preview-envs/my-app/my-app-685912d3-preview", + ) diff --git a/tests/commands/test_delete_preview.py b/tests/commands/test_delete_preview.py index d263c7e4..7de54fe1 100644 --- a/tests/commands/test_delete_preview.py +++ b/tests/commands/test_delete_preview.py @@ -45,6 +45,7 @@ def setUp(self): preview_target_branch="target-branch", preview_target_namespace_template="APP-${PREVIEW_ID_HASH}-preview", preview_target_max_namespace_length=50, + preview_target_path_template="", replacements={}, ) @@ -89,7 +90,7 @@ def test_delete_existing_happy_flow(self): call.GitRepoApiFactory.create(args, "PREVIEW_TARGET_ORG", "PREVIEW_TARGET_REPO"), call.GitRepo(self.git_repo_api_mock), call.GitRepo.clone("target-branch"), - call.logging.info("Preview folder name: %s", "app-685912d3-preview"), + call.logging.info("Preview folder name: %s (path: %s)", "app-685912d3-preview", "app-685912d3-preview"), call.GitRepo.get_full_file_path("app-685912d3-preview"), call.Path("/tmp/created-tmp-dir/app-685912d3-preview"), call.Path.exists(), @@ -128,7 +129,7 @@ def test_delete_missing_happy_flow(self): call.GitRepoApiFactory.create(args, "PREVIEW_TARGET_ORG", "PREVIEW_TARGET_REPO"), call.GitRepo(self.git_repo_api_mock), call.GitRepo.clone("target-branch"), - call.logging.info("Preview folder name: %s", "app-685912d3-preview"), + call.logging.info("Preview folder name: %s (path: %s)", "app-685912d3-preview", "app-685912d3-preview"), call.GitRepo.get_full_file_path("app-685912d3-preview"), call.Path("/tmp/created-tmp-dir/app-685912d3-preview"), call.Path.exists(), @@ -163,7 +164,7 @@ def test_delete_missing_but_expected_error(self): call.GitRepoApiFactory.create(args, "PREVIEW_TARGET_ORG", "PREVIEW_TARGET_REPO"), call.GitRepo(self.git_repo_api_mock), call.GitRepo.clone("target-branch"), - call.logging.info("Preview folder name: %s", "app-685912d3-preview"), + call.logging.info("Preview folder name: %s (path: %s)", "app-685912d3-preview", "app-685912d3-preview"), call.GitRepo.get_full_file_path("app-685912d3-preview"), call.Path("/tmp/created-tmp-dir/app-685912d3-preview"), call.Path.exists(), @@ -191,3 +192,47 @@ def test_missing_gitops_config_yaml_error(self): assert self.mock_manager.method_calls == [ call.load_gitops_config(args, "ORGA", "REPO"), ] + + def test_delete_existing_with_target_path(self): + gitops_config: GitOpsConfig = self.load_gitops_config_mock.return_value + self.load_gitops_config_mock.return_value = GitOpsConfig( + api_version=gitops_config.api_version, + application_name=gitops_config.application_name, + messages_created_template=gitops_config.messages_created_template, + messages_updated_template=gitops_config.messages_updated_template, + messages_uptodate_template=gitops_config.messages_uptodate_template, + preview_host_template=gitops_config.preview_host_template, + preview_template_organisation=gitops_config.preview_template_organisation, + preview_template_repository=gitops_config.preview_template_repository, + preview_template_path_template=gitops_config.preview_template_path_template, + preview_template_branch=gitops_config.preview_template_branch, + preview_target_organisation=gitops_config.preview_target_organisation, + preview_target_repository=gitops_config.preview_target_repository, + preview_target_branch=gitops_config.preview_target_branch, + preview_target_namespace_template=gitops_config.preview_target_namespace_template, + preview_target_max_namespace_length=gitops_config.preview_target_max_namespace_length, + preview_target_path_template="preview-envs/${APPLICATION_NAME}", + replacements=gitops_config.replacements, + ) + + args = DeletePreviewCommand.Args( + username="USERNAME", + password="PASSWORD", + git_user="GIT_USER", + git_email="GIT_EMAIL", + git_author_name="GIT_AUTHOR_NAME", + git_author_email="GIT_AUTHOR_EMAIL", + organisation="ORGA", + repository_name="REPO", + git_provider=GitProvider.GITHUB, + git_provider_url=None, + preview_id="PREVIEW_ID", + expect_preview_exists=False, + ) + DeletePreviewCommand(args).execute() + + self.git_repo_mock.get_full_file_path.assert_called_with("preview-envs/APP/app-685912d3-preview") + self.shutil_mock.rmtree.assert_called_once_with( + "/tmp/created-tmp-dir/preview-envs/APP/app-685912d3-preview", + ignore_errors=True, + ) diff --git a/tests/test_gitops_config_v0.py b/tests/test_gitops_config_v0.py index af51638f..3cc94eda 100644 --- a/tests/test_gitops_config_v0.py +++ b/tests/test_gitops_config_v0.py @@ -153,3 +153,8 @@ def test_replacements_invalid_list_items_unknown_variable(self): def test_replacements_invalid_list_items_invalid_variable(self): self.yaml["previewConfig"]["replace"][0]["variable"] = "{FOO" self.assert_load_error("Item 'previewConfig.replace.[0].variable' must not contain '{' or '}'!") + + def test_preview_target_path_defaults_to_root(self): + config = self.load() + self.assertEqual(config.preview_target_path_template, "") + self.assertEqual(config.preview_target_path, "") diff --git a/tests/test_gitops_config_v1.py b/tests/test_gitops_config_v1.py index b3e94032..81df1e1d 100644 --- a/tests/test_gitops_config_v1.py +++ b/tests/test_gitops_config_v1.py @@ -300,3 +300,14 @@ def test_replacements_invalid_list_items_value_not_a_string(self): def test_replacements_invalid_list_items_unknown_variable(self): self.yaml["previewConfig"]["replace"]["file_2.yaml"][0]["value"] = "{FOO}bar" self.assert_load_error("Replacement value '${FOO}bar' for path 'e.f' contains invalid variable: FOO") + + def test_preview_target_path(self): + self.yaml["previewConfig"]["target"]["path"] = "preview-envs/{APPLICATION_NAME}" + config = self.load() + self.assertEqual(config.preview_target_path_template, "preview-envs/${APPLICATION_NAME}") + self.assertEqual(config.preview_target_path, "preview-envs/my-app") + + def test_preview_target_path_default(self): + config = self.load() + self.assertEqual(config.preview_target_path_template, "") + self.assertEqual(config.preview_target_path, "") diff --git a/tests/test_gitops_config_v2.py b/tests/test_gitops_config_v2.py index c76b6aba..3066e6de 100644 --- a/tests/test_gitops_config_v2.py +++ b/tests/test_gitops_config_v2.py @@ -324,3 +324,27 @@ def test_replacements_invalid_list_items_value_not_a_string(self): def test_replacements_invalid_list_items_unknown_variable(self): self.yaml["previewConfig"]["replace"]["file_2.yaml"][0]["value"] = "${FOO}bar" self.assert_load_error("Replacement value '${FOO}bar' for path 'e.f' contains invalid variable: FOO") + + def test_preview_target_path(self): + self.yaml["previewConfig"]["target"]["path"] = "preview-envs/${APPLICATION_NAME}" + config = self.load() + self.assertEqual(config.preview_target_path_template, "preview-envs/${APPLICATION_NAME}") + self.assertEqual(config.preview_target_path, "preview-envs/my-app") + + def test_preview_target_path_default(self): + config = self.load() + self.assertEqual(config.preview_target_path_template, "") + self.assertEqual(config.preview_target_path, "") + + def test_preview_target_path_not_a_string(self): + self.yaml["previewConfig"]["target"]["path"] = [] + self.assert_load_error("Item 'previewConfig.target.path' should be a string in GitOps config!") + + def test_preview_target_path_contains_invalid_variable(self): + self.yaml["previewConfig"]["target"]["path"] = "${FOO}-bar" + self.assert_load_error("GitOps config template '${FOO}-bar' contains invalid variable: FOO") + + def test_preview_target_path_with_application_name(self): + self.yaml["previewConfig"]["target"]["path"] = "custom-${APPLICATION_NAME}" + config = self.load() + self.assertEqual(config.preview_target_path, "custom-my-app")