diff --git a/README.md b/README.md index 16d970c..736ba98 100644 --- a/README.md +++ b/README.md @@ -21,22 +21,29 @@ odoo-elabore-ci/ └── config/ ├── common/ # Shared files (all versions) │ ├── .editorconfig - │ └── .gitea/workflows/ - │ └── pre-commit.yml # CI workflow deployed to each repo + │ └── .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 + │ ├── .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 + ├── .ruff.toml + └── .gitea/workflows/ + └── test.yml # Odoo tests workflow (deployed to 18.0 repos) ``` ## How It Works @@ -68,6 +75,19 @@ Deployed to each target repository, this workflow runs on every Pull Request: 2. Installs and runs `pre-commit` with all configured hooks 3. 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`: + +1. Runs inside the Elabore doodba image for the repo's Odoo version +2. Starts a PostgreSQL 17.2 service container +3. Detects the installable modules touched by the PR +4. Installs them and runs their tests (`odoo --test-enable`) + +See [Odoo Tests (CI)](#odoo-tests-ci) for details. + ## Linting Tools | Tool | Purpose | Target Files | @@ -79,6 +99,66 @@ Deployed to each target repository, this workflow runs on every Pull Request: | **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_-ELABORE-LIGHT` (doodba) | +| Database | `docker.0k.io/postgres:17.2.0-myc` service container | +| Test runner | `.gitea/scripts/odoo-tests.sh` | + +The workflow: + +1. Checks out the PR head with full history. +2. Computes the changed installable modules with + `git diff origin/...HEAD` (first-level directories containing + `__manifest__.py`). +3. Runs `odoo-tests.sh ` inside the doodba image. The script + generates `odoo.conf` from the environment (via the doodba + entrypoint), then runs: + ``` + odoo --test-enable --stop-after-init -i \ + --addons-path="$PWD,/opt/odoo/auto/addons" --test-tags "/" + ``` + 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. + +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`](https://git.myceliandre.fr/0k/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 + +1. Add `config//.gitea/workflows/test.yml` (copy the closest + version, adjust the branch filter and the `container.image` tag). +2. 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: 1` on the runner). + ## Usage Guide ### Deploying Configuration @@ -155,6 +235,7 @@ Deployment is done via the Gitea Actions interface: | `.pylintrc-mandatory` | `valid-odoo-versions=19.0` | | `.ruff.toml` | `target-version` if Python version changes | | `.pre-commit-config.yaml` | Hook versions if needed | + | `.gitea/workflows/test.yml` | Branch filter and `container.image` tag | 4. **Commit and push**: ```bash diff --git a/config/16.0/.gitea/workflows/test.yml b/config/16.0/.gitea/workflows/test.yml new file mode 100644 index 0000000..a41ff78 --- /dev/null +++ b/config/16.0/.gitea/workflows/test.yml @@ -0,0 +1,44 @@ +name: tests + +on: + pull_request: + branches: + - "16.0*" + workflow_dispatch: + +jobs: + test: + runs-on: odoo-ci + container: + image: docker.0k.io/mirror/odoo:rc_16.0-ELABORE-LIGHT + services: + postgres: + image: docker.0k.io/postgres:17.2.0-myc + env: + POSTGRES_USER: odoo + POSTGRES_PASSWORD: odoopassword + POSTGRES_DB: postgres + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Detect changed modules + id: changed + run: | + base="${{ gitea.base_ref }}" + base="${base:-${{ gitea.event.pull_request.base.ref }}}" + git fetch origin "$base" + modules="$( + git diff --name-only "origin/$base...HEAD" | + awk -F/ '{print $1}' | sort -u | + while read -r dir; do + [ -f "$dir/__manifest__.py" ] && echo "$dir" + done | paste -sd, - + )" + echo "modules=$modules" >> "$GITHUB_OUTPUT" + echo "Changed installable modules: ${modules:-}" + + - name: Run Odoo tests + if: steps.changed.outputs.modules != '' + run: bash .gitea/scripts/odoo-tests.sh "${{ steps.changed.outputs.modules }}" diff --git a/config/18.0/.gitea/workflows/test.yml b/config/18.0/.gitea/workflows/test.yml new file mode 100644 index 0000000..526ce60 --- /dev/null +++ b/config/18.0/.gitea/workflows/test.yml @@ -0,0 +1,44 @@ +name: tests + +on: + pull_request: + branches: + - "18.0*" + workflow_dispatch: + +jobs: + test: + runs-on: odoo-ci + container: + image: docker.0k.io/mirror/odoo:rc_18.0-ELABORE-LIGHT + services: + postgres: + image: docker.0k.io/postgres:17.2.0-myc + env: + POSTGRES_USER: odoo + POSTGRES_PASSWORD: odoopassword + POSTGRES_DB: postgres + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Detect changed modules + id: changed + run: | + base="${{ gitea.base_ref }}" + base="${base:-${{ gitea.event.pull_request.base.ref }}}" + git fetch origin "$base" + modules="$( + git diff --name-only "origin/$base...HEAD" | + awk -F/ '{print $1}' | sort -u | + while read -r dir; do + [ -f "$dir/__manifest__.py" ] && echo "$dir" + done | paste -sd, - + )" + echo "modules=$modules" >> "$GITHUB_OUTPUT" + echo "Changed installable modules: ${modules:-}" + + - name: Run Odoo tests + if: steps.changed.outputs.modules != '' + run: bash .gitea/scripts/odoo-tests.sh "${{ steps.changed.outputs.modules }}" diff --git a/config/common/.gitea/scripts/odoo-tests.sh b/config/common/.gitea/scripts/odoo-tests.sh new file mode 100755 index 0000000..56e1f97 --- /dev/null +++ b/config/common/.gitea/scripts/odoo-tests.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# +# Run the Python tests of the given Odoo modules. +# +# This script is meant to be executed *inside* an Elabore doodba image +# (docker.0k.io/mirror/odoo:rc_-ELABORE-LIGHT), with a +# PostgreSQL service reachable at $PGHOST. The modules under test are +# read from the current working directory (the checked-out repository), +# which is prepended to the addons path so that the PR's code takes +# precedence over the modules already baked in the image. +# +# Usage: odoo-tests.sh + +set -euo pipefail + +modules="${1:?usage: odoo-tests.sh }" + +export PGHOST=postgres +export PGUSER=odoo +export PGPASSWORD=odoopassword +export PGDATABASE="test_$(basename "$PWD" | tr '.-' '__')" +export WITHOUT_DEMO=all +export DB_FILTER='.*' + +# Generate /opt/odoo/auto/odoo.conf from the environment and wait for +# the database to accept connections. +/opt/odoo/common/entrypoint + +# Odoo test-tags format: "/module1,/module2" (one leading slash). +tags="/$(echo "$modules" | tr ',' ',/')" + +exec odoo \ + --config=/opt/odoo/auto/odoo.conf \ + --max-cron-threads=0 \ + --limit-time-real=10000 \ + --workers=0 \ + --test-enable \ + --stop-after-init \ + --addons-path="$PWD,/opt/odoo/auto/addons" \ + -d "$PGDATABASE" \ + -i "$modules" \ + --test-tags "$tags"