on: pull_request: push: branches: - master name: Internal Tests permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || format('sha-{0}', github.sha) }} cancel-in-progress: true jobs: run-tests: # Skip if this is an external contribution. GitHub secrets will be empty, so the step would fail anyway. if: ${{ github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork }} runs-on: ubuntu-latest env: TARGET_OWNER: clockworklabs TARGET_REPO: SpacetimeDBPrivate steps: - id: dispatch name: Trigger tests uses: actions/github-script@v7 with: github-token: ${{ secrets.SPACETIMEDB_PRIVATE_TOKEN }} script: | const workflowId = 'ci.yml'; const targetRef = 'master'; const targetOwner = process.env.TARGET_OWNER; const targetRepo = process.env.TARGET_REPO; // Use the ref for pull requests because the head sha is brittle (github does some extra dance where it merges in master). const publicRef = (context.eventName === 'pull_request') ? context.payload.pull_request.head.ref : context.sha; const preDispatch = new Date().toISOString(); console.log("context.eventName =", context.eventName); console.log("context.ref =", context.ref); console.log("context.sha =", context.sha); console.log("Dispatch workflow with publicRef =", publicRef); // Dispatch the workflow in the target repository await github.rest.actions.createWorkflowDispatch({ owner: targetOwner, repo: targetRepo, workflow_id: workflowId, ref: targetRef, inputs: { public_ref: publicRef } }); const sleep = (ms) => new Promise(r => setTimeout(r, ms)); // Find the dispatched run by name let runId = null; for (let attempt = 0; attempt < 20 && !runId; attempt++) { // up to ~10 minutes to locate the run await sleep(5000); const runsResp = await github.rest.actions.listWorkflowRuns({ owner: targetOwner, repo: targetRepo, workflow_id: workflowId, event: 'workflow_dispatch', branch: targetRef, per_page: 50, }); const expectedName = `CI [public_ref=${publicRef}]`; const candidates = runsResp.data.workflow_runs .filter(r => r.name === expectedName && new Date(r.created_at) >= new Date(preDispatch)) .sort((a, b) => new Date(b.created_at) - new Date(a.created_at)); if (candidates.length > 0) { runId = candidates[0].id; break; } } if (!runId) { core.setFailed('Failed to locate dispatched run in the private repository.'); return; } // Provide direct link and context prior to waiting const runUrl = `https://github.com/${targetOwner}/${targetRepo}/actions/runs/${runId}`; core.info(`View run: ${runUrl}`); core.setOutput('run_id', String(runId)); core.setOutput('run_url', runUrl); - name: Wait for Internal Tests to complete uses: actions/github-script@v7 with: github-token: ${{ secrets.SPACETIMEDB_PRIVATE_TOKEN }} script: | const targetOwner = process.env.TARGET_OWNER; const targetRepo = process.env.TARGET_REPO; const runId = Number(`${{ steps.dispatch.outputs.run_id }}`); const runUrl = `${{ steps.dispatch.outputs.run_url }}`; const sleep = (ms) => new Promise(r => setTimeout(r, ms)); core.info(`Waiting for workflow result... ${runUrl}`); let conclusion = null; for (let attempt = 0; attempt < 240; attempt++) { // up to ~2 hours const runResp = await github.rest.actions.getWorkflowRun({ owner: targetOwner, repo: targetRepo, run_id: runId }); const { status, conclusion: c } = runResp.data; if (status === 'completed') { conclusion = c || 'success'; break; } await sleep(30000); } if (!conclusion) { core.setFailed('Timed out waiting for private workflow to complete.'); return; } core.info(`Private workflow conclusion: ${conclusion}`); if (conclusion !== 'success') { core.setFailed(`Private workflow failed with conclusion: ${conclusion}`); } - name: Cancel invoked run if workflow cancelled if: ${{ cancelled() }} uses: actions/github-script@v7 with: github-token: ${{ secrets.SPACETIMEDB_PRIVATE_TOKEN }} script: | const targetOwner = process.env.TARGET_OWNER; const targetRepo = process.env.TARGET_REPO; const runId = Number(`${{ steps.dispatch.outputs.run_id }}`); if (!runId) { core.warning('No run_id available to cancel.'); return; } core.info(`Cancelling private workflow run ${runId} in ${targetOwner}/${targetRepo}...`); await github.rest.actions.cancelWorkflowRun({ owner: targetOwner, repo: targetRepo, run_id: runId, }); core.info('Cancellation requested.');