Continuous Integration
.github/workflows/run-tests.yml runs the full automated test suite on every push and pull request targeting main or dev, against a real MySQL 8.0 service container on PHP 8.3 — the exact same bin/test command a developer runs locally, so CI can never diverge from the local dev workflow.
Automated Semantic Versioning — Zero Node, Zero npm
Every merge to main is automatically versioned and published, in keeping with the project's zero third-party-runtime-dependency ethos: no Node, no npm, no third-party release tooling. Two small PHP scripts under bin/, plus git and GitHub's own gh CLI (already present on every Actions runner), do the whole job.
Every commit subject must follow Conventional Commits: type(scope): description. The type determines the version bump:
feat(auth): add OAuth login support -> minor bump
fix: correct off-by-one in pagination -> patch bump
feat!: remove legacy API endpoint -> major bump
BREAKING CHANGE: the /v1/legacy endpoint has been removed entirely.Previewing the Next Release Locally
bin/release --dry-run
How the Two Release Workflows Fit Together
.github/workflows/lint-commit-messages.yml runs bin/check-commit-messages on every pull request, so a malformed commit subject is caught immediately instead of silently producing no release later.
.github/workflows/release.yml is triggered by workflow_run — it only fires after Run Automated Tests (CI) has already succeeded on main, so a broken commit is never tagged or published. When it runs, bin/release reads every commit since the last v* tag, computes the next version, appends a CHANGELOG.md section, tags the release, and publishes it with gh release create.