Skip to content

[ADD] oca-upstream-sync: weekly drift check against upstream OCA - #241

Open
AungKoKoLin1997 wants to merge 1 commit into
16.0from
16.0-add-oca-upstream-sync
Open

AungKoKoLin1997 wants to merge 1 commit into
16.0from
16.0-add-oca-upstream-sync

Conversation

@AungKoKoLin1997

@AungKoKoLin1997 AungKoKoLin1997 commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Weekly automated check for drift between the modules vendored here and the OCA repos they came from, so upstream fixes stop going unnoticed for months.

Draft: the seed config covers 3 of 97 modules deliberately — the rollout plan below explains why and what comes next.

Problem

We vendor OCA modules by copying them into this repo. OCA keeps fixing bugs and adding features, but nobody checks every week whether our copies have fallen behind. By the time someone notices, the gap is months wide and the sync is a large, risky diff.

What this PR adds

A GitHub Actions workflow + a Python script that compares each configured module against its upstream OCA repo.

How the weekly schedule works

Every Monday 02:20 UTC (09:20 Bangkok)
         │
         ▼
   compare each configured module against upstream
         │
         ▼
   open or update ONE GitHub issue:
   "OCA upstream drift — 16.0"
         │
         ▼
   that's it — no code is written, no PR is opened

The scheduled run is report-only. Writing to the repo is always a manual action from the Actions tab.

Manual actions (workflow_dispatch)

mode what it does when to use
check Same as the weekly run — reports drift Anytime you want to see the current state
discover-baselines Walks upstream history to find which commit each copy came from When adding new modules to the config
apply Overwrites copies proved untouched by their baseline After reviewing the drift issue and deciding what to sync
merge Three-way merges upstream into a locally patched module When a module has both upstream changes and local patches

Both apply and merge open a draft PR for review — they never push to 16.0 directly.

Why baselines, not just a diff

The obvious approach: diff each module against upstream tip, PR the difference. The problem: that diff mixes OCA's changes with our local patches, and an auto-sync reverts them.

Several modules here are patched on purpose. auditlog carries qrtl #172 and tests/test_multi_company.py (absent upstream); purchase_invoice_plan carries a local i18n/ja.po. A tool that cannot see the difference will silently revert all of it.

Each module therefore records a baseline — the upstream commit it was taken from, plus a fingerprint:

diff(upstream@baseline, local copy)   → what WE changed   (safety gate)
diff(upstream@baseline, upstream@tip) → what OCA changed  (the update)

A module is only auto-written when the first diff is empty, proved by measurement, not claimed in a config file.

Measured state of the three seeded modules

module upstream status behind code i18n/gen
purchase_exception OCA/purchase-workflow syncable 8 1 5
auditlog OCA/server-tools unattributed ? 11 73
purchase_invoice_plan OCA/purchase-workflow local only 0 7

Rollout plan

This is designed to be adopted gradually, not all at once. Only modules listed in .oca-sync.yml are looked at — everything else is untouched.

Phase 1: Merge this PR (3 modules seeded)

After merging, the Monday schedule starts producing the drift issue for the 3 seeded modules. Nothing else changes. This lets us confirm the workflow runs correctly in CI and the issue format is useful.

Phase 2: Map all modules

Add the remaining ~94 modules to .oca-sync.yml in batches, then run discover-baselines from the Actions tab. The script walks upstream history and automatically finds which commit each copy came from:

  • Exact match → pristine copy, safe for future auto-sync
  • Code-only match → code is upstream's but the copy carries local files (e.g. i18n/ja.po)
  • No match → the code itself is patched, needs a human to classify

This is where we learn which modules are category A (pure upstream), B (upstream + overlay PR), or C (locally patched). The script does the classification; we just need to review and confirm.

Phase 3: Review weekly issues

Let the Monday job run for a few weeks. Read the drift report. Get comfortable with how it classifies things and what it flags. No syncing yet — just observing.

Phase 4: Start syncing

Once confident in the baselines:

  1. Run apply from the Actions tab for the syncable modules → opens a draft PR with the upstream updates
  2. Review the PR, let CI run, merge
  3. For needs merge modules, run merge <module> → opens a draft PR with a three-way merge that preserves local work

Phase 5 (optional): Auto-sync on schedule

Once the process is proven, we can add --apply to the scheduled Monday run so pristine copies sync automatically and open a draft PR without manual dispatch. That's a one-line change to the workflow, but only worth doing after the baselines are populated and trusted.

Verified locally

  • --discover-baselines attributes purchase_exception exactly, purchase_invoice_plan code-only, and correctly finds nothing for auditlog (3.4s for both upstream repos)
  • --apply syncs purchase_exception to upstream tip and re-records its baseline
  • Safety gate: after editing a synced copy, it flips to needs merge and --apply refuses it even when named explicitly
  • --merge three-way merges 8 upstream commits into the patched copy, keeping the local edit
  • pre-commit passes on all added files

Known rough edges

Documented in README-oca-upstream-sync.md:

  • CI does not run on branches pushed with GITHUB_TOKEN — close/reopen the PR to trigger it
  • oca-gen-addon-readme regeneration flips a module out of syncable until re-baselined
  • The right answer for some modules may be to stop vendoring altogether and aggregate OCA/<repo> directly

Vendored copies drift from the OCA repos they came from, and checking by
hand every week does not happen. A scheduled workflow reports the drift
into a single issue; nothing is written to the repo on a schedule.

The design turns on recording a baseline per module -- the upstream commit
a copy was taken from, plus a fingerprint of the copy at that moment. That
separates what OCA changed from what we changed, which a plain diff against
the branch tip cannot do. Without it a sync job cannot tell an upstream fix
from a deliberate local patch, and reverts the patch.

Seeded with three modules. Their measured state is why the distinction
matters: purchase_exception is a pristine copy and can auto-sync; auditlog
is patched (qrtl #172, plus a test file absent upstream) and is refused;
purchase_invoice_plan carries a local ja.po and is refused.
@AungKoKoLin1997

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@AungKoKoLin1997

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Breezy!

Reviewed commit: 469d4c1694

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@AungKoKoLin1997
AungKoKoLin1997 marked this pull request as ready for review September 14, 2026 03:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant