Ejemplo n.º 1
0
def configure_application(target_environment):
    r"""Configure Heroku application settings.

    Run a diff between local configuration and remote settings
    and apply any updates to the remote application:

    1. Load local configuration (from target_environment.conf)\n
    2. Fetch remote application config vars (via API)\n
    3. Compare the two\n
    4. Display the diff\n
    5. Prompt user for confirmation to apply updates\n
    6. Apply updates

    """
    app = AppConfiguration.load(
        os.path.join(settings.app_conf_dir, '%s.conf' % target_environment)
    )
    app_name = app.app_name
    release = heroku.HerokuRelease.get_latest_deployment(app_name)
    diff = compare_settings(app.settings, release.get_config_vars())

    print u"\nLocal settings (diff shown by '!', '+' indicator):\n"
    print_diff(diff, statuses=['=', '+', '!'])

    print u"\nRemote-only settings (probably Heroku-specific and ignorable):\n"
    remote_only = [d[0] for d in diff if d[3] == '?']
    print u", ".join(remote_only)

    updates = [d for d in diff if d[3] in ['!', '+']]
    if len(updates) == 0:
        print u"\nAll settings are up-to-date. No action required."
        return

    print u"\nThe following settings will be applied to '%s':\n" % app_name
    for key, local, _, status in updates:
        print u"%s %s=%s" % (status, key, local)
    print u""

    if utils.prompt_for_pin(""):
        set_vars(app_name, updates)
