Skip to content
Snippets Groups Projects
Select Git revision
  • febfc3f86f4b9ea9b3e42a3ceff66cf8d7b6c86b
  • main default protected
2 results

cours_7.md

Blame
  • app.ts 7.78 KiB
    // Read from the .env file
    // ATTENTION : This lines MUST be the first of this file (except for the path import)
    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 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 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 () => {
        const execAsync = util.promisify(exec);
    
        HttpManager.registerAxiosInterceptor();
    
        console.log(Styles.APP_NAME(Config.appName));
    
        let exerciceEnonce: ExerciceEnonce | undefined;
        let exerciceDockerCompose: ExerciceDockerCompose;
        let exerciceResultsValidation: ExerciceResultsValidation;
    
        /*
         //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 1:
         -   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`));
            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);
            }
    
            exerciceEnonce.immutable.forEach(immutableFile => {
                const filePath = path.join(Config.folders.project, immutableFile.file_path);
                fs.mkdirSync(path.dirname(filePath), { recursive: true });
                fs.writeFileSync(filePath, immutableFile.content, { encoding: 'base64' });
            });
        }
    
    
        /*
         //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 2:
         - Get override of docker-compose file (for override the volume by a bind mount to the results folder shared between dind and the host)
         - Run docker-compose file
         - Get logs from linked services
         */
        {
            const composeOverridePath: string = path.join(Config.folders.project, 'docker-compose-override.yml');
    
            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 }`));
                    });
    
                    exerciceDockerCompose.events.on('endStep', (stepName: string, message: string, error: boolean) => {
                        if ( error ) {
                            console.error(Styles.ERROR(`${ Icon.ERROR } ${ message }`));
                        }
                    });
    
                    exerciceDockerCompose.events.on('finished', (success: boolean, exitCode: number) => {
                        success ? resolve() : reject();
                    });
    
                    exerciceDockerCompose.run();
                });
            } catch ( error ) { }
    
            fs.rmSync(composeOverridePath);
            fs.writeFileSync(path.join(Config.folders.resultsDojo, 'dockerComposeLogs.txt'), exerciceDockerCompose.allLogs);
    
            if ( !exerciceDockerCompose.success ) {
                console.error(Styles.ERROR(`${ Icon.ERROR } Execution logs are available in artifacts`));
                process.exit(exerciceDockerCompose.exitCode);
            }
        }
    
    
        //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 3: Check content requirements and content size
        {
            exerciceResultsValidation = new ExerciceResultsValidation(Config.folders.resultsDojo, Config.folders.resultsExercice);
    
            try {
                await new Promise<void>((resolve) => {
                    exerciceResultsValidation.events.on('step', (name: string, message: string) => {
                        console.log(Styles.INFO(`${ Icon.INFO } ${ message }`));
                    });
    
                    exerciceResultsValidation.events.on('endStep', (stepName: string, message: string, error: boolean) => {
                        if ( error ) {
                            console.error(Styles.ERROR(`${ Icon.ERROR } ${ message }`));
                        }
                    });
    
                    exerciceResultsValidation.events.on('finished', (success: boolean, exitCode: number) => {
                        if ( !success ) {
                            process.exit(exitCode);
                        }
    
                        resolve();
                    });
    
                    exerciceResultsValidation.run();
                });
            } catch ( error ) { }
        }
    
    
        //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 4: Upload results
        {
            try {
                console.log(Styles.INFO(`${ Icon.INFO } Uploading results to the dojo server`));
                const commit: any = {};
                Toolbox.getKeysWithPrefix(process.env, 'CI_COMMIT_').forEach(key => {
                    commit[Toolbox.snakeToCamel(key.replace('CI_COMMIT_', ''))] = process.env[key];
                });
    
                const files = await RecursiveFilesStats.explore(Config.folders.resultsVolume, {
                    replacePathByRelativeOne: true,
                    liteStats               : true
                });
    
                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 5:
         - Display results
         - Exit with container exit code
         */
        {
            ClientsSharedExerciceHelper.displayExecutionResults(exerciceResultsValidation.exerciceResults!, exerciceDockerCompose.exitCode, Styles, `\n\n${ Icon.INFO }️ More detailed logs and resources may be available in artifacts`);
    
            process.exit(exerciceDockerCompose.exitCode);
        }
    })();