Automating Rails CI/CD: From Bitbucket Pipelines to Heroku

December 18, 2018 · 3 min read

Update — April 4, 2026: This post has been updated to improve clarity and structure. Key changes include refined technical explanations for gem dependencies, improved pipeline configuration guidance, and standardized formatting for better readability.

During my time in college, I was tasked with developing a continuous integration (CI) system using a stack of my choice. Naturally, I chose Ruby on Rails. This post outlines the specific steps required to implement a CI/CD workflow using Bitbucket Pipelines and Heroku.

1. Initial Rails Configuration

We begin by creating a fresh Rails application. We'll use the -T flag to skip the default Minitest suite (opting for RSpec instead) and configure PostgreSQL as our database.

$ rails new ci-conceptual -T --database=postgresql

Essential Dependencies

To support a professional development and testing workflow, we add several key gems to the Gemfile:

group :development, :test do
  gem 'pry'
  gem 'pry-remote'
  gem 'rspec-rails'
  gem 'factory_bot_rails'
  gem 'shoulda-matchers'
end

group :development do
  gem 'listen'
  gem 'web-console'
  gem 'spring'
  gem 'erb2haml'
  gem 'rails-erd', require: false
  gem 'rubocop', '~> 0.46.0', require: false
end

group :test do
  gem 'simplecov', require: false
  gem 'database_cleaner'
end

Gem Breakdown

  • Testing Suite: We utilize RSpec for unit testing, FactoryBot for dummy data, and Shoulda Matchers for expressive validation tests.
  • Code Quality: Rubocop acts as our linter, enforcing community style guides or custom rules defined in a .rubocop.yml file.
  • Utilities: erb2haml is used to convert standard ERB templates to HAML, while rails-erd generates an Entity-Relationship Diagram (ERD) based on the database schema.
  • Coverage: SimpleCov provides insights into how much of our codebase is covered by tests.

2. Setting Up Bitbucket Pipelines

A Bitbucket Pipeline is essentially a Docker container that recreates your application's environment in the cloud. This allows us to run custom scripts automatically whenever code is pushed to the repository.

We define these operations in a bitbucket-pipelines.yml file. This configuration is highly flexible, allowing you to target specific branches or define distinct deployment environments.

Configuration Example

The pipeline is typically configured to run the linter and test suite on every push, ensuring that no broken code reaches the remote repository.

# Simplified bitbucket-pipelines.yml concept
image: ruby:2.5.1
pipelines:
  default:
    - step:
        script:
          - bundle install
          - bundle exec rubocop
          - bundle exec rspec

3. Automated Deployment to Heroku

To automate the transition from CI to CD (Continuous Deployment), we use shell scripts executed within the Bitbucket environment.

Secure Credentials

For Bitbucket to communicate with Heroku, it requires an API key. You can retrieve this via the Heroku CLI:

$ heroku auth:token

This token must be added as a repository variable named HEROKU_API_KEY under Settings > Repository Variables in Bitbucket.

Multi-Environment Strategy

One of the most powerful features of this setup is the ability to deploy to different Heroku apps based on the branch. For example:

  • master: Deploys to the production environment.
  • staging: Deploys to a staging site for external testing.
  • development: Deploys to a development site for internal review.

This approach allows developers, clients, and testers to interact with dedicated versions of the application without interference.

Final Resources

If you're looking for a reference implementation, you can check the original repository for detailed deployment scripts, Rubocop configurations, and RSpec setups.