diff --git a/helpers/Dojo/AssignmentValidator.ts b/helpers/Dojo/AssignmentValidator.ts index e5e86c5e793347405f50f8536aaea604533eb468..97c848fbe85518d03738c34728b2c4f89c1b9cdf 100644 --- a/helpers/Dojo/AssignmentValidator.ts +++ b/helpers/Dojo/AssignmentValidator.ts @@ -13,6 +13,10 @@ import ExerciseDockerCompose from './ExerciseDockerCompose'; import util from 'util'; import Assignment, { Language } from '../../models/Assignment'; import ClientsSharedAssignmentHelper from './ClientsSharedAssignmentHelper'; +import { spawnSync } from 'node:child_process'; +import SharedConfig from '../../../shared/config/SharedConfig'; +import Config from '../../../config/Config'; +import { add } from 'winston'; const execAsync = util.promisify(exec); @@ -79,7 +83,7 @@ class AssignmentValidator { this.finished(false, code); } - run(doDown: boolean = false) { + run(doDown: boolean = false, runSonar: boolean = false) { (async () => { let dockerComposeFile: DojoDockerCompose; let assignmentFile: AssignmentFile; @@ -127,17 +131,15 @@ class AssignmentValidator { { 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); + const resp = await ClientsSharedAssignmentHelper.getAssignmentByName(Config.assignment.name); 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); + this.endStep('Assignment exists', false); } @@ -274,7 +276,53 @@ class AssignmentValidator { /* - //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 6: Run + //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 6: Sonar analysis + - Analyse the project with SonarCube + */ + if (assignment.useSonar && runSonar) + { + this.newStep('ASSIGNMENT_SONAR', 'Please wait while we are running Sonar analysis on the assignment...'); + + let additionalParams: string[] = []; + + this.newSubStep('SONAR_BUILD', 'Build files'); + + const buildProcess = spawnSync('docker', ['build', '--tag', 'dojo-sonar-scanner', '/sonar']); + if ( buildProcess.status !== 0 ) { + this.emitError(`Build sonar image failed`, 'Sonar analysis failure', AssignmentCheckerError.SONAR_ANALYSIS_FAILED); + console.log(buildProcess.stdout.toString()) + console.log(buildProcess.stderr.toString()) + return; + } + + if ([Language.c, Language.cpp, Language.objc].includes(assignment.language) && assignmentFile.buildLine != undefined) { + const process = spawnSync('docker run -v ./:/usr/src dojo-sonar-scanner /usr/local/bin/build-wrapper-linux-x86-64 --out-dir bw-output ' + assignmentFile.buildLine, [], { shell: true }) + if ( process.status !== 0 ) { + this.emitError(`Failed to build files using buildLine`, 'Sonar analysis failure', AssignmentCheckerError.SONAR_ANALYSIS_FAILED); + console.log(process.stdout.toString()) + console.log(process.stderr.toString()) + return; + } + additionalParams = ['-Dsonar.cfamily.build-wrapper-output=/usr/src/bw-output']; + } + this.endSubStep('Sonar files build success', false); + + this.newSubStep('SONAR_RUN', 'Run sonar analysis'); + + + const process = spawnSync('docker', ['run', '-v', './:/usr/src', 'dojo-sonar-scanner' , 'sonar-scanner', '-Dsonar.qualitygate.wait=true', '-Dsonar.projectKey=' + assignment.sonarKey, '-Dsonar.sources=.', '-Dsonar.host.url=' + SharedConfig.sonar.url, '-Dsonar.login=' + SharedConfig.sonar.token, ...additionalParams]) + if ( process.status !== 0 ) { + this.emitError(`Sonar gate failed`, 'Sonar analysis failure', AssignmentCheckerError.SONAR_ANALYSIS_FAILED); + return; + } + this.endSubStep('Sonar gate passed', false); + + this.endStep('Sonar analysis success', false); + } + + + /* + //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 7: 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) */ { diff --git a/helpers/Dojo/ClientsSharedAssignmentHelper.ts b/helpers/Dojo/ClientsSharedAssignmentHelper.ts index 7bb900dba0ade77cffeacef087710f08b4ce4526..73c93eef91ed806d7b5a8d54f551a2b7f8f596ea 100644 --- a/helpers/Dojo/ClientsSharedAssignmentHelper.ts +++ b/helpers/Dojo/ClientsSharedAssignmentHelper.ts @@ -29,10 +29,11 @@ class ClientsSharedAssignmentHelper { })); } - private async getAssignment(url: string): Promise<Assignment | undefined> { + private async getAssignment(nameOrUrl: string): Promise<Assignment | undefined> { try { - return (await axios.get<DojoBackendResponse<Assignment>>(`${ ClientsSharedConfig.apiURL }${ ApiRoute.ASSIGNMENT_GET }`.replace('{{nameOrUrl}}', encodeURIComponent(url)))).data.data; + return (await axios.get<DojoBackendResponse<Assignment>>(`${ ClientsSharedConfig.apiURL }${ ApiRoute.ASSIGNMENT_GET }`.replace('{{nameOrUrl}}', encodeURIComponent(nameOrUrl)))).data.data; } catch ( error ) { + console.log(error); return undefined; } } @@ -42,6 +43,10 @@ class ClientsSharedAssignmentHelper { return Array.from(content.matchAll(regexp), m => m[1])[0]; } + async getAssignmentByName(name: string): Promise<Assignment | undefined> { + return await this.getAssignment(name); + } + async getAssignmentFromPath(path: string): Promise<Assignment | undefined> { const fullPath = join(path, "./.git/config"); if (!existsSync(fullPath)) { @@ -49,7 +54,6 @@ class ClientsSharedAssignmentHelper { } const content = readFileSync(fullPath, 'utf-8'); const url = await this.extractOriginUrl(content); - return await this.getAssignment(url); } }