From 918adb57494bab0660dc9fc4682ff89f17ac5f84 Mon Sep 17 00:00:00 2001 From: Andres Contreras Date: Wed, 30 Sep 2026 21:40:47 -0700 Subject: [PATCH] fix(release): wait for the tag on Composer's metadata endpoint, not the CDN-cached web API The publication job read packagist.org/packages/fireflyframework/larafly.json, which the CDN serves with s-maxage=43200. After v26.09.11 was indexed, Composer installed it from repo.packagist.org/p2 within a minute, but the job saw the twelve-hour-old document for its whole five-minute window and failed twice. It now reads the p2 metadata Composer uses, for up to ten minutes, and ReleaseWorkflowTest pins the endpoint. --- .github/workflows/release.yml | 10 +++++++--- CHANGELOG.md | 6 ++++++ docs/publishing.md | 5 ++++- tests/ReleaseWorkflowTest.php | 6 ++++++ 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7feccf26..9635a8b5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,11 +50,15 @@ jobs: coverage: none tools: composer:v2 - run: composer install --no-interaction --prefer-dist + # Composer's own metadata endpoint, which Packagist refreshes when the webhook indexes a tag. The web API + # (packagist.org/packages/.json) is cached by the CDN for twelve hours (s-maxage=43200), so it can + # keep answering without the new tag long after Composer already installs it. - name: Wait for Packagist to index this exact tag run: | - for attempt in $(seq 1 20); do - if curl --fail --silent --show-error https://packagist.org/packages/fireflyframework/larafly.json -o "$RUNNER_TEMP/larafly.json" && - php -r '$p = json_decode(file_get_contents($argv[1]), true); exit(($p["package"]["versions"][getenv("RELEASE_TAG")]["source"]["reference"] ?? null) === getenv("RELEASE_SHA") ? 0 : 1);' "$RUNNER_TEMP/larafly.json"; then + # shellcheck disable=SC2016 # the PHP program is single-quoted on purpose + for _ in $(seq 1 40); do + if curl --fail --silent --show-error https://repo.packagist.org/p2/fireflyframework/larafly.json -o "$RUNNER_TEMP/larafly.json" && + php -r '$p = json_decode(file_get_contents($argv[1]), true); foreach ($p["packages"]["fireflyframework/larafly"] ?? [] as $v) { if (($v["version"] ?? null) === getenv("RELEASE_TAG")) { exit(($v["source"]["reference"] ?? null) === getenv("RELEASE_SHA") ? 0 : 1); } } exit(1);' "$RUNNER_TEMP/larafly.json"; then exit 0 fi sleep 15 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f39a146..1b5b0a9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to LaraFly are documented here. This project uses CalVer (`Y ## [Unreleased] +### Fixed + +- **Release workflow:** the publication job waits for the tag on Composer's metadata endpoint + (`repo.packagist.org/p2`), which Packagist refreshes when it indexes a tag. It used to read the web API, which + the CDN caches for twelve hours, so 26.09.11 was installable from Packagist while its GitHub release waited. + ## [26.09.11] - 2026-09-30 ### Fixed diff --git a/docs/publishing.md b/docs/publishing.md index 74fbb0cf..580b84f6 100644 --- a/docs/publishing.md +++ b/docs/publishing.md @@ -67,13 +67,16 @@ CI runs these package checks on PHP 8.3, 8.4 and 8.5 for PRs to `main` and pushe `https://github.com/fireflyframework/fireflyframework-php` and enable the repository webhook. This is a one-time publisher action; subsequent releases use tags from this same repository. 5. Push the new release tag. **Release (single package)** validates the tagged distribution on PHP - 8.3, 8.4 and 8.5, waits for Packagist to index that exact commit, then installs it in a fresh stable + 8.3, 8.4 and 8.5, waits for Packagist's Composer metadata (`repo.packagist.org/p2/…`) to list that exact + commit for the tag, then installs it in a fresh stable consumer without custom repositories and exercises the bundled installer. Only after those checks pass does its final job build both books and create the GitHub release from the changelog with the English and Spanish PDF/EPUB files, checksums and source commit record. That job uses the repository's built-in `GITHUB_TOKEN` with `contents: write`; validation jobs remain read-only. 6. If indexing times out, repair the Packagist webhook or trigger an update on the package page, then rerun the failed job. Do not move the tag or create a GitHub release to bypass the public install gate. + Releases up to 26.09.11 waited on the web API (`packagist.org/packages/…json`), which the CDN caches for + twelve hours; for those tags a rerun succeeds once that cache has expired. To repeat the public install check locally: diff --git a/tests/ReleaseWorkflowTest.php b/tests/ReleaseWorkflowTest.php index 06ee108b..e5438eef 100644 --- a/tests/ReleaseWorkflowTest.php +++ b/tests/ReleaseWorkflowTest.php @@ -106,3 +106,9 @@ function releaseWorkflowYaml(): array } expect($verifyPosition)->toBeLessThan($releasePosition); }); + +it('waits for the tag on Composer\'s metadata endpoint, not on the CDN-cached web API', function () { + $blob = (string) file_get_contents(dirname(__DIR__).'/.github/workflows/release.yml'); + expect($blob)->toContain('https://repo.packagist.org/p2/fireflyframework/larafly.json') + ->not->toContain('https://packagist.org/packages/fireflyframework/larafly.json'); +});