Exemplo n.º 1
0
 def __create_preview_info_file(self, gitops_config: GitOpsConfig) -> None:
     preview_id = self.__args.preview_id
     yaml_file_dump(
         {
             "previewId": preview_id,
             "previewIdHash":
             gitops_config.create_preview_id_hash(preview_id),
             "routeHost": gitops_config.get_preview_host(preview_id),
             "namespace": gitops_config.get_preview_namespace(preview_id),
         },
         "/tmp/gitopscli-preview-info.yaml",
     )
Exemplo n.º 2
0
 def test_replacements(self):
     config = self.load()
     self.assertEqual(
         config.replacements,
         [
             GitOpsConfig.Replacement(
                 path="a.b",
                 variable=GitOpsConfig.Replacement.Variable.ROUTE_HOST),
             GitOpsConfig.Replacement(
                 path="c.d",
                 variable=GitOpsConfig.Replacement.Variable.GIT_COMMIT),
         ],
     )
Exemplo n.º 3
0
    def setUp(self):
        self.init_mock_manager(CreatePreviewCommand)

        self.os_mock = self.monkey_patch(os)
        self.os_mock.path.isdir.return_value = True

        self.shutil_mock = self.monkey_patch(shutil)
        self.shutil_mock.copytree.return_value = None

        self.logging_mock = self.monkey_patch(logging)
        self.logging_mock.info.return_value = None

        self.update_yaml_file_mock = self.monkey_patch(update_yaml_file)
        self.update_yaml_file_mock.return_value = True

        self.yaml_file_dump_mock = self.monkey_patch(yaml_file_dump)
        self.yaml_file_dump_mock.return_value = None

        self.load_gitops_config_mock = self.monkey_patch(load_gitops_config)
        self.load_gitops_config_mock.return_value = GitOpsConfig(
            team_config_org="TEAM_CONFIG_ORG",
            team_config_repo="TEAM_CONFIG_REPO",
            application_name="my-app",
            route_host_template="app.xy-{SHA256_8CHAR_BRANCH_HASH}.example.tld",
            replacements=[
                GitOpsConfig.Replacement(
                    path="image.tag",
                    variable=GitOpsConfig.Replacement.Variable.GIT_COMMIT),
                GitOpsConfig.Replacement(
                    path="route.host",
                    variable=GitOpsConfig.Replacement.Variable.ROUTE_HOST),
            ],
        )

        self.git_repo_api_mock = self.create_mock(GitRepoApi)

        self.git_repo_api_factory_mock = self.monkey_patch(GitRepoApiFactory)
        self.git_repo_api_factory_mock.create.return_value = self.git_repo_api_mock

        self.git_repo_mock = self.monkey_patch(GitRepo)
        self.git_repo_mock.return_value = self.git_repo_mock
        self.git_repo_mock.__enter__.return_value = self.git_repo_mock
        self.git_repo_mock.__exit__.return_value = False
        self.git_repo_mock.get_full_file_path.side_effect = lambda x: f"/tmp/created-tmp-dir/{x}"
        self.git_repo_mock.clone.return_value = None
        self.git_repo_mock.commit.return_value = None
        self.git_repo_mock.push.return_value = None

        self.seal_mocks()
Exemplo n.º 4
0
 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)
     context = GitOpsConfig.Replacement.PreviewContext(
         gitops_config, preview_id, self.__args.git_hash)
     any_value_replaced = False
     for file, replacements in gitops_config.replacements.items():
         for replacement in replacements:
             replacement_value = replacement.get_value(context)
             value_replaced = self.__update_yaml_file(
                 git_repo,
                 f"{preview_folder_name}/{file}",
                 replacement.path,
                 replacement_value,
             )
             if value_replaced:
                 any_value_replaced = True
                 logging.info(
                     "Replaced property '%s' in '%s' with value: %s",
                     replacement.path, file, replacement_value)
             else:
                 logging.info("Keep property '%s' in '%s' value: %s",
                              replacement.path, file, replacement_value)
     return any_value_replaced
