Build CI/CD pipelines using artifacts with GitHub Actions
This guide will differ from other guides about GitHub Actions in that it will be focused on how to transfer the build artifacts & outputs across multiple steps.
If you know what you're doing, you can skip the introduction and go straight to the Building CI/CD pipelines with GitHub Actions guide.
What is a CI/CD pipeline?
CI/CD pipeline is a sequence of steps that are executed to build, test, and deploy your website. It stands for Continuous Integration/Continuous Deployment.
Typically CI/CD pipelines are built by DevOps professionals using variety of tools such as GitHub Action, AWS CodePipeline, Jenkins, and others.
The above figure shows a typical CI/CD pipeline but depending on use case there could be fewer or more steps.
CI/CD pipelines makes it easier for a developer to build, test, and deploy their website or app by automating the steps associated with the deployement, e.g., in the above workflow, as soon as the developer pushes their code to the repository, the pipeline starts executing the steps associated with the build, test, and deployement.
What is a GitHub Action?
GitHub Action is GitHub's native CI/CD workflow management tool. It uses YAML files to declaratively define the steps that needs to be executed.
Like other tools, GitHub Actions provides an extensive set of tools and options to build CI/CD pipelines.
Deploying a Static Website to firebase
CloudBytes/dev> is built on JAMStack architecture and uses GitHub Actions to deploy the static website generated by Pelican to Firebase Hosting.
The simplest way to do that is by using the below GitHub Workflow.
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches:
- main
jobs:
build_and_deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: rehanhaider/pelican-build-action@v0.1.10
env:
PELICAN_CONFIG_FILE: app/publishconf.py
PELICAN_CONTENT_FOLDER: app/content
- uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: "${{ secrets.GITHUB_TOKEN }}"
firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_CLOUDBYTES_PROD }}"
channelId: live
projectId: cloudbytes-prod
The above workflow is execetud on
the push
event of the main
branch. It has only one job that does both build and deployment of the website. However, this will present a problem if we wanted to introduce additional jobs in the pipeline because each job runs on a separate container. So if we wanted to split build and deployment into two jobs, we would need to repeat the build process twice because the first job would build the website but the second job will not have access to the output.
So solve this, you need to use a GitHub Actions feature called GitHub Actions Artifacts to transfer the build artifacts from one job to another.
Using GitHub Artifacts
GitHub Artifacts can be used to transfer the build outputs and artifacts between two jobs. To do that you need to 1. Upload you build artifacts that includes the "output" and configuration files 2. Then add the build step as a dependency on the next job 3. And finally download the artifact
The above workflow can be modified to the following:
name: Deployment
on:
push:
branches:
- main
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build Pelican Website
uses: rehanhaider/pelican-build-action@v0.1.10
env:
PELICAN_CONFIG_FILE: app/publishconf.py
PELICAN_CONTENT_FOLDER: app/content
- name: Upload the build output
uses: actions/upload-artifact@v2
with:
name: build-output
path: |
output/
.firebaserc
firebase.json
retention-days: 1
deploy:
name: Deploy
needs: [build]
runs-on: ubuntu-latest
steps:
- name: Download the build output
uses: actions/download-artifact@v2
with:
name: build-output
- name: Deploy to Firebase
uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: "${{ secrets.GITHUB_TOKEN }}"
firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_CLOUDBYTES_PROD }}"
channelId: live
projectId: cloudbytes-prod
In the above example, we used upload-artifact@v2
action, named it build-output
and added the files & directories under path
. For pelican we needed the output folder, in this case output
, and the two Firebase configuration files.
Then during the deployment step, we used download-artifact@v2
action to download the build-output
and subsequently deployed the result to Firebase using FirebaseExtended/action-hosting-deploy@v0
action.
Once the above workflow is defined, any code that is pushed to the main
branch will trigger a GitHub Action and the workflow will look something like this:
Benefits of using GitHub Action artifacts
The biggest benefit of using GitHub Actions artifacts is that it allows you to transfer the build artifacts from one job to another. This is useful when you want to split the piepline into several steps and add or remove steps in future. E.g. in the above workflow, we can add a new job called test
that runs the tests without having to change the existing steps in the workflow.