Develop Staging Beta Release #392
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
| name: Develop Staging Beta Release | |
| on: | |
| workflow_run: | |
| workflows: ["Cloud CF Deploy"] | |
| types: [completed] | |
| workflow_dispatch: | |
| inputs: | |
| target_sha: | |
| description: Develop commit SHA to release. Defaults to the workflow ref SHA. | |
| required: false | |
| type: string | |
| permissions: | |
| actions: write | |
| checks: read | |
| contents: read | |
| concurrency: | |
| group: develop-staging-beta-${{ github.event.workflow_run.head_sha || inputs.target_sha || github.sha }} | |
| cancel-in-progress: false | |
| jobs: | |
| gate-and-release: | |
| name: Gate Develop and Dispatch Beta | |
| runs-on: ubuntu-latest | |
| if: >- | |
| ${{ | |
| github.event_name == 'workflow_dispatch' || | |
| ( | |
| github.event.workflow_run.conclusion == 'success' && | |
| github.event.workflow_run.head_branch == 'develop' && | |
| github.event.workflow_run.event == 'push' && | |
| github.event.workflow_run.head_repository.full_name == github.repository | |
| ) | |
| }} | |
| steps: | |
| - name: Resolve target commit | |
| id: target | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| WORKFLOW_RUN_SHA: ${{ github.event.workflow_run.head_sha || '' }} | |
| INPUT_SHA: ${{ inputs.target_sha || '' }} | |
| run: | | |
| if [ "$EVENT_NAME" = "workflow_run" ]; then | |
| TARGET_SHA="$WORKFLOW_RUN_SHA" | |
| elif [ -n "$INPUT_SHA" ]; then | |
| TARGET_SHA="$INPUT_SHA" | |
| else | |
| TARGET_SHA="${GITHUB_SHA}" | |
| fi | |
| if [ -z "$TARGET_SHA" ]; then | |
| echo "::error::Unable to resolve target SHA." | |
| exit 1 | |
| fi | |
| echo "sha=$TARGET_SHA" >> "$GITHUB_OUTPUT" | |
| echo "Develop staging gate target: $TARGET_SHA" >> "$GITHUB_STEP_SUMMARY" | |
| - name: Ensure target is current develop | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TARGET_SHA: ${{ steps.target.outputs.sha }} | |
| run: | | |
| DEVELOP_SHA="$(gh api "repos/${GITHUB_REPOSITORY}/git/ref/heads/develop" --jq '.object.sha')" | |
| echo "develop HEAD: ${DEVELOP_SHA}" >> "$GITHUB_STEP_SUMMARY" | |
| if [ "$TARGET_SHA" != "$DEVELOP_SHA" ]; then | |
| echo "Target ${TARGET_SHA} is no longer develop HEAD (${DEVELOP_SHA}); a newer develop run will handle staging beta." >> "$GITHUB_STEP_SUMMARY" | |
| echo "superseded=true" >> "$GITHUB_ENV" | |
| fi | |
| - name: Wait for all checks on target commit | |
| if: env.superseded != 'true' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TARGET_SHA: ${{ steps.target.outputs.sha }} | |
| TIMEOUT_SECONDS: ${{ vars.DEVELOP_STAGING_GATE_TIMEOUT_SECONDS || '3600' }} | |
| run: | | |
| set -euo pipefail | |
| deadline=$((SECONDS + TIMEOUT_SECONDS)) | |
| ignored_names_json='["Develop Staging Beta Release","NPM Release","Release Orchestrator"]' | |
| while [ "$SECONDS" -lt "$deadline" ]; do | |
| DEVELOP_SHA="$(gh api "repos/${GITHUB_REPOSITORY}/git/ref/heads/develop" --jq '.object.sha')" | |
| if [ "$TARGET_SHA" != "$DEVELOP_SHA" ]; then | |
| echo "Target ${TARGET_SHA} is no longer develop HEAD (${DEVELOP_SHA}); a newer develop run will handle staging beta." >> "$GITHUB_STEP_SUMMARY" | |
| exit 0 | |
| fi | |
| gh api \ | |
| "repos/${GITHUB_REPOSITORY}/actions/runs?head_sha=${TARGET_SHA}&per_page=100" \ | |
| > /tmp/workflow-runs.json | |
| set +e | |
| IGNORED_NAMES_JSON="$ignored_names_json" node <<'NODE' | |
| const fs = require("node:fs"); | |
| const payload = JSON.parse(fs.readFileSync("/tmp/workflow-runs.json", "utf8")); | |
| const runs = payload.workflow_runs ?? []; | |
| const ignoredNames = new Set(JSON.parse(process.env.IGNORED_NAMES_JSON)); | |
| const currentRunId = Number(process.env.GITHUB_RUN_ID); | |
| const successfulConclusions = new Set(["success", "neutral", "skipped"]); | |
| const relevant = runs.filter((run) => { | |
| if (Number(run.id) === currentRunId) return false; | |
| if (ignoredNames.has(run.name)) return false; | |
| return run.head_sha === process.env.TARGET_SHA; | |
| }); | |
| const failed = relevant.filter( | |
| (run) => run.status === "completed" && !successfulConclusions.has(run.conclusion), | |
| ); | |
| const pending = relevant.filter((run) => run.status !== "completed"); | |
| console.log(`Observed ${relevant.length} workflow run(s) for ${process.env.TARGET_SHA}.`); | |
| if (pending.length > 0) { | |
| console.log(`Pending: ${pending.map((run) => `${run.name}/${run.status}`).join(", ")}`); | |
| } | |
| if (failed.length > 0) { | |
| console.error( | |
| `Failed: ${failed.map((run) => `${run.name}/${run.conclusion}`).join(", ")}`, | |
| ); | |
| process.exit(2); | |
| } | |
| if (pending.length > 0) process.exit(1); | |
| if (relevant.length === 0) { | |
| console.log("No completed workflow runs are visible yet."); | |
| process.exit(1); | |
| } | |
| NODE | |
| status=$? | |
| set -e | |
| if [ "$status" -eq 0 ]; then | |
| echo "All observed workflows are green for ${TARGET_SHA}." >> "$GITHUB_STEP_SUMMARY" | |
| exit 0 | |
| fi | |
| if [ "$status" -eq 2 ]; then | |
| DEVELOP_SHA="$(gh api "repos/${GITHUB_REPOSITORY}/git/ref/heads/develop" --jq '.object.sha')" | |
| if [ "$TARGET_SHA" != "$DEVELOP_SHA" ]; then | |
| echo "Target ${TARGET_SHA} was superseded by ${DEVELOP_SHA}; ignoring cancelled checks from the old head." >> "$GITHUB_STEP_SUMMARY" | |
| exit 0 | |
| fi | |
| echo "::error::At least one workflow failed for ${TARGET_SHA}; beta release blocked." | |
| exit 1 | |
| fi | |
| sleep 30 | |
| done | |
| echo "::error::Timed out waiting for all workflows to finish for ${TARGET_SHA}." | |
| exit 1 | |
| - name: Dispatch beta release | |
| if: env.superseded != 'true' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| AUTO_BETA_RELEASE_FROM_DEVELOP: ${{ vars.AUTO_BETA_RELEASE_FROM_DEVELOP || 'true' }} | |
| TARGET_SHA: ${{ steps.target.outputs.sha }} | |
| run: | | |
| if [ "$AUTO_BETA_RELEASE_FROM_DEVELOP" != "true" ]; then | |
| echo "AUTO_BETA_RELEASE_FROM_DEVELOP is not true; beta release dispatch skipped." >> "$GITHUB_STEP_SUMMARY" | |
| exit 0 | |
| fi | |
| gh workflow run release.yaml --repo "$GITHUB_REPOSITORY" --ref develop -f release_type=beta | |
| echo "Dispatched release.yaml beta workflow for develop after ${TARGET_SHA} passed staging." >> "$GITHUB_STEP_SUMMARY" |