Ejemplo n.º 2
0
def deploy_application(target_environment, config_file, branch, force, collectstatic):  # noqa
    """Deploy a Heroku application.

    Push code via git, run collectstatic and migrate commands, and wrap
    all of this with the maintenance page to prevent users from using the
    site whilst the deployment is running.

    The user is prompted to confirm various options prior to the
    deployment running, and is then required to enter a random number
    displayed on the screen to invoke the deployment.

    The function encacsulates a fixed workflow that maps git-flow to
    heroku environments, by pushing specific branches to specific remotes:

    """
    # read in and parse configuration
    app = config.AppConfiguration.load(
        config_file or
        os.path.join(settings.app_conf_dir, '%s.conf' % target_environment)
    )
    app_name = app.app_name
    branch = branch or app.default_branch
    cmd_collectstatic = settings.commands.get('collectstatic')
    cmd_migrate = settings.commands.get('migrate')
    # used to work out whether the deployment contains migrations
    match_migrations = '/migrations/'

    # get the contents of the proposed deployment
    release = heroku.HerokuRelease.get_latest_deployment(app_name)
    # will collectstatic run as part of the buildpack - it will never run
    # if this is a pipeline deployment, as that bypasses the buildpack
    run_buildpack = not app.use_pipeline
    collectstatic_enabled = release.collectstatic_enabled()

    remote_hash = release.commit
    if app.use_pipeline:
        # if we are using pipelines, then the commit we need is not the
        # local one, but the latest version on the upstream app, as this
        # is the one that will be deployed.
        upstream_release = heroku.HerokuRelease.get_latest_deployment(app.upstream_app)  # noqa
        local_hash = upstream_release.commit
    else:
        local_hash = git.get_branch_head(branch)

    if local_hash == remote_hash:
        click.echo(u"Heroku application is up-to-date, aborting deployment.")
        return

    files = git.get_files(remote_hash, local_hash)
    commits = git.get_commits(remote_hash, local_hash)

    click.echo("")
    click.echo("Comparing %s..%s" % (remote_hash, local_hash))
    click.echo("")
    click.echo("The following files have changed since the last deployment:\n")  # noqa
    if len(files) == 0:
        click.echo("  (no change)")
    else:
        click.echo("".join(["  * %s\n" % f for f in files]))
    click.echo("")
    click.echo("The following commits will be included in this deployment:\n")  # noqa
    if len(commits) == 0:
        click.echo("  (no change)")
    else:
        click.echo("".join(["  [%s] %s\n" % (c[0], c[1]) for c in commits]))

    files_include = (lambda p: p in ''.join(files))
    files_include_migrations = files_include(match_migrations)

    # run migrations post-deployment
    run_migrate = force or utils.prompt_for_action(
        u"Do you want to run migrations?",
        files_include_migrations
    )
    run_collectstatic = collectstatic

    # ============== summarise actions ==========================
    click.echo("")
    click.echo("Summary of deployment options:")  # noqa
    click.echo("")
    click.echo("  ----- Deployment SETTINGS -----------")
    click.echo("")
    click.echo("  Git branch:    %s" % branch)
    click.echo("  Target env:    %s (%s)" % (target_environment, app_name))
    click.echo("  Force push:    %s" % force)
    # run the buildpack as a full deployment
    if run_buildpack is True:
        click.echo("  Run buildpack: True")
        click.echo("  Collectstatic: %s" % collectstatic_enabled)
    # pipeline promotion - buildpack won't run
    if app.use_pipeline is True:
        click.echo("  Pipeline:      True")
        click.echo("  Promote:       %s" % app.upstream_app)
    if app.add_rich_tag is True:
        click.echo("  Release tag:   custom")
    elif app.add_tag is True:
        click.echo("  Release tag:   default")
    else:
        click.echo("  Release tag:   none")
    click.echo("")
    click.echo("  ----- Post-deployment commands ------")
    click.echo("")
    if run_migrate:
        click.echo("  migrate:       %s" % cmd_migrate)
    if collectstatic:
        click.echo("  collectstatic: %s" % cmd_collectstatic)
    if not (run_migrate or run_collectstatic):
        click.echo("  (none specfied)")
    click.echo("")
    # ============== / summarise actions ========================

    # put up the maintenance page if required
    maintenance = utils.prompt_for_action(
        u"Do you want to put up the maintenance page?",
        run_migrate
    )

    if not utils.prompt_for_pin(""):
        exit(0)

    if maintenance:
        click.echo("Putting up maintenance page")
        heroku.toggle_maintenance(app_name, True)

    if app.use_pipeline:
        click.echo("Promoting upstream app: %s" % app.upstream_app)
        heroku.promote_app(app.upstream_app)
    else:
        click.echo("Pushing to git remote")
        git.push(
            remote=git.get_remote_url(app_name),
            local_branch=branch,
            remote_branch='master',
            force=force
        )

    if run_migrate is True:
        click.echo("Running migrate command")
        heroku.run_command(app_name, cmd_migrate)

    if run_collectstatic is True:
        click.echo("Running staticfiles command")
        heroku.run_command(app_name, cmd_collectstatic)

    if maintenance:
        click.echo("Pulling down maintenance page")
        heroku.toggle_maintenance(app_name, False)

    release = heroku.HerokuRelease.get_latest_deployment(app_name)

    if app.add_rich_tag or app.add_tag:
        click.echo("Applying git tag")
        default_msg = "Deployed to %s by %s" % (app_name, release.deployed_by)
        message = None if app.add_rich_tag else default_msg
        git.apply_tag(commit=local_hash, tag=release.version, message=message)

    click.echo(release)
