The ``oca-gen-addon-readme`` entry is a multi-line YAML scalar. The prettier hook rewrites it on every run in each target repo, producing a recurring local diff against the deployed copy. Format the source configs with the exact prettier versions deployed per version (2.7.1 for 16.0, 3.3.3 for 18.0) so the deployed files already match the hook output. No functional change: YAML folds the scalar newlines into spaces either way.
odoo-elabore-ci
Centralized CI/CD configuration for Elabore's Odoo repositories.
Purpose
This repository manages linting and CI configuration centrally for all Odoo repositories (*-addons and *-tools) in the Elabore organization on Gitea.
Benefits:
- Single, consistent configuration across all repos
- Automatic updates via deployment workflow
- Multi-version Odoo support (16.0, 18.0, etc.)
- Based on OCA (Odoo Community Association) standards
Architecture
odoo-elabore-ci/
├── .gitea/workflows/
│ └── deploy-config.yml # Manual deployment workflow (with dry-run)
└── config/
├── common/ # Shared files (all versions)
│ ├── .editorconfig
│ └── .gitea/
│ ├── workflows/
│ │ └── pre-commit.yml # Lint workflow deployed to each repo
│ └── scripts/
│ └── odoo-tests.sh # Odoo test runner used by test.yml
├── 16.0/ # Odoo 16.0 configuration
│ ├── .eslintrc.yml
│ ├── .prettierrc.yml
│ ├── .pre-commit-config.yaml
│ ├── .pylintrc
│ ├── .pylintrc-mandatory
│ ├── .ruff.toml
│ └── .gitea/workflows/
│ └── test.yml # Odoo tests workflow (deployed to 16.0 repos)
└── 18.0/ # Odoo 18.0 configuration
├── eslint.config.cjs
├── prettier.config.cjs
├── .pre-commit-config.yaml
├── .pylintrc
├── .pylintrc-mandatory
├── .ruff.toml
└── .gitea/workflows/
└── test.yml # Odoo tests workflow (deployed to 18.0 repos)
How It Works
Deployment Workflow (deploy-config.yml)
The deployment is manually triggered via Gitea Actions interface, giving you full control over what gets deployed and where.
Features:
- Version filter: Deploy to all versions or a specific one (16.0, 18.0)
- Repo filter: Deploy to all repos or specific ones (comma-separated)
- Dry-run mode: Preview changes without pushing anything
- Direct push: Commits are pushed directly to target branches (no PR)
Process:
- Detects available versions (folders in
config/other thancommon/) - For each target repository:
- For each selected Odoo version:
- Attempts to clone the corresponding branch
- Copies
config/common/thenconfig/{version}/ - In dry-run: shows what would change
- In live mode: commits and pushes directly to the branch
- For each selected Odoo version:
CI Workflow (pre-commit.yml)
Deployed to each target repository, this workflow runs on every Pull Request:
- Sets up Python 3.11 environment
- Installs and runs
pre-commitwith all configured hooks - Verifies no untracked files were generated
Test Workflow (test.yml)
Deployed to each target repository (per Odoo version), this workflow runs
the Python tests of the modules changed in a Pull Request, on the
self-hosted runner hosted at ci.elabore.coop:
- Runs inside the Elabore doodba image for the repo's Odoo version
- Starts a PostgreSQL 17.2 service container
- Detects the installable modules touched by the PR
- Installs them and runs their tests (
odoo --test-enable)
See Odoo Tests (CI) for details.
Linting Tools
| Tool | Purpose | Target Files |
|---|---|---|
| Ruff | Python linter + formatter | .py |
| Pylint-Odoo | Odoo-specific rules | .py, __manifest__.py, XML |
| ESLint | JavaScript linter | .js |
| Prettier | Multi-language formatter | JS, CSS, XML, JSON, YAML, MD |
| pre-commit-hooks | Generic checks | Trailing whitespace, merge conflicts, etc. |
| OCA hooks | Odoo community standards | Manifests, README, translations |
Odoo Tests (CI)
Each target repository gets a tests workflow (.gitea/workflows/test.yml)
that runs the Python tests of the modules changed in a Pull Request.
How it works
| Aspect | Value |
|---|---|
| Runner | self-hosted Gitea runner on ci.elabore.coop, label odoo-ci |
| Job image | docker.0k.io/mirror/odoo:rc_<version>-ELABORE-LIGHT (doodba) |
| Database | docker.0k.io/postgres:17.2.0-myc service container |
| Test runner | .gitea/scripts/odoo-tests.sh |
The workflow:
- Checks out the PR head with full history.
- Computes the changed installable modules with
git diff origin/<base>...HEAD(first-level directories containing__manifest__.py). - Runs
odoo-tests.sh <modules>inside the doodba image. The script generatesodoo.conffrom the environment (via the doodba entrypoint), then runs:The checked-out repository is prepended to the addons path, so the PR's code takes precedence over the modules already baked in the image.odoo --test-enable --stop-after-init -i <modules> \ --addons-path="$PWD,/opt/odoo/auto/addons" --test-tags "/<modules>"
If no installable module is touched (e.g. docs-only PR), the test step is skipped.
Runner (gitea-runner)
The runner is provided by the gitea-runner charm of the
0k-charms collection. It
registers against the Gitea instance with an organization-level token
and exposes the odoo-ci label; the job image is chosen by each
workflow through its container: key.
Required secrets (Gitea → organization Elabore → Settings → Actions
→ Runners): a registration token, configured in the runner's
deployment file on ci.elabore.coop. It is never stored in this
repository.
Adding a new Odoo version
- Add
config/<version>/.gitea/workflows/test.yml(copy the closest version, adjust the branch filter and thecontainer.imagetag). - Deploy as usual.
Limitations
- Modules are tested against the dependencies already present in the Elabore image. A dependency introduced in another Elabore repo and not yet baked in requires rebuilding that image.
- One job runs at a time (
capacity: 1on the runner).
Usage Guide
Deploying Configuration
Deployment is done via the Gitea Actions interface:
- Go to Gitea →
odoo-elabore-ci→ Actions - Select "Deploy CI Config" workflow
- Click "Run workflow"
- Fill in the parameters:
| Parameter | Description | Examples |
|---|---|---|
| Version | Odoo version to deploy | all, 16.0, 18.0 |
| Repos | Target repos (empty = all) | crm-addons, hr-addons |
| Dry-run | Preview without pushing | true (recommended first) |
Deployment Examples
| I want to... | Version | Repos | Dry-run |
|---|---|---|---|
| Preview all changes | all |
(empty) | ✅ |
| Deploy 16.0 to one repo | 16.0 |
crm-addons |
❌ |
| Deploy 18.0 to multiple repos | 18.0 |
crm-addons, hr-addons |
❌ |
| Deploy all versions everywhere | all |
(empty) | ❌ |
Recommended Workflow
1. Make changes in config/
2. git commit && git push origin main
→ Nothing happens (no auto-deploy)
3. Run workflow with DRY-RUN enabled
→ Review the logs to see what would change
4. If satisfied, run again WITHOUT dry-run
→ Changes are pushed directly to target branches
Modifying CI Configuration
-
Edit files in
config/:config/common/: changes applied to all versionsconfig/{version}/: version-specific changes
-
Commit and push to
main:git add . git commit -m "[IMP] description of change" git push origin main -
Trigger deployment manually (see above)
Adding a New Odoo Version
-
Create the configuration directory:
mkdir config/{new_version} -
Copy and adapt files from the closest version or from an OCA repo:
# Example for Odoo 19.0 based on 18.0 cp config/18.0/* config/19.0/ -
Adapt the copied files:
File Required Changes .pylintrcvalid-odoo-versions=19.0.pylintrc-mandatoryvalid-odoo-versions=19.0.ruff.tomltarget-versionif Python version changes.pre-commit-config.yamlHook versions if needed .gitea/workflows/test.ymlBranch filter and container.imagetag -
Commit and push:
git add config/19.0/ git commit -m "[ADD] support for Odoo 19.0 configuration" git push origin main -
Deploy via Gitea Actions:
- The new version will appear in the "Version" dropdown
- Use dry-run first to verify which repos have a
19.0branch
Secrets Configuration
The workflow requires a Gitea token with the following permissions:
- Read access to all organization repos
- Write access (to create PRs)
Configure the ELABORE_BOT_TOKEN secret in the repository settings.
Version Differences
16.0 vs 18.0
| Aspect | 16.0 | 18.0 |
|---|---|---|
| ESLint config | .eslintrc.yml |
eslint.config.cjs (flat config) |
| Prettier config | .prettierrc.yml |
prettier.config.cjs |
| Node.js | 16.17.0 | 22.9.0 |
| Prettier | 2.7.1 | 3.3.3 |
| ESLint | 8.x | 9.x |
| Additional hooks | - | whool-init, oca-gen-external-dependencies |
Configuration Files
.pylintrc vs .pylintrc-mandatory
.pylintrc: All rules (optional + mandatory), non-blocking mode (--exit-zero). Useful for IDEs..pylintrc-mandatory: Critical rules only, blocking mode. Used by CI.
Elabore-Specific Rules
Files are customized for Elabore:
manifest-required-authors=Elabore- URLs pointing to
https://git.elabore.coop/elabore/
Contributing
- Test changes locally with
pre-commit run --all-files - Follow commit conventions (tags
[IMP],[FIX],[ADD], etc.) - Auto-generated PRs should be reviewed before merging
Resources
License
AGPL-3.0