Skip to content
Snippets Groups Projects
Commit 6d9158bb authored by michael.minelli's avatar michael.minelli
Browse files

Update script with usage of shared functions

parent f37f50f0
No related branches found
No related tags found
No related merge requests found
Pipeline #25780 canceled
......@@ -4,20 +4,23 @@ const path = require('node:path');
require('dotenv').config({ path: path.join(__dirname, '../.env') });
require('./shared/helpers/TypeScriptExtensions'); // ATTENTION : This line MUST be the second of this file
import Styles from './types/Styles';
import Icon from './types/Icon';
import boxen from 'boxen';
import ClientsSharedConfig from './sharedByClients/config/ClientsSharedConfig';
import Styles from './types/Style';
import Icon from './sharedByClients/types/Icon';
import RecursiveFilesStats from './shared/helpers/recursiveFilesStats/RecursiveFilesStats';
import Toolbox from './shared/helpers/Toolbox';
import ExerciceHelper from './shared/helpers/ExerciceHelper';
import ExerciceCheckerError from './types/ExerciceCheckerError';
import { exec, spawn } from 'child_process';
import ExerciceCheckerError from './shared/types/Dojo/ExerciceCheckerError';
import { exec } from 'child_process';
import util from 'util';
import fs from 'fs-extra';
import HttpManager from './managers/HttpManager';
import DojoBackendManager from './managers/DojoBackendManager';
import Config from './config/Config';
import ArchiveHelper from './shared/helpers/ArchiveHelper';
import ExerciceDockerCompose from './sharedByClients/helpers/Dojo/ExerciceDockerCompose';
import ExerciceResultsValidation from './sharedByClients/helpers/Dojo/ExerciceResultsValidation';
import ExerciceEnonce from './sharedByClients/models/ExerciceEnonce';
import ClientsSharedExerciceHelper from './sharedByClients/helpers/Dojo/ClientsSharedExerciceHelper';
(async () => {
......@@ -27,13 +30,18 @@ import ArchiveHelper from './shared/helpers/ArchiveHelper';
console.log(Styles.APP_NAME(Config.appName));
let exerciceEnonce: ExerciceEnonce | undefined;
let exerciceDockerCompose: ExerciceDockerCompose;
let exerciceResultsValidation: ExerciceResultsValidation;
/*
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 1 & 2:
- Read the dojo enonce file from the enonce repository
- Download immutables files (maybe throw or show an error if the files have been modified ?)
*/
{
console.log(Styles.INFO(`${ Icon.INFO }️ Checking the exercice's enonce and his immutable files`));
const exerciceEnonce = await DojoBackendManager.getExerciceEnonce();
exerciceEnonce = await DojoBackendManager.getExerciceEnonce();
if ( !exerciceEnonce ) {
console.error(Styles.ERROR(`${ Icon.ERROR } Error while getting the exercice's enonce`));
process.exit(ExerciceCheckerError.EXERCICE_ENONCE_GET_ERROR);
......@@ -44,6 +52,7 @@ import ArchiveHelper from './shared/helpers/ArchiveHelper';
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, immutableFile.content, { encoding: 'base64' });
});
}
/*
......@@ -52,85 +61,75 @@ import ArchiveHelper from './shared/helpers/ArchiveHelper';
- Run docker-compose file
- Get logs from linked services
*/
console.log(Styles.INFO(`${ Icon.INFO } Run docker compose file`));
const dockerComposeOverride = fs.readFileSync(path.join(__dirname, '../assets/docker-compose-override.yml'), 'utf8').replace('{{VOLUME_NAME}}', exerciceEnonce.enonceFile.result.volume).replace('{{MOUNT_PATH}}', Config.folders.resultsExercice);
fs.writeFileSync(`${ Config.folders.project }/docker-compose-override.yml`, dockerComposeOverride);
const changeDirectoryCommand = `cd "${ Config.folders.project }"`;
const dockerComposeCommand = `docker compose --project-name ${ Config.dockerCompose.projectName } --progress plain --file docker-compose.yml --file docker-compose-override.yml`;
const containerExitStatus = await new Promise<[ number, string ]>((resolve) => {
let logs = '####################################################### Docker Compose & Main Container Logs #######################################################\n';
const dockerCompose = spawn(`${ dockerComposeCommand } run --build ${ exerciceEnonce.enonceFile.result.container }`, {
cwd : Config.folders.project,
shell: true,
env : {
'DOCKER_BUILDKIT' : '1',
'BUILDKIT_PROGRESS': 'plain', ...process.env
}
});
{
const composeOverridePath: string = path.join(Config.folders.project, 'docker-compose-override.yml');
dockerCompose.stdout.on('data', (data) => {
logs += data.toString();
console.log(data.toString());
const composeOverride = fs.readFileSync(path.join(__dirname, '../assets/docker-compose-override.yml'), 'utf8').replace('{{VOLUME_NAME}}', exerciceEnonce.enonceFile.result.volume).replace('{{MOUNT_PATH}}', Config.folders.resultsExercice);
fs.writeFileSync(composeOverridePath, composeOverride);
exerciceDockerCompose = new ExerciceDockerCompose(ClientsSharedConfig.dockerCompose.projectName, exerciceEnonce.enonceFile, Config.folders.project, [ composeOverridePath ]);
try {
await new Promise<void>((resolve, reject) => {
exerciceDockerCompose.events.on('step', (name: string, message: string) => {
console.log(Styles.INFO(`${ Icon.INFO } ${ message }`));
});
dockerCompose.stderr.on('data', (data) => {
logs += data.toString();
console.error(data.toString());
exerciceDockerCompose.events.on('endStep', (stepName: string, message: string, error: boolean) => {
if ( error ) {
console.error(Styles.ERROR(`${ Icon.ERROR } ${ message }`));
}
});
dockerCompose.on('exit', (code) => {
logs += '####################################################### Other Services Logs #######################################################\n';
resolve([ code ?? ExerciceCheckerError.DOCKER_COMPOSE_UP_ERROR, logs ]);
exerciceDockerCompose.events.on('finished', (success: boolean, exitCode: number) => {
success ? resolve() : reject();
});
exerciceDockerCompose.run();
});
const containerExitCode = containerExitStatus[0];
if ( containerExitCode === ExerciceCheckerError.DOCKER_COMPOSE_UP_ERROR ) {
console.error(Styles.ERROR(`${ Icon.ERROR } Error while running the docker compose file`));
process.exit(containerExitCode);
}
fs.writeFileSync(`${ Config.folders.resultsDojo }/dockerComposeLogs.txt`, containerExitStatus[1]);
} catch ( error ) { }
console.log(Styles.INFO(`${ Icon.INFO } Acquire logs of linked services`));
try {
await execAsync(`${ changeDirectoryCommand };${ dockerComposeCommand } logs --timestamps >> ${ Config.folders.resultsDojo }/dockerComposeLogs.txt`);
} catch ( error ) {
console.error(Styles.ERROR(`${ Icon.ERROR } Error while getting the linked services logs`));
process.exit(ExerciceCheckerError.DOCKER_COMPOSE_LOGS_ERROR);
fs.rmSync(composeOverridePath);
fs.writeFileSync(path.join(Config.folders.resultsDojo, 'dockerComposeLogs.txt'), exerciceDockerCompose.allLogs);
if ( !exerciceDockerCompose.success ) {
process.exit(exerciceDockerCompose.exitCode);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 6: Check content requirements and content size
console.log(Styles.INFO(`${ Icon.INFO } Validating results folder size`));
const resultsFolderSize = await Toolbox.fs.getTotalSize(Config.folders.resultsExercice);
if ( resultsFolderSize > Config.resultsFolderMaxSizeInBytes ) {
console.error(Styles.ERROR(`${ Icon.ERROR } Results folder size is too big (bigger than ${ Config.resultsFolderMaxSizeInBytes / 1000000 })`));
process.exit(ExerciceCheckerError.EXERCICE_RESULTS_FOLDER_TOO_BIG);
}
{
exerciceResultsValidation = new ExerciceResultsValidation(Config.folders.resultsDojo, Config.folders.resultsExercice);
console.log(Styles.INFO(`${ Icon.INFO } Checking results file`));
const resultsFileOriginPath = path.join(Config.folders.resultsExercice, Config.filenames.results);
const resultsFilePath = path.join(Config.folders.resultsDojo, Config.filenames.results);
try {
await new Promise<void>((resolve) => {
exerciceResultsValidation.events.on('step', (name: string, message: string) => {
console.log(Styles.INFO(`${ Icon.INFO } ${ message }`));
});
if ( !fs.existsSync(resultsFileOriginPath) ) {
console.error(Styles.ERROR(`${ Icon.ERROR } Results file not found.`));
process.exit(ExerciceCheckerError.EXERCICE_RESULTS_FILE_NOT_FOUND);
exerciceResultsValidation.events.on('endStep', (stepName: string, message: string, error: boolean) => {
if ( error ) {
console.error(Styles.ERROR(`${ Icon.ERROR } ${ message }`));
}
});
fs.moveSync(resultsFileOriginPath, resultsFilePath, { overwrite: true });
exerciceResultsValidation.events.on('finished', (success: boolean, exitCode: number) => {
if ( !success ) {
process.exit(exitCode);
}
const validationResults = ExerciceHelper.validateResultFile(resultsFilePath);
resolve();
});
if ( !validationResults.isValid ) {
console.error(Styles.ERROR(`${ Icon.ERROR } Results file is not valid. Here are the errors :`));
console.error(Styles.ERROR(JSON.stringify(validationResults.errors)));
process.exit(ExerciceCheckerError.EXERCICE_RESULTS_FILE_SCHEMA_NOT_VALID);
exerciceResultsValidation.run();
});
} catch ( error ) { }
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 7: Upload and show the results
{
try {
console.log(Styles.INFO(`${ Icon.INFO } Uploading results to the dojo server`));
const commit: any = {};
......@@ -143,34 +142,20 @@ import ArchiveHelper from './shared/helpers/ArchiveHelper';
liteStats : true
});
await DojoBackendManager.sendResults(containerExitCode, commit, validationResults.results!, files, await ArchiveHelper.getBase64(Config.folders.resultsVolume));
await DojoBackendManager.sendResults(exerciceDockerCompose.exitCode, commit, exerciceResultsValidation.exerciceResults!, files, await ArchiveHelper.getBase64(Config.folders.resultsVolume));
} catch ( error ) {
console.error(Styles.ERROR(`${ Icon.ERROR } Error while uploading the results`));
console.error(JSON.stringify(error));
process.exit(ExerciceCheckerError.UPLOAD);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 8: Exit with container exit code
const finalLogGlobalResult = `${ Styles.INFO('Global result') } : ${ validationResults.results!.success ? Styles.SUCCESS(`${ Icon.SUCCESS } Success`) : Styles.FAILURE(`${ Icon.FAILURE } Failure`) }`;
const finalLogExecutionExitCode = `${ Styles.INFO('Execution exit code') } : ${ (containerExitCode == 0 ? Styles.SUCCESS : Styles.ERROR)(containerExitCode) }`;
const finalLogResultNumbers = validationResults.results!.successfulTests || validationResults.results!.failedTests ? `\n\n${ Styles.SUCCESS('Tests passed') } : ${ validationResults.results!.successfulTests ?? '--' }\n${ Styles.ERROR('Tests failed') } : ${ validationResults.results!.failedTests ?? '--' }` : '';
const finalLogSuccessResultDetails = (validationResults.results!.successfulTestsList ?? []).map(testName => `- ${ Icon.SUCCESS } ${ testName }`).join('\n');
const finalLogFailedResultDetails = (validationResults.results!.failedTestsList ?? []).map(testName => `- ${ Icon.FAILURE } ${ testName }`).join('\n');
const finalLogResultDetails = validationResults.results!.successfulTestsList || validationResults.results!.failedTestsList ? `\n\n${ Styles.INFO('Tests') } :${ finalLogSuccessResultDetails != '' ? '\n' + finalLogSuccessResultDetails : '' }${ finalLogFailedResultDetails != '' ? '\n' + finalLogFailedResultDetails : '' }` : '';
{
ClientsSharedExerciceHelper.displayExecutionResults(exerciceResultsValidation.exerciceResults!, exerciceDockerCompose.exitCode, Styles);
}
console.log(boxen(`${ finalLogGlobalResult }\n\n${ finalLogExecutionExitCode }${ finalLogResultNumbers }${ finalLogResultDetails }`, {
title : 'Results',
titleAlignment: 'center',
borderColor : 'yellow',
borderStyle : 'bold',
margin : 1,
padding : 1,
textAlignment : 'left'
}));
process.exit(containerExitCode);
process.exit(exerciceDockerCompose.exitCode);
})();
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment