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 # # A v a i l a b l e I m a g e s \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 ( / ^ ( [ ^ ] * ?w o r k f l o w _ d i s p a t c h : [ ^ ] * ?r u n s - o n : [ ^ ] * ?d e f a u l t : ) (?: .* ) ( [ ^ ] * ?o p t i o n s : ) ( \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