Exemplo n.º 5
0
 def __create_preview_from_template_if_not_existing(
         self, template_git_repo: GitRepo, target_git_repo: GitRepo,
         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_env_already_exist = os.path.isdir(full_preview_folder_path)
     if preview_env_already_exist:
         logging.info("Use existing folder for preview: %s",
                      preview_namespace)
         return False
     logging.info("Create new folder for preview: %s", preview_namespace)
     full_preview_template_folder_path = template_git_repo.get_full_file_path(
         gitops_config.preview_template_path)
     if not os.path.isdir(full_preview_template_folder_path):
         raise GitOpsException(
             f"The preview template folder does not exist: {gitops_config.preview_template_path}"
         )
     logging.info("Using the preview template folder: %s",
                  gitops_config.preview_template_path)
     shutil.copytree(
         full_preview_template_folder_path,
         full_preview_folder_path,
     )
     return True
Exemplo n.º 6
0
 def __create_preview_from_template_if_not_existing(
         self, git_repo: GitRepo, gitops_config: GitOpsConfig) -> bool:
     preview_namespace = gitops_config.get_preview_namespace(
         self.__args.preview_id)
     full_preview_folder_path = git_repo.get_full_file_path(
         preview_namespace)
     preview_env_already_exist = os.path.isdir(full_preview_folder_path)
     if preview_env_already_exist:
         logging.info("Use existing folder for preview: %s",
                      preview_namespace)
         return False
     logging.info("Create new folder for preview: %s", preview_namespace)
     preview_template_folder_name = f".preview-templates/{gitops_config.application_name}"
     full_preview_template_folder_path = git_repo.get_full_file_path(
         preview_template_folder_name)
     if not os.path.isdir(full_preview_template_folder_path):
         raise GitOpsException(
             f"The preview template folder does not exist: {preview_template_folder_name}"
         )
     logging.info("Using the preview template folder: %s",
                  preview_template_folder_name)
     shutil.copytree(
         full_preview_template_folder_path,
         full_preview_folder_path,
     )
     self.__update_yaml_file(git_repo, f"{preview_namespace}/Chart.yaml",
                             "name", preview_namespace)
     return True
Exemplo n.º 7
0
def load_gitops_config(git_api_config: GitApiConfig, organisation: str,
                       repository_name: str) -> GitOpsConfig:
    git_repo_api = GitRepoApiFactory.create(git_api_config, organisation,
                                            repository_name)
    with GitRepo(git_repo_api) as git_repo:
        git_repo.clone()
        gitops_config_file_path = git_repo.get_full_file_path(
            ".gitops.config.yaml")
        try:
            gitops_config_yaml = yaml_file_load(gitops_config_file_path)
        except FileNotFoundError as ex:
            raise GitOpsException("No such file: .gitops.config.yaml") from ex
    return GitOpsConfig.from_yaml(gitops_config_yaml)
Exemplo n.º 8
0
 def __get_value_for_variable(
         self, gitops_config: GitOpsConfig,
         variable: GitOpsConfig.Replacement.Variable) -> str:
     mapping: Dict[GitOpsConfig.Replacement.Variable, Callable[[], str]] = {
         GitOpsConfig.Replacement.Variable.ROUTE_HOST:
         lambda: gitops_config.get_route_host(self.__args.preview_id),
         GitOpsConfig.Replacement.Variable.GIT_COMMIT:
         lambda: self.__args.git_hash,
     }
     assert set(
         mapping.keys()) == set(GitOpsConfig.Replacement.Variable
                                ), "variable to value mapping not complete"
     return mapping[variable]()
Exemplo n.º 9
0
    def setUp(self):
        self.init_mock_manager(DeletePreviewCommand)

        self.os_mock = self.monkey_patch(os)
        self.os_mock.path.exists.return_value = True

        self.shutil_mock = self.monkey_patch(shutil)
        self.shutil_mock.rmtree.return_value = None

        self.logging_mock = self.monkey_patch(logging)
        self.logging_mock.info.return_value = None

        self.load_gitops_config_mock = self.monkey_patch(load_gitops_config)
        self.load_gitops_config_mock.return_value = GitOpsConfig(
            api_version=0,
            application_name="APP",
            preview_host_template="www.foo.bar",
            preview_template_organisation="PREVIEW_TEMPLATE_ORG",
            preview_template_repository="PREVIEW_TEMPLATE_REPO",
            preview_template_path_template=".preview-templates/my-app",
            preview_template_branch="template-branch",
            preview_target_organisation="PREVIEW_TARGET_ORG",
            preview_target_repository="PREVIEW_TARGET_REPO",
            preview_target_branch="target-branch",
            preview_target_namespace_template="APP-${PREVIEW_ID_HASH}-preview",
            preview_target_max_namespace_length=50,
            replacements={},
        )

        self.git_repo_api_mock = self.create_mock(GitRepoApi)
        self.git_repo_api_mock.create_pull_request.return_value = GitRepoApi.PullRequestIdAndUrl(
            42, "<url of dummy pr>")

        self.git_repo_api_factory_mock = self.monkey_patch(GitRepoApiFactory)
        self.git_repo_api_factory_mock.create.return_value = self.git_repo_api_mock

        self.git_repo_mock = self.monkey_patch(GitRepo)
        self.git_repo_mock.return_value = self.git_repo_mock
        self.git_repo_mock.__enter__.return_value = self.git_repo_mock
        self.git_repo_mock.__exit__.return_value = False
        self.git_repo_mock.get_full_file_path.side_effect = lambda x: f"/tmp/created-tmp-dir/{x}"
        self.git_repo_mock.clone.return_value = None
        self.git_repo_mock.commit.return_value = None
        self.git_repo_mock.push.return_value = None

        self.seal_mocks()
Exemplo n.º 10
0
 def __replace_values(self, git_repo: GitRepo,
                      gitops_config: GitOpsConfig) -> bool:
     preview_folder_name = gitops_config.get_preview_namespace(
         self.__args.preview_id)
     any_value_replaced = False
     for replacement in gitops_config.replacements:
         replacement_value = self.__get_value_for_variable(
             gitops_config, replacement.variable)
         value_replaced = self.__update_yaml_file(
             git_repo,
             f"{preview_folder_name}/values.yaml",
             replacement.path,
             replacement_value,
         )
         if value_replaced:
             any_value_replaced = True
             logging.info("Replaced property '%s' with value: %s",
                          replacement.path, replacement_value)
         else:
             logging.info("Keep property '%s' value: %s", replacement.path,
                          replacement_value)
     return any_value_replaced
Exemplo n.º 11
0
    def setUp(self):
        self.init_mock_manager(DeletePreviewCommand)

        self.os_mock = self.monkey_patch(os)
        self.os_mock.path.exists.return_value = True

        self.shutil_mock = self.monkey_patch(shutil)
        self.shutil_mock.rmtree.return_value = None

        self.logging_mock = self.monkey_patch(logging)
        self.logging_mock.info.return_value = None

        self.load_gitops_config_mock = self.monkey_patch(load_gitops_config)
        self.load_gitops_config_mock.return_value = GitOpsConfig(
            application_name="APP",
            team_config_org="TEAM_CONFIG_ORG",
            team_config_repo="TEAM_CONFIG_REPO",
            route_host_template="www.foo.bar",
            replacements=[],
        )

        self.git_repo_api_mock = self.create_mock(GitRepoApi)
        self.git_repo_api_mock.create_pull_request.return_value = GitRepoApi.PullRequestIdAndUrl(
            42, "<url of dummy pr>")

        self.git_repo_api_factory_mock = self.monkey_patch(GitRepoApiFactory)
        self.git_repo_api_factory_mock.create.return_value = self.git_repo_api_mock

        self.git_repo_mock = self.monkey_patch(GitRepo)
        self.git_repo_mock.return_value = self.git_repo_mock
        self.git_repo_mock.__enter__.return_value = self.git_repo_mock
        self.git_repo_mock.__exit__.return_value = False
        self.git_repo_mock.get_full_file_path.side_effect = lambda x: f"/tmp/created-tmp-dir/{x}"
        self.git_repo_mock.clone.return_value = None
        self.git_repo_mock.commit.return_value = None
        self.git_repo_mock.push.return_value = None

        self.seal_mocks()
Exemplo n.º 12
0
 def load(self) -> GitOpsConfig:
     return GitOpsConfig.from_yaml(self.yaml)
Exemplo n.º 13
0
    def setUp(self):
        self.init_mock_manager(CreatePreviewCommand)

        self.os_mock = self.monkey_patch(os)
        self.os_mock.path.isdir.return_value = True

        self.shutil_mock = self.monkey_patch(shutil)
        self.shutil_mock.copytree.return_value = None

        self.logging_mock = self.monkey_patch(logging)
        self.logging_mock.info.return_value = None

        self.update_yaml_file_mock = self.monkey_patch(update_yaml_file)
        self.update_yaml_file_mock.return_value = True

        self.yaml_file_dump_mock = self.monkey_patch(yaml_file_dump)
        self.yaml_file_dump_mock.return_value = None

        self.load_gitops_config_mock = self.monkey_patch(load_gitops_config)
        self.load_gitops_config_mock.return_value = GitOpsConfig(
            api_version=2,
            application_name="my-app",
            preview_host_template="app.xy-${PREVIEW_ID_HASH}.example.tld",
            preview_template_organisation="PREVIEW_TEMPLATE_ORG",
            preview_template_repository="PREVIEW_TEMPLATE_REPO",
            preview_template_path_template=".preview-templates/my-app",
            preview_template_branch="template-branch",
            preview_target_organisation="PREVIEW_TARGET_ORG",
            preview_target_repository="PREVIEW_TARGET_REPO",
            preview_target_branch=None,
            preview_target_namespace_template=
            "my-app-${PREVIEW_ID_HASH}-preview",
            preview_target_max_namespace_length=50,
            replacements={
                "Chart.yaml": [
                    GitOpsConfig.Replacement(
                        path="name", value_template="${PREVIEW_NAMESPACE}"),
                ],
                "values.yaml": [
                    GitOpsConfig.Replacement(path="image.tag",
                                             value_template="${GIT_HASH}"),
                    GitOpsConfig.Replacement(path="route.host",
                                             value_template="${PREVIEW_HOST}"),
                ],
            },
        )

        self.template_git_repo_api_mock = self.create_mock(GitRepoApi)
        self.target_git_repo_api_mock = self.create_mock(GitRepoApi)

        self.git_repo_api_factory_mock = self.monkey_patch(GitRepoApiFactory)

        def git_repo_api_factory_create_mock(
                _: GitApiConfig, organisation: str,
                repository_name: str) -> GitRepoApi:
            if "TEMPLATE" in organisation and "TEMPLATE" in repository_name:
                return self.template_git_repo_api_mock
            if "TARGET" in organisation and "TARGET" in repository_name:
                return self.target_git_repo_api_mock
            raise Exception(f"no mock for {organisation}/{repository_name}")

        self.git_repo_api_factory_mock.create.side_effect = git_repo_api_factory_create_mock

        self.template_git_repo_mock = self.create_mock(GitRepo)
        self.template_git_repo_mock.__enter__.return_value = self.template_git_repo_mock
        self.template_git_repo_mock.__exit__.return_value = False
        self.template_git_repo_mock.get_full_file_path.side_effect = lambda x: f"/tmp/template-repo/{x}"
        self.template_git_repo_mock.clone.return_value = None
        self.template_git_repo_mock.commit.return_value = None
        self.template_git_repo_mock.push.return_value = None

        self.target_git_repo_mock = self.create_mock(GitRepo)
        self.target_git_repo_mock.__enter__.return_value = self.target_git_repo_mock
        self.target_git_repo_mock.__exit__.return_value = False
        self.target_git_repo_mock.get_full_file_path.side_effect = lambda x: f"/tmp/target-repo/{x}"
        self.target_git_repo_mock.clone.return_value = None

        def git_repo_constructor_mock(git_repo_api: GitRepoApi) -> GitRepo:
            if git_repo_api == self.template_git_repo_api_mock:
                return self.template_git_repo_mock
            if git_repo_api == self.target_git_repo_api_mock:
                return self.target_git_repo_mock
            raise Exception(f"no mock for {git_repo_api}")

        self.monkey_patch(GitRepo).side_effect = git_repo_constructor_mock

        self.seal_mocks()
Exemplo n.º 14
0
    def test_create_new_preview_from_same_template_target_repo(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,
            preview_host_template=gitops_config.preview_host_template,
            preview_template_organisation=gitops_config.
            preview_target_organisation,  # template = target
            preview_template_repository=gitops_config.
            preview_target_repository,  # template = target
            preview_template_path_template=gitops_config.
            preview_template_path_template,
            preview_template_branch=gitops_config.
            preview_target_branch,  # template = target
            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,
            replacements=gitops_config.replacements,
        )

        self.os_mock.path.isdir.side_effect = lambda path: {
            "/tmp/target-repo/my-app-685912d3-preview":
            False,  # doesn't exist yet -> expect create
            "/tmp/target-repo/.preview-templates/my-app": True,
        }[path]

        deployment_created_callback = Mock(return_value=None)

        command = CreatePreviewCommand(ARGS)
        command.register_callbacks(
            deployment_already_up_to_date_callback=lambda route_host: self.
            fail("should not be called"),
            deployment_updated_callback=lambda route_host: self.fail(
                "should not be called"),
            deployment_created_callback=deployment_created_callback,
        )
        command.execute()

        deployment_created_callback.assert_called_once_with(
            "app.xy-685912d3.example.tld")

        assert self.mock_manager.method_calls == [
            call.load_gitops_config(
                ARGS,
                "ORGA",
                "REPO",
            ),
            call.yaml_file_dump(
                {
                    "previewId": "PREVIEW_ID",
                    "previewIdHash": "685912d3",
                    "routeHost": "app.xy-685912d3.example.tld",
                    "namespace": "my-app-685912d3-preview",
                },
                "/tmp/gitopscli-preview-info.yaml",
            ),
            call.GitRepoApiFactory.create(
                ARGS,
                "PREVIEW_TARGET_ORG",
                "PREVIEW_TARGET_REPO",
            ),  # only clone once for template and target
            call.GitRepo(self.target_git_repo_api_mock),
            call.GitRepo.clone(None),
            call.GitRepo.get_full_file_path("my-app-685912d3-preview"),
            call.os.path.isdir("/tmp/target-repo/my-app-685912d3-preview"),
            call.logging.info("Create new folder for preview: %s",
                              "my-app-685912d3-preview"),
            call.GitRepo.get_full_file_path(".preview-templates/my-app"),
            call.os.path.isdir("/tmp/target-repo/.preview-templates/my-app"),
            call.logging.info("Using the preview template folder: %s",
                              ".preview-templates/my-app"),
            call.shutil.copytree("/tmp/target-repo/.preview-templates/my-app",
                                 "/tmp/target-repo/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"),
            call.logging.info("Replaced property '%s' in '%s' with value: %s",
                              "name", "Chart.yaml", "my-app-685912d3-preview"),
            call.GitRepo.get_full_file_path(
                "my-app-685912d3-preview/values.yaml"),
            call.update_yaml_file(
                "/tmp/target-repo/my-app-685912d3-preview/values.yaml",
                "image.tag",
                "3361723dbd91fcfae7b5b8b8b7d462fbc14187a9",
            ),
            call.logging.info(
                "Replaced property '%s' in '%s' with value: %s",
                "image.tag",
                "values.yaml",
                "3361723dbd91fcfae7b5b8b8b7d462fbc14187a9",
            ),
            call.GitRepo.get_full_file_path(
                "my-app-685912d3-preview/values.yaml"),
            call.update_yaml_file(
                "/tmp/target-repo/my-app-685912d3-preview/values.yaml",
                "route.host", "app.xy-685912d3.example.tld"),
            call.logging.info(
                "Replaced property '%s' in '%s' with value: %s",
                "route.host",
                "values.yaml",
                "app.xy-685912d3.example.tld",
            ),
            call.GitRepo.commit(
                "GIT_USER",
                "GIT_EMAIL",
                "Create new preview environment for 'my-app' and git hash '3361723dbd91fcfae7b5b8b8b7d462fbc14187a9'.",
            ),
            call.GitRepo.push(),
        ]