1+ #!/usr/bin/env node
2+
3+ import { appendFileSync } from 'node:fs' ;
4+
5+ class BuildContext {
6+ constructor ( ) {
7+ this . githubOutput = process . env . GITHUB_OUTPUT || null ;
8+ }
9+
10+ determine ( { event, pr, branch, version, releaseType, pushEnabled } ) {
11+ let context = {
12+ version : '' ,
13+ release_type : '' ,
14+ platforms : [ 'linux/amd64' , 'linux/arm64' ] ,
15+ push_to_ghcr : true ,
16+ push_to_docker : false ,
17+ } ;
18+
19+ // Determine version and release type based on event
20+ switch ( event ) {
21+ case 'schedule' :
22+ context . version = 'nightly' ;
23+ context . release_type = 'nightly' ;
24+ context . push_to_docker = true ;
25+ break ;
26+
27+ case 'pull_request' :
28+ context . version = `pr-${ pr } ` ;
29+ context . release_type = 'dev' ;
30+ context . push_to_ghcr = false ;
31+ break ;
32+
33+ case 'workflow_dispatch' :
34+ context . version = `branch-${ this . sanitizeBranch ( branch ) } ` ;
35+ context . release_type = 'branch' ;
36+ context . platforms = [ 'linux/amd64' ] ;
37+ break ;
38+
39+ case 'push' :
40+ if ( branch === 'master' ) {
41+ context . version = 'dev' ;
42+ context . release_type = 'dev' ;
43+ context . push_to_docker = true ;
44+ } else {
45+ context . version = `branch-${ this . sanitizeBranch ( branch ) } ` ;
46+ context . release_type = 'branch' ;
47+ context . platforms = [ 'linux/amd64' ] ;
48+ }
49+ break ;
50+
51+ case 'workflow_call' :
52+ case 'release' :
53+ if ( ! version ) throw new Error ( 'Version required for release' ) ;
54+ context . version = version ;
55+ context . release_type = releaseType || 'stable' ;
56+ context . push_to_docker = true ;
57+ break ;
58+
59+ default :
60+ throw new Error ( `Unknown event: ${ event } ` ) ;
61+ }
62+
63+ // Handle push_enabled override
64+ if ( pushEnabled !== undefined ) {
65+ context . push_enabled = pushEnabled ;
66+ } else {
67+ context . push_enabled = context . push_to_ghcr ;
68+ }
69+
70+ return context ;
71+ }
72+
73+ sanitizeBranch ( branch ) {
74+ if ( ! branch ) return 'unknown' ;
75+ return branch
76+ . toLowerCase ( )
77+ . replace ( / [ ^ a - z 0 - 9 . _ - ] / g, '-' )
78+ . replace ( / ^ [ . - ] / , '' )
79+ . replace ( / [ . - ] $ / , '' )
80+ . substring ( 0 , 128 ) ;
81+ }
82+
83+ buildMatrix ( platforms ) {
84+ const runners = {
85+ 'linux/amd64' : 'blacksmith-4vcpu-ubuntu-2204' ,
86+ 'linux/arm64' : 'blacksmith-4vcpu-ubuntu-2204-arm' ,
87+ } ;
88+
89+ const matrix = {
90+ platform : [ ] ,
91+ include : [ ] ,
92+ } ;
93+
94+ for ( const platform of platforms ) {
95+ const shortName = platform . split ( '/' ) . pop ( ) ; // amd64 or arm64
96+ matrix . platform . push ( shortName ) ;
97+ matrix . include . push ( {
98+ platform : shortName ,
99+ runner : runners [ platform ] ,
100+ docker_platform : platform ,
101+ } ) ;
102+ }
103+
104+ return matrix ;
105+ }
106+
107+ output ( context , matrix = null ) {
108+ const buildMatrix = matrix || this . buildMatrix ( context . platforms ) ;
109+
110+ if ( this . githubOutput ) {
111+ const outputs = [
112+ `version=${ context . version } ` ,
113+ `release_type=${ context . release_type } ` ,
114+ `platforms=${ JSON . stringify ( context . platforms ) } ` ,
115+ `push_to_ghcr=${ context . push_to_ghcr } ` ,
116+ `push_to_docker=${ context . push_to_docker } ` ,
117+ `push_enabled=${ context . push_enabled } ` ,
118+ `build_matrix=${ JSON . stringify ( buildMatrix ) } ` ,
119+ ] ;
120+ appendFileSync ( this . githubOutput , outputs . join ( '\n' ) + '\n' ) ;
121+ } else {
122+ console . log ( JSON . stringify ( { ...context , build_matrix : buildMatrix } , null , 2 ) ) ;
123+ }
124+ }
125+ }
126+
127+ // CLI - Simple argument parsing
128+ if ( import . meta. url === `file://${ process . argv [ 1 ] } ` ) {
129+ const args = process . argv . slice ( 2 ) ;
130+ const getArg = ( name ) => {
131+ const index = args . indexOf ( `--${ name } ` ) ;
132+ if ( index === - 1 || ! args [ index + 1 ] ) return undefined ;
133+ const value = args [ index + 1 ] ;
134+ // Handle empty strings and 'null' as undefined
135+ return value === '' || value === 'null' ? undefined : value ;
136+ } ;
137+
138+ try {
139+ const context = new BuildContext ( ) ;
140+ const pushEnabledArg = getArg ( 'push-enabled' ) ;
141+ const result = context . determine ( {
142+ event : getArg ( 'event' ) || process . env . GITHUB_EVENT_NAME ,
143+ pr : getArg ( 'pr' ) || process . env . GITHUB_PR_NUMBER ,
144+ branch : getArg ( 'branch' ) || process . env . GITHUB_REF_NAME ,
145+ version : getArg ( 'version' ) ,
146+ releaseType : getArg ( 'release-type' ) ,
147+ pushEnabled : pushEnabledArg === 'true' ? true : pushEnabledArg === 'false' ? false : undefined ,
148+ } ) ;
149+
150+ const matrix = context . buildMatrix ( result . platforms ) ;
151+
152+ // Debug output when GITHUB_OUTPUT is set (running in Actions)
153+ if ( context . githubOutput ) {
154+ console . log ( '=== Build Context ===' ) ;
155+ console . log ( `version: ${ result . version } ` ) ;
156+ console . log ( `release_type: ${ result . release_type } ` ) ;
157+ console . log ( `platforms: ${ JSON . stringify ( result . platforms , null , 2 ) } ` ) ;
158+ console . log ( `push_to_ghcr: ${ result . push_to_ghcr } ` ) ;
159+ console . log ( `push_to_docker: ${ result . push_to_docker } ` ) ;
160+ console . log ( `push_enabled: ${ result . push_enabled } ` ) ;
161+ console . log ( 'build_matrix:' , JSON . stringify ( matrix , null , 2 ) ) ;
162+ }
163+
164+ context . output ( result , matrix ) ;
165+ } catch ( error ) {
166+ console . error ( `Error: ${ error . message } ` ) ;
167+ process . exit ( 1 ) ;
168+ }
169+ }
170+
171+ export default BuildContext ;
0 commit comments