JBOSS uses GitHub Actions to automatically build and deploy your content whenever changes are pushed to GitHub. This ensures that the published materials stay up to date without requiring manual deployment.
How does it work?
Each repository using the starterkit template contains a GitHub Actions workflow file at: .github/workflows/deploy.yml. This file specifies when deployment should start and which build and validation steps should be performed.
By default, the workflow is triggered whenever a new commit is pushed to the main branch. The workflow calls the central JBOSS deployment workflow, so individual repositories do not need to maintain their own deployment scripts.
In the workflow you can specify whether you want a pdf output, whether it should execute python code, whether automated checks should be performed and whether a gallery of figures is to be made.
# Use this workflow to make use of the central workflows from https://github.com/TUD-JB-OS/deploy/.github/workflows/
name: Deploy
on:
push:
branches: [main]
permissions:
contents: read
pages: write
id-token: write
jobs:
deploy:
uses: TUD-JB-OS/deploy/.github/workflows/jboss.yml@main
with:
build_typst_pdf: true
build_latex_pdf: false
execute_python: false
run_nb_checks: false
run_fig_checks: false
run_code_checks: false
You can customize the deployment process by changing the values under the with: section. Set an option to true to enable it or false to disable it.
| Option | Description |
|---|---|
build_typst_pdf | Enable or disable PDF generation using Typst. |
build_latex_pdf | Enable or disable PDF generation using LaTeX. |
execute_python | Enable or disable Python code execution during the build. |
run_nb_checks | Enable or disable notebook validation checks. |
run_fig_checks | Enable or disable figure validation checks. |
run_code_checks | Enable or disable code validation checks. |
Automatic deployment with GitHub Actions
The JBOSS Starterkit includes a GitHub Actions workflow to automatically build and deploy your course materials to GitHub Pages. This workflow uses the central JBOSS deployment workflow, which handles building the website, generating PDFs, running checks, and publishing the results.
Enabling automatic deployment
The deployment workflow is already included in the .github/workflows/ folder of your repository. However, the automatic trigger is commented out by default, so deployment does not automatically start when you push changes.
If you want to enable automatic deployment, open the workflow file and uncomment (or add) the following lines:
on:
push:
branches: [main]From that point onward, every push to the main branch will automatically trigger the deployment workflow.
You can also enable manual deployment by adding workflow_dispatch:
on:
push:
branches: [main]
workflow_dispatch:This allows you to start a deployment manually from the Actions tab of your GitHub repository.
What happens during deployment?¶
The central workflow performs the following steps:
Set up the environment: Checks out the repository, installs MyST and other required tools, and prepares the Python environment using the selected dependency manager.
Run automated checks (optional): Checks notebooks and code-cell outputs, depending on your preferences.
Build a PDF (optional): Generates a PDF using Typst or LaTeX.
Build the HTML website: Builds the MyST website, optionally executing Python code during the process.
Generate reports (optional): Produces build error reports and optionally checks figures.
Deploy to GitHub Pages: Uploads the generated HTML website and publishes it through GitHub Pages.
You can follow the progress of each deployment in the Actions tab of your repository.
Customizing your deployment preferences¶
You can control which steps are performed by changing the settings in your repository’s deployment workflow.
# Build pages with Python execute
name: JBOSS Buildscript with menu
on:
workflow_call:
inputs:
dependency_manager:
description: "Dependency manager: pip, uv or pixi"
required: false
type: string
default: pip
build_typst_pdf:
description: "Build Typst PDF"
required: false
type: boolean
default: true
build_latex_pdf:
description: "Build LaTeX PDF"
required: false
type: boolean
default: false
execute_python:
description: "Execute Python code"
required: false
type: boolean
default: false
run_nb_checks:
description: "Run notebook checks"
required: false
type: boolean
default: false
run_fig_checks:
description: "Run figure checks"
required: false
type: boolean
default: false
run_code_checks:
description: "Run code cell checks"
required: false
type: boolean
default: false
env:
BASE_URL: /${{ github.event.repository.name }}
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
env:
TYPST_FONT_PATHS: ${{ github.workspace }}/typst_template/src/assets/fonts
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Checkout JB workflows
uses: actions/checkout@v5
with:
repository: FreekPols/JB-workflows
path: .jb-workflows
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Setup Node
uses: actions/setup-node@v5
with:
node-version: 24
- name: Install MyST
run: npm install -g mystmd
- name: Install ImageMagick
run: sudo apt-get update && sudo apt-get install -y imagemagick
- name: Warn when both PDF builds are requested
if: ${{ inputs.build_latex_pdf && inputs.build_typst_pdf }}
run: echo "only one pdf build allowed"
##### ---- SETUP PYTHON ---- ####
- name: Validate dependency manager
env:
DEPENDENCY_MANAGER: ${{ inputs.dependency_manager }}
run: |
case "$DEPENDENCY_MANAGER" in
pip|uv|pixi) ;;
*) echo "Unsupported dependency manager: $DEPENDENCY_MANAGER" >&2; exit 1 ;;
esac
- name: Set up Python (pip / uv)
if: ${{ inputs.dependency_manager != 'pixi' }}
uses: actions/setup-python@v5
with:
python-version: '3.14.10'
- name: Set up uv
if: ${{ inputs.dependency_manager == 'uv' }}
uses: astral-sh/setup-uv@v6
- name: Set up Pixi
if: ${{ inputs.dependency_manager == 'pixi' }}
uses: prefix-dev/setup-pixi@v0.9.1
with:
run-install: false
- name: Install CI dependencies (pip)
if: ${{ inputs.dependency_manager == 'pip' }}
run: |
test -f requirements-ci.txt || { echo 'Missing requirements-ci.txt'; exit 1; }
python -m venv .venv
.venv/bin/python -m pip install --upgrade pip
.venv/bin/python -m pip install -r requirements-ci.txt
echo "${{ github.workspace }}/.venv/bin" >> "$GITHUB_PATH"
- name: Install CI dependencies (uv)
if: ${{ inputs.dependency_manager == 'uv' }}
run: |
test -f pyproject.toml || { echo 'Missing pyproject.toml'; exit 1; }
test -f uv.lock || { echo 'Missing uv.lock (run uv lock and commit it)'; exit 1; }
uv sync --locked --no-default-groups --group ci
echo "${{ github.workspace }}/.venv/bin" >> "$GITHUB_PATH"
- name: Install CI dependencies (Pixi)
if: ${{ inputs.dependency_manager == 'pixi' }}
run: |
test -f pixi.toml || { echo 'Missing pixi.toml'; exit 1; }
pixi install --environment ci
# MyST invokes Jupyter kernels by name. Register the selected interpreter
# as python3 so notebook execution uses the same CI dependencies.
- name: Register Python kernel (pip / uv)
if: ${{ inputs.dependency_manager != 'pixi' }}
run: .venv/bin/python -m ipykernel install --user --name python3 --display-name 'Python 3 (CI)'
- name: Register Python kernel (Pixi)
if: ${{ inputs.dependency_manager == 'pixi' }}
run: pixi run --environment ci python -m ipykernel install --user --name python3 --display-name 'Python 3 (CI)'
- name: Automated file checks
if: ${{ inputs.run_nb_checks }}
run: |
if [ "${{ inputs.dependency_manager }}" = pixi ]; then
pixi run --environment ci python .jb-workflows/scripts/check.py
else
.venv/bin/python .jb-workflows/scripts/check.py
fi
- name: Check output codecells
if: ${{ inputs.run_code_checks }}
run: |
if [ "${{ inputs.dependency_manager }}" = pixi ]; then
pixi run --environment ci python .jb-workflows/scripts/codechecks.py
else
.venv/bin/python .jb-workflows/scripts/codechecks.py
fi
#### ---- BUILD TYPST PDF ---- ####
- name: Checkout Typst template fonts
if: ${{ inputs.build_typst_pdf }}
uses: actions/checkout@v5
with:
repository: TUD-JB-OS/typst_template
ref: main
path: typst_template
- name: Setup Typst
if: ${{ inputs.build_typst_pdf }}
uses: typst-community/setup-typst@v4
- name: Build PDF
if: ${{ inputs.build_typst_pdf }}
run: |
myst build --typst
# > build.log 2>&1 || true
- name: Upload Output PDF as Artifact
if: ${{ inputs.build_typst_pdf }}
uses: actions/upload-artifact@v4
with:
name: Output PDF
path: exports/*.pdf
compression-level: 0
- name: Write build errors to errorlog.md
if: ${{ inputs.build_typst_pdf }}
run: |
echo "# PDF Build Error Log" > errorlog.md
echo "" >> errorlog.md
echo "**Build time:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> errorlog.md
echo "" >> errorlog.md
echo '```text' >> errorlog.md
grep -iE "error|warning" build.log >> errorlog.md || echo "No errors or warnings." >> errorlog.md
echo '```' >> errorlog.md
#### ---- BUILD LATEX PDF ---- ####
- name: Install LaTeX
if: ${{ inputs.build_latex_pdf && !inputs.build_typst_pdf }}
run: |
sudo apt-get update
sudo apt-get install -y \
imagemagick \
texlive-latex-base \
texlive-latex-recommended \
texlive-fonts-recommended \
texlive-xetex \
latexmk \
texlive-latex-extra \
fonts-lmodern \
nodejs \
npm
- name: Build LaTeX PDF
if: ${{ inputs.build_latex_pdf && !inputs.build_typst_pdf }}
run: |
myst build --pdf > build.log 2>&1 || true
- name: Upload Output LaTeX PDF as Artifact
if: ${{ inputs.build_latex_pdf && !inputs.build_typst_pdf }}
uses: actions/upload-artifact@v4
with:
name: Output LaTeX PDF
path: exports/*.pdf
compression-level: 0
- name: Write build errors to errorlog.md
if: ${{ inputs.build_latex_pdf && !inputs.build_typst_pdf }}
run: |
echo "# PDF Build Error Log" > errorlog.md
echo "" >> errorlog.md
echo "**Build time:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> errorlog.md
echo "" >> errorlog.md
echo '```text' >> errorlog.md
grep -iE "error|warning" build.log >> errorlog.md || echo "No errors or warnings." >> errorlog.md
echo '```' >> errorlog.md
##### ---- BUILD HTML ---- ####
- name: Build HTML Assets with Python execution
if: ${{ inputs.execute_python }}
run: myst build --html --execute 2>&1 | tee build.log
- name: Build HTML Assets without Python execution
if: ${{ !inputs.execute_python }}
run: myst build --html 2>&1 | tee build.log
- name: Generate MyST error report
run: |
if [ "${{ inputs.dependency_manager }}" = pixi ]; then
pixi run --environment ci python .jb-workflows/scripts/errorlog.py
else
.venv/bin/python .jb-workflows/scripts/errorlog.py
fi
#### ---- ADD CHECK REPORT ---- ####
# not needed when reporting errors using markdown file
# - name: Add check report
# if: ${{ inputs.run_code_checks }}
# run: cp _checks/checks.html _build/html/checks.html
- name: Automated figure checks
if: ${{ inputs.run_fig_checks }}
run: |
if [ "${{ inputs.dependency_manager }}" = pixi ]; then
pixi run --environment ci python .jb-workflows/scripts/listoffigs.py
else
.venv/bin/python .jb-workflows/scripts/listoffigs.py
fi
#### ---- DEPLOY TO GITHUB PAGES ---- ####
- name: Upload HTML artifact
uses: actions/upload-pages-artifact@v5
with:
path: ./_build/html
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v5
# Build pages with Python execute
name: JBOSS Buildscript with menu
on:
workflow_call:
inputs:
dependency_manager:
description: "Dependency manager: pip, uv or pixi"
required: false
type: string
default: pip
build_typst_pdf:
description: "Build Typst PDF"
required: false
type: boolean
default: true
build_latex_pdf:
description: "Build LaTeX PDF"
required: false
type: boolean
default: false
execute_python:
description: "Execute Python code"
required: false
type: boolean
default: false
run_nb_checks:
description: "Run notebook checks"
required: false
type: boolean
default: false
run_fig_checks:
description: "Run figure checks"
required: false
type: boolean
default: false
run_code_checks:
description: "Run code cell checks"
required: false
type: boolean
default: false
env:
BASE_URL: /${{ github.event.repository.name }}
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
env:
TYPST_FONT_PATHS: ${{ github.workspace }}/typst_template/src/assets/fonts
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Checkout JB workflows
uses: actions/checkout@v5
with:
repository: FreekPols/JB-workflows
path: .jb-workflows
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Setup Node
uses: actions/setup-node@v5
with:
node-version: 24
- name: Install MyST
run: npm install -g mystmd
- name: Install ImageMagick
run: sudo apt-get update && sudo apt-get install -y imagemagick
- name: Warn when both PDF builds are requested
if: ${{ inputs.build_latex_pdf && inputs.build_typst_pdf }}
run: echo "only one pdf build allowed"
##### ---- SETUP PYTHON ---- ####
- name: Validate dependency manager
env:
DEPENDENCY_MANAGER: ${{ inputs.dependency_manager }}
run: |
case "$DEPENDENCY_MANAGER" in
pip|uv|pixi) ;;
*) echo "Unsupported dependency manager: $DEPENDENCY_MANAGER" >&2; exit 1 ;;
esac
- name: Set up Python (pip / uv)
if: ${{ inputs.dependency_manager != 'pixi' }}
uses: actions/setup-python@v5
with:
python-version: '3.14.10'
- name: Set up uv
if: ${{ inputs.dependency_manager == 'uv' }}
uses: astral-sh/setup-uv@v6
- name: Set up Pixi
if: ${{ inputs.dependency_manager == 'pixi' }}
uses: prefix-dev/setup-pixi@v0.9.1
with:
run-install: false
- name: Install CI dependencies (pip)
if: ${{ inputs.dependency_manager == 'pip' }}
run: |
test -f requirements-ci.txt || { echo 'Missing requirements-ci.txt'; exit 1; }
python -m venv .venv
.venv/bin/python -m pip install --upgrade pip
.venv/bin/python -m pip install -r requirements-ci.txt
echo "${{ github.workspace }}/.venv/bin" >> "$GITHUB_PATH"
- name: Install CI dependencies (uv)
if: ${{ inputs.dependency_manager == 'uv' }}
run: |
test -f pyproject.toml || { echo 'Missing pyproject.toml'; exit 1; }
test -f uv.lock || { echo 'Missing uv.lock (run uv lock and commit it)'; exit 1; }
uv sync --locked --no-default-groups --group ci
echo "${{ github.workspace }}/.venv/bin" >> "$GITHUB_PATH"
- name: Install CI dependencies (Pixi)
if: ${{ inputs.dependency_manager == 'pixi' }}
run: |
test -f pixi.toml || { echo 'Missing pixi.toml'; exit 1; }
pixi install --environment ci
# MyST invokes Jupyter kernels by name. Register the selected interpreter
# as python3 so notebook execution uses the same CI dependencies.
- name: Register Python kernel (pip / uv)
if: ${{ inputs.dependency_manager != 'pixi' }}
run: .venv/bin/python -m ipykernel install --user --name python3 --display-name 'Python 3 (CI)'
- name: Register Python kernel (Pixi)
if: ${{ inputs.dependency_manager == 'pixi' }}
run: pixi run --environment ci python -m ipykernel install --user --name python3 --display-name 'Python 3 (CI)'
- name: Automated file checks
if: ${{ inputs.run_nb_checks }}
run: |
if [ "${{ inputs.dependency_manager }}" = pixi ]; then
pixi run --environment ci python .jb-workflows/scripts/check.py
else
.venv/bin/python .jb-workflows/scripts/check.py
fi
- name: Check output codecells
if: ${{ inputs.run_code_checks }}
run: |
if [ "${{ inputs.dependency_manager }}" = pixi ]; then
pixi run --environment ci python .jb-workflows/scripts/codechecks.py
else
.venv/bin/python .jb-workflows/scripts/codechecks.py
fi
#### ---- BUILD TYPST PDF ---- ####
- name: Checkout Typst template fonts
if: ${{ inputs.build_typst_pdf }}
uses: actions/checkout@v5
with:
repository: TUD-JB-OS/typst_template
ref: main
path: typst_template
- name: Setup Typst
if: ${{ inputs.build_typst_pdf }}
uses: typst-community/setup-typst@v4
- name: Build PDF
if: ${{ inputs.build_typst_pdf }}
run: |
myst build --typst
# > build.log 2>&1 || true
- name: Upload Output PDF as Artifact
if: ${{ inputs.build_typst_pdf }}
uses: actions/upload-artifact@v4
with:
name: Output PDF
path: exports/*.pdf
compression-level: 0
- name: Write build errors to errorlog.md
if: ${{ inputs.build_typst_pdf }}
run: |
echo "# PDF Build Error Log" > errorlog.md
echo "" >> errorlog.md
echo "**Build time:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> errorlog.md
echo "" >> errorlog.md
echo '```text' >> errorlog.md
grep -iE "error|warning" build.log >> errorlog.md || echo "No errors or warnings." >> errorlog.md
echo '```' >> errorlog.md
#### ---- BUILD LATEX PDF ---- ####
- name: Install LaTeX
if: ${{ inputs.build_latex_pdf && !inputs.build_typst_pdf }}
run: |
sudo apt-get update
sudo apt-get install -y \
imagemagick \
texlive-latex-base \
texlive-latex-recommended \
texlive-fonts-recommended \
texlive-xetex \
latexmk \
texlive-latex-extra \
fonts-lmodern \
nodejs \
npm
- name: Build LaTeX PDF
if: ${{ inputs.build_latex_pdf && !inputs.build_typst_pdf }}
run: |
myst build --pdf > build.log 2>&1 || true
- name: Upload Output LaTeX PDF as Artifact
if: ${{ inputs.build_latex_pdf && !inputs.build_typst_pdf }}
uses: actions/upload-artifact@v4
with:
name: Output LaTeX PDF
path: exports/*.pdf
compression-level: 0
- name: Write build errors to errorlog.md
if: ${{ inputs.build_latex_pdf && !inputs.build_typst_pdf }}
run: |
echo "# PDF Build Error Log" > errorlog.md
echo "" >> errorlog.md
echo "**Build time:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> errorlog.md
echo "" >> errorlog.md
echo '```text' >> errorlog.md
grep -iE "error|warning" build.log >> errorlog.md || echo "No errors or warnings." >> errorlog.md
echo '```' >> errorlog.md
##### ---- BUILD HTML ---- ####
- name: Build HTML Assets with Python execution
if: ${{ inputs.execute_python }}
run: myst build --html --execute 2>&1 | tee build.log
- name: Build HTML Assets without Python execution
if: ${{ !inputs.execute_python }}
run: myst build --html 2>&1 | tee build.log
- name: Generate MyST error report
run: |
if [ "${{ inputs.dependency_manager }}" = pixi ]; then
pixi run --environment ci python .jb-workflows/scripts/errorlog.py
else
.venv/bin/python .jb-workflows/scripts/errorlog.py
fi
#### ---- ADD CHECK REPORT ---- ####
# not needed when reporting errors using markdown file
# - name: Add check report
# if: ${{ inputs.run_code_checks }}
# run: cp _checks/checks.html _build/html/checks.html
- name: Automated figure checks
if: ${{ inputs.run_fig_checks }}
run: |
if [ "${{ inputs.dependency_manager }}" = pixi ]; then
pixi run --environment ci python .jb-workflows/scripts/listoffigs.py
else
.venv/bin/python .jb-workflows/scripts/listoffigs.py
fi
#### ---- DEPLOY TO GITHUB PAGES ---- ####
- name: Upload HTML artifact
uses: actions/upload-pages-artifact@v5
with:
path: ./_build/html
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v5Managing dependencies with Pixi¶
The JBOSS Starterkit uses Pixi as its default dependency manager. The Starterkit includes a pixi.toml file in the root of the repository, which defines the dependencies needed to build and execute your project materials. The deployment workflow is designed to use this file, so you can manage your dependencies centrally without manually configuring the GitHub Actions environment.
When adding new Python packages to your project, make sure they are included in your Pixi configuration and available in the ci environment. If you prefer, you can switch to pip or uv by changing the dependency_manager setting. This requires the corresponding dependency files (requirements-ci.txt for pip, or pyproject.toml and uv.lock for uv).
Extending the workflow with your own jobs¶
Although the central workflow handles the standard build and deployment process, you are free to extend your repository’s workflow with additional jobs. For example, you might want to run your own tests, validate data files, or perform additional checks before deploying your website.