Written by Zafar Saleem✏️
The technology industry innovates quickly, requiring developers to deliver products and services at a rapid speed while still prioritizing high quality. Integration and delivery used to be a manual process, but automation makes it much faster and more reliable.
In this article, we’ll explore continuous integration and continuous delivery or deployment. CI/CD automates the delivery of our products and features, making it faster and helping us maintain high quality. There are several tools available to set up CI/CD pipelines, however, in this article, we’ll set up GitHub Actions with Heroku as our cloud hosting service and GitHub to host our repository.
In this tutorial, we’ll use the following tools: Git, GitHub, GitHub Actions, Heroku, React, Draw.io, and Swimlanes.io. You can access the repository for this project on my GitHub profile. Let’s get started!
CI/CD Pipeline using Github Actions and Heroku
Table of contents
- Fundamentals of CI/CD
- Git and CI/CD strategy
- Create a new React project
- Set up Heroku
- Set up the GitHub repository
- Set up GitHub Actions
- Testing
- Conclusion
Fundamentals of CI/CD
CI/CD has three important terminologies that we need to understand before jumping into the code.
Continuous integration
Continuous integration is an automation process for engineers and developers that allows us to test new features in our code, making sure they work as expected.
Continuous delivery
Continuous delivery comes next, ensuring that the new changes are well-tested, free of bugs, and ready to be deployed to the production environment.
Continuous deployment
In the continuous deployment stage, changes to the application are deployed to production by merging to a specific branch, like master
.
The sample diagram below fully details the CI/CD process:
Git and CI/CD strategy
Let’s set up the CI/CD strategy for our example application. We’ll have one GitHub repository with two branches, master
and develop
. We’ll make a new feature branch
from the develop
branch, where we’ll develop a new feature and push those changes to its own feature. Then, we’ll create a pull request against the develop
branch on GitHub.
We’ll also have two CI/CD yml
files for configuration, development
and production
. The development
file is set up to trigger the CI/CD pipeline and deploy our changes to the Heroku development environment when we successfully merge a pull request into the develop
branch.
The production.yml
file is set up to trigger a CI/CD pipeline for the production environment on Heroku when we pull the latest changes from the develop
branch, merge develop
into master
, and finally push those changes to the remote master
branch.
The diagram below fully details this strategy:
Create a new React project
First and foremost, we have to set up a simple React project. Run the command below to create a React project in your projects
folder:
npx create-react-app github-actions-heroku
The command above will generate a React project and install all the required dependencies. Below are some of the dependencies we’ll use and their current versions at the time of writing:
react 17.0.2
react-dom 17.0.2
react-scripts 5.0.0
node 17.2.0
Set up Heroku
We’ll set up two environments, one for development and one as a production environment. Go ahead and log into your Heroku account on Heroku.com. I’m using my free account for this blog post:
Once you’re logged in, simply click on the New button, as shown in the screenshot below:
Then, click on Create new app from the dropdown menu. Go ahead and give your app a name. I’m calling mine github-actions-heroku-develop
, as shown in the screenshot below.
Since I’ve already created a project with this name, it shows up as unavailable on my account. However, you should go ahead and click on Create app, and a development environment will be created for you:
We’ll merge a pull request to the develop
branch, then our app will be deployed to this environment.
Now, let’s repeat the same process to create a new app, which we’ll name github-actions-heroku-prod
. When we merge the develop
branch into master
and push those changes to the remote master
branch, those changes will be deployed to this environment.
With our Heroku environments set up, we should go ahead and click on our profile picture icon on the Heroku dashboard, then click Account settings, as shown in the screenshot below:
Scroll down to the API Key section to reveal the API Key. Copy and paste it somewhere safe because we’ll need it when we set up our GitHub repository:
Now that we’re done with our Heroku setup, let’s move on and set up our GitHub repo.
Set up the GitHub repository
Go ahead and log into your GitHub account. Click on the + sign in the top right corner, then click on New repository:
Fill out the form as follows:
In the screenshot above, the project name github-actions-heroku
is not available because I already built one with that name for this blog post. Therefore, I’ll use the one I already created. However, you should go ahead and create the project.
Once you create a project on GitHub, you’ll see a screen like the one below:
For now, you can leave this screen as is. We’ll return to this in a bit. Go back to your local environment terminal and cd
into the local project you created earlier:
cd github-actions-heroku
First, remove the .git
folder from the project as follows:
rm -rf .git
Then, go ahead and initialize this repo as a Git project:
git init
The command above will automatically create a master
branch for you. Simply create a new branch called develop
with the following command:
git checkout -b develop
Now, go back to the master
branch:
git checkout master
Add your GitHub repo to your local repo with the following command:
git remote add origin git@github.com:zafar-saleem/github-actions-heroku.git
Now stage, commit, and push your changes to the remote master
branch:
git add -A
git commit -m "Initial commit"
git push origin master
Next, we’ll check out the develop
branch:
git checkout develop
Finally, we’ll push changes to the remote develop
branch:
git push origin develop
Now, let’s go back to our project on github-actions-heroku
and click on Settings > Secrets > New repository secret, as shown in the screenshot below:
Once you click on New repository secret, you’ll be presented with the screen below:
Name your secret accordingly, as shown above, and paste the Heroku API key you copied earlier. Then, click on Add secret. Now, we’re done with our GitHub and local repo.
Set up GitHub Actions
Now, open github-actions-heroku
in your favorite editor; I’m using Sublime Text. Create a folder at the root of the project named .github
. Inside .github
, create a new folder called workflows
. Inside the workflows
folder, create a file named development.yml
and paste the code below in it:
name: Development workflow
on:
push:
branches:
- develop
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Development Code
uses: actions/checkout@v2
- name: Use Node.js 17.x
uses: actions/setup-node@v1
with:
node-version: 17.x
- run: npm install
- run: npm run build --if-present
- name: Deploy to Heroku
uses: akhileshns/heroku-deploy@v3.12.12
with:
args: deploy --dir=build --prod
heroku_api_key: ${{ secrets.HEROKU_API_KEY }}
heroku_app_name: 'github-actions-heroku-develop'
heroku_email: 'zafarsaleem3@gmail.com'
At the top of this file is a development workflow. Whenever we push any changes or merge a pull request to the develop
branch, the pipeline on line 6
will be triggered automatically. We’re using the latest ubuntu
machine.
On line 25
, we’re using the heroku_api_key
from GitHub secrets, which we set up earlier. The Heroku app name on line 26
should be identical to the Heroku environment we set up earlier.
Now, we’re done with development.yml
. Let’s create a new file inside the workflows
folder called production.yml
and paste the contents below into it:
name: Production workflow
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Use Node.js 17.x
uses: actions/setup-node@v1
with:
node-version: 17.x
- run: npm install
- run: npm run build --if-present
- name: Deploy to Heroku
uses: akhileshns/heroku-deploy@v3.12.12
with:
args: deploy --dir=build --prod
heroku_api_key: ${{ secrets.HEROKU_API_KEY }}
heroku_app_name: 'github-actions-heroku-prod'
heroku_email: 'zafarsaleem3@gmail.com'
The code above is for production and is triggered whenever we push new changes to the master repo.
Testing
To test if our workflow is working as expected, we’ll first make sure we're on the develop
branch in our local project:
git checkout -b feature/branch // creates a feature branch from develop branch
// make changes to App.js file.
git commit -am "minor changes"
git push origin feature/branch
On GitHub, create a pull request against the develop
branch. Merge that pull request, and it should trigger the development pipeline in the Actions
tab of your GitHub project. Let it finish, then follow the steps below:
>git checkout develop
git pull origin develop
git checkout master
git merge develop
git push origin master
To see the production
pipeline triggered, go to your GitHub project and click on the Actions tab. Once both are successfully finished and deployed, you can go ahead to Heroku and test the latest changes that are deployed.
Conclusion
In this article, we covered CI/CD with React, GitHub actions, and Heroku. By automating integration and delivery, we can improve the speed and accuracy with which we deploy our applications to production. I hope you enjoyed this article. Happy coding!
Full visibility into production React apps
Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.
The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.
Modernize how you debug your React apps — start monitoring for free.
Top comments (0)