CI/CD — GitHub Actions¶
Q7 wires two automated checks that run on every push to main and every pull request:
| Workflow | File | What it does | Typical runtime |
|---|---|---|---|
| Lint | .github/workflows/lint.yml | Runs the full pre-commit toolchain — ruff (format + lint), pylint_odoo, oca-checks-odoo-module, XML/YAML hygiene | ~1 min |
| Tests | .github/workflows/tests.yml | Spins up Postgres 15 + Odoo 18, installs every roots_hemms_* addon with --test-enable, fails on any test/install error | ~5-8 min |
A third workflow, Docs (docs.yml), was already shipped pre-Q7 and builds the MkDocs site on every push that touches docs/ or mkdocs.yml.
Triggers¶
Both Q7 workflows trigger on:
pushtomain— gate before docs buildpull_requestagainstmain— gate before mergeworkflow_dispatch— manual trigger from the Actions tab
To keep CI cheap, each workflow has paths: filters so docs-only PRs don't burn lint/test minutes, and concurrency: cancels in-progress runs when a newer commit lands on the same ref.
Lint workflow¶
The pre-commit/action caches hook environments by hash of .pre-commit-config.yaml, so subsequent runs are seconds — first run takes ~1 min to fetch ruff, pylint_odoo, and oca-checks.
The configuration mirrors OCA/maintenance 18.0 with three intentional deviations documented at the top of .pre-commit-config.yaml:
oca-gen-addon-readmeskipped (noreadme/directories yet)oca-fix-manifest-websiteskipped (HEMMS useshttps://roots.tech, not the OCA repo URL)prettier-xml+eslintcommented out (re-enable when a JS asset bundle ships)
Tests workflow¶
The job runs inside the official odoo:18.0 Docker image with a sibling Postgres 15 service container. Because Q6 (Mass Import) reads XLSX via openpyxl which is not bundled with the Odoo image, a single extra pip install step adds it before tests run:
Module selection¶
Rather than list all 10 roots_hemms_* modules, CI installs four leaf modules which transitively pull every other module via depends:
| Leaf | Pulls (transitively) |
|---|---|
roots_hemms_mass_import | Q6 + roots_hemms_ha_report + roots_hemms_pm + roots_hemms_asset_master |
roots_hemms_spare_parts | Q2 + roots_hemms_pm + roots_hemms_asset_master + roots_hemms_criticality |
roots_hemms_signature | Q4 + roots_hemms_asset_inspection + roots_hemms_service_contracts |
roots_hemms_ha_report | Q5 + roots_hemms_signature + roots_hemms_pm + roots_hemms_asset_inspection + ... |
The constant lives in two synchronized places:
.github/workflows/tests.yml—MODULES_TO_TESTenv varMakefile—HEMMS_MODULESvariable
If you add a top-of-tree HEMMS module, update both.
Detecting test failures¶
Odoo's exit code is 0 even when tests fail — it only reflects whether the CLI command itself crashed. The verify step scrapes odoo.log for three signatures:
grep -E "^(FAIL|ERROR): " odoo.log # unittest runner per-test
grep -E "odoo\.tests\.runner.*(FAIL|ERROR)" odoo.log # framework
! grep -q "Modules loaded\." # install crashed
Any match → job fails and the full odoo.log is uploaded as an artifact (odoo-log, 7-day retention) so you can debug without re-running CI.
Local CI parity¶
Reproduce CI on your laptop:
# Lint — same hooks GH runs
make lint
# Tests — runs inside the running private sandbox container
make up-private # if not already up
make test # installs into a throw-away DB
# Both together
make ci
If you don't have the local Docker stack, install the lint venv manually:
python3.10 -m venv .venv-lint
.venv-lint/bin/pip install ruff==0.6.8 pylint-odoo==9.1.3
.venv-lint/bin/ruff check addons/roots/
.venv-lint/bin/pylint --rcfile=.pylintrc addons/roots/
Status badges¶
Add to your README (replace OWNER/REPO):



Future hardening¶
These items are deliberately deferred from Q7 — capture in the next plan revision if they become priorities:
- Matrix Postgres versions (15 + 16) — once we have a customer running 16
- Code coverage report —
coverage.pyintegration + Codecov upload - Demo data smoke test — install with
--with-demoand assert expected record counts (right now demo loads but isn't asserted) - Two-DB matrix (
hemms_demovshemms_private) — Q5 has documented behavioural differences between fresh-install and Q2-installed databases that aren't exercised in CI