Skip to content

ci: make release version bump idempotent#43

Merged
mogita merged 1 commit into
masterfrom
fix/release-version-bump-idempotent
Jun 18, 2026
Merged

ci: make release version bump idempotent#43
mogita merged 1 commit into
masterfrom
fix/release-version-bump-idempotent

Conversation

@mogita

@mogita mogita commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Why the auto-release flow is stuck

The release workflow has failed on the last 3 PR merges (#39, #40, #42), all with the same fatal error at scripts/release/bump_version.php:152:

Uncaught ReleaseScriptException: Could not update version in composer.json

Two problems stacked together:

  1. State drift (trigger). PR feat: [CHA-2956] connection pooling: getstream-php #39 included a manual version bump inside the feature branch (composer.json v7.2.0 -> v7.3.0). So the declared version (7.3.0) is now ahead of the latest git tag (v7.2.0), and no v7.3.0 tag/release exists. The script computes the next version from the latest tag, so every feat/fix merge recomputes v7.2.0 + minor = 7.3.0, which is exactly what composer.json already says.

  2. Code brittleness (why drift = permanent deadlock). updateComposerVersion() treated a no-op regex replace ($updated === $raw) as fatal. When the file already holds the target version the replace changes nothing, so the script aborts before tagging/publishing. The sibling updateConstantVersion() never had this flaw.

The fix

Count actual replacements instead of comparing strings: throw only when the version field is genuinely absent (count === 0), and treat an already-correct value as success (idempotent). Mirrors updateConstantVersion().

Verification (local, PHP 8.5)

  • Reproduced the exact fatal error against the current repo state before the change.
  • After the change: a simulated feat merge exits 0 with correct outputs and leaves composer.json/Constant.php byte-identical when already at target.
  • Missing version field still throws (count === 0).

Recovery after merging this

This PR is titled ci: on purpose so merging it does not auto-trigger a release (the stale tag would otherwise drive the version).

After merge, reconcile the tag/composer drift and ship the pending v7.3.0 via the manual path (works because use_current_version=true skips the version bump entirely):

gh workflow run release.yml -f use_current_version=true -f version_bump=minor

That tags v7.3.0 at master, creates the GitHub release, and updates Packagist. From then on the flow is monotonic again (tag v7.3.0 -> next feat 7.4.0, fix 7.3.1).

Process note: avoid hand-editing the version field in composer.json/Constant.php inside feature PRs; the release automation owns those fields.

updateComposerVersion() treated a no-op regex replace as fatal, so when
composer.json already held the target version the release script aborted
before tagging/publishing. This deadlocked the auto-release flow whenever
the declared version drifted ahead of the latest git tag (e.g. a manual
version bump merged inside a feature PR, as in #39).

Count actual replacements instead: throw only when the version field is
genuinely absent, and treat an already-correct value as success. This
mirrors the existing behaviour of updateConstantVersion().
@mogita mogita merged commit 4980064 into master Jun 18, 2026
7 checks passed
@mogita mogita deleted the fix/release-version-bump-idempotent branch June 18, 2026 11:26
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