Exemplo n.º 1
0
def advance_workflow(current_step):
    """Advance the workflow for all applications able to be advanced."""
    Logger.info(
        {"current_step": current_step},
        "[/api/workflow/progress/<current_step>] Workflow advance started",
    )

    try:
        # Creating a copy of the working configuration directory
        config_dir = config_lib.create_temporary_config_copy()
        config_lib.change_environment(
            Configuration.get_config_default_branch(), config_dir)
        project_config = config_lib.get_project_config(config_dir)

        report_status, report = workflow_lib.advance_workflow(
            config_dir, project_config, current_step)

        status, message = _get_status_and_message(report_status)

        # Clean up
        non_blocking_clean(
            config_dir,
            message_prefix="[/api/workflow/progress/<current_step>]")

        # HTTP Response
        Logger.info(
            {
                "current_step": current_step,
                "report": report
            },
            f"[/api/workflow/progress/<current_step>] {message}",
        )
        return (
            {
                "current_step": current_step,
                "report": report,
                "message": message
            },
            status,
        )
    # pylint: disable=broad-except
    except Exception as err:
        Logger.error(
            {
                "current_step": current_step,
                "err": str(err)
            },
            "[/api/workflow/progress/<current_step>] Workflow advance failed",
        )

        # HTTP Response
        return (
            {
                "current_step": current_step,
                "err": str(err),
                "message": "Workflow advance failed",
            },
            HTTPStatus.INTERNAL_SERVER_ERROR,
        )
Exemplo n.º 2
0
    def test_change_environment(self, io_mock):
        config.change_environment("environment", "path/to/config")

        io_mock.execute.assert_has_calls([
            call("git stash", "path/to/config"),
            call("git fetch origin", "path/to/config"),
            call("git checkout environment", "path/to/config"),
            call("git reset --hard origin/environment", "path/to/config"),
        ])
Exemplo n.º 3
0
def test_change_environment(mocker):
    spy = mocker.patch.object(io, "execute")

    config.change_environment("environment", "path/to/config")

    spy.assert_has_calls([
        call("git stash", "path/to/config"),
        call("git fetch origin", "path/to/config"),
        call("git checkout environment", "path/to/config"),
        call("git reset --hard origin/environment", "path/to/config"),
    ])
Exemplo n.º 4
0
def _differed_build(app_name: str):
    config_dir = None
    app_dir = None

    try:
        # Retrieve app's configuration
        config_dir = config.create_temporary_config_copy()
        config.change_environment(Configuration.get_config_default_branch(), config_dir)
        app_config = config.get_app_config(app_name, config_dir)
        Logger.debug(
            {"app": app_name, "config_directory": config_dir},
            "[/api/builds/:app] Application's configuration retrieved",
        )

        # Retrieve app's repository
        app_dir = git.create_working_repository(app_name, app_config["git"]["origin"])
        git.branch(app_dir, app_config["workflow"][0])
        Logger.debug(
            {"app": app_name, "working_directory": app_dir},
            "[/api/builds/:app] Application's repository retrieved",
        )

        try:
            # Create a new tag
            version = app.get_version(app_dir)
            git_tag = git.tag(app_dir, version)
            Logger.debug(
                {"app": app_name, "tag": git_tag}, "[/api/builds/:app] New tag created",
            )
        except Exception as err:
            # The tag may already exist
            Logger.warn(
                {"app": app_name, "err": err}, "[/api/builds/:app] Error while tagging the app"
            )

        # Build and publish the new docker image
        image_tag = docker.build(app_name, app_dir, app_config)
        Logger.debug(
            {"app": app_name, "image": image_tag}, "[/api/builds/:app] Docker image created"
        )
        docker.push(app_name, image_tag, app_config)
        Logger.debug(
            {"app": app_name, "image": image_tag},
            "[/api/builds/:app] Docker image published on registry",
        )

        # Send the new tag to git
        git.push(app_dir)
        Logger.debug({"app": app_name}, "[/api/builds/:app] Tag pushed to Git")

    except Exception as err:
        Logger.error(
            {"app": app_name, "err": err},
            "[/api/builds/:app] Error while tagging and building the app",
        )

    # Clean up temporary directories
    try:
        if config_dir is not None:
            io.remove(config_dir)
        if app_dir is not None:
            io.remove(app_dir)
    except Exception as err:
        Logger.error({"app": app_name, "err": err}, "[/api/builds/:app] Error during cleanup")
