Skip to content

Modernize versioning: derive from build info, add CI + release workflow#4

Merged
lfstokols merged 3 commits into
mainfrom
claude/version-system-modernization
May 25, 2026
Merged

Modernize versioning: derive from build info, add CI + release workflow#4
lfstokols merged 3 commits into
mainfrom
claude/version-system-modernization

Conversation

@lfstokols
Copy link
Copy Markdown
Contributor

@lfstokols lfstokols commented May 25, 2026

Background

The library's printable version and its fetchable version had drifted apart by several minor releases. pdfer.Version() was a hardcoded string in pdfer.go, manually bumped via commit. Git tags were created manually. There was no CI tying them together.

Concretely, at the time of this PR:

Reference Version() returns
Tag v1.5.0 through v1.9.0 "1.3.0" (never bumped during five minor releases)
origin/main (untagged tip) "1.3.1"

A user running go get …@v1.9.0 and then pdfer.Version() would see "1.3.0". Module fetching itself worked correctly (Go uses tags), but the in-code version was misleading anyone who read it.

What this PR does

Eliminates the constant. Version() now reads the resolved module version via runtime/debug.ReadBuildInfo(). Returns the git tag a consumer pinned (e.g., "v1.10.0"), "(devel)" for local builds, "(unknown)" if build info is unavailable. Impossible to drift from the tag.

Adds CI (.github/workflows/ci.yml):

  • go vet + go test against Go 1.21, 1.22, 1.23 on every push to main and every PR
  • gofmt check (enabled now that style: apply gofmt to entire codebase #5 cleaned up pre-existing drift)
  • A version-guard job that greps for the regression pattern (return "v?N.N.N" in pdfer.go) and fails CI if anyone reintroduces a hardcoded literal

Adds release workflow (.github/workflows/release.yml):

  • Manual workflow_dispatch with version input (e.g., v1.10.0)
  • Validates semver format, refuses to overwrite existing tags
  • Runs the test suite, creates an annotated tag, pushes it, publishes a GitHub release with auto-generated notes

Slims the pre-push hook. Drops the version-bump enforcement (no longer meaningful). Keeps the local test runner for fast feedback.

Updates CONTRIBUTING.md. Removes the defunct "version bump requirement" section, documents the new release dispatch flow.

Test plan

  • go test ./... passes locally
  • go vet ./... passes locally
  • gofmt -l . is clean after rebase onto style: apply gofmt to entire codebase #5
  • Smoke test from a consumer module with replace directive: Version() returns the expected pseudo-version
  • Smoke test inside the pdfer module: Version() returns "(devel)"
  • Version-guard regex self-test: passes against new pdfer.go, would have rejected the old one
  • CI green on this PR (verify after open)
  • After merge: dispatch the Release workflow with v1.10.0 to validate the release path end-to-end

Known follow-ups (deliberately out of scope)

  • examples/kitchen_sink/main.go:628-634 has another hand-maintained version table (per-feature versions like "AcroForm v1.9.0"). Belongs in a CHANGELOG.md, not source — but unrelated to the library Version() issue.
  • First release post-merge should be v1.10.0 to stay monotonically ahead of v1.9.0.

🤖 Generated with Claude Code

lfstokols and others added 3 commits May 25, 2026 14:14
Replaces the hardcoded version string in pdfer.Version() with a lookup
against runtime/debug.ReadBuildInfo(). The function now returns whatever
version Go's module system resolved for this dependency — matching the
git tag a consumer pinned — instead of a constant that had drifted
several minor versions behind the actual tags (v1.9.0 was latest,
constant said "1.3.0"/"1.3.1").

Returns "(devel)" for local builds and "(unknown)" if build info is
unavailable. Honest about its source, impossible to drift.

No callers in the repo passed the old format-without-v-prefix
expectation; consumers comparing to a literal string will need to
update, but no internal test or example does.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The repo previously had no CI and no release automation. A local
pre-push hook enforced that pdfer.go's version string changed before
push to main, but the actual git tags were created manually and
drifted from the constant by several minor versions over time.

This adds:

- .github/workflows/ci.yml — runs go vet + go test on Go 1.21/1.22/1.23
  for every push to main and every PR. Includes a version-guard job
  that rejects reintroduction of a hardcoded version literal in
  pdfer.go (catches the exact regression pattern that caused the
  drift).

- .github/workflows/release.yml — manual workflow_dispatch with a
  version input (e.g., v1.10.0). Validates format, refuses to overwrite
  existing tags, runs the test suite, creates an annotated tag, pushes
  it, and publishes a GitHub release with auto-generated notes.

- pre-push hook — drops the version-bump enforcement (no longer
  meaningful now that Version() derives at runtime). Keeps the test
  runner for fast local feedback.

- CONTRIBUTING.md — documents the new release process and removes the
  defunct "version bump requirement" section.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Originally omitted from this PR because the repo had pre-existing
gofmt drift across 16 files. Rebased onto main (8b00bd1) which
includes the fmt cleanup, so the check can now be enabled.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@lfstokols lfstokols force-pushed the claude/version-system-modernization branch from b1833ec to abe8a3f Compare May 25, 2026 18:15
@lfstokols lfstokols merged commit da4a0b1 into main May 25, 2026
5 checks passed
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