Skip to content

Commit 9bc6f17

Browse files
committed
When all git-artifacts runs are done for a snapshot, upload it
The `tag-git` workflow can be used to handle Git for Windows' snapshots via the `snapshot` Boolean that is part of its inputs. The idea is that once that workflow has completed, the `git-artifacts` workflow runs are triggered automatically via GitForWindowsHelper, one per supported CPU architecture. Now this commit introduces the logic to trigger the `upload-snapshot` workflow once all of those `git-artifacts` runs completed successfully. Naturally, we have to be careful to do this only when the snapshot has not yet been uploaded, and only when the snapshot is built from a commit that is actually on git-for-windows/git's default branch. Signed-off-by: Johannes Schindelin <[email protected]>
1 parent e4f4be9 commit 9bc6f17

File tree

1 file changed

+114
-0
lines changed

1 file changed

+114
-0
lines changed

GitForWindowsHelper/cascading-runs.js

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,120 @@ const cascadingRuns = async (context, req) => {
133133

134134
return comment
135135
}
136+
if (checkRunOwner === 'git-for-windows'
137+
&& checkRunRepo === 'git'
138+
&& name.startsWith('git-artifacts-')) {
139+
const output = req.body.check_run.output
140+
const match = output.summary.match(
141+
/Build Git (\S+) artifacts from commit (\S+) \(tag-git run #(\d+)\)/
142+
)
143+
if (!match) throw new Error(
144+
`Could not parse 'summary' attribute of check-run ${req.body.check_run.id}: ${output.summary}`
145+
)
146+
const [, ver, commit, tagGitWorkflowRunID] = match
147+
const snapshotTag = `prerelease-${ver.replace(/^v/, '')}`
148+
149+
// First, verify that the snapshot has not been uploaded yet
150+
const gitSnapshotsToken = await getToken(context, checkRunOwner, 'git-snapshots')
151+
const githubApiRequest = require('./github-api-request')
152+
try {
153+
const releasePath = `${checkRunOwner}/git-snapshots/releases/tags/${snapshotTag}`
154+
await githubApiRequest(
155+
context,
156+
gitSnapshotsToken,
157+
'GET',
158+
`/repos/${releasePath}`,
159+
)
160+
return `Ignoring ${name} check-run because the snapshot for ${commit} was already uploaded`
161+
+ ` to https://github.com/${releasePath}`
162+
} catch(e) {
163+
if (e?.statusCode !== 404) throw e
164+
// The snapshot does not exist yet
165+
}
166+
167+
// Next, check that the commit is on the `main` branch
168+
const gitToken = await getToken(context, checkRunOwner, checkRunRepo)
169+
const { behind_by } = await githubApiRequest(
170+
context,
171+
gitToken,
172+
'GET',
173+
`/repos/${checkRunOwner}/${checkRunRepo}/compare/HEAD...${commit}`,
174+
)
175+
if (behind_by > 0) {
176+
return `Ignoring ${name} check-run because its corresponding commit ${commit} is not on the main branch`
177+
}
178+
179+
const workFlowRunIDs = {}
180+
const { listCheckRunsForCommit, queueCheckRun } = require('./check-runs')
181+
for (const architecture of ['x86_64', 'i686', 'aarch64']) {
182+
const workflowName = `git-artifacts-${architecture}`
183+
const runs = name === workflowName ? [req.body.check_run] : await listCheckRunsForCommit(
184+
context,
185+
gitToken,
186+
checkRunOwner,
187+
checkRunRepo,
188+
commit,
189+
workflowName
190+
)
191+
const needle =
192+
`Build Git ${ver} artifacts from commit ${commit} (tag-git run #${tagGitWorkflowRunID})`
193+
const latest = runs
194+
.filter(run => run.output.summary === needle)
195+
.sort((a, b) => a.id - b.id)
196+
.pop()
197+
if (latest) {
198+
if (latest.status !== 'completed') {
199+
return `The '${workflowName}' run at ${latest.html_url} did not complete yet.`
200+
}
201+
if (latest.conclusion !== 'success') {
202+
throw new Error(`The '${workflowName}' run at ${latest.html_url} did not succeed.`)
203+
}
204+
205+
const match = latest.output.text.match(
206+
/For details, see \[this run\]\(https:\/\/github.com\/([^/]+)\/([^/]+)\/actions\/runs\/(\d+)\)/
207+
)
208+
if (!match) throw new Error(`Unhandled 'text' attribute of git-artifacts run ${latest.id}: ${latest.url}`)
209+
const owner = match[1]
210+
const repo = match[2]
211+
workFlowRunIDs[architecture] = match[3]
212+
if (owner !== 'git-for-windows' || repo !== 'git-for-windows-automation') {
213+
throw new Error(`Unexpected repository ${owner}/${repo} for git-artifacts run ${latest.id}: ${latest.url}`)
214+
}
215+
} else {
216+
return `Won't trigger 'upload-snapshot' in reaction to ${name} because the '${workflowName}' run does not exist.`
217+
}
218+
}
219+
220+
const checkRunTitle = `Upload snapshot ${snapshotTag}`
221+
await queueCheckRun(
222+
context,
223+
gitToken,
224+
'git-for-windows',
225+
'git',
226+
commit,
227+
'upload-snapshot',
228+
checkRunTitle,
229+
checkRunTitle
230+
)
231+
232+
const gitForWindowsAutomationToken =
233+
await getToken(context, checkRunOwner, 'git-for-windows-automation')
234+
const triggerWorkflowDispatch = require('./trigger-workflow-dispatch')
235+
const answer = await triggerWorkflowDispatch(
236+
context,
237+
gitForWindowsAutomationToken,
238+
'git-for-windows',
239+
'git-for-windows-automation',
240+
'upload-snapshot.yml',
241+
'main', {
242+
git_artifacts_x86_64_workflow_run_id: workFlowRunIDs['x86_64'],
243+
git_artifacts_i686_workflow_run_id: workFlowRunIDs['i686'],
244+
git_artifacts_aarch64_workflow_run_id: workFlowRunIDs['aarch64'],
245+
}
246+
)
247+
248+
return `The 'upload-snapshot' workflow run was started at ${answer.html_url}`
249+
}
136250
return `Not a cascading run: ${name}; Doing nothing.`
137251
}
138252
return `Unhandled action: ${action}`

0 commit comments

Comments
 (0)