11#!/usr/bin/env node
22
33import { readFileSync } from 'node:fs' ;
4- import { basename , join } from 'node:path' ;
4+ import { basename } from 'node:path' ;
55import { execSync } from 'node:child_process' ;
66
77// Grab last git commit
88function getCommitHasForPath ( path ) {
99 return execSync ( `git log -1 --format=%H HEAD -- ${ path } ` ) . toString ( ) . trim ( ) ;
1010}
1111
12+ // Grab nodejs/Release values as the authoritative start/maintenance/end dates
13+ const releaseTimes = await fetch (
14+ 'https://raw.githubusercontent.com/nodejs/Release/refs/heads/main/schedule.json' ,
15+ ) ;
16+ const releaseJson = await releaseTimes . json ( ) ;
17+
18+ // Grab the nodejs.org index.json as the authoritative Codename values, since that can lag the Release repo JSON
19+ const availableVersions = await fetch (
20+ 'https://nodejs.org/download/release/index.json' ,
21+ ) ;
22+ const officialIndexJson = await availableVersions . json ( ) ;
23+
1224const stackbrewPath = basename ( import . meta. filename ) ;
1325
1426// Header
@@ -21,7 +33,7 @@ GitFetch: refs/heads/main\n`;
2133// Loop versions
2234const config = JSON . parse ( readFileSync ( 'versions.json' ) ) ;
2335
24- const versions = Object . keys ( config ) . reverse ( ) ;
36+ const localVersions = Object . keys ( config ) . reverse ( ) ;
2537
2638let midnight = new Date ( ) ;
2739midnight . setHours ( 0 , 0 , 0 , 0 ) ;
@@ -31,126 +43,140 @@ const slimRE = new RegExp(/\*-slim/);
3143let foundLTS = false ;
3244let foundCurrent = false ;
3345
34- for ( const version of versions ) {
35- let lts = new Date ( `${ config [ version ] . lts } T00:00:00.00` ) . getTime ( ) ;
36- let isCurrent = foundCurrent ? false : isNaN ( lts ) || lts >= now ;
46+ for ( const majorVersion of localVersions ) {
47+ let releaseRepoInfo = releaseJson [ `v${ majorVersion } ` ] ;
48+ let nodejsOrgReleaseInfo = officialIndexJson . find ( ( indexVersion ) =>
49+ indexVersion . version . startsWith ( `v${ majorVersion } ` ) ,
50+ ) ;
51+ let lts = new Date ( `${ releaseRepoInfo . lts } T00:00:00.00` ) . getTime ( ) ;
52+ // First Alpha build is the only active one, and when the "start" of the release hasn't cut over
53+ let isAlpha = nodejsOrgReleaseInfo . version . includes ( 'alpha' ) ;
54+ // The Current/Latest release is the first non-Alpha major
55+ let isCurrent = foundCurrent ? false : ! isAlpha ;
3756 foundCurrent = isCurrent || foundCurrent ;
57+ // The LTS tag is only set on the most recent LTS release
3858 let isLTS = foundLTS ? false : now >= lts ;
3959 foundLTS = isLTS || foundLTS ;
40- let codename = config [ version ] . codename ;
41- let defaultAlpine = config [ version ] [ 'alpine-default' ] ;
42- let defaultDebian = config [ version ] [ 'debian-default' ] ;
43- let variants = config [ version ] . variants ;
60+ let codename = nodejsOrgReleaseInfo . lts
61+ ? nodejsOrgReleaseInfo . lts . toLowerCase ( )
62+ : '' ;
63+ let defaultAlpine = config [ majorVersion ] [ 'alpine-default' ] ;
64+ let defaultDebian = config [ majorVersion ] [ 'debian-default' ] ;
65+ let variants = config [ majorVersion ] . variants ;
4466 for ( const variant in variants ) {
45- let dockerfilePath = join ( version , variant , 'Dockerfile' ) ;
46- let isAlpine = alpineRE . test ( variant ) ;
47- let isSlim = slimRE . test ( variant ) ;
48- let isDefaultSlim = new RegExp ( `${ defaultDebian } -slim` ) . test ( variant ) ;
49-
50- // Get full version from the Dockerfile
51- let dockerfile = readFileSync ( dockerfilePath , 'utf-8' ) ;
52- let fullVersion = dockerfile . match (
53- / E N V N O D E _ V E R S I O N = (?< major > \d + ) \. (?< minor > \d + ) \. (?< patch > \d + ) / ,
54- ) ;
55-
56- let tags = [
57- `${ fullVersion . groups . major } .${ fullVersion . groups . minor } .${ fullVersion . groups . patch } -${ variant } ` ,
58- `${ fullVersion . groups . major } .${ fullVersion . groups . minor } -${ variant } ` ,
59- `${ fullVersion . groups . major } -${ variant } ` ,
60- ] ;
61-
62- if ( codename ) {
63- tags . push ( `${ codename } -${ variant } ` ) ;
64- }
65-
66- if ( variant === defaultAlpine ) {
67- tags . push (
68- `${ fullVersion . groups . major } .${ fullVersion . groups . minor } .${ fullVersion . groups . patch } -alpine` ,
67+ let tags ;
68+
69+ if ( isAlpha ) {
70+ // Only push explicit variants during the Alpha phase
71+ tags = [ `${ nodejsOrgReleaseInfo . version . substring ( 1 ) } -${ variant } ` ] ;
72+ } else {
73+ let isAlpine = alpineRE . test ( variant ) ;
74+ let isSlim = slimRE . test ( variant ) ;
75+ let isDefaultSlim = new RegExp ( `${ defaultDebian } -slim` ) . test ( variant ) ;
76+ let fullVersion = nodejsOrgReleaseInfo . version . match (
77+ / v (?< major > \d + ) \. (?< minor > \d + ) \. (?< patch > \d + ) / ,
6978 ) ;
70- tags . push (
71- `${ fullVersion . groups . major } .${ fullVersion . groups . minor } -alpine` ,
72- ) ;
73- tags . push ( `${ fullVersion . groups . major } -alpine` ) ;
74- if ( codename ) {
75- tags . push ( `${ codename } -alpine` ) ;
76- }
77- }
79+ tags = [
80+ `${ fullVersion . groups . major } .${ fullVersion . groups . minor } .${ fullVersion . groups . patch } -${ variant } ` ,
81+ `${ fullVersion . groups . major } .${ fullVersion . groups . minor } -${ variant } ` ,
82+ `${ fullVersion . groups . major } -${ variant } ` ,
83+ ] ;
7884
79- if ( variant === defaultDebian ) {
80- tags . push (
81- `${ fullVersion . groups . major } .${ fullVersion . groups . minor } .${ fullVersion . groups . patch } ` ,
82- ) ;
83- tags . push ( `${ fullVersion . groups . major } .${ fullVersion . groups . minor } ` ) ;
84- tags . push ( `${ fullVersion . groups . major } ` ) ;
85- if ( isSlim ) {
86- tags . push (
87- `${ fullVersion . groups . major } .${ fullVersion . groups . minor } .${ fullVersion . groups . patch } -slim` ,
88- ) ;
89- tags . push (
90- `${ fullVersion . groups . major } .${ fullVersion . groups . minor } -slim` ,
91- ) ;
92- tags . push ( `${ fullVersion . groups . major } -slim` ) ;
93- }
94- if ( codename ) {
95- tags . push ( `${ codename } ` ) ;
96- }
97- }
98- if ( isDefaultSlim ) {
99- tags . push (
100- `${ fullVersion . groups . major } .${ fullVersion . groups . minor } .${ fullVersion . groups . patch } -slim` ,
101- ) ;
102- tags . push ( `${ fullVersion . groups . major } .${ fullVersion . groups . minor } -slim` ) ;
103- tags . push ( `${ fullVersion . groups . major } -slim` ) ;
10485 if ( codename ) {
105- tags . push ( `${ codename } -slim ` ) ;
86+ tags . push ( `${ codename } -${ variant } ` ) ;
10687 }
107- }
10888
109- if ( isCurrent ) {
11089 if ( variant === defaultAlpine ) {
111- tags . push ( variant ) ;
11290 tags . push (
11391 `${ fullVersion . groups . major } .${ fullVersion . groups . minor } .${ fullVersion . groups . patch } -alpine` ,
11492 ) ;
11593 tags . push (
11694 `${ fullVersion . groups . major } .${ fullVersion . groups . minor } -alpine` ,
11795 ) ;
11896 tags . push ( `${ fullVersion . groups . major } -alpine` ) ;
119- tags . push ( 'alpine' ) ;
120- tags . push ( 'current-alpine' ) ;
121- }
122- if ( variant === defaultDebian ) {
123- tags . push ( variant ) ;
124- tags . push ( 'latest' ) ;
125- tags . push ( 'current' ) ;
126- }
127- if ( isAlpine ) {
128- tags . push ( `${ variant } ` ) ;
129- tags . push ( `current-${ variant } ` ) ;
130- }
131- if ( ! isAlpine ) {
132- tags . push ( `${ variant } ` ) ;
133- tags . push ( `current-${ variant } ` ) ;
134- }
135- if ( isDefaultSlim ) {
136- tags . push ( 'slim' ) ;
137- tags . push ( 'current-slim' ) ;
97+ if ( codename ) {
98+ tags . push ( `${ codename } -alpine` ) ;
99+ }
138100 }
139- }
140101
141- if ( isLTS ) {
142- tags . push ( `lts-${ variant } ` ) ;
143102 if ( variant === defaultDebian ) {
144- tags . push ( 'lts' ) ;
103+ tags . push (
104+ `${ fullVersion . groups . major } .${ fullVersion . groups . minor } .${ fullVersion . groups . patch } ` ,
105+ ) ;
106+ tags . push ( `${ fullVersion . groups . major } .${ fullVersion . groups . minor } ` ) ;
107+ tags . push ( `${ fullVersion . groups . major } ` ) ;
108+ if ( isSlim ) {
109+ tags . push (
110+ `${ fullVersion . groups . major } .${ fullVersion . groups . minor } .${ fullVersion . groups . patch } -slim` ,
111+ ) ;
112+ tags . push (
113+ `${ fullVersion . groups . major } .${ fullVersion . groups . minor } -slim` ,
114+ ) ;
115+ tags . push ( `${ fullVersion . groups . major } -slim` ) ;
116+ }
145117 if ( codename ) {
146- tags . push ( `lts- ${ codename } ` ) ;
118+ tags . push ( `${ codename } ` ) ;
147119 }
148120 }
149121 if ( isDefaultSlim ) {
150- tags . push ( `lts-slim` ) ;
122+ tags . push (
123+ `${ fullVersion . groups . major } .${ fullVersion . groups . minor } .${ fullVersion . groups . patch } -slim` ,
124+ ) ;
125+ tags . push (
126+ `${ fullVersion . groups . major } .${ fullVersion . groups . minor } -slim` ,
127+ ) ;
128+ tags . push ( `${ fullVersion . groups . major } -slim` ) ;
129+ if ( codename ) {
130+ tags . push ( `${ codename } -slim` ) ;
131+ }
151132 }
152- if ( variant === defaultAlpine ) {
153- tags . push ( `lts-alpine` ) ;
133+
134+ if ( isCurrent ) {
135+ if ( variant === defaultAlpine ) {
136+ tags . push ( variant ) ;
137+ tags . push (
138+ `${ fullVersion . groups . major } .${ fullVersion . groups . minor } .${ fullVersion . groups . patch } -alpine` ,
139+ ) ;
140+ tags . push (
141+ `${ fullVersion . groups . major } .${ fullVersion . groups . minor } -alpine` ,
142+ ) ;
143+ tags . push ( `${ fullVersion . groups . major } -alpine` ) ;
144+ tags . push ( 'alpine' ) ;
145+ tags . push ( 'current-alpine' ) ;
146+ }
147+ if ( variant === defaultDebian ) {
148+ tags . push ( variant ) ;
149+ tags . push ( 'latest' ) ;
150+ tags . push ( 'current' ) ;
151+ }
152+ if ( isAlpine ) {
153+ tags . push ( `${ variant } ` ) ;
154+ tags . push ( `current-${ variant } ` ) ;
155+ }
156+ if ( ! isAlpine ) {
157+ tags . push ( `${ variant } ` ) ;
158+ tags . push ( `current-${ variant } ` ) ;
159+ }
160+ if ( isDefaultSlim ) {
161+ tags . push ( 'slim' ) ;
162+ tags . push ( 'current-slim' ) ;
163+ }
164+ }
165+
166+ if ( isLTS ) {
167+ tags . push ( `lts-${ variant } ` ) ;
168+ if ( variant === defaultDebian ) {
169+ tags . push ( 'lts' ) ;
170+ if ( codename ) {
171+ tags . push ( `lts-${ codename } ` ) ;
172+ }
173+ }
174+ if ( isDefaultSlim ) {
175+ tags . push ( `lts-slim` ) ;
176+ }
177+ if ( variant === defaultAlpine ) {
178+ tags . push ( `lts-alpine` ) ;
179+ }
154180 }
155181 }
156182
@@ -159,9 +185,9 @@ Tags: ${tags
159185 . filter ( ( x , i , a ) => a . indexOf ( x ) == i )
160186 . sort ( )
161187 . join ( ', ' ) }
162- Architectures: ${ config [ version ] . variants [ variant ] . join ( ', ' ) }
163- GitCommit: ${ getCommitHasForPath ( `${ version } /${ variant } ` ) }
164- Directory: ${ `${ version } /${ variant } ` } \n` ;
188+ Architectures: ${ config [ majorVersion ] . variants [ variant ] . join ( ', ' ) }
189+ GitCommit: ${ getCommitHasForPath ( `${ majorVersion } /${ variant } ` ) }
190+ Directory: ${ `${ majorVersion } /${ variant } ` } \n` ;
165191 }
166192}
167193
0 commit comments