Skip to content
Snippets Groups Projects
Commit 2b574d9a authored by joel.vonderwe's avatar joel.vonderwe
Browse files

Add check buildline in assignment check

parent 20ec89ce
Branches
No related tags found
No related merge requests found
import { TypedEmitter } from 'tiny-typed-emitter'; import { TypedEmitter } from 'tiny-typed-emitter';
import AssignmentValidatorEvents from '../../types/Dojo/AssignmentValidatorEvents'; import AssignmentValidatorEvents from '../../types/Dojo/AssignmentValidatorEvents';
import SharedAssignmentHelper from '../../../shared/helpers/Dojo/SharedAssignmentHelper'; import SharedAssignmentHelper from '../../../shared/helpers/Dojo/SharedAssignmentHelper';
import path from 'node:path'; import path from 'node:path';
import AssignmentCheckerError from '../../../shared/types/Dojo/AssignmentCheckerError'; import AssignmentCheckerError from '../../../shared/types/Dojo/AssignmentCheckerError';
import fs from 'fs-extra'; import fs from 'fs-extra';
import ClientsSharedConfig from '../../config/ClientsSharedConfig'; import ClientsSharedConfig from '../../config/ClientsSharedConfig';
import YAML from 'yaml'; import YAML from 'yaml';
import DojoDockerCompose from '../../types/Dojo/DojoDockerCompose'; import DojoDockerCompose from '../../types/Dojo/DojoDockerCompose';
import { exec, spawn } from 'child_process'; import { exec, spawn } from 'child_process';
import AssignmentFile from '../../../shared/types/Dojo/AssignmentFile'; import AssignmentFile from '../../../shared/types/Dojo/AssignmentFile';
import ExerciseDockerCompose from './ExerciseDockerCompose'; import ExerciseDockerCompose from './ExerciseDockerCompose';
import util from 'util'; import util from 'util';
import Assignment, { Language } from '../../models/Assignment';
import ClientsSharedAssignmentHelper from './ClientsSharedAssignmentHelper';
const execAsync = util.promisify(exec); const execAsync = util.promisify(exec);
...@@ -81,7 +83,7 @@ class AssignmentValidator { ...@@ -81,7 +83,7 @@ class AssignmentValidator {
(async () => { (async () => {
let dockerComposeFile: DojoDockerCompose; let dockerComposeFile: DojoDockerCompose;
let assignmentFile: AssignmentFile; let assignmentFile: AssignmentFile;
let assignment: Assignment;
/* /*
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 1: Check requirements //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 1: Check requirements
...@@ -118,11 +120,32 @@ class AssignmentValidator { ...@@ -118,11 +120,32 @@ class AssignmentValidator {
this.endStep('All requirements are satisfied', false); this.endStep('All requirements are satisfied', false);
} }
/*
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 2: Check assignment
- Check if assignment exists in backend
*/
{
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 {
assignment = resp;
}
this.endSubStep('Assignment exists', false);
this.endStep('Assignment exists and is valid', false);
}
/* /*
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 2: dojo_assignment.json file validation //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 3: dojo_assignment.json file validation
- Structure validation - Structure validation
- Immutable files validation (Check if exists and if the given type is correct) - Immutable files validation (Check if exists and if the given type is correct)
- Build line validation (for C-derived languages and sonar activated projects)
*/ */
{ {
this.newStep('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...');
...@@ -159,13 +182,23 @@ class AssignmentValidator { ...@@ -159,13 +182,23 @@ class AssignmentValidator {
} }
this.endSubStep('Immutable files are valid', false); 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(assignment.language) && 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); this.endStep('dojo_assignment.json file is valid', false);
} }
/* /*
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 3: Docker Compose file validation //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 4: Docker Compose file validation
- Global validation - Global validation
- Validation of the containers and volumes named in dojo_assignment.json - Validation of the containers and volumes named in dojo_assignment.json
*/ */
...@@ -218,7 +251,7 @@ class AssignmentValidator { ...@@ -218,7 +251,7 @@ class AssignmentValidator {
/* /*
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 4: Dockerfiles validation //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 5: Dockerfiles validation
- Check if file exists - Check if file exists
- TODO - Dockerfile structure linter - Issue #51 - https://github.com/hadolint/hadolint - TODO - Dockerfile structure linter - Issue #51 - https://github.com/hadolint/hadolint
*/ */
...@@ -241,7 +274,7 @@ class AssignmentValidator { ...@@ -241,7 +274,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) - 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)
*/ */
{ {
......
import chalk from 'chalk'; import { existsSync, readFileSync } from 'fs';
import boxen from 'boxen'; import { join } from 'path';
import Icon from '../../../shared/types/Icon'; import chalk from 'chalk';
import AssignmentValidator from './AssignmentValidator'; 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 { class ClientsSharedAssignmentHelper {
...@@ -21,6 +28,30 @@ class ClientsSharedAssignmentHelper { ...@@ -21,6 +28,30 @@ class ClientsSharedAssignmentHelper {
textAlignment : 'left' 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 { ...@@ -11,6 +11,8 @@ interface Assignment {
gitlabLastInfo: GitlabRepository; gitlabLastInfo: GitlabRepository;
gitlabLastInfoDate: string; gitlabLastInfoDate: string;
published: boolean; published: boolean;
useSonar: boolean;
language: Language;
staff: Array<User>; staff: Array<User>;
exercises: Array<Exercise>; exercises: Array<Exercise>;
...@@ -19,4 +21,74 @@ interface Assignment { ...@@ -19,4 +21,74 @@ interface Assignment {
} }
export default Assignment; export enum Language {
\ No newline at end of file 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