@@ -20,9 +20,9 @@ const XCODE_FEED = "https://xcodereleases.com/data.json";
2020const NODE_FEED = "https://nodejs.org/dist/index.json" ;
2121const ANDROID_REPOSITORY = "https://dl.google.com/android/repository/repository2-3.xml" ;
2222const ADOPTIUM_RELEASES = "https://api.adoptium.net/v3/info/available_releases" ;
23- // Newest image first: an Xcode line shipped by several images runs on the newest one.
24- const MACOS_RUNNERS = [ "macos-26" , "macos-15" , "macos-14" ] ;
25- const RUNNER_README = ( image ) => ` https://raw.githubusercontent.com/actions/runner-images/main/images/macos/ ${ image } -Readme .md` ;
23+ // The runner-images README lists every hosted image with its labels and readme,
24+ // so new macOS images and Xcode preview images are discovered, not configured.
25+ const RUNNER_IMAGES_README = " https://raw.githubusercontent.com/actions/runner-images/main/README .md" ;
2626
2727const CLI_VERSIONS = 2 ; // newest stable CLI releases
2828const RUNTIME_VERSIONS = 2 ; // newest stable releases of each runtime
@@ -93,21 +93,59 @@ async function xcodeLines() {
9393 return [ ...lines ] . sort ( compareVersions ) . slice ( 0 , XCODE_LINES ) ;
9494}
9595
96- // Which GitHub macOS runner image ships each Xcode line, from the images' published readmes.
96+ // macOS images from the runner-images README table: name, arch, labels, readme.
97+ async function macosRunnerImages ( ) {
98+ const readme = await text ( RUNNER_IMAGES_README ) ;
99+ const links = new Map (
100+ [ ...readme . matchAll ( / ^ \[ ( [ ^ \] ] + ) \] : \s * ( \S + ) / gm) ] . map ( ( [ , ref , url ] ) => [ ref . toLowerCase ( ) , url ] ) ,
101+ ) ;
102+ const images = [ ] ;
103+ for ( const row of readme . split ( "\n" ) ) {
104+ const cols = row . split ( "|" ) . map ( ( c ) => c . trim ( ) ) ;
105+ if ( cols . length < 5 ) {
106+ continue ;
107+ }
108+ const [ , name , arch , labelCell , refCell ] = cols ;
109+ const ref = refCell . match ( / ^ \[ ( [ ^ \] ] + ) \] $ / ) ?. [ 1 ] ;
110+ if ( ! ref || ! / m a c o s | x c o d e / i. test ( name ) ) {
111+ continue ;
112+ }
113+ const url = links . get ( ref . toLowerCase ( ) ) ;
114+ const labels = [ ...labelCell . matchAll ( / ` ( [ ^ ` ] + ) ` / g) ] . map ( ( m ) => m [ 1 ] ) ;
115+ if ( ! url || ! labels . length ) {
116+ continue ;
117+ }
118+ images . push ( {
119+ name : name . replace ( / < b r > .* $ / s, "" ) . trim ( ) ,
120+ arch,
121+ // The plain label: not the "-large" size variants, and not "macos-latest", which moves.
122+ label : labels . find ( ( label ) => ! / l a r g e | l a t e s t / . test ( label ) ) ?? labels [ 0 ] ,
123+ readme : url . replace ( "github.com/" , "raw.githubusercontent.com/" ) . replace ( "/blob/" , "/" ) ,
124+ os : Number ( name . match ( / m a c O S ( \d + ) / ) ?. [ 1 ] ?? 0 ) ,
125+ preview : / x c o d e / i. test ( name ) ,
126+ } ) ;
127+ }
128+ // arm64 first, regular images before Xcode preview images, newest OS first.
129+ return images . sort (
130+ ( a , b ) => Number ( b . arch === "arm64" ) - Number ( a . arch === "arm64" ) || Number ( a . preview ) - Number ( b . preview ) || b . os - a . os ,
131+ ) ;
132+ }
133+
134+ // Which runner label ships each Xcode line, from every image's readme.
97135async function runnerXcodes ( ) {
98136 const byLine = new Map ( ) ;
99- for ( const image of MACOS_RUNNERS ) {
137+ for ( const image of await macosRunnerImages ( ) ) {
100138 try {
101- const readme = await text ( RUNNER_README ( image ) ) ;
139+ const readme = await text ( image . readme ) ;
102140 const section = readme . split ( / ^ # + .* X c o d e .* $ / m) [ 1 ] ?? readme ;
103141 for ( const [ , version ] of section . matchAll ( / ^ \| \s * ( \d + \. \d + (?: \. \d + ) ? ) / gm) ) {
104142 const line = version . split ( "." ) . slice ( 0 , 2 ) . join ( "." ) ;
105143 if ( ! byLine . has ( line ) ) {
106- byLine . set ( line , image ) ;
144+ byLine . set ( line , image . label ) ;
107145 }
108146 }
109147 } catch ( err ) {
110- console . warn ( `${ image } readme unavailable (${ err . message } )` ) ;
148+ console . warn ( `${ image . name } readme unavailable (${ err . message } )` ) ;
111149 }
112150 }
113151 return byLine ;
0 commit comments