-
-
Save richardkmichael/3912072 to your computer and use it in GitHub Desktop.
#!/bin/bash | |
# FIXME: Can't node write a PID file? This hopes the current user doesn't run more | |
# than one node process. | |
kill_node_server() { | |
kill -9 $(ps | grep -m 1 "node" | cut -c 1-5) | |
} | |
setup_heroku() { | |
gem install heroku -d --no-rdoc --no-ri | |
# export HEROKU_API_KEY=<api key> | |
heroku keys:clear | |
yes | heroku keys:add | |
sleep 3 | |
} | |
# FIXME: Environments need a fail-consequence action, then the "else" | |
# can move inside this function too. | |
run_tests_in_environment() { | |
local environment=$1 | |
NODE_ENV=$environment ./run_tests.sh $environment | |
} | |
print_banner(){ | |
echo "" | |
echo "" | |
echo "---------- $1 ----------" | |
} | |
print_banner 'DEVELOPMENT' | |
# Node server removed: | |
# Do we really need to run a node server? run_tests.sh is just using cucumber. | |
if ! run_tests_in_environment development; then | |
echo "DEVELOPMENT tests fail." | |
exit 1 | |
fi | |
print_banner 'STAGING' | |
# FIXME: The gem command is not the Unix-way(tm), so this won't work. | |
gem list heroku || setup_heroku | |
deploy_to_heroku_environment(){ | |
local environment=$1 | |
echo "" | |
echo "Started DEPLOYMENT to the ${environment} server" | |
git remote rm heroku >/dev/null 2>&1 | |
yes | ruby travis-deployer.rb heroku-app-${environment} | |
git remote -v | |
yes | git push heroku master 2>&1 | grep -q "Everything up-to-date" | |
PUSH_TO_HEROKU_RESULT=$? | |
if [ $PUSH_TO_HEROKU_RESULT -eq 0 ] | |
then | |
# To really test for this, read the latest SHA1 from master and the remote; | |
# the 0 exit status is an indirect test.. ? | |
echo "${environment} server already has latest code deployed!" | |
echo "STOPPING, you should look into why this happened!" | |
echo "" | |
exit 0 | |
fi | |
heroku config:set NODE_ENV=${environment} --app heroku-app-${environment} | |
} | |
echo "VERIFYING the STAGING server DEPLOYMENT" | |
if ! run_tests_in_environment staging; then | |
echo "STAGING tests fail, ROLLING BACK." | |
heroku releases:rollback --app heroku-app-staging | |
exit 1 | |
fi | |
echo "DEPLOYMENT to STAGING was SUCCESSFUL" | |
print_banner 'PRODUCTION' | |
echo "" | |
echo "Started DEPLOYMENT to the PRODUCTION server" | |
git remote rm heroku >/dev/null 2>&1 | |
yes | ruby travis-deployer.rb heroku-app-production | |
git remote -v | |
yes | git push heroku master 2>&1 | grep -q "Everything up-to-date" | |
RESULT=$? | |
if [ $RESULT -eq 0 ] | |
then | |
echo "PRODUCTION server already has latest code deployed!" | |
echo "STOPPING, you should look into why this happened!" | |
echo "" | |
exit 0 | |
fi | |
heroku config:set NODE_ENV=production --app heroku-app-production | |
echo "VERIFYING the PRODUCTION server DEPLOYMENT" | |
if ! NODE_ENV=production ./run_tests.sh PRODUCTION | |
then | |
echo "DEPLOYMENT to PRODUCTION was NOT SUCCESSFUL" | |
echo "ROLLING-BACK PRODUCTION" | |
heroku releases:rollback --app heroku-app-production | |
echo "ROLLING-BACK STAGING" | |
git remote rm heroku >/dev/null 2>&1 | |
yes | ruby travis-deployer.rb heroku-app-staging | |
heroku releases:rollback --app heroku-app-staging | |
exit 1 | |
fi | |
echo "DEPLOYMENT to PRODUCTION was SUCCESSFUL" | |
echo "!!! AWESOME !!!" | |
exit 0 |
run_development() { | |
echo "Running All Features on DEVELOPMENT" | |
NODE_ENV=development ./node_modules/.bin/cucumber.js tests/cucumber/features | |
features=$? | |
exit $features | |
} | |
run_staging() { | |
echo "Running All Features on STAGING" | |
curl --silent --insecure --url "https://test.example.com/hirefire" # check if heroku is up | |
echo "" | |
NODE_ENV=staging ./node_modules/.bin/cucumber.js tests/cucumber/features | |
features=$? | |
exit $features | |
} | |
run_production() { | |
echo "Running @verify-against-production && ~@clean-mongo-db Features on PRODUCTION" | |
curl --silent --url "https://example.com/hirefire" # check if heroku is up | |
echo "" | |
NODE_ENV=production ./node_modules/.bin/cucumber.js tests/cucumber/features --tags @verify-against-production --tags ~@clean-mongo-db | |
features=$? | |
exit $features | |
} | |
TARGET_ENVIRONMENT=$1 | |
run_${TARGET_ENVIRONMENT} |
#!/usr/bin/env ruby | |
if ARGV.empty? | |
puts "Please provide the Heroku app name." | |
exit | |
end | |
heroku_app_name = ARGV[0] | |
File.open(".git/config", "a") do |git_config| | |
git_config.puts <<-EOF | |
[remote "heroku"] | |
url = [email protected]:#{heroku_app_name}.git | |
fetch = +refs/heads/*:refs/remotes/heroku/* | |
EOF | |
end | |
ssh_config = File.expand_path("~/.ssh/config") | |
File.open(ssh_config, "a") do |ssh_config| | |
ssh_config.puts <<-EOF | |
Host heroku.com | |
StrictHostKeyChecking no | |
CheckHostIP no | |
UserKnownHostsFile=/dev/null | |
EOF | |
end |
Hi Richard,
Thanks for the feedback!
removed arg checking at beginning, it’s never used
I added this to make sure that I cannot accidentally call the deploy script locally after I committed some not ready to push yet code.removed running node development server
This was of course not clear because you do not have the cucumber setup, but it would first run all tests locally against a local Node instance, MongoDB instance and RedisDB instance running the website. Then push to Heroku Staging and run all these tests again, I do this because running locally is a lot faster then against Heroku and the remote DB's. Then finally it goes to Heroku Production where only a subset of tests are being run.refactor heroku setup
Yes this was one of my pain points as well, instead of doing things over and over again I should do it once and setup all different remotes at once.add a test for expected code version on a remote server
This is interesting, how do you suggest we keep the history and update the version (I know Heroku has a deployment ID, so that could be stored somewhere. That I like a lotconfig block
Here I don't exactly know what you mean by that?
move to deploy.sh?
I have this so that I can run the script locally on my machine, to ensure that the way I do stuff locally is how I do stuff on the CI as well.is this adapted from something else, because it has nothing to do with travis
True I got this code from the TravisCI guys to use how to setup the Heroku remote for Git, I was lazy and just kept using that, would be nicer if I refactored that.cleanup
Here I lack knowledgegit config juggling can be removed if multiple heroku remotes
Indeed that I am aware of, it would be good to pull this functionality into deploy.sh and setup everything in one go.re Ruby vs Bash
I really don't care what language this is written in, I started in Bash because I execute a lot of commands and then I don't have to sh `` stuff from Ruby, but honestly performance in this script is not important at all :)
This is used in on the TravisCI server which will hook into GitHub so after each commit it will run (already does run now). so exit code basically 0 all is good anything else will fail the build and send me an e-mail after which I look at the logs.
https://travis-ci.org/ my project is a private repo so it is under a different url
Thanks again for all the feedback! Are you willing to keep helping me with this?
Re: the running Node server in development.
I did understand that you run tests locally, then staging, then production. But, I guessed the cucumber in the DEVELOPMENT
case in run_tests.sh
would handle the starting the development server, as cucumber in a Rails project doesn't require me to start the development Rails server separately.
In any case, if required, it would be nice to push the server-start down to hide it; it jumped out at me in the middle of the script - the other environments don't start a server (always running presumably, though, you do curl to test them -- that's a similar idea: "make sure test target server is available".).
The reason that my script doesn't do this is because in development I most of the time have the server running already and then it would fail to start on the same port, but I am open to suggestions on that one. Happy to kill the server before starting it again as well as this would mean all new code will be loaded.
The curl is also because Heroku has a long spinn up time and I don't want my first test to timeout because of that.
deploy.sh
run_tests.sh
travis-deployer.rb
known_hosts
is reallyssh_config
, not a known hosts (also, it doesn’t need to run every time)Perhaps write it entirely in Ruby? But, it’s a Node project… so maybe only bash, and no Ruby? Although, the heroku gem introduces a Ruby dependency; so, use Ruby to make refactoring and config easier… ?
Give thought to exit status, where will the script be used?