%%{init: {'theme': 'neutral', 'look': 'handDrawn', 'themeVariables': { 'fontFamily': 'monospace', "fontSize":"14px"}}}%%
flowchart TD
Push(["Developer<br>pushes to <code>main</code>"]) -->|"triggers"| GHA["GitHub Actions<br>Runner (ubuntu-latest)"]
GHA --> Step1("<strong>Step 1</strong><br>Checkout Repository<br><code>actions/checkout@v4</code>")
Step1 --> Step2("<strong>Step 2</strong><br>Set up Quarto<br><code>quarto-actions/setup@v2</code>")
Step2 --> Step3("<strong>Step 3</strong><br>Render & Publish<br><code>quarto-actions/publish@v2</code>")
Step3 -->|"authenticates with"| Token["<cdde>GITHUB_TOKEN</code><br>(auto-provided<br>by GitHub)"]
Token -->|"writes rendered output"| GHPages("<code>gh-pages</code><br>branch")
GHPages -->|"served as"| Site(["Live GitHub<br>Pages Site"])
style Push fill:#F9E79F,stroke:#D4AC0D,color:#000
style GHA fill:#D4E6F1,stroke:#2E86C1,color:#000
style Step1 fill:#EBF5FB,stroke:#2E86C1,color:#000
style Step2 fill:#EBF5FB,stroke:#2E86C1,color:#000
style Step3 fill:#EBF5FB,stroke:#2E86C1,color:#000
style Token fill:#FDEDEC,stroke:#C0392B,color:#000
style GHPages fill:#D5F5E3,stroke:#1E8449,color:#000
style Site fill:#D5F5E3,stroke:#1E8449,color:#000
GitHub Actions as CI/CD
In this lab, we’re going to cover using GitHub Actions (or just Actions) for deploying R or Python code (i.e., models, APIs, apps, etc) to a published website. View the original lab file here.
To help explain/demonstrate GitHub Actions, I’ll cover a few examples I use often.
Publishing Quarto/GitHub Pages
This book is published using GitHub Pages, which is a free hosting service provided by GitHub. Quarto provides an easy Terminal command for publishing using GitHub Pages:
quarto publish gh-pages The lab for this section will accomplish the same thing, but does so using a GitHub Action workflow file. However, if you run the commands above – as I did – the workflow files don’t exist because the site isn’t published via GitHub Actions. Instead, this repo uses local publishing.
There are two valid ways to publish a Quarto book to GitHub Pages, and running quarto publish gh-pages creates a local setup. This means Quarto renders the files locally, then pushes the rendered HTML directly to the gh-pages branch. The commit log for this branch confirms it:
git log gh-pages --oneline -5
# 76175e88 Built site for gh-pages
# 559df417 Built site for gh-pages
# ...The Built site for gh-pages messages are Quarto’s signature commit message when it pushes to the branch itself. No workflow file is involved.
To convert this to CI publishing, we’ll have to create and commit .github/workflows/publish.yml and _publish.yml files, so GitHub Actions can render and deploy on every push to main.
Workflow file
In the .github/workflows/publish.yml directory, create …
_publish.yml
Create _publish.yml and include the following …
What they do
Running Tests
You can also use GitHub Actions to run tests on your code. For example, if you have an R package, you can set up a workflow to run testthat tests when code is pushed to the test branch, and only promote to the prod branch if the tests pass.
Workflow file
# stored in .github/workflows/r-package-tests.yml
name: R Package Tests
on:
push:
branches: [test]
pull_request:
branches: [prod]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up R
uses: r-lib/actions/setup-r@v2
with:
use-public-rspm: true
- name: Install system dependencies
uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: |
any::rcmdcheck
any::testthat
any::devtools
- name: Run tests
uses: r-lib/actions/check-r-package@v2
with:
error-on: '"error"'What it does
- The workflow above triggers on pushes to
test(fromdev) and on pull requests targetingprod
error-on: '"error"'means the workflow only fails on hard errors — warnings won’t block promotion
- To enforce that tests must pass before merging to
prod, enable branch protection rules in GitHub (Settings → Branches → Add rule forprod) and require this workflow as a status check
%%{init: {'theme': 'neutral', 'look': 'handDrawn', 'themeVariables': { 'fontFamily': 'monospace', "fontSize":"14px"}}}%%
flowchart TD
DevBr(["<code>dev</code> branch"]) -->|"push to test"| TestBr("<code>test</code> branch")
TestBr -->|"triggers"| GHA["GitHub Actions<br>Run <code>testthat</code> suite"]
GHA -->|"✅ tests pass"| PR["Pull Request<br><code>test</code> → <code>prod</code>"]
GHA -->|"❌ tests fail"| Block["Promotion<br>Blocked"]
PR -->|"approved & merged"| ProdBr("<code>prod</code> branch")
style DevBr fill:#D4E6F1,stroke:#2E86C1,color:#000
style TestBr fill:#D5F5E3,stroke:#1E8449,color:#000
style ProdBr fill:#FADBD8,stroke:#C0392B,color:#000
style Block fill:#F9E79F,stroke:#D4AC0D,color:#000