@@ -10,6 +10,8 @@ import { pipeline } from "stream/promises";
1010import fetch from "node-fetch" ;
1111import { createLogger , format , transports } from "winston" ;
1212import * as crossZip from "cross-zip" ;
13+ import { GitHub } from "../../utils/src/github" ;
14+ import { getPackageFileContent } from "../../utils/src/package-info" ;
1315
1416const execAsync = promisify ( exec ) ;
1517
@@ -46,9 +48,9 @@ interface TestProject {
4648 branchName : string ;
4749}
4850
49- interface WidgetPackage {
50- name : string ;
51- version : string ;
51+ interface WidgetPackageJson {
52+ name ? : string ;
53+ version ? : string ;
5254 scripts ?: {
5355 [ key : string ] : string ;
5456 } ;
@@ -109,51 +111,42 @@ class DockerError extends SnapshotUpdaterError {
109111 }
110112}
111113
112- // Utility classes
113- class FileSystem {
114- static async ensureDir ( dirPath : string ) : Promise < void > {
114+ // Utility functions
115+ const FileSystem = {
116+ async ensureDir ( dirPath : string ) : Promise < void > {
115117 try {
116118 await fs . mkdir ( dirPath , { recursive : true } ) ;
117- } catch ( error ) {
119+ } catch ( _error ) {
118120 throw new SnapshotUpdaterError ( `Failed to create directory: ${ dirPath } ` , "FS_ERROR" ) ;
119121 }
120- }
122+ } ,
121123
122- static async removeDir ( dirPath : string ) : Promise < void > {
124+ async removeDir ( dirPath : string ) : Promise < void > {
123125 if ( existsSync ( dirPath ) ) {
124126 await fs . rm ( dirPath , { recursive : true , force : true } ) ;
125127 }
126- }
128+ } ,
127129
128- static async copyFile ( src : string , dest : string ) : Promise < void > {
130+ async copyFile ( src : string , dest : string ) : Promise < void > {
129131 await fs . copyFile ( src , dest ) ;
130- }
131-
132- static async readJsonFile < T > ( filePath : string ) : Promise < T > {
133- try {
134- const content = await fs . readFile ( filePath , "utf8" ) ;
135- return JSON . parse ( content ) ;
136- } catch ( error ) {
137- throw new SnapshotUpdaterError ( `Failed to read JSON file: ${ filePath } ` , "JSON_ERROR" ) ;
138- }
139- }
132+ } ,
140133
141- static async createTempDir ( ) : Promise < string > {
142- return await fs . mkdtemp ( path . join ( process . env . TMPDIR || "/tmp" , "mx-e2e-" ) ) ;
134+ async createTempDir ( ) : Promise < string > {
135+ return fs . mkdtemp ( path . join ( process . env . TMPDIR || "/tmp" , "mx-e2e-" ) ) ;
143136 }
144- }
137+ } ;
145138
146- class DockerManager {
147- static async isRunning ( ) : Promise < boolean > {
139+ const DockerManager = {
140+ async isRunning ( ) : Promise < boolean > {
148141 try {
149142 await execAsync ( "docker info" ) ;
150143 return true ;
151144 } catch {
152145 return false ;
153146 }
154- }
147+ } ,
155148
156- static async findFreePort ( ) : Promise < number > {
149+ async findFreePort ( ) : Promise < number > {
157150 try {
158151 const { stdout } = await execAsync (
159152 "node -e \"const net = require('net'); const server = net.createServer(); server.listen(0, () => { console.log(server.address().port); server.close(); });\""
@@ -163,9 +156,9 @@ class DockerManager {
163156 // Fallback to random port in ephemeral range
164157 return Math . floor ( Math . random ( ) * ( 65535 - 49152 ) + 49152 ) ;
165158 }
166- }
159+ } ,
167160
168- static async runContainer ( options : {
161+ async runContainer ( options : {
169162 image : string ;
170163 name ?: string ;
171164 ports ?: Record < number , number > ;
@@ -205,50 +198,52 @@ class DockerManager {
205198 try {
206199 const { stdout } = await execAsync ( `docker ${ args . join ( " " ) } ` ) ;
207200 return stdout . trim ( ) ;
208- } catch ( error ) {
209- throw new DockerError ( `Failed to run container: ${ error } ` ) ;
201+ } catch ( _error ) {
202+ throw new DockerError ( `Failed to run container: ${ _error } ` ) ;
210203 }
211- }
204+ } ,
212205
213- static async isContainerRunning ( name : string ) : Promise < boolean > {
206+ async isContainerRunning ( name : string ) : Promise < boolean > {
214207 try {
215208 const { stdout } = await execAsync ( `docker ps --filter name=${ name } --format "{{.Names}}"` ) ;
216209 return stdout . trim ( ) === name ;
217210 } catch {
218211 return false ;
219212 }
220- }
213+ } ,
221214
222- static async stopContainer ( name : string ) : Promise < void > {
215+ async stopContainer ( name : string ) : Promise < void > {
223216 try {
224217 await execAsync ( `docker rm -f ${ name } ` ) ;
225218 } catch {
226219 // Container might not exist or already stopped
227220 }
228- }
221+ } ,
229222
230- static async getContainerLogs ( name : string ) : Promise < string > {
223+ async getContainerLogs ( name : string ) : Promise < string > {
231224 try {
232225 const { stdout } = await execAsync ( `docker logs ${ name } ` ) ;
233226 return stdout ;
234227 } catch {
235228 return "No logs available" ;
236229 }
237230 }
238- }
231+ } ;
239232
240- class GitHubClient {
233+ class GitHubHelper extends GitHub {
241234 private readonly baseUrl = "https://api.github.com" ;
242235 private readonly headers : Record < string , string > ;
243236
244237 constructor ( private readonly token ?: string ) {
238+ super ( ) ;
245239 this . headers = {
246240 "User-Agent" : "mx-e2e-script" ,
247- Accept : "application/vnd.github+json"
241+ Accept : "application/vnd.github+json" ,
242+ "X-GitHub-Api-Version" : "2022-11-28"
248243 } ;
249244
250245 if ( token ) {
251- this . headers [ " Authorization" ] = `Bearer ${ token } ` ;
246+ this . headers . Authorization = `Bearer ${ token } ` ;
252247 }
253248 }
254249
@@ -286,7 +281,7 @@ class GitHubClient {
286281
287282class AtlasUpdater {
288283 constructor (
289- private readonly githubClient : GitHubClient ,
284+ private readonly githubClient : GitHubHelper ,
290285 private readonly tempDir : string
291286 ) { }
292287
@@ -463,7 +458,7 @@ class SnapshotUpdater {
463458 }
464459
465460 private setupCleanup ( ) : void {
466- const cleanup = async ( ) => {
461+ const cleanup = async ( ) : Promise < void > => {
467462 if ( this . tempDir ) {
468463 await FileSystem . removeDir ( this . tempDir ) ;
469464 }
@@ -527,7 +522,7 @@ class SnapshotUpdater {
527522 logger . info ( `Setting up test project for ${ widgetName } ...` ) ;
528523
529524 const widgetDir = path . join ( this . rootDir , CONFIG . PATHS . PLUGGABLE_WIDGETS , widgetName ) ;
530- const widgetPkg = await FileSystem . readJsonFile < WidgetPackage > ( path . join ( widgetDir , "package.json" ) ) ;
525+ const widgetPkg = ( await getPackageFileContent ( widgetDir ) ) as WidgetPackageJson ;
531526
532527 if ( ! widgetPkg . testProject ) {
533528 throw new ValidationError ( "No testProject field in widget package.json" ) ;
@@ -538,7 +533,7 @@ class SnapshotUpdater {
538533
539534 // Update Atlas components
540535 if ( options . githubToken ) {
541- const githubClient = new GitHubClient ( options . githubToken ) ;
536+ const githubClient = new GitHubHelper ( options . githubToken ) ;
542537 const atlasUpdater = new AtlasUpdater ( githubClient , this . tempDir ! ) ;
543538
544539 const testProjectDir = path . join ( this . rootDir , CONFIG . PATHS . TEST_PROJECT ) ;
@@ -554,7 +549,8 @@ class SnapshotUpdater {
554549 }
555550
556551 // Build and copy widget
557- await this . buildAndCopyWidget ( widgetName , widgetPkg . version ) ;
552+ const version = widgetPkg . version || "0.0.0" ;
553+ await this . buildAndCopyWidget ( widgetName , version ) ;
558554 }
559555
560556 private async downloadTestProject ( testProject : TestProject ) : Promise < void > {
@@ -612,7 +608,7 @@ class SnapshotUpdater {
612608 logger . info ( `Building widget ${ widgetName } ...` ) ;
613609
614610 const widgetDir = path . join ( this . rootDir , CONFIG . PATHS . PLUGGABLE_WIDGETS , widgetName ) ;
615- const widgetPkg = await FileSystem . readJsonFile < WidgetPackage > ( path . join ( widgetDir , "package.json" ) ) ;
611+ const widgetPkg = ( await getPackageFileContent ( widgetDir ) ) as WidgetPackageJson ;
616612
617613 if ( ! widgetPkg || typeof widgetPkg . version !== "string" ) {
618614 throw new SnapshotUpdaterError ( `Invalid package.json in widget ${ widgetName } ` ) ;
@@ -759,7 +755,7 @@ class SnapshotUpdater {
759755 if ( runtimeContainerId ) {
760756 break ;
761757 }
762- } catch ( error ) {
758+ } catch ( _error ) {
763759 // Continue waiting
764760 }
765761 await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ;
@@ -789,7 +785,7 @@ class SnapshotUpdater {
789785 logger . info ( "Mendix runtime is ready" ) ;
790786 return ;
791787 }
792- } catch ( error ) {
788+ } catch ( _error ) {
793789 logger . info ( `Could not reach http://${ ip } :${ port } , trying again...` ) ;
794790 }
795791 await new Promise ( resolve => setTimeout ( resolve , 3000 ) ) ;
@@ -801,7 +797,7 @@ class SnapshotUpdater {
801797 try {
802798 const logContent = await fs . readFile ( path . join ( this . rootDir , "results/runtime.log" ) , "utf8" ) ;
803799 logger . error ( logContent ) ;
804- } catch ( error ) {
800+ } catch ( _error ) {
805801 logger . error ( "Could not read runtime.log" ) ;
806802 }
807803 throw new DockerError ( "Runtime didn't start in time, exiting now..." ) ;
0 commit comments