Skip to content

Commit 5597f02

Browse files
committed
Handle snapshot builds/uploads on pushes to git-for-windows/git
When a new commit is pushed to Git for Windows' default branch, we either need to trigger a new snapshot build (namely when the `tag-git` workflow has not yet run on that commit) or upload the snapshot (this is the case when a new Git for Windows has been branch-deployed in a PR and the PR is now "merged" by pushing its tip to `main`). Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 2c788f9 commit 5597f02

File tree

2 files changed

+193
-2
lines changed

2 files changed

+193
-2
lines changed

GitForWindowsHelper/cascading-runs.js

Lines changed: 189 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,195 @@ const cascadingRuns = async (context, req) => {
252252
return `Unhandled action: ${action}`
253253
}
254254

255+
const handlePush = async (context, req) => {
256+
const pushOwner = req.body.repository.owner.login
257+
const pushRepo = req.body.repository.name
258+
const ref = req.body.ref
259+
const commit = req.body.after
260+
261+
if (pushOwner !== 'git-for-windows' || pushRepo !== 'git') {
262+
throw new Error(`Refusing to handle push to ${pushOwner}/${pushRepo}`)
263+
}
264+
265+
if (ref !== 'refs/heads/main') return `Ignoring push to ${ref}`
266+
267+
// See whether there was are already a `tag-git` check-run for this commit
268+
const { listCheckRunsForCommit, queueCheckRun, updateCheckRun } = require('./check-runs')
269+
const gitToken = await getToken(context, pushOwner, pushRepo)
270+
const runs = await listCheckRunsForCommit(
271+
context,
272+
gitToken,
273+
pushOwner,
274+
pushRepo,
275+
commit,
276+
'tag-git'
277+
)
278+
279+
const latest = runs
280+
.sort((a, b) => a.id - b.id)
281+
.pop()
282+
283+
if (latest && latest.status !== 'completed') throw new Error(`The 'tag-git' run at ${latest.html_url} did not complete yet before ${commit} was pushed to ${ref}!`)
284+
285+
const gitForWindowsAutomationToken =
286+
await getToken(context, pushOwner, 'git-for-windows-automation')
287+
const triggerWorkflowDispatch = require('./trigger-workflow-dispatch')
288+
if (!latest) {
289+
// There is no `tag-git` workflow run; Trigger it to build a new snapshot
290+
const tagGitCheckRunTitle = `Tag snapshot Git @${commit}`
291+
const tagGitCheckRunId = await queueCheckRun(
292+
context,
293+
gitForWindowsAutomationToken,
294+
pushOwner,
295+
pushRepo,
296+
commit,
297+
'tag-git',
298+
tagGitCheckRunTitle,
299+
tagGitCheckRunTitle
300+
)
301+
302+
try {
303+
const answer = await triggerWorkflowDispatch(
304+
context,
305+
gitForWindowsAutomationToken,
306+
pushOwner,
307+
'git-for-windows-automation',
308+
'tag-git.yml',
309+
'main', {
310+
rev: commit,
311+
owner: pushOwner,
312+
repo: pushRepo,
313+
snapshot: 'true'
314+
}
315+
)
316+
return `The 'tag-git' workflow run was started at ${answer.html_url}`
317+
} catch (e) {
318+
await updateCheckRun(
319+
context,
320+
gitForWindowsAutomationToken,
321+
pushOwner,
322+
pushRepo,
323+
tagGitCheckRunId, {
324+
status: 'completed',
325+
conclusion: 'failure',
326+
output: {
327+
title: tagGitCheckRunTitle,
328+
summary: tagGitCheckRunTitle,
329+
text: e.message || JSON.stringify(e, null, 2)
330+
}
331+
}
332+
)
333+
throw e
334+
}
335+
}
336+
337+
if (latest.conclusion !== 'success') throw new Error(
338+
`The 'tag-git' run at ${latest.html_url} did not succeed (conclusion = ${latest.conclusion}).`
339+
)
340+
341+
// There is already a `tag-git` workflow run; Is there already an `upload-snapshot` run?
342+
const latestUploadSnapshotRun = (await listCheckRunsForCommit(
343+
context,
344+
gitToken,
345+
pushOwner,
346+
pushRepo,
347+
commit,
348+
'upload-snapshot'
349+
)).pop()
350+
if (latestUploadSnapshotRun) return `The 'upload-snapshot' check-run already exists for ${commit}: ${latestUploadSnapshotRun.html_url}`
351+
352+
// Trigger the `upload-snapshot` run directly
353+
const tagGitCheckRunTitle = `Upload snapshot Git @${commit}`
354+
const tagGitCheckRunId = await queueCheckRun(
355+
context,
356+
await getToken(),
357+
pushOwner,
358+
pushRepo,
359+
commit,
360+
'tag-git',
361+
tagGitCheckRunTitle,
362+
tagGitCheckRunTitle
363+
)
364+
365+
const match = latest.output.summary.match(/^Tag Git (\S+) @([0-9a-f]+)$/)
366+
if (!match) throw new Error(`Unexpected summary '${latest.output.summary}' of tag-git run: ${latest.html_url}`)
367+
if (!match[2] === commit) throw new Error(`Unexpected revision ${match[2]} '${latest.output.summary}' of tag-git run: ${latest.html_url}`)
368+
const ver = match[1]
369+
370+
try {
371+
const workFlowRunIDs = {}
372+
for (const architecture of ['x86_64', 'i686', 'aarch64']) {
373+
const workflowName = `git-artifacts-${architecture}`
374+
const runs = await listCheckRunsForCommit(
375+
context,
376+
gitToken,
377+
pushOwner,
378+
pushRepo,
379+
commit,
380+
workflowName
381+
)
382+
const needle =
383+
`Build Git ${ver} artifacts from commit ${commit} (tag-git run #${latest.id})`
384+
const latest2 = runs
385+
.filter(run => run.output.summary === needle)
386+
.sort((a, b) => a.id - b.id)
387+
.pop()
388+
if (latest2) {
389+
if (latest2.status !== 'completed' || latest2.conclusion !== 'success') {
390+
throw new Error(`The '${workflowName}' run at ${latest2.html_url} did not succeed.`)
391+
}
392+
393+
const match = latest2.output.text.match(
394+
/For details, see \[this run\]\(https:\/\/github.com\/([^/]+)\/([^/]+)\/actions\/runs\/(\d+)\)/
395+
)
396+
if (!match) throw new Error(`Unhandled 'text' attribute of git-artifacts run ${latest2.id}: ${latest2.url}`)
397+
const owner = match[1]
398+
const repo = match[2]
399+
workFlowRunIDs[architecture] = match[3]
400+
if (owner !== 'git-for-windows' || repo !== 'git-for-windows-automation') {
401+
throw new Error(`Unexpected repository ${owner}/${repo} for git-artifacts run ${latest2.id}: ${latest2.url}`)
402+
}
403+
} else {
404+
return `Won't trigger 'upload-snapshot' on pushing ${commit} because the '${workflowName}' run does not exist.`
405+
}
406+
}
407+
408+
const answer = await triggerWorkflowDispatch(
409+
context,
410+
gitForWindowsAutomationToken,
411+
pushRepo,
412+
'git-for-windows-automation',
413+
'upload-snapshot.yml',
414+
'main', {
415+
git_artifacts_x86_64_workflow_run_id: workFlowRunIDs['x86_64'],
416+
git_artifacts_i686_workflow_run_id: workFlowRunIDs['i686'],
417+
git_artifacts_aarch64_workflow_run_id: workFlowRunIDs['aarch64'],
418+
}
419+
)
420+
421+
return `The 'upload-snapshot' workflow run was started at ${answer.html_url}`
422+
} catch (e) {
423+
await updateCheckRun(
424+
context,
425+
gitForWindowsAutomationToken,
426+
pushOwner,
427+
pushRepo,
428+
tagGitCheckRunId, {
429+
status: 'completed',
430+
conclusion: 'failure',
431+
output: {
432+
title: tagGitCheckRunTitle,
433+
summary: tagGitCheckRunTitle,
434+
text: e.message || JSON.stringify(e, null, 2)
435+
}
436+
}
437+
)
438+
throw e
439+
}
440+
}
441+
255442
module.exports = {
256443
triggerGitArtifactsRuns,
257-
cascadingRuns
444+
cascadingRuns,
445+
handlePush
258446
}

GitForWindowsHelper/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,13 @@ module.exports = async function (context, req) {
6262
}
6363

6464
try {
65-
const { cascadingRuns } = require('./cascading-runs.js')
65+
const { cascadingRuns, handlePush } = require('./cascading-runs.js')
6666
if (req.headers['x-github-event'] === 'check_run'
6767
&& req.body.repository.full_name === 'git-for-windows/git'
6868
&& req.body.action === 'completed') return ok(await cascadingRuns(context, req))
69+
70+
if (req.headers['x-github-event'] === 'push'
71+
&& req.body.repository.full_name === 'git-for-windows/git') return ok(await handlePush(context, req))
6972
} catch (e) {
7073
context.log(e)
7174
return withStatus(500, undefined, e.message || JSON.stringify(e, null, 2))

0 commit comments

Comments
 (0)