# Continuous Integration (CI)
This document describes the minimal Continuous Integration (CI) pipeline configured for the
FORJA / HPC Framework repository.
The CI is implemented via GitHub Actions and defined in:
```text
.github/workflows/ci.yml
1. Triggers and scope¶
The workflow is named "CI (minimal)" and is triggered on:
- any
pushto any branch (branches: ['**']), ignoring changes undersite/**; - any
pull_requesttargetingmainordev, also ignoringsite/**.
This ensures that:
- every commit pushed to the repository gets basic QA checks;
- every PR into the protected branches (
main,dev) runs the same pipeline.
A concurrency block groups runs by ref:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
so that older runs for the same branch/PR are cancelled when a new commit arrives.
2. Job: tests¶
The workflow defines a single job, tests, which runs on Ubuntu 22.04:
jobs:
tests:
runs-on: ubuntu-22.04
The steps in this job are:
2.1. Checkout with Git LFS¶
- name: Checkout (with LFS)
uses: actions/checkout@v4
with:
fetch-depth: 0
lfs: true
This checkout:
- fetches the full history (
fetch-depth: 0), which is useful for some tools; - enables Git LFS, so that large files (e.g. instances under
data/instances/) are available.
2.2. Ensure Git LFS and materialise blobs¶
- name: Ensure Git LFS & materialize blobs
run: |
set -euxo pipefail
if ! command -v git-lfs >/dev/null 2>&1; then
sudo apt-get update
sudo apt-get install -y git-lfs
fi
git lfs version
git lfs install --local
git lfs fetch --all
git lfs checkout
git lfs ls-files || true
ls -lh data/instances/synthetic || true
if grep -R -n "version https://git-lfs.github.com/spec/v1" data/instances/synthetic/*.json.gz >/dev/null 2>&1; then
echo "ERROR: still seeing LFS pointers in *.json.gz" >&2
exit 2
fi
Purpose:
- guarantee that Git LFS is installed and configured;
- fetch and checkout all LFS objects;
- list LFS-tracked files and the synthetic instance directory;
- fail fast if any
*.json.gzunderdata/instances/synthetic/is still an LFS pointer instead of a real gzip payload.
This prevents corrupted or placeholder instances from entering the test pipeline.
2.3. GZIP sanity check¶
- name: GZIP sanity (gzip -t)
run: |
set -e
shopt -s nullglob
files=(data/instances/synthetic/*.json.gz)
if [ ${#files[@]} -eq 0 ]; then
echo "No *.json.gz in data/instances/synthetic" >&2
exit 2
fi
for f in "${files[@]}"; do
echo "Testing gzip: $f"
if ! gzip -t "$f"; then
echo "Corrupted file or LFS pointer: $f" >&2
head -c 64 "$f" | sed 's/[^[:print:]]/./g' || true
exit 2
fi
done
echo "GZIP OK"
This step:
- ensures there is at least one
*.json.gzin the synthetic instances directory; - runs
gzip -ton each file, failing if any is invalid; - prints a small diagnostic prefix for corrupted files.
Together with the previous step, this enforces LFS + gzip integrity for the synthetic panel.
2.4. Python setup¶
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: "pip"
cache-dependency-path: |
pyproject.toml
setup.cfg
setup.py
This configures Python 3.11 with pip caching, keying the cache on the dependency descriptors.
2.5. System dependencies (METIS)¶
- name: System deps (METIS for gpmetis)
run: |
sudo apt-get update
sudo apt-get install -y metis
gpmetis -h | head -n1 || true
This installs the metis package and checks that gpmetis is callable. KaHIP is not installed in this minimal job; tests that require it are excluded by the pytest selection.
2.6. Python dependencies (pip-only)¶
- name: Install Python deps (pip only)
run: |
python -m pip install --upgrade pip
pip install -U pytest
pip install .
This:
- upgrades
pip; - installs
pytest; - installs the current project into the environment via
pip install ..
Unlike local development, CI does not use Poetry here; this keeps the workflow minimal while still respecting pyproject.toml.
2.7. Run tests¶
- name: Run tests
env:
OMP_NUM_THREADS: "1"
OPENBLAS_NUM_THREADS: "1"
MKL_NUM_THREADS: "1"
run: pytest -q -k "not (kahip or solvers_external)"
The final step:
- enforces single-threaded execution for numerical backends (OMP / BLAS / MKL);
- runs pytest in quiet mode;
- excludes tests related to KaHIP and heavy external-solver integration, keeping the pipeline fast and robust across environments.
A more exhaustive suite (including KaHIP and extended solver tests) is expected to be run locally by developers when the appropriate solvers are installed.
3. Relation to branch policy and contributions¶
The repository follows a simple contribution workflow:
- feature branches are created from
dev; - pull requests target
dev(notmain); - CI must pass before merging;
devis merged intomainvia pull request, and themainbranch is protected.
The CI workflow acts as a gatekeeper for:
- LFS / gzip integrity of synthetic instances;
- basic installation viability (
pip install .); - the core test suite (with external-solver-heavy tests excluded in this minimal job).
Developers are encouraged to:
- run tests locally via Poetry (
poetry run pytest ...); - use
pre-commithooks for fast feedback on style and basic QA; - keep
.github/workflows/ci.ymlanddocs/testing/*.mdaligned when the testing strategy evolves.