Skip to content

ci: add GitHub Actions workflow - #8

Merged
JeremieSamson merged 2 commits into
mainfrom
ci/github-actions
Aug 19, 2026
Merged

JeremieSamson merged 2 commits into
mainfrom
ci/github-actions

Conversation

@JeremieSamson

Copy link
Copy Markdown
Owner

The repo had no CI. Rather than bolt on generic PHP tooling, this wires up the checks that map to how this plugin actually breaks.

Jobs

Job What it catches
guards Version drift across the 4 places it lives, external HTTP calls, em dashes in user facing copy, wrong JS translation hash
lint Parse errors on PHP 8.0 to 8.4
i18n Stale POT, stale MO
plugin-check Everything WordPress.org gates on

Why these

Version consistency. The release touches Version:, BIOLINKS_VERSION, Stable tag: and Tested up to: in two files. A Tested up to mismatch triggers mismatched_tested_up_to_header and drops the plugin out of directory search, which is only visible after publishing. The check also asserts readme.txt documents the version under both == Changelog == and == Upgrade Notice ==.

Zero external HTTP. A product promise since 1.1.2, previously protected by nothing but discipline. Fails if wp_remote_*, curl_init, fsockopen, a remote src=, @import url(http or fetch() reappears outside assets/vendor.

JS translation hash. wp-cli 2.12 names make-json output after assets/a.js instead of assets/admin.js, so WordPress never finds the file and the admin silently stays in English. This is the exact bug 1.1.10 had to fix. The check asserts every locale has biolinks-<locale>-$(md5 'assets/admin.js').json.

Stale MO. The .po is never read at runtime. If it is updated without recompiling, the old translations keep being served with no error anywhere. The check compares translated-message counts between each PO and its MO.

Plugin Check runs on a staged copy built with the release zip exclusions, so it validates the shipped artifact rather than the repo, tooling included. Warnings are ignored since the ~102 DirectDatabaseQuery / InterpolatedNotPrepared ones are structural: the 5.9 floor rules out prepared %i placeholders.

Verification

Each guard was run twice locally: once on the current tree, where all six pass, and once against a seeded regression to confirm it actually fails and prints something actionable. A guard that cannot fail is worse than no guard. The POT check found its own bug during this: it was swallowing a make-pot failure and reporting a false stale POT. Fixed before commit.

.github/scripts/check-all.sh runs the full set locally. The i18n scripts need wp-cli and gettext; the others need nothing.

No CI existed. The checks that matter here are not generic PHP tooling but
the project invariants that were only enforced by prose in CLAUDE.md.

- guards: version consistent across the four places it lives, no external
  HTTP call outside assets/vendor, no em dash in user facing copy, and JS
  translation files named after the right handle hash. That last one guards
  the wp-cli 2.12 make-json bug, which names files after assets/a.js and
  silently leaves JS strings in English.
- lint: php -l from 8.0, the declared floor, up to 8.4.
- i18n: POT covers every source string, and each MO matches its PO. A stale
  MO serves the previous translations with no error anywhere.
- plugin-check: the official WordPress action, run on a staged copy that
  mirrors the release zip so it sees the real artifact. Warnings ignored,
  errors fail the build.

Every guard was verified to fail on a seeded regression, not just to pass.
.github/scripts/check-all.sh runs the whole set locally.
@JeremieSamson JeremieSamson self-assigned this Aug 19, 2026
@JeremieSamson JeremieSamson added the enhancement New feature or request label Aug 19, 2026
The i18n job hung for 12 minutes on `apt-get update` before being cancelled:
unattended-upgrades holds the dpkg lock on the runner image often enough for
this to be a real failure mode, not bad luck.

gettext already ships with ubuntu-latest, so only reach for apt when msgfmt is
genuinely missing, and never refresh the package lists. Both tools now print
their version so a future breakage is visible in the log.

Adds timeout-minutes: 15 to every job. A hung step was otherwise free to burn
the six hour default.
@JeremieSamson
JeremieSamson merged commit f1743f9 into main Aug 19, 2026
8 checks passed
@JeremieSamson
JeremieSamson deleted the ci/github-actions branch August 19, 2026 09:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant