Jump to
↵select↑↓navigateescclose

Standards

CI

The gates odoo-nix's standards run, the caller workflows sync writes, the reusable odoo-*.yml workflows they call, the CI App, and the Dependabot decision table.

Updated
Tags
  • standards
  • ci
  • github-actions
  • gates
  • dependabot
On this page

With ci on, sync writes small caller workflows into .github/workflows/. Each calls a reusable workflow of odoo-nix (Avunu/odoo-nix/.github/workflows/odoo-*.yml) at the revision your flake.lock pins, so CI moves only when odoo-nix does (odoo-init --sync rewrites the uses: SHAs). Every job is named ci, so a gate's check reads ci / lint, ci / test or ci / pr-policy. The required checks are the gates that are on: lint with any lint module, test with tests and an installable addon that is not untested, pr-policy with commits or releases. A gate that is off has no caller, so its check never reports; do not require it.

The gates

A gate is one command that a developer runs the same way CI does.

lint

nix develop --no-pure-eval .#odoo-nix-lint -c odoo-nix gate lint
StepWhatModule
sync-checkodoo-nix sync --check (with --expect-rev $ODOO_NIX_EXPECT_REV)always
prekevery hook of .pre-commit-config.yaml, with -cany hook module
manifestsodoo-nix check manifests: the website template, <series>.x.y.z versions, the series branch and .odoo-seriesaddon-manifest
iconsodoo-nix check icons: a square static/description/icon.png of at least icons.min-size pixels and at most icons.max-bytes bytes (--fix adds a missing one from the org profile's icons.src-icon)icons
submodulesodoo-nix check submodules: every .gitmodules entry on branch = <series> (projects)ci
ratchetodoo-nix ratchet coverage --base <merge-base>: fail_under does not fall, untested does not growtests

The lint shell is the one the odoo-nix your flake.lock pins builds over the checkout's path: it links tools/.venv, tools/.bin and node_modules from the checkout's locks, and never evaluates the checkout's own flake, so a project's submodules are not fetched.

test

ODOO_NIX_CI=1 nix develop --no-pure-eval -c odoo-nix gate test
StepWhatModule
modulesthe installable addons, less [[tool.odoo-nix.untested]]tests
postgresunder ODOO_NIX_CI, a throwaway cluster: its data directory is .odoo-nix/test/pg, its socket in a temporary directorytests
odoo-testodoo test <modules> --fresh-db --coverage tools/pyproject.toml --log .odoo-nix/test/odoo.logtests
checklogchecklog-odoo over that log with checklog-odoo.cfgtests.checklog
coveragecombine, report against fail_under, write coverage.xmltests
manifestoocheck-licenses and check-dev-status (an addon with no development_status counts as Beta, as in OCA)addon-manifest

Outside CI the test gate uses the dev shell's PostgreSQL. COVERAGE_FILE is .odoo-nix/coverage/.coverage unless you export one.

What a gate reports

Every step runs, and a step whose module is off is skipped with the reason. --report (default .odoo-nix/gate/<gate>.json, schema odoo-nix data-path schema/gate-report.schema.json) lists each step's status, command, exit code and time; under GitHub Actions a table goes to the job summary and problems become ::error annotations (--format github). The gate exits 1 when a step failed; 2 and 3 only for its own configuration and environment errors and those of the odoo-nix … sub-steps. A tool that exits non-zero, coverage under fail_under included, is a failed step, exit 1.

pr-policy

odoo-nix policy --pr checks a pull request: its base is the integration branch, a commits.pr-allowed-bases glob or (with commits.allow-stacked) another open PR's head; its title and every commit pass committed with the rendered committed.toml; under develop+series no addon's manifest version was moved by hand (the bump owns it). A Dependabot PR is exempt from the subject length alone. odoo-nix policy --commit-msg-file F is the same per-commit check as a commit-msg hook.

The callers

CallerTriggersCalls
ci.yml (name: ci), when the lint or the test gate is onpush to the integration branch, pull_request, workflow_dispatch, and ci.schedules.ci when setodoo-lint.yml, odoo-test.yml (each gate that is on)
pr-policy.yml (name: pr-policy), only with commits or releases onpull_request (opened, edited, synchronize, reopened), push to the integration branch, workflow_dispatchodoo-pr-policy.yml (skipped on the push, which a required check counts as passed)
release.ymlpush to the integration branch, workflow_run of ci on it, workflow_dispatch; concurrency release, never cancelledodoo-release.yml (Versioning)
deps.ymlpull_request, push to the integration branch (with dependabot.update-branches), the ci.project-update schedule (projects), workflow_dispatchodoo-deps.yml

release.yml is written only where the checkout has a release branch: an addon repository with releases on.

The reusable workflows

All of them pin every action by SHA, pass inputs through env:, clear $RUNNER_TEMP on self-hosted runners, and run a fork's pull request on ubuntu-latest whatever ci.runs-on says. On a GitHub-hosted runner, odoo-test.yml also deletes the preinstalled toolchains it doesn't use and clones submodules at depth 1, because Nix clones each submodule's full history itself.

WorkflowInputsWhat it runs
odoo-lint.ymlintegration-branch, runs-onthe lint shell of the locked odoo-nix, then odoo-nix gate lint --format github
odoo-test.ymlintegration-branch, runs-on, test-timeout-minutes, client-id; secret APP_PRIVATE_KEYthe checkout with its submodules (the App's token for private ones), ODOO_NIX_CI=1 nix develop --no-pure-eval -c odoo-nix gate test, the log and coverage.xml as an artifact
odoo-pr-policy.ymlintegration-branch, runs-onodoo-nix-tools installed at the locked revision, committed from the locked odoo-nix, then the policy
odoo-release.ymlintegration-branch, release-branch (required), runs-on, client-id; secret APP_PRIVATE_KEYthe bump and the fast-forward, with the App's token
odoo-deps.ymlshape (required), integration-branch, runs-on, auto-merge, auto-merge-policy, update-branches, merge-method, client-id; secret APP_PRIVATE_KEYrelock-plan/relock-push (addons), automerge, update-branches, project-update (projects)

Where a job needs odoo-nix itself, it installs odoo-nix-tools with uv tool install at the odoo-nix revision the checkout's flake.lock pins, through python-devops-nix's composite actions (standards-install, then standards-pr-policy, standards-release-ff, standards-deps-automerge or standards-update-branches); standards-install exports ODOO_NIX_EXPECT_REV for the skew check. It reads the revision from flake.lock's odoo-nix node, which must be locked from a github: URL: with dev-shell.odoo-nix-url set to a git+… URL, odoo-pr-policy.yml, odoo-release.yml, odoo-deps.yml and fleet-audit.yml fail (odoo-lint.yml and odoo-test.yml still run). Nix runs what needs it: the lint shell, the test gate, committed, the relock and odoo project update.

The CI App

ci.github-app names the Actions variable that holds a GitHub App's client ID and the secret that holds its private key:

[tool.odoo-nix.ci]
github-app = { app-id = "AVUNU_CI_APP_ID", private-key = "AVUNU_CI_PRIVATE_KEY" }

The release flow needs it: the bump commit and the series branch's move are pushed with its token, which the integration ruleset lets past its pull-request rule. odoo-deps.yml uses it when it is there, so its pushes, PRs and merges start CI by themselves. Without one ("", the default), GITHUB_TOKEN pushes raise no event, so the jobs dispatch ci.yml and pr-policy.yml on the new head instead. A Dependabot run sees only Dependabot secrets: store the private key there too. odoo-nix repo doctor lists what is missing (Fleet).

Dependabot

.github/dependabot.yml updates GitHub Actions and the Nix inputs, one entry per dependabot.target-branches branch (default: the integration branch), on dependabot.schedule with a cooldown-days cooldown, except for an addon repository's ocb input, which follows the branch tip (a cooldown would lock an odoo/odoo commit that OCB merged, which has no OCB pyproject.toml); its updates local region takes your own entries (an addon's own package.json, say). The locked tools (tools/uv.lock, package-lock.json) are not configured: they follow the series data.

With dependabot.auto-merge, odoo-deps.yml gives every Dependabot PR a verdict, auto (auto-merge, where every enabled gate is a required check of the integration branch), review (labelled needs-review), relock or close. The first rule of the PR's ecosystem that matches decides:

#EcosystemMatchesVerdict
1github-actionsodoo-nix's reusable workflows ($engine, Avunu/odoo-nix/*)review, sticky: they move with the locked odoo-nix
2github-actionsAvunu/python-devops-nix, Avunu/python-devops-nix/*review, sticky
3, 4github-actionsgrouped, or a single named actionauto
5nixodoo-nix, standards-profileclose: they move with odoo-nix repo rollout
6nixany other input (nixpkgs, ocb, an oca-* source)relock: nix run .#relock on the PR first (addons mode)
7, 8npm, uvthe locked tools at / and /toolsclose, sticky
9npman addon's own package.json, minor or patchauto
10submodulesa project's submodulerelock

No match is review. dependabot.auto-merge-policy = "all" auto-merges everything a sticky rule does not hold. A nix PR in an addon repository is relocked by relock-plan (which runs the PR's code with no write token) and relock-push (which applies the patch with the App's token); in a project nothing relocks it here, so its verdict leaves it to a person, and project-update (on ci.project-update's schedule) moves every submodule to its branch's tip with odoo project update, relocks, and opens standards/project-update. With dependabot.update-branches, bot PRs that fall behind the integration branch are brought up to date on every push.