Ejemplo n.º 3
0
def deploy_application(target_environment, auto, branch, config_file,
                       force, run_collectstatic, run_migrate):
    """Deploy a Heroku application.

    Push code via git, run collectstatic and migrate commands, and wrap
    all of this with the maintenance page to prevent users from using the
    site whilst the deployment is running.

    The user is prompted to confirm various options prior to the
    deployment running, and is then required to enter a random number
    displayed on the screen to invoke the deployment.

    The function encacsulates a fixed workflow that maps git-flow to
    heroku environments, by pushing specific branches to specific remotes:

    """
    # read in and parse configuration
    app = AppConfiguration.load(
        config_file or
        os.path.join(SETTINGS['app_conf_dir'], '%s.conf' % target_environment)
    )
    app_name = app.app_name
    branch = branch or app.default_branch
    cmd_collectstatic = SETTINGS['commands']['collectstatic']
    cmd_migrate = SETTINGS['commands']['migrate']
    match_migrations = SETTINGS['matches']['migrations']
    match_staticfiles = SETTINGS['matches']['staticfiles']

    # get the contents of the proposed deployment
    release = heroku.HerokuRelease.get_latest_deployment(app_name)
    remote_hash = release.commit
    local_hash = git.get_branch_head(branch)
    if local_hash == remote_hash:
        click.echo(u"Heroku application is up-to-date, aborting deployment.")
        return

    files = git.get_files(remote_hash, local_hash)
    commits = git.get_commits(remote_hash, local_hash)

    click.echo("")
    click.echo("Comparing %s..%s" % (remote_hash, local_hash))
    click.echo("")
    click.echo("The following files have changed since the last deployment:\n")  # noqa
    click.echo("".join(["  * %s\n" % f for f in files]))
    click.echo("")
    click.echo("The following commits will be included in this deployment:\n")  # noqa
    click.echo("".join(["  [%s] %s\n" % (c[0], c[1]) for c in commits]))
    click.echo("")

    files_include = (lambda p: p in ''.join(files))
    files_include_migrations = files_include(match_migrations)
    files_include_static = files_include(match_staticfiles)

    if force:
        run_migrate = True
        run_collectstatic = True
    elif auto:
        run_migrate = run_migrate or files_include_migrations
        run_collectstatic = run_collectstatic or files_include_static
    else:
        run_migrate = run_migrate or utils.prompt_for_action(
            u"Do you want to run migrations?",
            files_include_migrations
        )
        run_collectstatic = run_collectstatic or utils.prompt_for_action(
            u"Do you want to run collectstatic?",
            files_include_static
        )

    # ============== summarise actions ==========================
    click.echo("")
    click.echo("Summary of deployment options:")  # noqa
    click.echo("")
    click.echo("  ----- Deployment SETTINGS -----------")
    click.echo("")
    click.echo("  Git branch:    %s" % branch)
    click.echo("  Target env:    %s (%s)" % (target_environment, app_name))
    click.echo("  Force push:    %s" % force)
    click.echo("  Pipeline:      %s" % app.use_pipeline)
    if app.use_pipeline is True:
        click.echo("  Promote:       %s" % app.upstream_app)
    click.echo("")
    click.echo("  ----- Post-deployment commands ------")
    click.echo("")
    if run_migrate:
        click.echo("  migrate:       %s" % cmd_migrate)
    if run_collectstatic:
        click.echo("  collectstatic: %s" % cmd_collectstatic)
    if not (run_migrate or run_collectstatic):
        click.echo("  (none specfied)")
    click.echo("")
    # ============== / summarise actions ========================

    if not utils.prompt_for_pin(""):
        exit(0)

    # click.echo("Putting up maintenance page")
    # heroku.toggle_maintenance(app_name, True)

    if app.use_pipeline:
        click.echo("Promoting upstream app: %s" % app.upstream_app)
        heroku.promote_app(app.upstream_app)
    else:
        click.echo("Pushing to git remote")
        git.push(
            remote=git.get_remote_url(app_name),
            local_branch=branch,
            remote_branch='master',
            force=force
        )

    if run_migrate is True:
        click.echo("Running migrate command")
        heroku.run_command(app_name, cmd_migrate)

    if run_collectstatic is True:
        click.echo("Running staticfiles command")
        heroku.run_command(app_name, cmd_collectstatic)

    # click.echo("Pulling down maintenance page")
    # heroku.toggle_maintenance(app_name, False)

    release = heroku.HerokuRelease.get_latest_deployment(app_name)

    if app.add_tag:
        click.echo("Applying git tag")
        git.apply_tag(
            commit=local_hash,
            tag=release.version,
            message="Deployed to %s by %s" % (
                app_name,
                release.deployed_by
            )
        )

    click.echo(release)