Continuous Integration and Continuous Deployment
Over the course of development, software changes continuously and as software changes bugs & misfeatures will arise. In order to ensure feedback is as relevant as possible continuous deployment was introduced.
Continuous integration is a way of working where developers reintegrate their code into the upstream repository as frequently as possible. Continuous Deployment takes this one step further and automatically builds, tests and deploys applications so long as the steps complete successfully.
If you have built this project with other people, pair or mob with them through this guide.
This guide assumes you are already familiar with Git, and the concept of Pull Requests.
In this guide we assume that you have locally configured your shared git remote to be named
You will need a project hosted on GitHub (preferably open-sourced, and without an automated build tool configured for it) and accounts on Heroku and CircleCI.
You will need to install the Heroku command line client.
We’re going to use CircleCI to automate some tests.
First, you’ll need to pick a project to automate tests on.
If you are using RSpec, all you need to know is your Ruby version for the docker image section (use
ruby -v on the command line), and then your
config.yml file can be as simple as:
version: 2.1 orbs: ruby: email@example.com jobs: build: docker: - image: circleci/ruby:2.6.3-stretch-node executor: ruby/default steps: - checkout - ruby/bundle-install - run: bundle exec rspec
If you are using a Ruby project, note that this config should be very similar to the pre-populated
config.yml file you got in the
Setting up CircleCI step of the instructions linked above.
Note that the above config.yml assumes you have a
Gemfile - which can be as simple as this one. You’ll also need a
Gemfile.lock later on to get Heroku working - you can create one by running
bundle install after you’ve added your
If your GitHub project is at
github.com/craigjbass/tictactoe, your CircleCI build will be at
- Trigger a build on CircleCI. Does it pass?
- Does it run tests if you push to your main branch in GitHub?
- Does it run tests if you open a pull request? Note that you will only be dealing with pull requests if you are using branches in your branching strategy - see Git Branching below.
- To open a pull request:
- Create a branch (
git checkout -b branch_name)
- Commit some code
- Push the branch (it will prompt you to run
git push --set-upstream origin branch_namefirst)
- At GitHub, go to your repo and click Pull Requests at the top
- Click Compare & pull request next to “branch_name had recent pushes n minutes ago” (If you don’t see that, you might need to select your branch from the dropdown on the right).
- Enter a description, and click to create the pull request
- You should see it running tests in CircleCI
- You can now click Merge pull request to get your changes merged into the main branch.
- What happens if you open a pull request from a branch with failing tests? Can you still merge the request? What changes?
Using CircleCI and Heroku you can configure your application to be automatically deployed to the web. However, note that if your app has a command-line interface (rather than a web interface), then you don’t gain much from Heroku deployment. In that case I would recommend you create a new repo with a simple Sinatra app as described at the beginning of Learn Enough Ruby here, or you can fork this simple Sinatra app.
Follow the Creating an application on Heroku, Configuring Heroku access on CircleCI and Adding the deploy configuration sections here to deploy your app to Heroku. Note that the
config.yml file referenced in the Adding the deploy configuration section is the same one that you created in the Automating Tests step above, so you can just add to the existing file.
### Things to think about
- Does the app still deploy if the tests fail? If so, see the
requiresstep in the
heroku_deployworkflow here to make a step dependent on a previous step.
- If you are using branches, are changes to all branches deployed? If so, is this desirable? See the
filtersstep in the
heroku_deployworkflow here to only deploy for a specific branch.
- An alternative way to deploy to Heroku is that you could remove the
heroku/deploy-via-gitjob from the CircleCI
config.ymland try configuring the deployment through Heroku by integrating with GitHub directly. Note in particular the Enabling GitHub integration section and the Wait for CI to pass before deploy checkbox detailed in the Automatic deploys section.
- Use the CircleCI language docs and the CircleCI deployment docs to help you identify problems.
- If you’re on Windows and you get the error “Your bundle only supports platforms [“x86-mingw32”]”, then replace
- If you get errors about Bundler versions, add the following to
config.ymlon the line before the
ruby/bundle-installstep (explanation here - note that this explanation is in reference to travis, but it’s the same principle):
- run: gem install bundler
- If you’re using a Rack-based framework such as Sinatra and are experiencing issues when deploying to Heroku, this article about the
config.rufile may be helpful.
Have a read through of Martin Fowler’s article on the various approaches to branching to get an understanding of the pros and cons of each approach. It’s a long article though, so you might want to jump straight to the section on continuous integration.
At Made Tech we practice Continuous Integration, as we have come to the agreement that the pros of this approach outweigh the cons.
- Why do you think that is?
- Discuss scenarios where Continuous Integration wouldn’t be appropriate
Continuous integration is a branching style with more stringent rules than others and so requires a level of commitment from developers in order to do its job.
origin/mastershould pass its tests at all times. All commits in master should compile and pass all tests.
origin/mastershould be deployable at all times. All commits in master should be of sufficient quality to be deployed.
- Where necessary, release should be decoupled from deploy. It should be possible to deploy master, and turn on new features independently. For instance the latest deployment contains a new feature, but your users can’t actually see or use that feature yet - ie it hasn’t been released. This approach is commonly referred to as “feature toggling” or “feature flagging”.
- Pull requests should be short lived (~4 working hours maximum), and short (~400 lines of code maximum). Pull requests should be simple to review.
- Pull requests should pass all tests, and not have any linter warnings (where appropriate). Pull requests should be tested before merging.
- Build new functionality in small increments, by employing a good software architecture and a comprehensive suite of tests.
- Use an automated build tool (e.g. Jenkins, Travis, Gitlab CI, CircleCI, etc) to run tests every time a new commit is pushed to
- Use an automated build tool to run tests every time a new commit is pushed to a Pull Request branch, and also run the tests as an “Integration” with master. (More on this later)
- Use your automated build tool to deploy successful builds
If you do plan on using feature branches, you might want to refresh your understanding of git merges. Make sure that you can:
- Draw out a simple Git branch with commits that apply on top of each other.
- Draw out what happens when a Git branch is merged with two parent commits.
- Draw out what happens when a Git branch is rebased ontop of a branch with commits.
- Explain what
Speak to your mentor if you need a refresher.