Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,15 @@

## **Related links**

---

### Reviewer checklist

<!-- Full rules: see CLAUDE.md → "PR Review Checklist". Tick what applies. -->

- [ ] **Changelog + version** — every changed module has a `readme/HISTORY.md` entry **and** a matching `__manifest__.py` version bump; `README.rst`/`index.html` regenerated if a `readme/` fragment changed
- [ ] **Odoo 19** — `view_mode` uses `list` (not `tree`); no `attrs=`/`states=`
- [ ] **Security** — no PII/secrets in logs; API/DCI endpoints authenticated; parameterized SQL; new models have ACLs
- [ ] **Scope** — no unrelated changes bundled in
- [ ] **Tests** — affected module suite run locally (not just CI); pre-commit clean via `ci-local`
- [ ] **Runtime** — the changed path was actually exercised, not just read
122 changes: 122 additions & 0 deletions CLAUDE.md

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@emjay0921 I think this should be in https://github.com/ACN-org/acn-workspace/blob/main/internal/claude-config/OpenSPP2/CLAUDE.md. We are standardizing on using the acn-workspace that is why you will notice that there are no claude files in the OpenSPP2 repo.

Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# OpenSPP2 — Contributor & PR Review Guide

OpenSPP2 is an Odoo 19 monorepo of OpenSPP addons. This file is the **repo-wide
source of truth for how we review pull requests** — for human reviewers and for
AI-assisted review (Claude Code auto-loads it). The PR template links here.

> **Status: proposal.** Opened for the team to weigh in — refine, cut, or add
> rules as we agree on them.

## PR Review Checklist

When reviewing a PR, explicitly check each of these and cite `file:line` for
anything raised:

### 1. Correctness

