ci: add release-version validation and PR-title enforcement - #5
Merged
Conversation
9 tasks
- release.yml: a validate job gates the build matrix on the pushed tag
matching .tabularium's version field (stripped of the v prefix) —
ported from the tabularis-elasticsearch-plugin sibling's pattern. Not
just convention: the registry's own manifest schema documents this as
a hard rule ("the registry rejects ingests whose tag and manifest
version disagree"), so this catches the mismatch at tag-push time
instead of at registry-submission time.
- ci.yml: a pr-title job enforces Conventional Commits PR titles via
amannn/action-semantic-pull-request, on plain pull_request (not
pull_request_target) since this repo doesn't need fork-PR support and
the plain event avoids the elevated-permission surface entirely.
Rebased onto the current main (already at 1.0.0-beta.2 with its own
release/CI fixes) — drops the version-bump/CHANGELOG changes this PR
originally carried, since main now covers that independently.
aesslinger
force-pushed
the
ci/semver-checks
branch
from
August 11, 2026 17:28
8ed9c87 to
8e3425b
Compare
aesslinger
added a commit
that referenced
this pull request
Aug 11, 2026
A precursor to eventually automating tag/release creation: when a PR's title implies a version bump, CI now posts a comment suggesting the next tag/version — without creating anything. Several real design decisions, each resolved with the user rather than assumed: - Type -> bump mapping: standard Conventional Commits (feat->minor, fix/refactor/perf->patch, docs/style/chore/test/ci/build->none, !/BREAKING CHANGE->major). - Beta-phase behavior: while the baseline version carries a -beta.N/-rc.N suffix, a release-worthy PR just increments that stage's counter, not a full patch/minor/major recompute -- nothing has shipped stable yet. - Prerelease channel: NOT signaled in the title. Checked precedent first (semantic-release/release-please control channel via labels or release- train branches, not embedded title syntax; no Tabularis repo does this either) and settled on a required prerelease:alpha|beta|rc|stable PR label. Missing label is a hard error -- the job fails rather than guessing a default channel. - Version baseline: latest git tag on main, falling back to main's .tabularium version field if no tag exists (true right now). - "Meaningful change" trigger: only re-comments when the PR's *derived classification* (type+breaking+channel) changes, not on every title edit -- tracked via a hidden HTML marker in the comment body, robust across opened/edited/reopened/synchronize/labeled/unlabeled. - Marking old suggestions outdated: GitHub's real minimizeComment GraphQL mutation with classifier: OUTDATED -- the same action available via the web UI's "..." menu -> "Hide comment" -> "Outdated". - Found and fixed a real trigger gap: the existing pull_request: block had no types:, defaulting to opened/synchronize/reopened -- a title-only edit never even re-ran CI. Widened to include edited/labeled/unlabeled (shared by all pull_request-triggered jobs, including the existing pr-title job, which also now re-validates on edited). Checked precedent before implementing: no sibling Tabularis plugin repo or tabularis itself has anything like this. A separate internal repo has a fuller PR-title-driven auto-tag/auto-release pipeline; decided against porting that whole pipeline here since it's a much larger behavioral change (replaces manual tagging entirely) with no Tabularis-org precedent -- this stays comment-only. Verified thoroughly before trusting the logic in CI: - Extracted the embedded classification regex and ran it in a real bash subshell (not zsh, which handles BASH_REMATCH differently) against 8 title cases -- all classified correctly, including a deliberately unparseable title correctly erroring. - Extracted the embedded version-arithmetic JS and unit-tested it standalone against 7 cases (beta-counter increment, stage transitions, graduation to stable from both beta and rc, stable->prerelease restart) -- all passed. - Wrote a full mock harness for the comment-orchestration logic (fake github.rest.issues.listComments/createComment and github.graphql) and ran 8 end-to-end scenarios covering: fresh suggestion, idempotent no-op on unchanged classification, minimize-and-repost on changed classification, silent on non-release-worthy titles, and the "no-release-needed" transition in both directions. This caught a real bug before it ever reached CI: the "already said none, still none" case incorrectly reposted because the idempotency check compared against a hardcoded string instead of the full classification -- fixed and reverified all 8 scenarios pass. - Confirmed the baseline resolves correctly against the actual current repo state: main now has real tags (v1.0.0-beta.1, v1.0.0-beta.2), so `git describe --tags` resolves directly against origin/main rather than the PR branch; the .tabularium fallback remains for the no-tags-yet case this repo has already moved past. - Both workflow YAML files re-validated after every edit. Also added contributor-facing docs (README's "Contributing: PR Titles & Versioning" section, cross-referenced from CLAUDE.md) so future maintainers understand the convention without reading the workflow YAML. Standard verification: cargo build/test (82/82)/clippy/fmt all pass, no Cargo.lock drift, markdownlint clean across the whole repo, both workflow files parse as valid YAML. Rebased onto main after #5 merged (adds the pr-title job and release validate job this PR builds on) — no functional changes beyond the rebase itself, CHANGELOG merge conflict resolved by keeping both entries.
aesslinger
added a commit
that referenced
this pull request
Aug 11, 2026
A precursor to eventually automating tag/release creation: when a PR's title implies a version bump, CI now posts a comment suggesting the next tag/version — without creating anything. Several real design decisions, each resolved with the user rather than assumed: - Type -> bump mapping: standard Conventional Commits (feat->minor, fix/refactor/perf->patch, docs/style/chore/test/ci/build->none, !/BREAKING CHANGE->major). - Beta-phase behavior: while the baseline version carries a -beta.N/-rc.N suffix, a release-worthy PR just increments that stage's counter, not a full patch/minor/major recompute -- nothing has shipped stable yet. - Prerelease channel: NOT signaled in the title. Checked precedent first (semantic-release/release-please control channel via labels or release- train branches, not embedded title syntax; no Tabularis repo does this either) and settled on a required prerelease:alpha|beta|rc|stable PR label. Missing label is a hard error -- the job fails rather than guessing a default channel. - Version baseline: latest git tag on main, falling back to main's .tabularium version field if no tag exists (true right now). - "Meaningful change" trigger: only re-comments when the PR's *derived classification* (type+breaking+channel) changes, not on every title edit -- tracked via a hidden HTML marker in the comment body, robust across opened/edited/reopened/synchronize/labeled/unlabeled. - Marking old suggestions outdated: GitHub's real minimizeComment GraphQL mutation with classifier: OUTDATED -- the same action available via the web UI's "..." menu -> "Hide comment" -> "Outdated". - Found and fixed a real trigger gap: the existing pull_request: block had no types:, defaulting to opened/synchronize/reopened -- a title-only edit never even re-ran CI. Widened to include edited/labeled/unlabeled (shared by all pull_request-triggered jobs, including the existing pr-title job, which also now re-validates on edited). Checked precedent before implementing: no sibling Tabularis plugin repo or tabularis itself has anything like this. A separate internal repo has a fuller PR-title-driven auto-tag/auto-release pipeline; decided against porting that whole pipeline here since it's a much larger behavioral change (replaces manual tagging entirely) with no Tabularis-org precedent -- this stays comment-only. Verified thoroughly before trusting the logic in CI: - Extracted the embedded classification regex and ran it in a real bash subshell (not zsh, which handles BASH_REMATCH differently) against 8 title cases -- all classified correctly, including a deliberately unparseable title correctly erroring. - Extracted the embedded version-arithmetic JS and unit-tested it standalone against 7 cases (beta-counter increment, stage transitions, graduation to stable from both beta and rc, stable->prerelease restart) -- all passed. - Wrote a full mock harness for the comment-orchestration logic (fake github.rest.issues.listComments/createComment and github.graphql) and ran 8 end-to-end scenarios covering: fresh suggestion, idempotent no-op on unchanged classification, minimize-and-repost on changed classification, silent on non-release-worthy titles, and the "no-release-needed" transition in both directions. This caught a real bug before it ever reached CI: the "already said none, still none" case incorrectly reposted because the idempotency check compared against a hardcoded string instead of the full classification -- fixed and reverified all 8 scenarios pass. - Confirmed the baseline resolves correctly against the actual current repo state: main now has real tags (v1.0.0-beta.1, v1.0.0-beta.2), so `git describe --tags` resolves directly against origin/main rather than the PR branch; the .tabularium fallback remains for the no-tags-yet case this repo has already moved past. - Both workflow YAML files re-validated after every edit. Also added contributor-facing docs (README's "Contributing: PR Titles & Versioning" section, cross-referenced from CLAUDE.md) so future maintainers understand the convention without reading the workflow YAML. Standard verification: cargo build/test (82/82)/clippy/fmt all pass, no Cargo.lock drift, markdownlint clean across the whole repo, both workflow files parse as valid YAML. Rebased onto main after #5 merged (adds the pr-title job and release validate job this PR builds on) — no functional changes beyond the rebase itself, CHANGELOG merge conflict resolved by keeping both entries.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds two CI checks:
1. Release-version validation (
release.yml)A
validatejob now gates the build matrix on the pushed tag matching.tabularium'sversionfield (stripped of thevprefix):Ported from the
tabularis-elasticsearch-pluginsibling — the only Tabularis plugin repo with this check today. This isn't just a nice-to-have: the registry's own manifest schema (registry.tabularis.dev/manifest.schema.json?kind=driver) documents this as a hard rule on theversionfield — "REQUIRED — must match the release tag stripped of any 'v' prefix. The registry rejects ingests whose tag and manifest version disagree." This catches that mismatch at tag-push time instead of at registry-submission time.2. PR title convention (
ci.yml)A
pr-titlejob enforces Conventional Commits-style PR titles viaamannn/action-semantic-pull-request. Checked what precedent exists first:TabularisDB/tabularis(the main app) doesn't either — tags are pushed manually, no PR-title convention.Configured on plain
pull_request(notpull_request_target): the latter exists specifically to support PRs from forks with elevated permissions, which this repo doesn't need (all contributors so far have write access) — plainpull_requestavoids that elevated-permission surface entirely.Rebased onto current
main, which has moved on since this PR was opened (now at1.0.0-beta.2, with its own CI/release fixes already merged). This PR no longer carries any version-bump or CHANGELOG changes of its own — those are covered independently onmain.Test plan
cargo build/test --lib --bins(82/82)/clippy/fmt --checkall passjs-yaml)1.0.0-beta.2value (match — passes) and reasoned through the mismatch case (fails, as intended)vprefix matches convention used bytabularisand every tagged sibling plugin repogit diff --exit-code Cargo.lockclean (no incidental lockfile drift from the rebase)