Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • ask-user-to-delete-exercises-on-duplicates
  • jw_sonar
  • jw_sonar_backup
  • main
  • move-to-esm-only
  • open_tool_for_self_hosting
  • v5.0
  • v6.0
  • v4.1
  • v4.2
10 results

Target

Select target project
  • dojo_project/projects/shared/nodeclientsharedcode
1 result
Select Git revision
  • ask-user-to-delete-exercises-on-duplicates
  • jw_sonar
  • jw_sonar_backup
  • main
  • move-to-esm-only
  • open_tool_for_self_hosting
  • v5.0
  • v6.0
  • v4.1
  • v4.2
10 results
Show changes
Commits on Source (1)
......@@ -10,7 +10,7 @@ class ClientsSharedConfig {
projectName: string
};
public readonly exerciceResultsFolderMaxSizeInBytes: number;
public readonly exerciseResultsFolderMaxSizeInBytes: number;
public readonly filenames: {
results: string;
......@@ -32,10 +32,10 @@ class ClientsSharedConfig {
projectName: process.env.DOCKER_COMPOSE_PROJECT_NAME || ''
};
this.exerciceResultsFolderMaxSizeInBytes = Number(process.env.EXERCICE_RESULTS_FOLDER_MAX_SIZE_IN_BYTES || 0);
this.exerciseResultsFolderMaxSizeInBytes = Number(process.env.EXERCISE_RESULTS_FOLDER_MAX_SIZE_IN_BYTES || 0);
this.filenames = {
results: process.env.EXERCICE_RESULTS_FILENAME || ''
results: process.env.EXERCISE_RESULTS_FILENAME || ''
};
}
}
......
import ExerciceResultsFile from '../../../shared/types/Dojo/ExerciceResultsFile';
import ExerciseResultsFile from '../../../shared/types/Dojo/ExerciseResultsFile';
import chalk from 'chalk';
import boxen from 'boxen';
import Icon from '../../types/Icon';
class ClientsSharedExerciceHelper {
displayExecutionResults(exerciceResults: ExerciceResultsFile, containerExitCode: number, Style: { INFO: chalk.Chalk, SUCCESS: chalk.Chalk, FAILURE: chalk.Chalk }, additionalText: string = '') {
const finalLogGlobalResult = `${ Style.INFO('Global result') } : ${ exerciceResults.success ? Style.SUCCESS(`${ Icon.SUCCESS } Success`) : Style.FAILURE(`${ Icon.FAILURE } Failure`) }`;
class ClientsSharedExerciseHelper {
displayExecutionResults(exerciseResults: ExerciseResultsFile, containerExitCode: number, Style: { INFO: chalk.Chalk, SUCCESS: chalk.Chalk, FAILURE: chalk.Chalk }, additionalText: string = '') {
const finalLogGlobalResult = `${ Style.INFO('Global result') } : ${ exerciseResults.success ? Style.SUCCESS(`${ Icon.SUCCESS } Success`) : Style.FAILURE(`${ Icon.FAILURE } Failure`) }`;
const finalLogExecutionExitCode = `${ Style.INFO('Execution exit code') } : ${ (containerExitCode == 0 ? Style.SUCCESS : Style.FAILURE)(containerExitCode) }`;
const finalLogResultNumbers = exerciceResults.successfulTests || exerciceResults.failedTests ? `\n\n${ Style.SUCCESS('Tests passed') } : ${ exerciceResults.successfulTests ?? '--' }\n${ Style.FAILURE('Tests failed') } : ${ exerciceResults.failedTests ?? '--' }` : '';
const finalLogResultNumbers = exerciseResults.successfulTests || exerciseResults.failedTests ? `\n\n${ Style.SUCCESS('Tests passed') } : ${ exerciseResults.successfulTests ?? '--' }\n${ Style.FAILURE('Tests failed') } : ${ exerciseResults.failedTests ?? '--' }` : '';
const finalLogSuccessResultDetails = (exerciceResults.successfulTestsList ?? []).map(testName => `- ${ Icon.SUCCESS } ${ testName }`).join('\n');
const finalLogFailedResultDetails = (exerciceResults.failedTestsList ?? []).map(testName => `- ${ Icon.FAILURE } ${ testName }`).join('\n');
const finalLogResultDetails = exerciceResults.successfulTestsList || exerciceResults.failedTestsList ? `\n\n${ Style.INFO('Tests') } :${ finalLogSuccessResultDetails != '' ? '\n' + finalLogSuccessResultDetails : '' }${ finalLogFailedResultDetails != '' ? '\n' + finalLogFailedResultDetails : '' }` : '';
const finalLogSuccessResultDetails = (exerciseResults.successfulTestsList ?? []).map(testName => `- ${ Icon.SUCCESS } ${ testName }`).join('\n');
const finalLogFailedResultDetails = (exerciseResults.failedTestsList ?? []).map(testName => `- ${ Icon.FAILURE } ${ testName }`).join('\n');
const finalLogResultDetails = exerciseResults.successfulTestsList || exerciseResults.failedTestsList ? `\n\n${ Style.INFO('Tests') } :${ finalLogSuccessResultDetails != '' ? '\n' + finalLogSuccessResultDetails : '' }${ finalLogFailedResultDetails != '' ? '\n' + finalLogFailedResultDetails : '' }` : '';
console.log(boxen(`${ finalLogGlobalResult }\n\n${ finalLogExecutionExitCode }${ finalLogResultNumbers }${ finalLogResultDetails }${ additionalText }`, {
title : 'Results',
......@@ -29,4 +29,4 @@ class ClientsSharedExerciceHelper {
}
export default new ClientsSharedExerciceHelper();
\ No newline at end of file
export default new ClientsSharedExerciseHelper();
\ No newline at end of file
import EnonceFile from '../../../shared/types/Dojo/EnonceFile';
import AssignmentFile from '../../../shared/types/Dojo/AssignmentFile';
import { TypedEmitter } from 'tiny-typed-emitter';
import ExerciceRunningEvents from '../../types/Dojo/ExerciceRunningEvents';
import ExerciseRunningEvents from '../../types/Dojo/ExerciseRunningEvents';
import { spawn } from 'child_process';
import ExerciceCheckerError from '../../../shared/types/Dojo/ExerciceCheckerError';
import ExerciseCheckerError from '../../../shared/types/Dojo/ExerciseCheckerError';
class ExerciceDockerCompose {
readonly events: TypedEmitter<ExerciceRunningEvents> = new TypedEmitter<ExerciceRunningEvents>();
class ExerciseDockerCompose {
readonly events: TypedEmitter<ExerciseRunningEvents> = new TypedEmitter<ExerciseRunningEvents>();
public displayableLogs: string = '';
public allLogs: string = '';
......@@ -15,7 +15,7 @@ class ExerciceDockerCompose {
public success: boolean = false;
public exitCode: number = -1;
constructor(private projectName: string, private enonceFile: EnonceFile, private executionFolder: string, private composeFileOverride: Array<string> = []) {
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;
this.displayableLogs += displayable ? log : '';
......@@ -43,7 +43,7 @@ class ExerciceDockerCompose {
this.events.emit('logs', '####################################################### Docker Compose & Main Container Logs #######################################################\n', false, false);
const dockerCompose = spawn(`${ dockerComposeCommand } run --build --rm ${ this.enonceFile.result.container }`, {
const dockerCompose = spawn(`${ dockerComposeCommand } run --build --rm ${ this.assignmentFile.result.container }`, {
cwd : this.executionFolder,
shell: true,
env : {
......@@ -66,7 +66,7 @@ class ExerciceDockerCompose {
});
} catch ( error ) {
this.events.emit('endStep', 'COMPOSE_RUN', `Error while running the docker compose file`, true);
this.events.emit('finished', false, ExerciceCheckerError.DOCKER_COMPOSE_RUN_ERROR);
this.events.emit('finished', false, ExerciseCheckerError.DOCKER_COMPOSE_RUN_ERROR);
return;
}
this.events.emit('endStep', 'COMPOSE_RUN', `Docker Compose file run successfully`, false);
......@@ -100,7 +100,7 @@ class ExerciceDockerCompose {
});
} catch ( error ) {
this.events.emit('endStep', 'COMPOSE_LOGS', `Error while getting the linked services logs`, true);
this.events.emit('finished', false, ExerciceCheckerError.DOCKER_COMPOSE_LOGS_ERROR);
this.events.emit('finished', false, ExerciseCheckerError.DOCKER_COMPOSE_LOGS_ERROR);
return;
}
this.events.emit('endStep', 'COMPOSE_LOGS', `Linked services logs acquired`, false);
......@@ -135,7 +135,7 @@ class ExerciceDockerCompose {
});
} catch ( error ) {
this.events.emit('endStep', 'COMPOSE_DOWN', `Error stop and remove containers`, true);
this.events.emit('finished', false, ExerciceCheckerError.DOCKER_COMPOSE_DOWN_ERROR);
this.events.emit('finished', false, ExerciseCheckerError.DOCKER_COMPOSE_DOWN_ERROR);
return;
}
this.events.emit('endStep', 'COMPOSE_DOWN', `Containers stopped and removed`, false);
......@@ -148,4 +148,4 @@ class ExerciceDockerCompose {
}
export default ExerciceDockerCompose;
\ No newline at end of file
export default ExerciseDockerCompose;
\ No newline at end of file
import { TypedEmitter } from 'tiny-typed-emitter';
import ExerciceRunningEvents from '../../types/Dojo/ExerciceRunningEvents';
import ExerciceCheckerError from '../../../shared/types/Dojo/ExerciceCheckerError';
import ExerciseRunningEvents from '../../types/Dojo/ExerciseRunningEvents';
import ExerciseCheckerError from '../../../shared/types/Dojo/ExerciseCheckerError';
import path from 'node:path';
import SharedExerciceHelper from '../../../shared/helpers/Dojo/SharedExerciceHelper';
import SharedExerciseHelper from '../../../shared/helpers/Dojo/SharedExerciseHelper';
import ClientsSharedConfig from '../../config/ClientsSharedConfig';
import Toolbox from '../../../shared/helpers/Toolbox';
import * as fs from 'fs-extra';
import ExerciceResultsFile from '../../../shared/types/Dojo/ExerciceResultsFile';
import ExerciseResultsFile from '../../../shared/types/Dojo/ExerciseResultsFile';
class ExerciceResultsValidation {
readonly events: TypedEmitter<ExerciceRunningEvents> = new TypedEmitter<ExerciceRunningEvents>();
class ExerciseResultsValidation {
readonly events: TypedEmitter<ExerciseRunningEvents> = new TypedEmitter<ExerciseRunningEvents>();
public exerciceResults: ExerciceResultsFile | undefined = undefined;
public exerciseResults: ExerciseResultsFile | undefined = undefined;
constructor(private folderResultsDojo: string, private folderResultsExercice: string) { }
constructor(private folderResultsDojo: string, private folderResultsExercise: string) { }
run() {
(async () => {
......@@ -24,12 +24,12 @@ class ExerciceResultsValidation {
// Results file existence
{
this.events.emit('step', 'CHECK_RESULTS_FILE_EXIST', 'Checking if results file exists');
const resultsFileOriginPath = path.join(this.folderResultsExercice, ClientsSharedConfig.filenames.results);
const resultsFileOriginPath = path.join(this.folderResultsExercise, ClientsSharedConfig.filenames.results);
resultsFilePath = path.join(this.folderResultsDojo, ClientsSharedConfig.filenames.results);
if ( !fs.existsSync(resultsFileOriginPath) ) {
this.events.emit('endStep', 'CHECK_RESULTS_FILE_EXIST', `Results file not found`, true);
this.events.emit('finished', false, ExerciceCheckerError.EXERCICE_RESULTS_FILE_NOT_FOUND);
this.events.emit('finished', false, ExerciseCheckerError.EXERCISE_RESULTS_FILE_NOT_FOUND);
return;
}
this.events.emit('endStep', 'CHECK_RESULTS_FILE_EXIST', 'Results file found', false);
......@@ -41,13 +41,13 @@ class ExerciceResultsValidation {
// Results file schema validation
{
this.events.emit('step', 'VALIDATE_RESULTS_FILE', 'Validating results file schema');
const validationResults = SharedExerciceHelper.validateResultFile(resultsFilePath);
const validationResults = SharedExerciseHelper.validateResultFile(resultsFilePath);
if ( !validationResults.isValid ) {
this.events.emit('endStep', 'VALIDATE_RESULTS_FILE', `Results file is not valid. Here are the errors :\n${ JSON.stringify(validationResults.errors) }`, true);
this.events.emit('finished', false, ExerciceCheckerError.EXERCICE_RESULTS_FILE_SCHEMA_NOT_VALID);
this.events.emit('finished', false, ExerciseCheckerError.EXERCISE_RESULTS_FILE_SCHEMA_NOT_VALID);
return;
}
this.exerciceResults = validationResults.results;
this.exerciseResults = validationResults.results;
this.events.emit('endStep', 'VALIDATE_RESULTS_FILE', 'Results file is valid', false);
}
......@@ -56,10 +56,10 @@ class ExerciceResultsValidation {
// ATTENTION: This test is at the end because even if it fail the local execution will continue and we need the other test above to be done
{
this.events.emit('step', 'CHECK_SIZE', 'Validating results folder size');
const resultsFolderSize = await Toolbox.fs.getTotalSize(this.folderResultsExercice);
if ( resultsFolderSize > ClientsSharedConfig.exerciceResultsFolderMaxSizeInBytes ) {
this.events.emit('endStep', 'CHECK_SIZE', `Results folder size is too big (bigger than ${ ClientsSharedConfig.exerciceResultsFolderMaxSizeInBytes / 1000000 } MB)`, true);
this.events.emit('finished', false, ExerciceCheckerError.EXERCICE_RESULTS_FOLDER_TOO_BIG);
const resultsFolderSize = await Toolbox.fs.getTotalSize(this.folderResultsExercise);
if ( resultsFolderSize > ClientsSharedConfig.exerciseResultsFolderMaxSizeInBytes ) {
this.events.emit('endStep', 'CHECK_SIZE', `Results folder size is too big (bigger than ${ ClientsSharedConfig.exerciseResultsFolderMaxSizeInBytes / 1000000 } MB)`, true);
this.events.emit('finished', false, ExerciseCheckerError.EXERCISE_RESULTS_FOLDER_TOO_BIG);
return;
}
this.events.emit('endStep', 'CHECK_SIZE', 'Results folder size is in bounds', false);
......@@ -71,4 +71,4 @@ class ExerciceResultsValidation {
}
export default ExerciceResultsValidation;
\ No newline at end of file
export default ExerciseResultsValidation;
\ No newline at end of file
import GitlabRepository from '../../shared/types/Gitlab/GitlabRepository';
import User from './User';
import Exercice from './Exercice';
import Exercise from './Exercise';
interface Enonce {
interface Assignment {
name: string;
gitlabId: number;
gitlabLink: string;
......@@ -13,8 +13,8 @@ interface Enonce {
published: boolean;
staff: Array<User>;
exercices: Array<Exercice>;
exercises: Array<Exercise>;
}
export default Enonce;
\ No newline at end of file
export default Assignment;
\ No newline at end of file
import EnonceFile from '../../shared/types/Dojo/EnonceFile';
import Enonce from './Enonce';
import GitlabFile from '../../shared/types/Gitlab/GitlabFile';
interface ExerciceEnonce {
enonce: Enonce;
enonceFile: EnonceFile;
immutable: Array<GitlabFile>;
}
export default ExerciceEnonce;
\ No newline at end of file
import GitlabRepository from '../../shared/types/Gitlab/GitlabRepository';
interface Exercice {
interface Exercise {
id: string;
enonceName: string;
assignmentName: string;
name: string;
gitlabId: number;
gitlabLink: string;
......@@ -13,4 +13,4 @@ interface Exercice {
}
export default Exercice;
\ No newline at end of file
export default Exercise;
\ No newline at end of file
import AssignmentFile from '../../shared/types/Dojo/AssignmentFile';
import Assignment from './Assignment';
import GitlabFile from '../../shared/types/Gitlab/GitlabFile';
interface ExerciseAssignment {
assignment: Assignment;
assignmentFile: AssignmentFile;
immutable: Array<GitlabFile>;
}
export default ExerciseAssignment;
\ No newline at end of file
......@@ -2,13 +2,13 @@ enum ApiRoute {
LOGIN = '/login',
TEST_SESSION = '/test_session',
GITLAB_CHECK_TEMPLATE_ACCESS = '/gitlab/project/{{id}}/checkTemplateAccess',
ENONCE_GET = '/enonces/{{nameOrUrl}}',
ENONCE_CREATE = '/enonces',
ENONCE_PUBLISH = '/enonces/{{nameOrUrl}}/publish',
ENONCE_UNPUBLISH = '/enonces/{{nameOrUrl}}/unpublish',
EXERCICE_CREATE = '/enonces/{{nameOrUrl}}/exercices',
EXERCICE_ENONCE = '/exercices/{{id}}/enonce',
EXERCICE_RESULTS = '/exercices/{{id}}/results'
ASSIGNMENT_GET = '/assignments/{{nameOrUrl}}',
ASSIGNMENT_CREATE = '/assignments',
ASSIGNMENT_PUBLISH = '/assignments/{{nameOrUrl}}/publish',
ASSIGNMENT_UNPUBLISH = '/assignments/{{nameOrUrl}}/unpublish',
EXERCISE_CREATE = '/assignments/{{nameOrUrl}}/exercises',
EXERCISE_ASSIGNMENT = '/exercises/{{id}}/assignment',
EXERCISE_RESULTS = '/exercises/{{id}}/results'
}
......
interface ExerciceRunningEvents {
interface ExerciseRunningEvents {
step: (name: string, message: string) => void;
endStep: (stepName: string, message: string, error: boolean) => void;
logs: (log: string, error: boolean, displayable: boolean) => void;
......@@ -6,4 +6,4 @@ interface ExerciceRunningEvents {
}
export default ExerciceRunningEvents;
\ No newline at end of file
export default ExerciseRunningEvents;
\ No newline at end of file