From cd789d8ce9f9c3b812dd6353d5a5f1a08b4f0b93 Mon Sep 17 00:00:00 2001 From: Joel von der Weid <joel.von-der-weid@hesge.ch> Date: Mon, 17 Jun 2024 15:02:25 +0200 Subject: [PATCH] Create SonarAnalyzer --- helpers/Dojo/AssignmentValidator.ts | 32 +++++++---------- helpers/Dojo/SonarAnalyzer.ts | 54 +++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 20 deletions(-) create mode 100644 helpers/Dojo/SonarAnalyzer.ts diff --git a/helpers/Dojo/AssignmentValidator.ts b/helpers/Dojo/AssignmentValidator.ts index 9caa62f..a7c783b 100644 --- a/helpers/Dojo/AssignmentValidator.ts +++ b/helpers/Dojo/AssignmentValidator.ts @@ -13,8 +13,7 @@ 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 SonarAnalyzer from './SonarAnalyzer'; const execAsync = util.promisify(exec); @@ -141,7 +140,7 @@ class AssignmentValidator { const resp = await ClientsSharedAssignmentHelper.getAssignmentByName(ClientsSharedConfig.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; + throw new Error(); } else { this.assignment = resp; } @@ -293,37 +292,30 @@ class AssignmentValidator { if ( this.assignment.useSonar && this.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 ) { + const buildSuccess = SonarAnalyzer.buildDocker(); + if ( !buildSuccess ) { this.emitError(`Build sonar image failed`, 'Sonar analysis failure', AssignmentCheckerError.SONAR_ANALYSIS_FAILED); - console.log(buildProcess.stdout.toString()); - console.log(buildProcess.stderr.toString()); - return; + throw new Error(); } - if ( [ Language.c, Language.cpp, Language.objc ].includes(this.assignment.language) && this.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 ' + this.assignmentFile.buildLine, [], { shell: true }); - if ( process.status !== 0 ) { + if ( SonarAnalyzer.mustRunBuild(this.assignment.language, this.assignmentFile.buildLine) ) { + const buildSuccess = SonarAnalyzer.runBuildStep(this.assignmentFile.buildLine as string); + if ( !buildSuccess ) { 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; + throw new Error(); } - 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=' + this.assignment.sonarKey, '-Dsonar.sources=.', '-Dsonar.host.url=' + SharedConfig.sonar.url, '-Dsonar.login=' + SharedConfig.sonar.token, ...additionalParams ]); - if ( process.status !== 0 ) { + const runSuccess = SonarAnalyzer.runAnalysis(this.assignment.sonarKey, this.assignment.language, this.assignmentFile.buildLine); + if ( runSuccess ) { this.emitError(`Sonar gate failed`, 'Sonar analysis failure', AssignmentCheckerError.SONAR_ANALYSIS_FAILED); - return; + throw new Error(); } this.endSubStep('Sonar gate passed', false); diff --git a/helpers/Dojo/SonarAnalyzer.ts b/helpers/Dojo/SonarAnalyzer.ts new file mode 100644 index 0000000..d763d32 --- /dev/null +++ b/helpers/Dojo/SonarAnalyzer.ts @@ -0,0 +1,54 @@ +import { spawnSync } from 'node:child_process'; +import { Language } from '../../models/Assignment'; +import SharedConfig from '../../../shared/config/SharedConfig'; + +const IMAGE_NAME = 'dojo-sonar-scanner' +const OUT_DIR = 'bw-output'; + +class SonarAnalyzer { + buildDocker = () => { + const buildProcess = spawnSync('docker', ['build', '--tag', IMAGE_NAME, '/sonar']); + if ( buildProcess.status !== 0 ) { + console.log(buildProcess.stdout.toString()) + console.log(buildProcess.stderr.toString()) + return false; + } + return true; + } + + mustRunBuild = (language: Language, buildLine: string | undefined) => { + return [Language.c, Language.cpp, Language.objc].includes(language) && buildLine != undefined; + } + + runBuildStep = (buildLine: string) => { + const process = spawnSync(`docker run -v ./:/usr/src ${IMAGE_NAME} /usr/local/bin/build-wrapper-linux-x86-64 --out-dir ${OUT_DIR} ` + buildLine, [], { shell: true }) + if ( process.status !== 0 ) { + console.log(process.stdout.toString()) + console.log(process.stderr.toString()) + return false; + } + return true; + } + + runAnalysis = (sonarKey: string, language: Language, buildLine: string | undefined) => { + let addParam: string[] = []; + if (this.mustRunBuild(language, buildLine)) { + addParam = [ `-Dsonar.cfamily.build-wrapper-output=/usr/src/${OUT_DIR}`]; + } + + const process = spawnSync( + 'docker', + ['run', '-v', './:/usr/src', + IMAGE_NAME , 'sonar-scanner', + '-Dsonar.qualitygate.wait=true', + '-Dsonar.projectKey=' + sonarKey, + '-Dsonar.sources=.', + '-Dsonar.host.url=' + SharedConfig.sonar.url, + '-Dsonar.login=' + SharedConfig.sonar.token, + ...addParam]) + + return process.status === 0; + } +} + +export default new SonarAnalyzer(); \ No newline at end of file -- GitLab