Deploying to Github Pages
The final step of our Target workflow is automatically deploying our application to Github Pages when it is merged into main
. This is the CD of CI/CD!
However, as Github Actions does not express "merging into main
" as an event, we will instead be thinking in terms of deploying when changes are pushed to main
instead.
Constructing the workflow
We first go through the same questions as Linting code:
"When will it run?" — when changes are pushed to
main
"What will it do?" — compile and build the React project and publish the generated build files to Github Pages
"Is this going to be a separate workflow? A separate job in the same workflow? Or just another step in the existing job?" — this will be a separate workflow because (a) the events that trigger it are different from
ci.yml
, and (b) it is not logically a part of theci
workflow
If we look at our answer for (2), you may notice that we are essentially describing two separate tasks:
Compiling and building the React project
Publishing the generated build files to Github Pages
While we can represent them as a single job, we would like to explore what it's like to design jobs that are dependent on one another and passing around artifacts in Github Actions.
We also realize that (3) reveals that we are no longer treating ci.yml
as the full CI/CD pipeline, so you are free to rename the workflow!
Designing the workflow
Breaking it down
What a mouthful! That's quite a lot of new steps and concepts. Fret not, we will be explaining each step individually.
Conditional workflow trigger
build job
Similar to the jobs written in Running unit tests and Linting code, we will declare a job to
Fetch the repository
Setup Node.js
Install project dependencies
Build the production distribution
Doing so, we should now have a dist/
folder in our virtual machine runner for the build
job.
Let's talk more about the final step of the build
job.
Publishing artifacts
Artifacts are files or collections of files produced during a workflow run. These artifacts are stored on Github. You may wish to use artifacts for things like storing build logs, test results, binary or compressed files, etc.
For our use case, we want to publish the generated dist/
folder from the previous step in build
as an artifact, so that our next job, deploy
has access to the files and can publish them accordingly.
Thankfully, there is an existing action actions/upload-pages-artifact@v3
that handles this process, as we specify the name of the artifact generated github-pages
and the path to the directory containing the static assets, i.e. dist/
.
So, after build
runs, we would have an artifact called github-pages
uploaded to Github and accessible to subsequent jobs. You can read more about artifacts on the Github Actions documentation.
deploy job
We then declare a new job, deploy
that needs
the build
job. This is how we construct the dependency graph between jobs, requiring one to complete before the other can execute.
Permissions & secrets
In order to ensure that we can successfully publish to Github Pages, we also need to modify the default permissions of GITHUB_TOKEN
.
GITHUB_TOKEN
is a special access token that is automatically created as a secret in all workflows. It has access to the current repository, and it expires after the workflow completes. Secrets are a way of storing sensitive information in an organization, repository, or repository environment.
Essentially, GITHUB_TOKEN
allows steps in the job to have some access to the current repository. So, in order for the job to publish to Github Actions, we want to grant the token write
access to both pages
and id-token
. More information about the various permissions of GITHUB_TOKEN
can be found here.
Environments
An environment in Github refers to a general deployment target that can be configured with protection rules and secrets. Essentially, they allow you to handle different stages of your project, like development
, production
, and in our case, github-pages
.
These environments are displayed on the repository page.
For our scenario, we want to set the url
of the environment to point to the output (page_url
) of one of the job steps with step id deployment
.
Deploying the artifact
Finally, we can start deploying the artifact we published earlier. We use the action actions/deploy-pages@v4
, targeting the artifact named github-pages
, which we named earlier.
Notice that we also give an additional id
to the step, deployment
. This allows the step to be accessible via ${{ steps.deployment }}
and allows the outputs of the action to be accessible to the environment (seen above). ${{ ... }}
is a way of declaring expressions in a workflow file. More information about expressions in Github Actions can be found here.
Visualizing the workflow
We now have a workflow with sequential jobs, with build
generating the production build as an artifact, and deploy
consuming that artifact and publishing it to Github Pages.
We can also visualize the process of uploading an artifact as such:
Verifying the workflow
As per usual, add cd.yml
, create a commit, and push to main
.
This should already trigger the workflow to run. However, if you navigate to Actions and select the "Deploying the Github Pages" workflow, you will notice that it fails:
If you select the specific workflow run, go to the deploy
job, and select the "Publishing production artifact" step, you will see the following error:
The last message tells us what went wrong:
So, visit the URL provided (it is different from the one above!) and select "Github Actions" instead:
Finally, to re-run the workflow, go back to Actions and return to the failed workflow run. At the top right corner, you should see a button to "Re-run worflows", choose to re-run all jobs:
This time, you should see the following:
You can select the URL in the deploy
job component and you should be greeted with the following UI:
Next up: we will be exploring some unique workflows in Github Actions!
Last updated