ci: gate cacti.pot updates on i18n diff instead of regenerating - #150
Conversation
The "Verify translation template is up to date" step regenerated locales/po/cacti.pot with locales/build_gettext.sh and compared it (ignoring POT-Creation-Date). That couples the check to an exact gettext/xgettext toolchain and fails on unrelated version drift. Replace it with tests/bin/check-i18n-pot.php, which inspects the pull request diff: if any changed line adds, removes, or edits a Cacti i18n call (__(), __n(), __esc(), ... the same keywords build_gettext.sh feeds xgettext) in a file that feeds the template, then locales/po/cacti.pot must also be part of the pull request. The check fails only when that pot update is missing. The step now runs only on pull_request events and diffs against the PR base SHA, mirroring the existing patch-coverage.php approach.
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
The validator has false-negative and false-positive cases that make the CI gate unreliable.
Review effort: Balanced
Findings: None
What changed in this PR
Replaces toolchain-dependent POT regeneration with PR-diff-based i18n validation.
Changes:
- Adds a PHP script to detect changed translation calls.
- Updates CI to run it on pull requests.
| File | Description |
|---|---|
tests/bin/check-i18n-pot.php |
Implements diff-based POT validation. |
.github/workflows/plugin-ci-workflow.yml |
Invokes the validator for pull requests. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Address the reviewer note that the pot gate had false-positive and false-negative cases. The previous check scanned the unified diff line by line and compared whole normalised lines. That produced: - false positives: changing unrelated code on a line that also holds an i18n call (e.g. a width argument next to __()) demanded a pot update even though the translatable string was unchanged; and - false negatives: a multi-line i18n call whose string literal sits on its own line was missed, so changing the string slipped through. Rebuild the comparison from the tokens instead. For the merge-base and for HEAD, tokenize every template-feeding PHP file (the same find . -maxdepth 2 set build_gettext.sh scans), find the Cacti i18n helper calls, and collect the literal string arguments that actually form each pot entry (msgctxt/msgid/plural, per the xgettext -k spec). A call only contributes when those positions are constant strings, mirroring xgettext. If the extracted set differs between base and HEAD, locales/po/cacti.pot must be part of the pull request. Because it reads whole files rather than diff lines, surrounding-code edits and quote-style-only changes no longer trigger it, and multi-line calls are handled correctly.
|
Addressed the automated review's "false-negative and false-positive" concern in Root cause The first version scanned the unified diff line-by-line and compared whole normalised lines containing an i18n call. That is both too loose and too strict. I reproduced both failure modes against real branch diffs:
Fix The check no longer looks at diff lines. For the merge-base and for HEAD it tokenizes every template-feeding PHP file (the same Because it reads whole files via the tokenizer rather than diff lines:
Validation — ran a scenario matrix locally against real commits, all passing:
|

What
Replaces the
Verify translation template is up to dateCI step. It no longerregenerates
locales/po/cacti.potwithlocales/build_gettext.shand comparesit (ignoring
POT-Creation-Date). Instead it inspects the pull request diff andrequires that
locales/po/cacti.potbe part of the PR whenever the translatablestrings actually change.
Why
The old check coupled CI to an exact gettext/xgettext toolchain: a different
GNU gettext version reorders or re-wraps the template and the step fails even
when no translatable string changed. The real intent is simply "if you changed
i18n strings, regenerate and commit the template".
How
New script
tests/bin/check-i18n-pot.php:tests/bin/patch-coverage.php).calls that
build_gettext.shfeeds toxgettext(
__ __n __x __xn __esc __esc_n __esc_x __esc_xn __date __gettext), limited tothe files that feed the template (
find . -maxdepth 2 -name '*.php').change (the added/removed i18n lines are compared as sets).
locales/po/cacti.potis not in the PR, thestep fails with the list of offending files; otherwise it passes.
The step now runs on
pull_requestevents only.Testing
Validated locally against real branch diffs: adding an
__()call without a potupdate fails; adding it with the pot update passes; a non-i18n change passes; a
pure re-indent of an i18n line passes; deleting a template-feeding PHP file that
contained
__()without a pot update fails.