Skip to content

Commit 9ca687b

Browse files
committed
Add a node.js script to update manual-test's runs-on options
As I had suggested in mxschmitt#224 (comment), it would be good to have some sort of automation to update the ever-changing list of runner pools that are supported by GitHub. Signed-off-by: Johannes Schindelin <[email protected]>
1 parent c5b3b09 commit 9ca687b

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/usr/bin/env node
2+
3+
// Update the `runs-on` options of the `manual-test.yml` workflow file with the
4+
// latest available images from the GitHub Actions runner images README file.
5+
6+
(async () => {
7+
const fs = require('fs')
8+
9+
const readme = await (await fetch("https://github.com/actions/runner-images/raw/HEAD/README.md")).text()
10+
11+
// This will be the first `ubuntu` one.
12+
let defaultOption = ''
13+
14+
const choices = readme
15+
// Get the "Available Images" section
16+
.split(/\n## Available Images\n/)[1]
17+
.split(/##\s*[^#]/)[0]
18+
// Split by lines
19+
.split('\n')
20+
.map(line => {
21+
// The relevant lines are table rows; The first column is the image name,
22+
// the second one contains a relatively free-form list of the `runs-on`
23+
// options that we are interested in. Those `runs-on` options are
24+
// surrounded by backticks.
25+
const match = line.match(/^\|\s*([^|]+)\s*\|([^|]*)`([^`|]+)`\s*\|/)
26+
if (!match) return false // Skip e.g. the table header and empty lines
27+
let runsOn = match[3] // default to the last `runs-on` option
28+
const alternatives = match[2]
29+
.split(/`([^`]*)`/) // split by backticks
30+
.filter((_, i) => (i % 2)) // keep only the text between backticks
31+
.sort((a, b) => a.length - b.length) // order by length
32+
if (alternatives.length > 0 && alternatives[0].length < runsOn.length) runsOn = alternatives[0]
33+
if (!defaultOption && match[3].startsWith('ubuntu-')) defaultOption = runsOn
34+
return runsOn
35+
})
36+
.filter(runsOn => runsOn)
37+
38+
// Now edit the `manual-test` workflow definition
39+
const ymlPath = `${__dirname}/manual-test.yml`
40+
const yml = fs.readFileSync(ymlPath, 'utf8')
41+
42+
// We want to replace the `runs-on` options and the `default` value. This
43+
// would be easy if there was a built-in YAML parser and renderer in Node.js,
44+
// but there is none. Therefore, we use a regular expression to find certain
45+
// "needles" near the beginning of the file: first `workflow_dispatch:`,
46+
// after that `runs-on:` and then `default:` and `options:`. Then we replace
47+
// the `default` value and the `options` values with the new ones.
48+
const [, beforeDefault, beforeOptions, optionsIndent, afterOptions] =
49+
yml.match(/^([^]*?workflow_dispatch:[^]*?runs-on:[^]*?default:)(?:.*)([^]*?options:)(\n +- )(?:.*)(?:\3.*)*([^]*)/) || []
50+
if (!beforeDefault) throw new Error(`The 'manual-test.yml' file does not match the expected format!`)
51+
const newYML =
52+
`${beforeDefault} ${defaultOption}${[beforeOptions, ...choices].join(optionsIndent)}${afterOptions}`
53+
fs.writeFileSync(ymlPath, newYML)
54+
})().catch(e => {
55+
console.error(e)
56+
process.exitCode = 1
57+
})

0 commit comments

Comments
 (0)