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
+ // The Windows/ARM64 runners are in public preview (and for the time being,
39
+ // not listed in the `runner-images` README file), so we need to add this
40
+ // manually.
41
+ if ( ! choices . includes ( 'windows-11-arm' ) ) choices . push ( 'windows-11-arm' )
42
+
43
+ // Now edit the `manual-test` workflow definition
44
+ const ymlPath = `${ __dirname } /manual-test.yml`
45
+ const yml = fs . readFileSync ( ymlPath , 'utf8' )
46
+
47
+ // We want to replace the `runs-on` options and the `default` value. This
48
+ // would be easy if there was a built-in YAML parser and renderer in Node.js,
49
+ // but there is none. Therefore, we use a regular expression to find certain
50
+ // "needles" near the beginning of the file: first `workflow_dispatch:`,
51
+ // after that `runs-on:` and then `default:` and `options:`. Then we replace
52
+ // the `default` value and the `options` values with the new ones.
53
+ const [ , beforeDefault , beforeOptions , optionsIndent , afterOptions ] =
54
+ 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.* ) * ( [ ^ ] * ) / ) || [ ]
55
+ if ( ! beforeDefault ) throw new Error ( `The 'manual-test.yml' file does not match the expected format!` )
56
+ const newYML =
57
+ `${ beforeDefault } ${ defaultOption } ${ [ beforeOptions , ...choices ] . join ( optionsIndent ) } ${ afterOptions } `
58
+ fs . writeFileSync ( ymlPath , newYML )
59
+ } ) ( ) . catch ( e => {
60
+ console . error ( e )
61
+ process . exitCode = 1
62
+ } )
0 commit comments