Last active
May 29, 2019 14:53
-
-
Save jonah-williams/5979761 to your computer and use it in GitHub Desktop.
Automating deployments to Heroku from CircleCI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
test: | |
override: | |
- bundle exec rspec spec | |
deployment: | |
acceptance: | |
branch: master | |
commands: | |
- ./script/heroku_deploy.sh <ACCEPTANCE_HEROKU_APP>: | |
timeout: 300 | |
staging: | |
branch: staging | |
commands: | |
- ./script/heroku_deploy.sh <STAGING_HEROKU_APP>: | |
timeout: 300 | |
production: | |
branch: production | |
commands: | |
- ./script/heroku_deploy.sh <PRODUCTION_HEROKU_APP>: | |
timeout: 300 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh -e | |
APP_NAME=$1 | |
git remote add heroku git@heroku.com:$APP_NAME.git | |
git fetch heroku | |
MIGRATION_CHANGES=$(git diff HEAD heroku/master --name-only -- db | wc -l) | |
echo "$MIGRATION_CHANGES db changes." | |
PREV_WORKERS=$(heroku ps --app $APP_NAME | grep "^worker." | wc -l | tr -d ' ') | |
# migrations require downtime so enter maintenance mode | |
if test $MIGRATION_CHANGES -gt 0; then | |
heroku maintenance:on --app $APP_NAME | |
# Make sure workers are not running during a migration | |
heroku scale worker=0 --app $APP_NAME | |
fi | |
# deploy code changes (and implicitly restart the app and any running workers) | |
git push heroku $CIRCLE_SHA1:refs/heads/master | |
# run database migrations if needed and restart background workers once finished | |
if test $MIGRATION_CHANGES -gt 0; then | |
heroku run rake db:migrate db:seed --app $APP_NAME | |
heroku scale worker=$PREV_WORKERS --app $APP_NAME | |
heroku restart --app $APP_NAME | |
fi | |
heroku run rake cache:flush --app $APP_NAME | |
heroku maintenance:off --app $APP_NAME |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh -e | |
APP_NAME=$1 | |
heroku maintenance:on --app $APP_NAME | |
git push heroku $CIRCLE_SHA1:refs/heads/master | |
heroku run rake db:migrate db:seed --app $APP_NAME | |
heroku restart --app $APP_NAME | |
heroku maintenance:off --app $APP_NAME |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh -e | |
APP_NAME=$1 | |
PIPELINE_APP_NAME=$APP_NAME-slug | |
HEROKU_APP_REMOTE=git@heroku.com:$APP_NAME.git | |
HEROKU_PIPELINE_REMOTE=git@heroku.com:$PIPELINE_APP_NAME.git | |
WORKERS_COUNT=$(heroku ps --app $APP_NAME | grep "^worker." | wc -l | tr -d ' ') | |
# configure pipeline deploy https://devcenter.heroku.com/articles/labs-pipelines | |
heroku plugins:install git://github.com/heroku/heroku-pipeline.git | |
if test $(heroku apps | grep $PIPELINE_APP_NAME -c) -gt 0; then | |
echo "Using existing pipeline $PIPELINE_APP_NAME" | |
git remote add pipeline $HEROKU_PIPELINE_REMOTE | |
DIFF_REMOTE=pipeline | |
else | |
heroku apps:create $PIPELINE_APP_NAME --remote pipeline | |
heroku labs:enable pipelines --app $PIPELINE_APP_NAME | |
heroku pipeline:add $APP_NAME --app $PIPELINE_APP_NAME | |
heroku pipeline --app $PIPELINE_APP_NAME | |
git remote add heroku $HEROKU_APP_REMOTE | |
DIFF_REMOTE=heroku | |
fi | |
# configure app and check for db changes | |
git fetch $DIFF_REMOTE | |
MIGRATION_CHANGES=$(git diff $CIRCLE_SHA1 $DIFF_REMOTE/master --name-only -- db | wc -l) | |
echo "$MIGRATION_CHANGES db changes since last deploy." | |
# use pipeline to prepare a slug to deploy | |
git push pipeline $CIRCLE_SHA1:refs/heads/master | |
DEPLOY_START=`date +%s` | |
# migrations require downtime so enter maintenance mode | |
if test $MIGRATION_CHANGES -gt 0; then | |
heroku maintenance:on --app $APP_NAME | |
# Make sure workers are not running during a migration | |
heroku scale worker=0 --app $APP_NAME | |
fi | |
# Run our migrations in a subprocess so that failed db migrations | |
# don't immediately abort our deploy script. | |
( | |
# promote the compiled slug | |
heroku pipeline:promote --app $PIPELINE_APP_NAME | |
# run database migrations if needed and restart background workers once finished | |
if test $MIGRATION_CHANGES -gt 0; then | |
heroku run rake db:migrate --app $APP_NAME | |
heroku run rake db:seed --app $APP_NAME | |
heroku restart --app $APP_NAME | |
fi | |
) | |
MIGRATION_EXIT=$? # store the exit code | |
# Always scale our workers back up, regardless of whether the migration failed | |
if test $MIGRATION_CHANGES -gt 0; then | |
heroku scale worker=$WORKERS_COUNT --app $APP_NAME | |
fi | |
# If the migration failed, now we can exit with that exit code | |
if test $MIGRATION_EXIT -ne 0; then | |
exit $MIGRATION_EXIT | |
fi | |
heroku run rake cache:flush --app $APP_NAME | |
heroku maintenance:off --app $APP_NAME | |
DEPLOY_END=`date +%s` | |
ELAPSED=$(( $DEPLOY_END - $DEPLOY_START )) | |
echo "Deploy completed!" | |
if test $MIGRATION_CHANGES -gt 0; then | |
echo " $ELAPSED seconds in maintenance mode." | |
else | |
echo " $ELAPSED seconds, without maintenance mode." | |
fi | |
exit 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh -e | |
APP_NAME=$1 | |
PIPELINE_APP_NAME=$APP_NAME-slug | |
HEROKU_APP_REMOTE=git@heroku.com:$APP_NAME.git | |
HEROKU_PIPELINE_REMOTE=git@heroku.com:$PIPELINE_APP_NAME.git | |
WORKERS_COUNT=$(heroku ps --app $APP_NAME | grep "^worker." | wc -l | tr -d ' ') | |
# configure pipeline deploy https://devcenter.heroku.com/articles/labs-pipelines | |
if test $(heroku apps | grep $PIPELINE_APP_NAME -c) -gt 0; then | |
echo "Using existing pipeline $PIPELINE_APP_NAME" | |
git remote add pipeline $HEROKU_PIPELINE_REMOTE | |
else | |
heroku apps:create $PIPELINE_APP_NAME --remote pipeline | |
heroku labs:enable pipelines --app $PIPELINE_APP_NAME | |
fi | |
heroku plugins:install git://github.com/heroku/heroku-pipeline.git | |
heroku pipeline:add $APP_NAME --app $PIPELINE_APP_NAME | |
heroku pipeline --app $PIPELINE_APP_NAME | |
# configure app and check for db changes | |
git remote add heroku $HEROKU_APP_REMOTE | |
git fetch heroku | |
MIGRATION_CHANGES=$(git diff $CIRCLE_SHA1 heroku/master --name-only -- db | wc -l) | |
echo "$MIGRATION_CHANGES db changes since last deploy." | |
# use pipeline to prepare a slug to deploy | |
git push pipeline $CIRCLE_SHA1:refs/heads/master | |
DEPLOY_START=`date +%s` | |
# migrations require downtime so enter maintenance mode | |
if test $MIGRATION_CHANGES -gt 0; then | |
heroku maintenance:on --app $APP_NAME | |
# Make sure workers are not running during a migration | |
heroku scale worker=0 --app $APP_NAME | |
fi | |
# promote the compiled slug | |
heroku pipeline:promote --app $PIPELINE_APP_NAME | |
# run database migrations if needed and restart background workers once finished | |
if test $MIGRATION_CHANGES -gt 0; then | |
heroku run rake db:migrate db:seed --app $APP_NAME | |
heroku restart --app $APP_NAME | |
heroku scale worker=$PREV_WORKERS --app $APP_NAME | |
fi | |
heroku run rake cache:flush --app $APP_NAME | |
heroku maintenance:off --app $APP_NAME | |
DEPLOY_END=`date +%s` | |
ELAPSED=$(( $DEPLOY_END - $DEPLOY_START )) | |
# HACK! | |
# Pipelines do not update the git repository on downstream apps. | |
# | |
# In order to be able to diff for db changes against the app overwrite the pipeline | |
# deploy with a git push of the same commit. | |
# | |
# Since this we already ran any required migrations this can always be a | |
# zero-downtime deploy we don't need to enable maintenance mode and are no longer | |
# sensetive to long asset precompilation times or other delays. | |
# | |
# We could remove this if we want to maintain a persistent pipeline app and always | |
# diff against that app to determine if db changes exist. Alternately we might | |
# be able to parse `heroku pipeline:diff` output for commit hashes and check for | |
# db changes in each commit. | |
git push heroku $CIRCLE_SHA1:refs/heads/master -f | |
# remove the pipeline app | |
heroku apps:destroy --app $PIPELINE_APP_NAME --confirm $PIPELINE_APP_NAME | |
echo "Deploy completed!" | |
if test $MIGRATION_CHANGES -gt 0; then | |
echo " $ELAPSED seconds in maintenance mode." | |
else | |
echo " $ELAPSED seconds, without maintenance mode." | |
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh -e | |
APP_NAME=$1 | |
git remote add heroku git@heroku.com:$APP_NAME.git | |
git fetch heroku | |
MIGRATION_CHANGES=$(git diff HEAD heroku/master --name-only -- db | wc -l) | |
echo "$MIGRATION_CHANGES db changes since last deploy." | |
rake assets:precompile | |
git config user.name "CircleCi" | |
git config user.email "ci@example.com" | |
git add public/assets | |
git commit -m "Precompile assets" | |
PREV_WORKERS=$(heroku ps --app $APP_NAME | grep "^worker." | wc -l | tr -d ' ') | |
# migrations require downtime so enter maintenance mode | |
if test $MIGRATION_CHANGES -gt 0; then | |
heroku maintenance:on --app $APP_NAME | |
# Make sure workers are not running during a migration | |
heroku scale worker=0 --app $APP_NAME | |
fi | |
# deploy code changes (and implicitly restart the app and any running workers) | |
git push heroku HEAD:refs/heads/master -f | |
# run database migrations if needed and restart background workers once finished | |
if test $MIGRATION_CHANGES -gt 0; then | |
heroku run rake db:migrate db:seed --app $APP_NAME | |
heroku restart --app $APP_NAME | |
heroku scale worker=$PREV_WORKERS --app $APP_NAME | |
fi | |
heroku run rake cache:flush --app $APP_NAME | |
heroku maintenance:off --app $APP_NAME |
Added git fetch heroku
to make sure the CI box can diff against the latest git deploy to Heroku.
Added example of circle.yml
.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@jonah-carbonfive what does your circle.yml file look like?