From 7a67e2e3d6f851bbd9f1f8ba27da5c57fe8c0144 Mon Sep 17 00:00:00 2001 From: Patrick Dodgen Date: Tue, 23 Jun 2026 12:45:41 -0600 Subject: [PATCH] feat: add rt_mode to build-php-v1 orchestrator When rt_mode=true (caller triggers on rt-* refs), the orchestrator: - skips mathieudutour's dry-run + final tag-and-release jobs - adds a compute-rt-tag job that calls encodium/actions' _compute-rt-tag composite to push the rt rc tag and create the GH pre-release atomically up front - routes build at matrix-time to consume that tag Non-rt callers see no behavior change (rt_mode defaults to false). The shared output 'tag' now resolves from whichever path ran. Skipped jobs return empty-string outputs in GitHub Actions, so the '||' guard picks the active path's tag without further gating. Caller responsibilities (per DEVEX-1653): - gate the rt-build job on startsWith(github.ref, 'refs/heads/rt-') - grant 'permissions: contents: write' to that job - pass a token with contents:write via secrets.gh_token DEVEX-1653 --- .github/workflows/build-php-v1.yaml | 61 +++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-php-v1.yaml b/.github/workflows/build-php-v1.yaml index 96cf2b9..5f58270 100644 --- a/.github/workflows/build-php-v1.yaml +++ b/.github/workflows/build-php-v1.yaml @@ -18,6 +18,16 @@ on: required: false type: string default: "gha" + rt_mode: + description: | + Release-train mode. When true, skips mathieudutour and the trailing + GH Release step; the encodium/actions _compute-rt-tag composite + pushes the rt rc tag and creates the GH pre-release atomically up + front, and `build` uses that tag. Caller must trigger on rt-* refs + and grant `contents: write` to this job (see DEVEX-1653). + required: false + type: boolean + default: false secrets: packagist_username: required: true @@ -27,12 +37,17 @@ on: required: true outputs: tag: - description: "The released tag" - value: ${{ jobs.tag-and-release.outputs.tag }} + description: "The released tag (either the main vX.Y.Z tag or the rt rc tag)." + value: ${{ jobs.tag-and-release.outputs.tag || jobs.compute-rt-tag.outputs.tag }} jobs: + # ─── non-rt path ──────────────────────────────────────────────────────── + # Dry-run mathieudutour to compute what tag-and-release will emit; build + # uses that pre-computed value so the image tag and the eventual git tag + # agree. Skipped under rt_mode (the composite handles tagging atomically). calculate-tag: name: Calculate Build Tag + if: ${{ !inputs.rt_mode }} runs-on: ubuntu-latest outputs: tag: ${{ steps.dry_tag_version.outputs.new_tag }} @@ -48,9 +63,40 @@ jobs: fetch_all_tags: true dry_run: true + # ─── rt-mode path ─────────────────────────────────────────────────────── + # Single source of truth for rt rc tagging: the composite parses the + # rt- branch, computes the next iter, pushes the lightweight + # tag, and creates the GH pre-release. Build then consumes its output. + compute-rt-tag: + name: Compute RT Tag + if: ${{ inputs.rt_mode }} + runs-on: ubuntu-latest + permissions: + contents: write + outputs: + tag: ${{ steps.rt_tag.outputs.tag }} + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + fetch-tags: true + - id: rt_tag + uses: encodium/actions/.github/actions/_compute-rt-tag@main + with: + github_token: ${{ secrets.gh_token }} + build: name: Build ${{ matrix.image.tag_prefix }}image - needs: [calculate-tag] + # Either calculate-tag (non-rt) or compute-rt-tag (rt) will run; the + # other is skipped by its branch gate. `always()` keeps build alive + # despite the skipped need, and the explicit success check prevents a + # false start if the active tag job actually failed. + needs: [calculate-tag, compute-rt-tag] + if: | + always() && ( + needs.calculate-tag.result == 'success' || + needs.compute-rt-tag.result == 'success' + ) strategy: matrix: image: ${{ fromJSON(inputs.images) }} @@ -60,7 +106,9 @@ jobs: image_name: ${{ matrix.image.image_name }} dockerfile: ${{ matrix.image.dockerfile }} build_target: ${{ matrix.image.target }} - tag: ${{ matrix.image.tag_prefix }}${{ needs.calculate-tag.outputs.tag }} + # Skipped jobs return empty-string outputs, so `||` picks the active + # path's tag without further gating. + tag: ${{ matrix.image.tag_prefix }}${{ needs.calculate-tag.outputs.tag || needs.compute-rt-tag.outputs.tag }} extra_tag: ${{ matrix.image.extra_tag }} cache_type: ${{ inputs.cache_type }} secrets: @@ -68,8 +116,13 @@ jobs: packagist_password: ${{ secrets.packagist_password }} gh_token: ${{ secrets.gh_token }} + # ─── non-rt path (tail) ──────────────────────────────────────────────── + # Re-runs mathieudutour (this time not dry) to actually push the tag, + # then creates the GH pre-release. Skipped under rt_mode — the composite + # already did both up front. tag-and-release: name: Github Tag and Release + if: ${{ !inputs.rt_mode }} needs: [build] runs-on: ubuntu-latest outputs: