From dd1de8405e50b7e26b70b5676ee303ac71c56dd0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C3=ABl=20Minelli?= <michael@minelli.me>
Date: Thu, 10 Aug 2023 01:01:37 +0200
Subject: [PATCH] Add icon and styles provided by types (remove code
 duplicates)

---
 ExerciceChecker/src/app.ts           | 63 +++++++++++++---------------
 ExerciceChecker/src/config/Config.ts |  4 ++
 ExerciceChecker/src/types/Icon.ts    |  9 ++++
 ExerciceChecker/src/types/Styles.ts  | 13 ++++++
 4 files changed, 55 insertions(+), 34 deletions(-)
 create mode 100644 ExerciceChecker/src/types/Icon.ts
 create mode 100644 ExerciceChecker/src/types/Styles.ts

diff --git a/ExerciceChecker/src/app.ts b/ExerciceChecker/src/app.ts
index 8a3695a..afc0cb6 100644
--- a/ExerciceChecker/src/app.ts
+++ b/ExerciceChecker/src/app.ts
@@ -4,6 +4,8 @@ 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 RecursiveFilesStats  from './shared/helpers/recursiveFilesStats/RecursiveFilesStats';
 import Toolbox              from './shared/helpers/Toolbox';
@@ -12,7 +14,6 @@ import ExerciceCheckerError from './types/ExerciceCheckerError';
 import { exec, spawn }      from 'child_process';
 import util                 from 'util';
 import fs                   from 'fs-extra';
-import chalk                from 'chalk';
 import HttpManager          from './managers/HttpManager';
 import DojoBackendManager   from './managers/DojoBackendManager';
 import Config               from './config/Config';
@@ -24,22 +25,17 @@ import ArchiveHelper        from './shared/helpers/ArchiveHelper';
 
     HttpManager.registerAxiosInterceptor();
 
-    const chalkInfo: chalk.Chalk = chalk.blue;
-    const chalkError: chalk.Chalk = chalk.red;
-    const chalkSuccess: chalk.Chalk = chalk.green;
-    const chalkFailure: chalk.Chalk = chalk.red;
-
-    console.log(chalk.bgBlue.black.bold('DOJO EXERCICE CHECKER'));
+    console.log(Styles.APP_NAME(Config.appName));
 
     /*
-     Step 1 & 2:
+     //////////////////////////////////////////////////////////////////////////////////////////////////////////// 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(chalkInfo(`- Checking the exercice's enonce and his immutable files`));
+    console.log(Styles.INFO(`${ Icon.INFO }️ Checking the exercice's enonce and his immutable files`));
     const exerciceEnonce = await DojoBackendManager.getExerciceEnonce();
     if ( !exerciceEnonce ) {
-        console.error(chalkError(`X Error while getting the exercice's enonce`));
+        console.error(Styles.ERROR(`${ Icon.ERROR } Error while getting the exercice's enonce`));
         process.exit(ExerciceCheckerError.EXERCICE_ENONCE_GET_ERROR);
     }
 
@@ -51,12 +47,12 @@ import ArchiveHelper        from './shared/helpers/ArchiveHelper';
 
 
     /*
-     Step 3 & 4 & 5:
+     //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 3 & 4 & 5:
      - 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
      */
-    console.log(chalkInfo('- Run docker compose file'));
+    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);
 
@@ -92,34 +88,34 @@ import ArchiveHelper        from './shared/helpers/ArchiveHelper';
     });
     const containerExitCode = containerExitStatus[0];
     if ( containerExitCode === ExerciceCheckerError.DOCKER_COMPOSE_UP_ERROR ) {
-        console.error(chalkError(`X Error while running the docker compose file`));
+        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]);
 
-    console.log(chalkInfo('- Acquire logs of linked services'));
+    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(chalkError(`X Error while getting the linked services logs`));
+        console.error(Styles.ERROR(`${ Icon.ERROR } Error while getting the linked services logs`));
         process.exit(ExerciceCheckerError.DOCKER_COMPOSE_LOGS_ERROR);
     }
 
 
-    // Step 6: Check content requirements and content size
-    console.log(chalkInfo('- Validating results folder size'));
+    //////////////////////////////////////////////////////////////////////////////////////////////////////////// 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(chalkError(`X Results folder size is too big (bigger than ${ Config.resultsFolderMaxSizeInBytes / 1000000 })`));
+        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);
     }
 
-    console.log(chalkInfo('- Checking results file'));
+    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);
 
     if ( !fs.existsSync(resultsFileOriginPath) ) {
-        console.error(chalkError(`X Results file not found.`));
+        console.error(Styles.ERROR(`${ Icon.ERROR } Results file not found.`));
         process.exit(ExerciceCheckerError.EXERCICE_RESULTS_FILE_NOT_FOUND);
     }
 
@@ -128,15 +124,15 @@ import ArchiveHelper        from './shared/helpers/ArchiveHelper';
     const validationResults = ExerciceHelper.validateResultFile(resultsFilePath);
 
     if ( !validationResults.isValid ) {
-        console.error(chalkError(`X Results file is not valid. Here are the errors :`));
-        console.error(chalkError(JSON.stringify(validationResults.errors)));
+        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);
     }
 
 
-    // Step 7: Upload and show the results
+    //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 7: Upload and show the results
     try {
-        console.log(chalkInfo(`- Uploading results to the dojo server`));
+        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];
@@ -149,22 +145,22 @@ import ArchiveHelper        from './shared/helpers/ArchiveHelper';
 
         await DojoBackendManager.sendResults(containerExitCode, commit, validationResults.results!, files, await ArchiveHelper.getBase64(Config.folders.resultsVolume));
     } catch ( error ) {
-        console.error(chalkError(`X Error while uploading the results`));
+        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 = `${ chalkInfo('Global result') } : ${ validationResults.results!.success ? chalkSuccess('✅ Success') : chalkFailure('❌ Failure') }`;
+    //////////////////////////////////////////////////////////////////////////////////////////////////////////// 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 = `${ chalkInfo('Execution exit code') } : ${ (containerExitCode == 0 ? chalkSuccess : chalkError)(containerExitCode) }`;
+    const finalLogExecutionExitCode = `${ Styles.INFO('Execution exit code') } : ${ (containerExitCode == 0 ? Styles.SUCCESS : Styles.ERROR)(containerExitCode) }`;
 
-    const finalLogResultNumbers = validationResults.results!.successfulTests || validationResults.results!.failedTests ? `\n\n${ chalkSuccess('Tests passed') } : ${ validationResults.results!.successfulTests ?? '--' }\n${ chalkError('Tests failed') } : ${ validationResults.results!.failedTests ?? '--' }` : '';
+    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 => `- ✅ ${ testName }`).join('\n');
-    const finalLogFailedResultDetails = (validationResults.results!.failedTestsList ?? []).map(testName => `- ❌ ${ testName }`).join('\n');
-    const finalLogResultDetails = validationResults.results!.successfulTestsList || validationResults.results!.failedTestsList ? `\n\n${ chalkInfo('Tests') } :${ finalLogSuccessResultDetails != '' ? '\n' + finalLogSuccessResultDetails : '' }${ finalLogFailedResultDetails != '' ? '\n' + finalLogFailedResultDetails : '' }` : '';
+    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 : '' }` : '';
 
     console.log(boxen(`${ finalLogGlobalResult }\n\n${ finalLogExecutionExitCode }${ finalLogResultNumbers }${ finalLogResultDetails }`, {
         title         : 'Results',
@@ -177,5 +173,4 @@ import ArchiveHelper        from './shared/helpers/ArchiveHelper';
     }));
 
     process.exit(containerExitCode);
-})();
-
+})();
\ No newline at end of file
diff --git a/ExerciceChecker/src/config/Config.ts b/ExerciceChecker/src/config/Config.ts
index 2b47064..6782c14 100644
--- a/ExerciceChecker/src/config/Config.ts
+++ b/ExerciceChecker/src/config/Config.ts
@@ -3,6 +3,8 @@ import path from 'path';
 
 
 class Config {
+    public readonly appName: string;
+
     public readonly resultsFolderMaxSizeInBytes: number;
 
     public readonly folders: {
@@ -22,6 +24,8 @@ class Config {
     };
 
     constructor() {
+        this.appName = process.env.APP_NAME || '';
+
         this.resultsFolderMaxSizeInBytes = Number(process.env.RESULTS_FOLDER_MAX_SIZE_IN_BYTES || 0);
 
         this.folders = {
diff --git a/ExerciceChecker/src/types/Icon.ts b/ExerciceChecker/src/types/Icon.ts
new file mode 100644
index 0000000..9d5a0ec
--- /dev/null
+++ b/ExerciceChecker/src/types/Icon.ts
@@ -0,0 +1,9 @@
+enum Icon {
+    INFO    = 'ℹ️',
+    ERROR   = '⛔️',
+    SUCCESS = '✅',
+    FAILURE = '❌'
+}
+
+
+export default Icon;
\ No newline at end of file
diff --git a/ExerciceChecker/src/types/Styles.ts b/ExerciceChecker/src/types/Styles.ts
new file mode 100644
index 0000000..64f6bdd
--- /dev/null
+++ b/ExerciceChecker/src/types/Styles.ts
@@ -0,0 +1,13 @@
+import chalk from 'chalk';
+
+
+class Styles {
+    public readonly APP_NAME = chalk.bgBlue.black.bold;
+    public readonly INFO = chalk.blue;
+    public readonly ERROR = chalk.red;
+    public readonly SUCCESS = chalk.green;
+    public readonly FAILURE = chalk.red;
+}
+
+
+export default new Styles();
\ No newline at end of file
-- 
GitLab