Skip to content
Snippets Groups Projects
Commit b648cbdf authored by joel.vonderwe's avatar joel.vonderwe Committed by michael.minelli
Browse files

Add check buildline in assignment check

parent a8c208ab
Branches
No related tags found
No related merge requests found
import { TypedEmitter } from 'tiny-typed-emitter';
import AssignmentValidatorEvents from '../../types/Dojo/AssignmentValidatorEvents.js';
import SharedAssignmentHelper from '../../../shared/helpers/Dojo/SharedAssignmentHelper.js';
import path from 'node:path';
import AssignmentCheckerError from '../../../shared/types/Dojo/AssignmentCheckerError.js';
import fs from 'fs-extra';
import YAML from 'yaml';
import DojoDockerCompose from '../../types/Dojo/DojoDockerCompose.js';
import { exec, spawn } from 'child_process';
import AssignmentFile from '../../../shared/types/Dojo/AssignmentFile.js';
import ExerciseDockerCompose from './ExerciseDockerCompose.js';
import util from 'util';
import ClientsSharedConfig from '../../config/ClientsSharedConfig';
import { TypedEmitter } from 'tiny-typed-emitter';
import AssignmentValidatorEvents from '../../types/Dojo/AssignmentValidatorEvents';
import SharedAssignmentHelper from '../../../shared/helpers/Dojo/SharedAssignmentHelper';
import path from 'node:path';
import AssignmentCheckerError from '../../../shared/types/Dojo/AssignmentCheckerError';
import fs from 'fs-extra';
import ClientsSharedConfig from '../../config/ClientsSharedConfig';
import YAML from 'yaml';
import DojoDockerCompose from '../../types/Dojo/DojoDockerCompose';
import { exec, spawn } from 'child_process';
import AssignmentFile from '../../../shared/types/Dojo/AssignmentFile';
import ExerciseDockerCompose from './ExerciseDockerCompose';
import util from 'util';
import Assignment, { Language } from '../../models/Assignment';
import ClientsSharedAssignmentHelper from './ClientsSharedAssignmentHelper';
const execAsync = util.promisify(exec);
......@@ -35,6 +37,7 @@ class AssignmentValidator {
private dockerComposeFile!: DojoDockerCompose;
private assignmentFile!: AssignmentFile;
private assignment!: Assignment;
constructor(folderAssignment: string, doDown: boolean = false) {
this.folderAssignment = folderAssignment;
......@@ -123,9 +126,31 @@ class AssignmentValidator {
}
/**
* Step 2: dojo_assignment.json file validation
* Step 2: Check assignment
* - Check if assignment exists in backend
* @private
*/
private async checkAssignment() {
this.newStep('ASSIGNMENT_CHECKING', 'Please wait while we are checking the assignment...');
this.newSubStep('ASSIGNMENT_EXISTS', 'Checking if the assignment exists');
const resp = await ClientsSharedAssignmentHelper.getAssignmentFromPath(this.folderAssignment);
if ( resp == undefined ) {
this.emitError(`The assignment doesn't exist. An assignment must be created with "assignment create" before checking it.`, `Assignment doesn't exists`, AssignmentCheckerError.ASSIGNMENT_MISSING);
return;
} else {
this.assignment = resp;
}
this.endSubStep('Assignment exists', false);
this.endStep('Assignment exists and is valid', false);
}
/**
* Step 3: dojo_assignment.json file validation
* - Structure validation
* - Immutable files validation (Check if exists and if the given type is correct)
* - Build line validation (for C-derived languages and sonar activated projects)
* @private
*/
private dojoAssignmentFileValidation() {
......@@ -164,12 +189,22 @@ class AssignmentValidator {
}
this.endSubStep('Immutable files are valid', false);
// Build line validation (only if language is C/CPP/OBJ-C and sonar activated)
if ( [ Language.c, Language.cpp, Language.objc ].includes(this.assignment.language) && this.assignment.useSonar ) {
this.newSubStep('ASSIGNMENT_FILE_BUILD_LINE_VALIDATION', 'Validating build line');
const build = validationResults.content!.buildLine;
if ( build == undefined || build.trim() == '' ) {
this.emitError(`BuildLine is required for this language`, 'dojo_assignment.json file is invalid', AssignmentCheckerError.BUILD_LINE_MISSING);
return;
}
this.endSubStep('Build line is valid', false);
}
this.endStep('dojo_assignment.json file is valid', false);
}
/**
* Step 3: Docker Compose file validation
* Step 4: Docker Compose file validation
* - Global validation
* - Validation of the containers and volumes named in dojo_assignment.json
* @private
......@@ -223,7 +258,7 @@ class AssignmentValidator {
}
/**
* Step 4: Dockerfiles validation
* Step 5: Dockerfiles validation
* - Check if file exists
* - TODO - Dockerfile structure linter - Issue #51 - https://github.com/hadolint/hadolint
* @private
......@@ -246,7 +281,7 @@ class AssignmentValidator {
}
/**
* Step 5: Run
* Step 6: Run
* - 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)
* @private
*/
......@@ -292,6 +327,8 @@ class AssignmentValidator {
try {
await this.checkRequirements();
await this.checkAssignment();
this.dojoAssignmentFileValidation();
await this.dockerComposeFileValidation();
......
import chalk from 'chalk';
import boxen from 'boxen';
import Icon from '../../../shared/types/Icon.js';
import AssignmentValidator from './AssignmentValidator.js';
import { existsSync, readFileSync } from 'fs';
import { join } from 'path';
import chalk from 'chalk';
import boxen from 'boxen';
import Icon from '../../../shared/types/Icon';
import AssignmentValidator from './AssignmentValidator';
import Assignment from '../../models/Assignment';
import axios from 'axios';
import DojoBackendResponse from '../../../shared/types/Dojo/DojoBackendResponse';
import ApiRoute from '../../types/Dojo/ApiRoute';
import ClientsSharedConfig from '../../config/ClientsSharedConfig';
class ClientsSharedAssignmentHelper {
......@@ -22,6 +29,30 @@ class ClientsSharedAssignmentHelper {
textAlignment : 'left'
}));
}
private async getAssignment(url: string): Promise<Assignment | undefined> {
try {
return (await axios.get<DojoBackendResponse<Assignment>>(`${ ClientsSharedConfig.apiURL }${ ApiRoute.ASSIGNMENT_GET }`.replace('{{nameOrUrl}}', encodeURIComponent(url)))).data.data;
} catch ( error ) {
return undefined;
}
}
private async extractOriginUrl(content: string): Promise<string> {
const regexp = /\[remote "origin"]\r?\n\s*url\s*=\s*(.*)\s*\n/gm;
return Array.from(content.matchAll(regexp), m => m[1])[0];
}
async getAssignmentFromPath(path: string): Promise<Assignment | undefined> {
const fullPath = join(path, "./.git/config");
if (!existsSync(fullPath)) {
return undefined;
}
const content = readFileSync(fullPath, 'utf-8');
const url = await this.extractOriginUrl(content);
return await this.getAssignment(url);
}
}
......
......@@ -11,6 +11,8 @@ interface Assignment {
gitlabLastInfo: Gitlab.ProjectSchema;
gitlabLastInfoDate: string;
published: boolean;
useSonar: boolean;
language: Language;
staff: Array<User>;
exercises: Array<Exercise>;
......@@ -19,4 +21,74 @@ interface Assignment {
}
export default Assignment;
\ No newline at end of file
export enum Language {
abap = "abap",
ada = "ada",
asm = "asm",
bash = "bash",
bqn = "bqn",
c = "c",
caml = "caml",
cloudformation = "cloudformation",
cpp = "cpp",
csharp = "csharp",
css = "css",
cuda = "cuda",
dart = "dart",
delphi = "delphi",
docker = "docker",
erlang = "erlang",
f = "f",
fsharp = "fsharp",
flex = "flex",
fortran = "fortran",
futhark = "futhark",
go = "go",
groovy = "groovy",
haskell = "haskell",
hepial = "hepial",
json = "json",
jsp = "jsp",
java = "java",
js = "js",
julia = "julia",
kotlin = "kotlin",
kubernetes = "kubernetes",
latex = "latex",
lisp = "lisp",
lua = "lua",
matlab = "matlab",
objc = "objc",
ocaml = "ocaml",
pascal = "pascal",
pearl = "pearl",
perl = "perl",
php = "php",
postscript = "postscript",
powershell = "powershell",
prolog = "prolog",
promela = "promela",
python = "python",
r = "r",
ruby = "ruby",
rust = "rust",
scala = "scala",
sql = "sql",
smalltalk = "smalltalk",
swift = "swift",
terraform = "terraform",
text = "text",
ts = "ts",
tsql = "tsql",
typst = "typst",
vba = "vba",
vbnet = "vbnet",
web = "web",
xml = "xml",
yaml = "yaml",
other = "other"
}
export default Assignment;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment