diff --git a/helpers/Dojo/ExerciseDockerCompose.ts b/helpers/Dojo/ExerciseDockerCompose.ts index 8d766aabf6c34f02b954fad0e3a4a3d6bbe40b4f..dafa4bdc8690fff4bbb74b02e8a0340c686d9b70 100644 --- a/helpers/Dojo/ExerciseDockerCompose.ts +++ b/helpers/Dojo/ExerciseDockerCompose.ts @@ -16,6 +16,8 @@ class ExerciseDockerCompose { public success: boolean = false; public exitCode: number = -1; + private currentStep: string = 'NOT_RUNNING'; + constructor(private projectName: string, private assignmentFile: AssignmentFile, private executionFolder: string, private composeFileOverride: Array<string> = []) { this.events.on('logs', (log: string, _error: boolean, displayable: boolean) => { this.allLogs += log; @@ -29,13 +31,26 @@ class ExerciseDockerCompose { }); } - private registerChildProcess(childProcess: ChildProcessWithoutNullStreams, resolve: (value: (number | PromiseLike<number>)) => void, reject: (reason?: unknown) => void) { + private newStep(name: string, message: string) { + this.currentStep = name; + this.events.emit('step', name, message); + } + + private endStep(message: string, error: boolean) { + this.events.emit('endStep', this.currentStep, message, error); + } + + private log(message: string, error: boolean, displayable: boolean) { + this.events.emit('logs', message, error, displayable, this.currentStep); + } + + private registerChildProcess(childProcess: ChildProcessWithoutNullStreams, resolve: (value: (number | PromiseLike<number>)) => void, reject: (reason?: unknown) => void, displayable: boolean) { childProcess.stdout.on('data', (data) => { - this.events.emit('logs', data.toString(), false, false); + this.log(data.toString(), false, displayable); }); childProcess.stderr.on('data', (data) => { - this.events.emit('logs', data.toString(), true, false); + this.log(data.toString(), true, displayable); }); childProcess.on('exit', (code) => { @@ -52,11 +67,11 @@ class ExerciseDockerCompose { // Run the service { try { - this.events.emit('step', 'COMPOSE_RUN', 'Running Docker Compose file'); + this.newStep('COMPOSE_RUN', 'Running Docker Compose file'); containerExitCode = await new Promise<number>((resolve, reject) => { - this.events.emit('logs', '####################################################### Docker Compose & Main Container Logs #######################################################\n', false, false); + this.log('####################################################### Docker Compose & Main Container Logs #######################################################\n', false, false); const dockerCompose = spawn(`${ dockerComposeCommand } run --build --rm ${ this.assignmentFile.result.container }`, { cwd : this.executionFolder, @@ -67,63 +82,63 @@ class ExerciseDockerCompose { } }); - this.registerChildProcess(dockerCompose, resolve, reject); + this.registerChildProcess(dockerCompose, resolve, reject, true); }); } catch ( error ) { - this.events.emit('endStep', 'COMPOSE_RUN', `Error while running the docker compose file`, true); + this.endStep(`Error while running the docker compose file`, true); this.events.emit('finished', false, ExerciseCheckerError.DOCKER_COMPOSE_RUN_ERROR); return; } - this.events.emit('endStep', 'COMPOSE_RUN', `Docker Compose file run successfully`, false); + this.endStep(`Docker Compose file run successfully`, false); } // Get linked services logs { try { - this.events.emit('step', 'COMPOSE_LOGS', 'Linked services logs acquisition'); + this.newStep('COMPOSE_LOGS', 'Linked services logs acquisition'); await new Promise<number>((resolve, reject) => { - this.events.emit('logs', '####################################################### Other Services Logs #######################################################\n', false, false); + this.log('####################################################### Other Services Logs #######################################################\n', false, false); const dockerCompose = spawn(`${ dockerComposeCommand } logs --timestamps`, { cwd : this.executionFolder, shell: true }); - this.registerChildProcess(dockerCompose, resolve, reject); + this.registerChildProcess(dockerCompose, resolve, reject, false); }); } catch ( error ) { - this.events.emit('endStep', 'COMPOSE_LOGS', `Error while getting the linked services logs`, true); + this.endStep(`Error while getting the linked services logs`, true); this.events.emit('finished', false, ExerciseCheckerError.DOCKER_COMPOSE_LOGS_ERROR); return; } - this.events.emit('endStep', 'COMPOSE_LOGS', `Linked services logs acquired`, false); + this.endStep(`Linked services logs acquired`, false); } // Remove containers if asked { if ( doDown ) { try { - this.events.emit('step', 'COMPOSE_DOWN', 'Stopping and removing containers'); + this.newStep('COMPOSE_DOWN', 'Stopping and removing containers'); await new Promise<number>((resolve, reject) => { - this.events.emit('logs', '####################################################### Stop and remove containers #######################################################\n', false, false); + this.log('####################################################### Stop and remove containers #######################################################\n', false, false); const dockerCompose = spawn(`${ dockerComposeCommand } down --volumes --rmi`, { cwd : this.executionFolder, shell: true }); - this.registerChildProcess(dockerCompose, resolve, reject); + this.registerChildProcess(dockerCompose, resolve, reject, false); }); } catch ( error ) { - this.events.emit('endStep', 'COMPOSE_DOWN', `Error stop and remove containers`, true); + this.endStep(`Error stop and remove containers`, true); this.events.emit('finished', false, ExerciseCheckerError.DOCKER_COMPOSE_DOWN_ERROR); return; } - this.events.emit('endStep', 'COMPOSE_DOWN', `Containers stopped and removed`, false); + this.events.emit('endStep', this.currentStep, `Containers stopped and removed`, false); } } @@ -131,25 +146,25 @@ class ExerciseDockerCompose { { if ( doDown ) { try { - this.events.emit('step', 'COMPOSE_REMOVE_DANGLING', 'Removing dangling images'); + this.newStep('COMPOSE_REMOVE_DANGLING', 'Removing dangling images'); await new Promise<number>((resolve, reject) => { - this.events.emit('logs', '####################################################### Remove dangling images #######################################################\n', false, false); + this.log('####################################################### Remove dangling images #######################################################\n', false, false); const dockerCompose = spawn(`docker image prune --force`, { cwd : this.executionFolder, shell: true }); - this.registerChildProcess(dockerCompose, resolve, reject); + this.registerChildProcess(dockerCompose, resolve, reject, false); }); } catch ( error ) { - this.events.emit('endStep', 'COMPOSE_REMOVE_DANGLING', `Error while removing dangling images`, true); + this.endStep(`Error while removing dangling images`, true); this.events.emit('finished', false, ExerciseCheckerError.DOCKER_COMPOSE_REMOVE_DANGLING_ERROR); return; } - this.events.emit('endStep', 'COMPOSE_REMOVE_DANGLING', `Dangling images removed`, false); + this.events.emit('endStep', this.currentStep, `Dangling images removed`, false); } } diff --git a/types/Dojo/ExerciseRunningEvents.ts b/types/Dojo/ExerciseRunningEvents.ts index 34ed6a16dbf2ba79163b57b575aeb1a0aa59f061..1aafa3586372ae3204dce45d52b6bf2e9f90c922 100644 --- a/types/Dojo/ExerciseRunningEvents.ts +++ b/types/Dojo/ExerciseRunningEvents.ts @@ -1,7 +1,7 @@ interface ExerciseRunningEvents { step: (name: string, message: string) => void; endStep: (stepName: string, message: string, error: boolean) => void; - logs: (log: string, error: boolean, displayable: boolean) => void; + logs: (log: string, error: boolean, displayable: boolean, currentStep: string) => void; finished: (success: boolean, exitCode: number) => void; }