- **Deleted code** — diff *both* directions. Count deleted test methods and
confirm coverage isn't quietly dropped.
- **Runtime behavior** — verify the changed path actually works (drive it or run
the module's tests), not just that the code reads correctly. A "column-shape"
test can pass green while the total is wrong.
- **Dependency completeness** — trace what happens when an *optional* dependency
isn't installed.
- **Edge cases** — None/empty handling; migrations (`migrations/*`) must be
idempotent and safe to re-run.

### 2. Scope

- Flag unrelated changes bundled into one PR. Prefer one concern per PR — it
makes review and rollback cleaner.

### 3. Release hygiene — REQUIRED (the most-missed rule)

- **Every changed module gets a `readme/HISTORY.md` changelog entry AND a
matching `__manifest__.py` version bump.** (See _Changelog & versioning_
below.) This is the rule that most often slips — check it first.
- If any `readme/` fragment changed, **regenerate** `README.rst` and
`static/description/index.html` with the OCA generator
(`oca-gen-addon-readme`) and commit the regenerated files.
Comment on lines +37 to +39

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When regenerating files using oca-gen-addon-readme, do not manually add a final newline to the auto-generated files, as any manual changes will be overwritten. The lack of a trailing newline should be addressed in the upstream tool.

Suggested change
- If any `readme/` fragment changed, **regenerate** `README.rst` and
`static/description/index.html` with the OCA generator
(`oca-gen-addon-readme`) and commit the regenerated files.
- If any `readme/` fragment changed, **regenerate** `README.rst` and
`static/description/index.html` with the OCA generator
(`oca-gen-addon-readme`) and commit the regenerated files. Do not manually add a final newline to these auto-generated files, as manual changes will be overwritten.
References
  1. Do not manually add a final newline to files auto-generated by the oca-gen-addon-readme tool, as any manual changes will be overwritten.


### 4. Odoo 19 compatibility

- `view_mode` uses **`list`**, not `tree`.
- No deprecated `attrs=` / `states=` — use `invisible=` / `readonly=` /
`required=` expressions.
- Manifest `depends` is complete and correct.
- The `openspp-check-odoo19-python` / `openspp-check-odoo19-xml` pre-commit
hooks catch common cases, but the reviewer still verifies.

### 5. Security

- **No PII or secrets in logs** (`openspp-no-pii-in-logs`, `gitleaks`).
- **API v2 / DCI / controllers:** endpoints are authenticated; JWT is
algorithm-pinned with audience/issuer validated; token comparisons are
constant-time; no unauthenticated PII exposure; **SQL is parameterized** (no
string-interpolated queries); controller routes set `auth=` correctly.
- New models have **ACLs** (`openspp-check-acl`); XML IDs follow naming
(`openspp-check-xml-ids`); no over-broad `sudo()` (scope + annotate).

### 6. Tests

- CI runs the module test matrix on PRs, but **run the affected module's suite
locally** too before opening/updating — and again after a rebase (git merges
text, not behavior). See _Running tests_.
- **Pre-commit must be clean** via the CI-matching container — see _Pre-commit_.

## Review protocol (esp. for AI-assisted review)

- **Recommend first**, then get maintainer confirmation **before submitting a
formal GitHub review** (Approve / Request changes).
- **Verify load-bearing claims against the actual code** — don't rely on the PR
description; spot-check the riskiest assertions.
- **Run the tests.** A green PR check is not proof everything passes.

## Changelog & versioning (`readme/HISTORY.md`)

Every module tracks changes in `readme/HISTORY.md`, rendered as the "Changelog"
in the generated `README.rst`.

```
### {version} # must match `version` in __manifest__.py

- type(scope): description (#PR)
```

- **Types:** `feat`, `fix`, `refactor`, `docs`, `test`, `chore`.
- Newest version on top; newest entry first within a version.
- **Version bump:** patch for fixes, minor for features, major for breaking
changes.
- _Open question for the team:_ bump in the feature branch vs. on `19.0` after
merge. Both patterns exist today — let's settle it here.

## Running locally

### Pre-commit (CI-matching container)

Run the same hooks CI runs, on your changed files, before pushing:

```bash
/Users/<you>/Projects/ci-local/run.sh OpenSPP2 --files <changed files>
# regenerate READMEs when a readme/ fragment changed:
/Users/<you>/Projects/ci-local/run.sh OpenSPP2 oca-gen-addon-readme --all-files --hook-stage manual
Comment on lines +100 to +102

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using /Users/<you>/ is specific to macOS. Using ~/ is more portable and works across both macOS and Linux environments.

Suggested change
/Users/<you>/Projects/ci-local/run.sh OpenSPP2 --files <changed files>
# regenerate READMEs when a readme/ fragment changed:
/Users/<you>/Projects/ci-local/run.sh OpenSPP2 oca-gen-addon-readme --all-files --hook-stage manual
~/Projects/ci-local/run.sh OpenSPP2 --files <changed files>
# regenerate READMEs when a readme/ fragment changed:
~/Projects/ci-local/run.sh OpenSPP2 oca-gen-addon-readme --all-files --hook-stage manual

```

Hooks include: `ruff` / `ruff-format`, `pylint_odoo`, the OCA checks, the
`openspp-*` custom checks (naming, XML IDs, ACL, PII-in-logs, performance,
Odoo-19 py/xml, API-auth), `gitleaks`, `bandit`, `semgrep`.

### Module tests (Docker)

```bash
cd OpenSPP2
docker compose exec -T db psql -U odoo -d postgres -c "CREATE DATABASE test_MODULE;"
docker compose run --rm --entrypoint "" test \
/opt/odoo/odoo/odoo-bin \
--addons-path=/opt/odoo/odoo/addons,/opt/odoo/odoo/odoo/addons,/mnt/extra-addons/openspp,/mnt/extra-addons/server-ux,/mnt/extra-addons/server-tools,/mnt/extra-addons/queue,/mnt/extra-addons/odoo-job-worker,/mnt/extra-addons/server-backend,/mnt/extra-addons/rest-framework,/mnt/extra-addons/muk-it \
-d test_MODULE --db_host=db --db_port=5432 --db_user=odoo --db_password=odoo \
--stop-after-init --no-http -i MODULE --test-tags /MODULE --log-level=test 2>&1 | tail -80
docker compose exec -T db psql -U odoo -d postgres -c "DROP DATABASE IF EXISTS test_MODULE;"
```

Look for the summary line: `0 failed, 0 error(s) of N tests`.
Loading