Migrate to GitHub Actions from Travis CI
GitHub Actions should simplify continuous integration (CI) for public repositories hosted on GitHub when compared with external services like Travis CI or CircleCI. To test this, I decided to migrate one of my public repositories from Travis CI to GitHub Actions. This post describes my approach and also lists the resources I found helpful. Overall I am satisfied with the outcome, but found getting there somewhat tricky; documentation on workflow syntax and individual Actions is plentiful, but few examples describe how to combine Actions into jobs that accomplish specific tasks. My hope is that this post can help others construct GitHub Actions workflows that require more than testing source code.
The test repository
After writing my PhD thesis in LaTeX, I published a thesis template designed to help others save time. In this Stanford LaTeX Thesis Example repository, I use CI to compile a PDF and upload it as a Release asset so that the PDF available for download from the README always corresponds to the latest Release version.
Previous implementation
Previously, I used Travis CI to pull a Docker image and compile a PDF from LaTeX source files. For tagged commits, a distinct GitHub account with write privileges to the repository (a Machine user) then uploaded the compiled PDF as a Release asset. Using Docker within Travis CI to compile the PDF worked well, but having to create a new GitHub account for the sole purpose of deploying to GitHub Releases, as is recommended for security purposes, was not ideal and further required the Travis gem to encrypt a personal access token.
Current implementation (2020/09/06)
You can view the full workflow on GitHub (note that this URL points to the current commit as of this writing and not the master branch). Currently, two sequential jobs within a single GitHub Actions workflow mirror the two steps in the previous implementation: compilation and Release asset upload. Using two jobs within one workflow rather than two distinct workflows avoids performing the compilation step twice; however, an if
conditional within the second job is necessary to limit its execution to only when the workflow is triggered by a tagged commit (rather than, for example, a PR). The two jobs consist of the following steps:
(1) Triggered by a push or pull request (PR), the first workflow job compiles the PDF from source and uploads it as a build artifact. The job’s four steps are:
- Checkout source code using the Checkout GitHub Action.
- Compile the LaTeX PDF file using the Marketplace Action: GitHub Action for LaTeX by
xu-cheng
. - Rename the compiled PDF using a bash shell. Note that this isn’t strictly necessary, but retaining the PDF filename allowed me to maintain backwards compatibility.
- Upload the PDF as an artifact using the Upload a Build Artifact GitHub Action. This Action allows data to persist beyond the lifetime of the job and in my case allows the PDF to be inspected, for example to evaluate changes from a PR.
(2) For a PR or an untagged commit, the GitHub Actions workflow ends here with success or failure. If instead the commit is tagged and the tag starts with v
(i.e. uses semantic versioning of the form v#.#.#
), then this job downloads the previously uploaded artifact, creates a draft Release, and uploads the PDF as a Release asset. The three steps are:
- Download the artifact from the previous job using the Download a Build Artifact GitHub Action.
- Create a draft Release using the Create a Release GitHub Action. The benefit of GitHub Actions over Travis CI is particularly apparent in this step as the Action automatically provides the appropriate GitHub Token for authentication.
- Upload the PDF as a Release asset. After this succeeds I can add a changelog to the draft Release and publish. The repository’s README will then automatically point to this new PDF because the URL uses
latest
: https://github.com/dcroote/stanford-thesis-example/releases/latest/download/thesis-example.pdf.
If you have suggestions for improving the workflow, let me know!
Helpful resources:
- GitHub Docs on: Workflow syntax reference for GitHub Actions, especially the job if conditional
- GitHub Docs on: Persisting workflow data using artifacts
- GitHub Docs on: Context and expression syntax for GitHub Actions
- Stack Overflow: github actions: how to check if current push has new tag (is new release)?
This work by Derek Croote is licensed under CC BY-NC 4.0