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)
......@@ -28,6 +28,9 @@ class AssignmentValidator {
public exitCode: number = -1;
public fatalErrorMessage: string = '';
private currentStep: string = 'NOT_RUNNING';
private currentSubStep: string = 'NOT_RUNNING';
constructor(private folderAssignment: string) {
this.events.on('logs', (log: string, _error: boolean, displayable: boolean) => {
this.allLogs += log;
......@@ -41,19 +44,45 @@ class AssignmentValidator {
});
}
private newStep(name: string, message: string) {
this.currentStep = name;
this.events.emit('step', name, message);
}
private newSubStep(name: string, message: string) {
this.currentSubStep = name;
this.events.emit('subStep', name, message);
}
private endStep(message: string, error: boolean) {
this.events.emit('endStep', this.currentStep, message, error);
}
private endSubStep(message: string, error: boolean) {
this.events.emit('endSubStep', this.currentStep, message, error);
}
private log(message: string, error: boolean, displayable: boolean) {
this.events.emit('logs', message, error, displayable, this.currentStep, this.currentSubStep);
}
private finished(success: boolean, code: number) {
this.events.emit('finished', success, code);
}
private emitError(subStepMessage: string, stepMessage: string, code: AssignmentCheckerError) {
this.fatalErrorMessage = stepMessage;
this.endSubStep(subStepMessage, true);
this.endStep(stepMessage, true);
this.finished(false, code);
}
run(doDown: boolean = false) {
(async () => {
let dockerComposeFile: DojoDockerCompose;
let assignmentFile: AssignmentFile;
const emitError = (subStepName: string, subStepMessage: string, stepName: string, stepMessage: string, code: AssignmentCheckerError) => {
this.fatalErrorMessage = stepMessage;
this.events.emit('endSubStep', subStepName, subStepMessage, true);
this.events.emit('endStep', stepName, stepMessage, true);
this.events.emit('finished', false, code);
};
/*
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 1: Check requirements
......@@ -61,33 +90,33 @@ class AssignmentValidator {
- Check if required files exists
*/
{
this.events.emit('step', 'REQUIREMENTS_CHECKING', 'Please wait while we are checking requirements...');
this.newStep('REQUIREMENTS_CHECKING', 'Please wait while we are checking requirements...');
// Check requirements
this.events.emit('subStep', 'DOCKER_RUNNING', 'Checking if Docker daemon is running');
this.newSubStep('DOCKER_RUNNING', 'Checking if Docker daemon is running');
try {
await execAsync(`docker ps`);
} catch ( error ) {
emitError('DOCKER_RUNNING', `Docker daemon isn't running`, 'REQUIREMENTS_CHECKING', `Some requirements are not satisfied.`, AssignmentCheckerError.DOCKER_DAEMON_NOT_RUNNING);
this.emitError(`Docker daemon isn't running`, `Some requirements are not satisfied.`, AssignmentCheckerError.DOCKER_DAEMON_NOT_RUNNING);
return;
}
this.events.emit('endSubStep', 'DOCKER_RUNNING', 'Docker daemon is running', false);
this.endSubStep('Docker daemon is running', false);
// Check if required files exists
this.events.emit('subStep', 'REQUIRED_FILES_EXISTS', 'Checking if required files exists');
this.newSubStep('REQUIRED_FILES_EXISTS', 'Checking if required files exists');
const files = fs.readdirSync(this.folderAssignment);
const missingFiles = ClientsSharedConfig.assignment.neededFiles.map((file: string): [ string, boolean ] => [ file, files.includes(file) ]).filter((file: [ string, boolean ]) => !file[1]);
if ( missingFiles.length > 0 ) {
emitError('REQUIRED_FILES_EXISTS', `The exercise folder is missing the following files: ${ missingFiles.map((file: [ string, boolean ]) => file[0]).join(', ') }`, 'REQUIREMENTS_CHECKING', 'Some requirements are not satisfied', AssignmentCheckerError.REQUIRED_FILES_MISSING);
this.emitError(`The exercise folder is missing the following files: ${ missingFiles.map((file: [ string, boolean ]) => file[0]).join(', ') }`, 'Some requirements are not satisfied', AssignmentCheckerError.REQUIRED_FILES_MISSING);
return;
}
this.events.emit('endSubStep', 'REQUIRED_FILES_EXISTS', 'All required files exists', false);
this.endSubStep('All required files exists', false);
this.events.emit('endStep', 'REQUIREMENTS_CHECKING', 'All requirements are satisfied', false);
this.endStep('All requirements are satisfied', false);
}
......@@ -97,42 +126,42 @@ class AssignmentValidator {
- Immutable files validation (Check if exists and if the given type is correct)
*/
{
this.events.emit('step', 'ASSIGNMENT_FILE_VALIDATION', 'Please wait while we are validating dojo_assignment.json file...');
this.newStep('ASSIGNMENT_FILE_VALIDATION', 'Please wait while we are validating dojo_assignment.json file...');
// Structure validation
this.events.emit('subStep', 'ASSIGNMENT_FILE_SCHEMA_VALIDATION', 'Validating dojo_assignment.json file schema');
this.newSubStep('ASSIGNMENT_FILE_SCHEMA_VALIDATION', 'Validating dojo_assignment.json file schema');
const validationResults = SharedAssignmentHelper.validateDescriptionFile(path.join(this.folderAssignment, ClientsSharedConfig.assignment.filename));
if ( !validationResults.isValid ) {
emitError('ASSIGNMENT_FILE_SCHEMA_VALIDATION', `dojo_assignment.json file schema is invalid.\nHere are the errors:\n${ JSON5.stringify(validationResults.errors) }`, 'ASSIGNMENT_FILE_VALIDATION', 'dojo_assignment.json file is invalid', AssignmentCheckerError.ASSIGNMENT_FILE_SCHEMA_ERROR);
this.emitError(`dojo_assignment.json file schema is invalid.\nHere are the errors:\n${ JSON5.stringify(validationResults.errors) }`, 'dojo_assignment.json file is invalid', AssignmentCheckerError.ASSIGNMENT_FILE_SCHEMA_ERROR);
return;
}
assignmentFile = validationResults.results!;
this.events.emit('endSubStep', 'ASSIGNMENT_FILE_SCHEMA_VALIDATION', 'dojo_assignment.json file schema is valid', false);
this.endSubStep('dojo_assignment.json file schema is valid', false);
// Immutable files validation (Check if exists and if the given type is correct)
this.events.emit('subStep', 'ASSIGNMENT_FILE_IMMUTABLES_VALIDATION', 'Validating immutable files');
this.newSubStep('ASSIGNMENT_FILE_IMMUTABLES_VALIDATION', 'Validating immutable files');
for ( const immutable of validationResults.results!.immutable ) {
const immutablePath = path.join(this.folderAssignment, immutable.path);
if ( !fs.existsSync(immutablePath) ) {
emitError('ASSIGNMENT_FILE_IMMUTABLES_VALIDATION', `Immutable path not found: ${ immutable.path }`, 'ASSIGNMENT_FILE_VALIDATION', 'dojo_assignment.json file is invalid', AssignmentCheckerError.IMMUTABLE_PATH_NOT_FOUND);
this.emitError(`Immutable path not found: ${ immutable.path }`, 'dojo_assignment.json file is invalid', AssignmentCheckerError.IMMUTABLE_PATH_NOT_FOUND);
return;
}
const isDirectory = fs.lstatSync(immutablePath).isDirectory();
if ( isDirectory && !immutable.isDirectory ) {
emitError('ASSIGNMENT_FILE_IMMUTABLES_VALIDATION', `Immutable (${ immutable.path }) is declared as a file but is a directory.`, 'ASSIGNMENT_FILE_VALIDATION', 'dojo_assignment.json file is invalid', AssignmentCheckerError.IMMUTABLE_PATH_IS_NOT_DIRECTORY);
this.emitError(`Immutable (${ immutable.path }) is declared as a file but is a directory.`, 'dojo_assignment.json file is invalid', AssignmentCheckerError.IMMUTABLE_PATH_IS_NOT_DIRECTORY);
return;
} else if ( !isDirectory && immutable.isDirectory === true ) {
emitError('ASSIGNMENT_FILE_IMMUTABLES_VALIDATION', `Immutable (${ immutable.path }) is declared as a directory but is a file.`, 'ASSIGNMENT_FILE_VALIDATION', 'dojo_assignment.json file is invalid', AssignmentCheckerError.IMMUTABLE_PATH_IS_DIRECTORY);
this.emitError(`Immutable (${ immutable.path }) is declared as a directory but is a file.`, 'dojo_assignment.json file is invalid', AssignmentCheckerError.IMMUTABLE_PATH_IS_DIRECTORY);
return;
}
}
this.events.emit('endSubStep', 'ASSIGNMENT_FILE_IMMUTABLES_VALIDATION', 'Immutable files are valid', false);
this.endSubStep('Immutable files are valid', false);
this.events.emit('endStep', 'ASSIGNMENT_FILE_VALIDATION', 'dojo_assignment.json file is valid', false);
this.endStep('dojo_assignment.json file is valid', false);
}
......@@ -142,15 +171,15 @@ class AssignmentValidator {
- Validation of the containers and volumes named in dojo_assignment.json
*/
{
this.events.emit('step', 'DOCKER_COMPOSE_VALIDATION', 'Please wait while we are validating docker compose file...');
this.newStep('DOCKER_COMPOSE_VALIDATION', 'Please wait while we are validating docker compose file...');
// Global validation
this.events.emit('subStep', 'DOCKER_COMPOSE_STRUCTURE_VALIDATION', 'Docker compose file structure validation');
this.newSubStep('DOCKER_COMPOSE_STRUCTURE_VALIDATION', 'Docker compose file structure validation');
try {
dockerComposeFile = YAML.parse(fs.readFileSync(path.join(this.folderAssignment, 'docker-compose.yml'), 'utf8')) as DojoDockerCompose;
} catch ( error ) {
emitError('DOCKER_COMPOSE_STRUCTURE_VALIDATION', `Docker compose file yaml structure is invalid.`, 'DOCKER_COMPOSE_VALIDATION', 'Docker compose file is invalid', AssignmentCheckerError.COMPOSE_FILE_YAML_ERROR);
this.emitError(`Docker compose file yaml structure is invalid.`, 'Docker compose file is invalid', AssignmentCheckerError.COMPOSE_FILE_YAML_ERROR);
return;
}
......@@ -166,26 +195,26 @@ class AssignmentValidator {
});
});
} catch ( error ) {
emitError('DOCKER_COMPOSE_STRUCTURE_VALIDATION', `Docker compose file structure is invalid.`, 'DOCKER_COMPOSE_VALIDATION', 'Docker compose file is invalid', AssignmentCheckerError.COMPOSE_FILE_SCHEMA_ERROR);
this.emitError(`Docker compose file structure is invalid.`, 'Docker compose file is invalid', AssignmentCheckerError.COMPOSE_FILE_SCHEMA_ERROR);
return;
}
this.events.emit('endSubStep', 'DOCKER_COMPOSE_STRUCTURE_VALIDATION', 'Docker compose file structure is valid', false);
this.endSubStep('Docker compose file structure is valid', false);
// Validation of the containers and volumes named in dojo_assignment.json
this.events.emit('subStep', 'DOCKER_COMPOSE_CONTENT_VALIDATION', 'Docker compose file content validation');
this.newSubStep('DOCKER_COMPOSE_CONTENT_VALIDATION', 'Docker compose file content validation');
if ( !(assignmentFile.result.container in dockerComposeFile!.services) ) {
emitError('DOCKER_COMPOSE_CONTENT_VALIDATION', `Container specified in ${ ClientsSharedConfig.assignment.filename } is missing from compose file.`, 'DOCKER_COMPOSE_VALIDATION', 'Docker compose file is invalid', AssignmentCheckerError.COMPOSE_FILE_CONTAINER_MISSING);
this.emitError(`Container specified in ${ ClientsSharedConfig.assignment.filename } is missing from compose file.`, 'Docker compose file is invalid', AssignmentCheckerError.COMPOSE_FILE_CONTAINER_MISSING);
return;
}
if ( assignmentFile.result.volume && (!dockerComposeFile!.volumes || !(assignmentFile.result.volume in dockerComposeFile!.volumes)) ) {
emitError('DOCKER_COMPOSE_CONTENT_VALIDATION', `Volume specified in ${ ClientsSharedConfig.assignment.filename } is missing from compose file.`, 'DOCKER_COMPOSE_VALIDATION', 'Docker compose file is invalid', AssignmentCheckerError.COMPOSE_FILE_VOLUME_MISSING);
this.emitError(`Volume specified in ${ ClientsSharedConfig.assignment.filename } is missing from compose file.`, 'Docker compose file is invalid', AssignmentCheckerError.COMPOSE_FILE_VOLUME_MISSING);
return;
}
this.events.emit('endSubStep', 'DOCKER_COMPOSE_CONTENT_VALIDATION', 'Docker compose file content is valid', false);
this.endSubStep('Docker compose file content is valid', false);
this.events.emit('endStep', 'DOCKER_COMPOSE_VALIDATION', 'Docker compose file is valid', false);
this.endStep('Docker compose file is valid', false);
}
......@@ -195,20 +224,20 @@ class AssignmentValidator {
- TODO - Dockerfile structure linter - Issue #51 - https://github.com/hadolint/hadolint
*/
{
this.events.emit('step', 'DOCKERFILE_VALIDATION', 'Please wait while we are validating dockerfiles...');
this.newStep('DOCKERFILE_VALIDATION', 'Please wait while we are validating dockerfiles...');
this.events.emit('subStep', 'DOCKERFILE_EXIST', 'Docker compose file content validation');
this.newSubStep('DOCKERFILE_EXIST', 'Docker compose file content validation');
const dockerfilesPaths = Object.values(dockerComposeFile!.services).filter((service) => service.build).map((service) => path.join(this.folderAssignment, service.build!.context ?? '', service.build!.dockerfile!));
const filesNotFound = dockerfilesPaths.filter((dockerfilePath) => !fs.existsSync(dockerfilePath));
if ( filesNotFound.length > 0 ) {
emitError('DOCKERFILE_VALIDATION', `Dockerfiles not found: ${ filesNotFound.join(', ') }`, 'DOCKERFILE_VALIDATION', 'Dockerfiles are invalid', AssignmentCheckerError.DOCKERFILE_NOT_FOUND);
this.emitError(`Dockerfiles not found: ${ filesNotFound.join(', ') }`, 'Dockerfiles are invalid', AssignmentCheckerError.DOCKERFILE_NOT_FOUND);
return;
}
this.events.emit('endSubStep', 'DOCKER_COMPOSE_CONTENT_VALIDATION', 'Docker compose file content is valid', false);
this.endSubStep('Docker compose file content is valid', false);
this.events.emit('endStep', 'DOCKERFILE_VALIDATION', 'Dockerfiles are valid', false);
this.endStep('Dockerfiles are valid', false);
}
......@@ -217,7 +246,7 @@ class AssignmentValidator {
- Make a run of the assignment (If the return code is 0, the assignment is not valid because it means that there no need of modification for succeed the exercise)
*/
{
this.events.emit('step', 'ASSIGNMENT_RUN', 'Please wait while we are running the assignment...');
this.newStep('ASSIGNMENT_RUN', 'Please wait while we are running the assignment...');
const exerciseDockerCompose = new ExerciseDockerCompose(ClientsSharedConfig.dockerCompose.projectName, assignmentFile, this.folderAssignment);
......@@ -225,15 +254,15 @@ class AssignmentValidator {
try {
await new Promise<void>((resolve, reject) => {
exerciseDockerCompose.events.on('logs', (log: string, error: boolean, displayable: boolean) => {
this.events.emit('logs', log, error, displayable);
this.log(log, error, displayable);
});
exerciseDockerCompose.events.on('step', (name: string, message: string) => {
this.events.emit('subStep', name, message);
this.newSubStep(name, message);
});
exerciseDockerCompose.events.on('endStep', (stepName: string, message: string, error: boolean) => {
this.events.emit('endSubStep', stepName, message, error);
this.endSubStep(message, error);
});
exerciseDockerCompose.events.on('finished', (success: boolean, exitCode: number) => {
......@@ -244,17 +273,17 @@ class AssignmentValidator {
});
} catch ( error ) {
this.fatalErrorMessage = 'Assignment is already solved';
this.events.emit('endStep', 'ASSIGNMENT_RUN', this.fatalErrorMessage, true);
this.events.emit('finished', false, AssignmentCheckerError.COMPOSE_RUN_SUCCESSFULLY);
this.endStep(this.fatalErrorMessage, true);
this.finished(false, AssignmentCheckerError.COMPOSE_RUN_SUCCESSFULLY);
return;
}
this.events.emit('endStep', 'ASSIGNMENT_RUN', 'Assignment run successfully', false);
this.endStep('Assignment run successfully', false);
}
this.events.emit('finished', true, 0);
this.finished(true, 0);
})();
}
}
......
......@@ -3,7 +3,7 @@ interface AssignmentValidatorEvents {
subStep: (name: string, message: string) => void;
endStep: (stepName: string, message: string, error: boolean) => void;
endSubStep: (subStepName: string, message: string, error: boolean) => void;
logs: (log: string, error: boolean, displayable: boolean) => void;
logs: (log: string, error: boolean, displayable: boolean, currentStep: string, currentSubStep: string) => void;
finished: (success: boolean, exitCode: number) => void;
}
......