-
Notifications
You must be signed in to change notification settings - Fork 1k
161 lines (142 loc) · 6 KB
/
internal-tests.yml
File metadata and controls
161 lines (142 loc) · 6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
name: Internal Tests
on:
pull_request:
push:
branches:
- master
merge_group:
workflow_dispatch:
run-name: Internal Tests [ref=${{ github.ref }}]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: read
jobs:
internal-tests:
name: Internal Tests
# Skip if not a PR or a push to master
# 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_name == 'push' && github.ref == 'refs/heads/master'))
&& (github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork) }}
runs-on: ubuntu-latest
env:
TARGET_OWNER: clockworklabs
TARGET_REPO: SpacetimeDBPrivate
steps:
# Skip the private dispatch entirely when only `docs/` is touched. The job
# itself still completes successfully so required-status-check gating is
# satisfied without spending private-runner time on a docs-only change.
- name: Detect non-docs changes
id: filter
uses: dorny/paths-filter@v3
with:
filters: |
non_docs:
- '!docs/**'
- id: dispatch
name: Trigger tests
if: steps.filter.outputs.non_docs == 'true'
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 publicPrNumber = context.payload.pull_request?.number;
const preDispatch = new Date().toISOString();
const inputs = { public_ref: publicRef };
if (publicPrNumber) {
inputs.public_pr_number = String(publicPrNumber);
}
// Dispatch the workflow in the target repository
await github.rest.actions.createWorkflowDispatch({
owner: targetOwner,
repo: targetRepo,
workflow_id: workflowId,
ref: targetRef,
inputs,
});
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;
}
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
if: steps.filter.outputs.non_docs == 'true'
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;
}
if (conclusion !== 'success') {
core.setFailed(`Private workflow failed with conclusion: ${conclusion}`);
}
- name: Cancel invoked run if workflow cancelled
if: ${{ cancelled() && steps.dispatch.outputs.run_id }}
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) return;
await github.rest.actions.cancelWorkflowRun({
owner: targetOwner,
repo: targetRepo,
run_id: runId,
});