Exemplo n.º 5
0
def init_workflow(organization, app):
    """Initialize the workflow of an application."""
    Logger.info(
        {"app": app, "organization": organization},
        "[/api/workflow/init/:org/:app] Workflow initialization started",
    )

    report = None
    try:
        # Retrieve project configuration
        config_dir = config_lib.create_temporary_config_copy()
        config_lib.change_environment(Configuration.get_config_default_branch(), config_dir)
        project_config = config_lib.get_project_config(config_dir)

        git_provider = get_git_provider(project_config)
        report_status, report = workflow_lib.init_workflow(organization, app, git_provider)

        if report_status == workflow_lib.WorkflowInitStatus.FAIL:
            status = HTTPStatus.INTERNAL_SERVER_ERROR
            message = "Workflow initialization failed"
        elif report_status == workflow_lib.WorkflowInitStatus.SUCCESS:
            status = HTTPStatus.OK
            message = "Workflow initialization succeeded"
        else:
            raise ValueError(f"Unexpected status: '{report_status}'")

        # Clean the temporary directory
        try:
            io_lib.remove(config_dir)
        # pylint: disable=broad-except
        except Exception as err:
            Logger.warn(
                {"config_dir": config_dir, "err": err}, "Failed to clean temporary config dir"
            )

        # HTTP Response
        Logger.info(
            {"organization": organization, "app": app, "report": report},
            f"[/api/workflow/init/:org/:app] {message}",
        )
        return (
            {"organization": organization, "app": app, "report": report, "message": message},
            status,
        )
    # pylint: disable=broad-except
    except Exception as err:
        Logger.error(
            {"organization": organization, "app": app, "report": report, "err": str(err)},
            "[/api/workflow/init/:org/:app] Workflow initialization failed",
        )

        # HTTP Response
        return (
            {
                "organization": organization,
                "app": app,
                "err": str(err),
                "message": "Workflow initialization failed",
            },
            HTTPStatus.INTERNAL_SERVER_ERROR,
        )
Exemplo n.º 6
0
def init_workflow(
        organization: str, app_name: str, git_provider: AbstractGitProvider
) -> Tuple[WorkflowInitStatus, Report]:
    """Initialize the workflow of an application's repository by creating
    all workflow branches. This function is idempotent which means it will not
    try to recreate a branch that already exists. However if a branch
    already exists but is not protected, it will be set to protected."""

    # Create temporary copy for avoiding concurrency problems
    config_path = config.create_temporary_config_copy()

    # Switch to staging environment in order to get application configuration
    config.change_environment("staging", config_path)

    # Get application configuration to get the list of workflow branches
    app_config = config.get_app_config(app_name, config_path)
    master_tag = GitConfiguration.get_master_tag()

    workflow_branches = _get_workflow_branches(app_config, master_tag)
    branches = {}
    status = WorkflowInitStatus.SUCCESS

    if len(workflow_branches) != 0:
        status = WorkflowInitStatus.FAIL
        try:
            # Get user_login linked to the GITHUB_TOKEN
            user_info = git_provider.get_user_info()
            user_login = user_info.login if user_info else None
            Logger.info({"user_login": user_login}, "User login retrieved")

            # Get the last commit's sha on master branch
            branch = git_provider.get_branch(organization, app_name,
                                             master_tag)
            master_head_sha = branch and branch.commit and branch.commit.sha
            Logger.info({"sha": master_head_sha},
                        "master last commit sha retrieved")

            # Sync all workflow branches with master's head and
            # protect them by limiting push rights to user_login
            for branch_name in workflow_branches:
                branches[branch_name] = _create_and_protect_branch(
                    organization, app_name, branch_name, master_head_sha,
                    user_login, git_provider)
        except GitResourceNotFoundError as err:
            Logger.error(
                {
                    "master_branch_name": master_tag,
                    "err": err
                },
                "master last commit sha failed to be retrieved.",
            )
        except GitProviderError as err:
            Logger.error(
                {
                    "organization": organization,
                    "app_name": app_name,
                    "err": err
                },
                "Fail to initialize workflow",
            )
        else:
            status = WorkflowInitStatus.SUCCESS

    # Clean temporary copy
    non_blocking_clean(config_path)

    return status, branches