From 21f9293b6303b9ce2c98afa52f336e33629a4166 Mon Sep 17 00:00:00 2001 From: Doglightning <170844007+Doglightning@users.noreply.github.com> Date: Thu, 16 Oct 2025 12:00:29 +0000 Subject: [PATCH] refactor(monorepo): move workflow to correct location (#251) # Auto Deploy Preview Workflow Closes: WORLD-XXX ## Overview This PR adds a new GitHub workflow for automatically deploying preview environments. The workflow is designed to be called from other workflows and handles the coordination with World Forge for deployments. ## Brief Changelog - Added new reusable workflow `auto_deploy.yml` that can be triggered via `workflow_call` - Implemented a signal job that emits a repository dispatch event to trigger auto-deployment - Added status monitoring that waits for World Forge deployment statuses - Implemented timeout handling with both initial (2 min) and hard (45 min) deadlines - Added failure detection and reporting for deployment issues ## Testing and Verifying This change can be verified by triggering the workflow from another workflow and confirming that it properly signals the auto-deploy event and correctly monitors the deployment statuses. --- .github/workflows/auto_deploy.yml | 67 +++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 .github/workflows/auto_deploy.yml diff --git a/.github/workflows/auto_deploy.yml b/.github/workflows/auto_deploy.yml new file mode 100644 index 00000000..a8dafe05 --- /dev/null +++ b/.github/workflows/auto_deploy.yml @@ -0,0 +1,67 @@ +name: Auto Deploy Preview + +on: + workflow_call: + inputs: + base: + type: string + required: true + head: + type: string + required: true + +permissions: + contents: write + statuses: read + +jobs: + signal: + runs-on: ubuntu-latest + steps: + - name: Emit repository_dispatch to App + uses: actions/github-script@v7 + with: + script: | + await github.rest.repos.createDispatchEvent({ + owner: context.repo.owner, + repo: context.repo.repo, + event_type: "auto-deploy", + client_payload: { base: inputs.base, head: inputs.head } + }) + - name: Wait for World Forge status + uses: actions/github-script@v7 + with: + script: | + const owner = context.repo.owner, repo = context.repo.repo, ref = inputs.head; + const prefix = "world-forge/auto-deploy"; + const initDeadline = Date.now() + 2*60*1000; + const hardDeadline = Date.now() + 45*60*1000; + const sleep = (ms) => new Promise(r => setTimeout(r, ms)); + async function allStatuses() { + const { data } = await github.rest.repos.getCombinedStatusForRef({ owner, repo, ref }); + return data.statuses || []; + } + let expected = null; + while (Date.now() < initDeadline) { + const statuses = await allStatuses(); + const aggFail = statuses.find(s => s.context === prefix && (s.state === "failure" || s.state === "error")); + if (aggFail) { core.setFailed(aggFail.description || "Auto-deploy aggregate failed"); return; } + const aggs = statuses.filter(s => s.context === prefix && s.state === "pending"); + for (const a of aggs) { + const n = parseInt(a.description || "0", 10); + if (!Number.isNaN(n) && n > 0) { expected = n; break; } + } + if (expected) break; + await sleep(5000); + } + if (!expected) { core.setFailed("Auto-deploy did not publish expected deployment count."); return; } + while (Date.now() < hardDeadline) { + const statuses = await allStatuses(); + const perProject = statuses.filter(s => s.context.startsWith(prefix + "/")); + const success = perProject.filter(s => s.state === "success").length; + const failed = perProject.filter(s => s.state === "failure" || s.state === "error").length; + if (success + failed >= expected) { if (failed > 0) core.setFailed(`Deploy failures: ${failed}/${expected}`); return; } + await sleep(10000); + } + core.setFailed("Timed out waiting for auto-deploy results."); + \ No newline at end of file