Thanks to a pull-request "Install TagBot as a GitHub Action", which was created by a bot, I realized now is the time to move one of my Julia projects, Recommendation.jl, from Travis CI to GitHub Actions.
Since I haven't had enough time to work on the project for a year, migration was not straightforward as I expected. Hence, this post summarizes what I've undergone to get there. As always, I referred to some of the most actively/recently maintained official Julia packages (e.g., Statistics.jl, Tokenize.jl) to see what is the most 'modern' way to organize a Julia project.
Original .travis.yml
I've written the following Travis CI configuration more than a year ago:
language: julia
os:
- linux
- osx
julia:
- 0.7
- 1.0
- nightly
matrix:
allow_failures:
- julia: nightly
notifications:
email: false
after_success:
- julia -e 'using Pkg; Pkg.add("Coverage"); using Coverage; Coveralls.submit(process_folder())'
jobs:
include:
- stage: "Documentation"
julia: 1.0
os: linux
script:
- julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd()));
Pkg.build("Recommendation");
Pkg.instantiate()'
- julia --project=docs/ docs/make.jl
after_success: skip
The workflow breaks down into three pieces:
- Unit testing over multiple Julia versions
- Profiling test coverage
- Building and publishing a documentation page to GitHub Pages
Running a Workflow over multiple Julia versions
First and foremost, what I like about GitHub Actions is the easiness of using a build matrix.
For every pull-requests onto the master branch, as well as push event to the master with an arbitrary tag, the following workflow executes 3x3=9 jobs for 3 Julia versions and 3 operating systems:
name: CI
on:
pull_request:
branches:
- master
push:
branches:
- master
tags: '*'
jobs:
test:
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
version:
- '1.0'
- '1' # automatically expands to the latest stable 1.x release of Julia
- 'nightly'
os:
- ubuntu-latest
- macOS-latest
- windows-latest
arch:
- x64
steps:
# (actual tasks are defined here)
Having a comprehensive build matrix is particularly important for Julia because Julia is one of the rare programming languages that aggressively introduce backward-incompatible changes as the version number grows.
Notice that I dropped Julia 0.7 from the matrix when I switched out the Travis config with GitHub Workflow; considering the stable version is 1.5.3 as of Nov 2020, it's reasonable not to support Julia < 1.0 anymore.
Testing and reporting coverage
Next, we could leverage julia-actions/julia-runtest and julia-actions/julia-processcoverage as follows:
jobs:
test:
# (define a build matrix - see above)
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@v1
with:
version: ${{ matrix.version }}
arch: ${{ matrix.arch }}
- uses: actions/cache@v1
env:
cache-name: cache-artifacts
with:
path: ~/.julia/artifacts
key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}
restore-keys: |
${{ runner.os }}-test-${{ env.cache-name }}-
${{ runner.os }}-test-
${{ runner.os }}-
- uses: julia-actions/julia-buildpkg@v1
- uses: julia-actions/julia-runtest@v1
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v1
with:
file: lcov.info
As long as your repository is registered to Codecov.io, test coverage is automatically reported in a pull-request. See this comment as an example.
Documenting and hosting on GitHub Pages
Finally, we can define a dedicated job for building and publishing a documentation page using Documenter.jl.
Luckily, there is an official step-by-step guide: Hosting Documentation, and the definition of the job looks like:
jobs:
docs:
name: Documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@v1
with:
version: '1'
- run: |
julia --project=docs -e '
using Pkg
Pkg.develop(PackageSpec(path=pwd()))
Pkg.instantiate()'
- run: julia --project=docs docs/make.jl
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }}
DOCUMENTER_DEBUG: true
secrets.GITHUB_TOKEN is automatically set by GitHub Workflow.
Meanwhile, secrets.DOCUMENTER_KEY can be generated as explained in Authentication: SSH Deploy Keys and be configured as a custom GitHub repository secret at: https://github.com/{user}/{repository}/settings/secrets/.
It is important to note that we should accordingly update TagBot Workflow:
- uses: JuliaRegistries/TagBot@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
+ ssh: ${{ secrets.DOCUMENTER_KEY }}
Moreover, in case you're using an old version of Documenter.jl like me, you probably need to update the version in docs/Project.toml first of all because GitHub Actions are supported since Documenter.jl 0.24:
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
[compat]
- Documenter = "~0.20"
+ Documenter = "0.24"
That's all, and here is a complete set of GitHub Actions Workflows for my Julia project.
Support
Gift a cup of coffeeCategories
See also
- July 26, 2019
- Lightning Talk about Recommender Systems in Julia at #JuliaCon 2019
- March 31, 2019
- Publishing My Master's Thesis with Documenter.jl
- June 26, 2017
- Deploying Static Site to GitHub Pages via Travis CI
Author: Takuya Kitazawa
I am a product builder, mentor, and advocate for sustainable technology development with a decade of experience in AI/ML products, data systems, and digital transformation. Based in Canada and originally from Japan, I have lived and worked globally, including part-time residence in Malawi, Africa. Visit my portfolio to learn more about my work, or reach out to me at [email protected].
NowDisclaimer
- Opinions are my own and do not represent the views of organizations I am/was belonging to.
- I use Grammarly and LanguageTool for correcting grammatical errors, but I do not rely on any other generative AI tools to create my blog content.
- I am doing my best to ensure the accuracy and fair use of the information. However, there might be some errors, outdated information, or biased subjective statements due to the nature of a personal website. Visitors understand the limitations and rely on any information at their own risk.
- If there are any issues with the content, please contact me so I can take the necessary action.