Skip to content
Snippets Groups Projects
Commit 7363e902 authored by michael.minelli's avatar michael.minelli
Browse files

Sonar => Resolve issues

parent 9a20c1a9
No related branches found
No related tags found
No related merge requests found
Pipeline #30056 passed
...@@ -5,6 +5,9 @@ Wiki/.idea ...@@ -5,6 +5,9 @@ Wiki/.idea
ExerciseChecker/src/config/Version.ts ExerciseChecker/src/config/Version.ts
sonarlint.xml
sonarlint/
############################ MacOS ############################ MacOS
# General # General
.DS_Store .DS_Store
......
...@@ -15,4 +15,7 @@ ...@@ -15,4 +15,7 @@
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
<component name="SonarLintModuleSettings">
<option name="uniqueId" value="39cd055e-87b7-4af4-82da-6d4c7c75ce23" />
</component>
</module> </module>
\ No newline at end of file
This diff is collapsed.
...@@ -29,17 +29,20 @@ ...@@ -29,17 +29,20 @@
"test" : "echo \"Error: no test specified\" && exit 1" "test" : "echo \"Error: no test specified\" && exit 1"
}, },
"dependencies" : { "dependencies" : {
"@gitbeaker/rest" : "^39.34.3",
"axios" : "^1.6.5", "axios" : "^1.6.5",
"boxen" : "^5.1.2", "boxen" : "^5.1.2",
"chalk" : "^4.1.2", "chalk" : "^4.1.2",
"dotenv" : "^16.3.1", "dotenv" : "^16.3.1",
"dotenv-expand" : "^10.0.0", "dotenv-expand" : "^10.0.0",
"form-data" : "^4.0.0",
"fs-extra" : "^11.2.0", "fs-extra" : "^11.2.0",
"http-status-codes" : "^2.3.0", "http-status-codes" : "^2.3.0",
"json5" : "^2.2.3", "json5" : "^2.2.3",
"ora" : "^5.4.1", "ora" : "^5.4.1",
"tar-stream" : "^3.1.6", "tar-stream" : "^3.1.6",
"winston" : "^3.11.0", "winston" : "^3.11.0",
"winston-transport" : "^4.7.0",
"yaml" : "^2.3.4", "yaml" : "^2.3.4",
"zod" : "^3.22.4", "zod" : "^3.22.4",
"zod-validation-error": "^3.0.0" "zod-validation-error": "^3.0.0"
......
...@@ -30,24 +30,18 @@ import ClientsSharedExerciseHelper from './sharedByClients/helpers/Dojo ...@@ -30,24 +30,18 @@ import ClientsSharedExerciseHelper from './sharedByClients/helpers/Dojo
import Icon from './shared/types/Icon'; import Icon from './shared/types/Icon';
(async () => {
HttpManager.registerAxiosInterceptor();
console.log(Styles.APP_NAME(`${ Config.appName } (version {{VERSION}})`));
let exerciseAssignment: ExerciseAssignment | undefined; let exerciseAssignment: ExerciseAssignment | undefined;
let exerciseDockerCompose: ExerciseDockerCompose; let exerciseDockerCompose: ExerciseDockerCompose;
let exerciseResultsValidation: ExerciseResultsSanitizerAndValidator; let exerciseResultsValidation: ExerciseResultsSanitizerAndValidator;
let haveResultsVolume: boolean; let haveResultsVolume: boolean;
/**
/* * Step 1:
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 1: * - Read the dojo assignment file from the assignment repository
- Read the dojo assignment file from the assignment repository * - Download immutables files (maybe throw or show an error if the files have been modified ?)
- Download immutables files (maybe throw or show an error if the files have been modified ?)
*/ */
{ async function downloadImmutablesFiles() {
console.log(Styles.INFO(`${ Icon.INFO }️ Checking the exercise's assignment and his immutable files`)); console.log(Styles.INFO(`${ Icon.INFO }️ Checking the exercise's assignment and his immutable files`));
exerciseAssignment = await DojoBackendManager.getExerciseAssignment(); exerciseAssignment = await DojoBackendManager.getExerciseAssignment();
if ( !exerciseAssignment ) { if ( !exerciseAssignment ) {
...@@ -65,23 +59,23 @@ import Icon from './shared/types/Icon'; ...@@ -65,23 +59,23 @@ import Icon from './shared/types/Icon';
} }
/* /**
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 2: * Step 2:
- Get override of docker-compose file (for override the volume by a bind mount to the results folder shared between dind and the host) * - Get override of docker-compose file (for override the volume by a bind mount to the results folder shared between dind and the host)
- Run docker-compose file * - Run docker-compose file
- Get logs from linked services * - Get logs from linked services
*/ */
{ async function runDockerCompose() {
let composeFileOverride: string[] = []; let composeFileOverride: string[] = [];
const composeOverridePath: string = path.join(Config.folders.project, 'docker-compose-override.yml'); const composeOverridePath: string = path.join(Config.folders.project, 'docker-compose-override.yml');
if ( haveResultsVolume ) { if ( haveResultsVolume ) {
const composeOverride = fs.readFileSync(path.join(__dirname, '../assets/docker-compose-override.yml'), 'utf8').replace('{{VOLUME_NAME}}', exerciseAssignment.assignmentFile.result.volume!).replace('{{MOUNT_PATH}}', Config.folders.resultsExercise); const composeOverride = fs.readFileSync(path.join(__dirname, '../assets/docker-compose-override.yml'), 'utf8').replace('{{VOLUME_NAME}}', exerciseAssignment!.assignmentFile.result.volume!).replace('{{MOUNT_PATH}}', Config.folders.resultsExercise);
fs.writeFileSync(composeOverridePath, composeOverride); fs.writeFileSync(composeOverridePath, composeOverride);
composeFileOverride = [ composeOverridePath ]; composeFileOverride = [ composeOverridePath ];
} }
exerciseDockerCompose = new ExerciseDockerCompose(ClientsSharedConfig.dockerCompose.projectName, exerciseAssignment.assignmentFile, Config.folders.project, composeFileOverride); exerciseDockerCompose = new ExerciseDockerCompose(ClientsSharedConfig.dockerCompose.projectName, exerciseAssignment!.assignmentFile, Config.folders.project, composeFileOverride);
try { try {
await new Promise<void>((resolve, reject) => { await new Promise<void>((resolve, reject) => {
...@@ -113,12 +107,15 @@ import Icon from './shared/types/Icon'; ...@@ -113,12 +107,15 @@ import Icon from './shared/types/Icon';
} }
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 3: Check content requirements and content size /**
{ * Step 3:
* - Check content requirements and content size
*/
async function checkExecutionContent() {
exerciseResultsValidation = new ExerciseResultsSanitizerAndValidator(Config.folders.resultsDojo, Config.folders.resultsExercise, exerciseDockerCompose.exitCode); exerciseResultsValidation = new ExerciseResultsSanitizerAndValidator(Config.folders.resultsDojo, Config.folders.resultsExercise, exerciseDockerCompose.exitCode);
try { try {
await new Promise<void>((resolve) => { await new Promise<void>(resolve => {
exerciseResultsValidation.events.on('step', (_name: string, message: string) => { exerciseResultsValidation.events.on('step', (_name: string, message: string) => {
console.log(Styles.INFO(`${ Icon.INFO } ${ message }`)); console.log(Styles.INFO(`${ Icon.INFO } ${ message }`));
}); });
...@@ -142,9 +139,11 @@ import Icon from './shared/types/Icon'; ...@@ -142,9 +139,11 @@ import Icon from './shared/types/Icon';
} catch ( error ) { /* empty */ } } catch ( error ) { /* empty */ }
} }
/**
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 4: Upload results * Step 4:
{ * - Upload results
*/
async function uploadResults() {
try { try {
console.log(Styles.INFO(`${ Icon.INFO } Uploading results to the dojo server`)); console.log(Styles.INFO(`${ Icon.INFO } Uploading results to the dojo server`));
const commit: Record<string, string> = {}; const commit: Record<string, string> = {};
...@@ -166,14 +165,26 @@ import Icon from './shared/types/Icon'; ...@@ -166,14 +165,26 @@ import Icon from './shared/types/Icon';
} }
/* /**
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 5: * Step 5:
- Display results * - Display results
- Exit with container exit code * - Exit with container exit code
*/ */
{ async function displayResults() {
ClientsSharedExerciseHelper.displayExecutionResults(exerciseResultsValidation.exerciseResults, exerciseDockerCompose.exitCode, Styles, `\n\n${ Icon.INFO }️ More detailed logs and resources may be available in artifacts`); ClientsSharedExerciseHelper.displayExecutionResults(exerciseResultsValidation.exerciseResults, exerciseDockerCompose.exitCode, Styles, `\n\n${ Icon.INFO }️ More detailed logs and resources may be available in artifacts`);
process.exit(exerciseDockerCompose.exitCode); process.exit(exerciseDockerCompose.exitCode);
} }
(async () => {
HttpManager.registerAxiosInterceptor();
console.log(Styles.APP_NAME(`${ Config.appName } (version {{VERSION}})`));
await downloadImmutablesFiles();
await runDockerCompose();
await checkExecutionContent();
await uploadResults();
await displayResults();
})(); })();
\ No newline at end of file
...@@ -20,7 +20,7 @@ class Config { ...@@ -20,7 +20,7 @@ class Config {
}; };
constructor() { constructor() {
this.appName = process.env.APP_NAME || ''; this.appName = process.env.APP_NAME ?? '';
this.folders = { this.folders = {
project : process.env.PROJECT_FOLDER?.convertWithEnvVars() ?? './', project : process.env.PROJECT_FOLDER?.convertWithEnvVars() ?? './',
...@@ -31,13 +31,13 @@ class Config { ...@@ -31,13 +31,13 @@ class Config {
this.resetResultsVolume(); this.resetResultsVolume();
this.exercise = { this.exercise = {
id : process.env.DOJO_EXERCISE_ID || '', id : process.env.DOJO_EXERCISE_ID ?? '',
secret: process.env.DOJO_SECRET || '' secret: process.env.DOJO_SECRET ?? ''
}; };
this.dockerhub = { this.dockerhub = {
repositories: { repositories: {
exerciseChecker: process.env.DOCKERHUB_EXERCISE_CHECKER_REPOSITORY || '' exerciseChecker: process.env.DOCKERHUB_EXERCISE_CHECKER_REPOSITORY ?? ''
} }
}; };
} }
......
import ClientsSharedConfig from '../sharedByClients/config/ClientsSharedConfig';
import axios from 'axios'; import axios from 'axios';
import DojoBackendResponse from '../shared/types/Dojo/DojoBackendResponse'; import DojoBackendResponse from '../shared/types/Dojo/DojoBackendResponse';
import ExerciseAssignment from '../sharedByClients/models/ExerciseAssignment'; import ExerciseAssignment from '../sharedByClients/models/ExerciseAssignment';
...@@ -6,23 +5,20 @@ import Config from '../config/Config'; ...@@ -6,23 +5,20 @@ import Config from '../config/Config';
import ExerciseResultsFile from '../shared/types/Dojo/ExerciseResultsFile'; import ExerciseResultsFile from '../shared/types/Dojo/ExerciseResultsFile';
import ApiRoute from '../sharedByClients/types/Dojo/ApiRoute'; import ApiRoute from '../sharedByClients/types/Dojo/ApiRoute';
import { IFileDirStat } from '../shared/helpers/recursiveFilesStats/RecursiveFilesStats'; import { IFileDirStat } from '../shared/helpers/recursiveFilesStats/RecursiveFilesStats';
import DojoBackendHelper from '../sharedByClients/helpers/Dojo/DojoBackendHelper';
class DojoBackendManager { class DojoBackendManager {
public getApiUrl(route: ApiRoute): string {
return `${ ClientsSharedConfig.apiURL }${ route }`;
}
public async getExerciseAssignment(): Promise<ExerciseAssignment | undefined> { public async getExerciseAssignment(): Promise<ExerciseAssignment | undefined> {
try { try {
return (await axios.get<DojoBackendResponse<ExerciseAssignment>>(this.getApiUrl(ApiRoute.EXERCISE_ASSIGNMENT).replace('{{id}}', Config.exercise.id))).data.data; return (await axios.get<DojoBackendResponse<ExerciseAssignment>>(DojoBackendHelper.getApiUrl(ApiRoute.EXERCISE_ASSIGNMENT, { exerciseIdOrUrl: Config.exercise.id }))).data.data;
} catch ( error ) { } catch ( error ) {
return undefined; return undefined;
} }
} }
public async sendResults(exitCode: number, commit: Record<string, string>, results: ExerciseResultsFile, files: Array<IFileDirStat>, archiveBase64: string): Promise<void> { public async sendResults(exitCode: number, commit: Record<string, string>, results: ExerciseResultsFile, files: Array<IFileDirStat>, archiveBase64: string): Promise<void> {
await axios.post(this.getApiUrl(ApiRoute.EXERCISE_RESULTS).replace('{{id}}', Config.exercise.id), { await axios.post(DojoBackendHelper.getApiUrl(ApiRoute.EXERCISE_RESULTS, { exerciseIdOrUrl: Config.exercise.id }), {
exitCode : exitCode, exitCode : exitCode,
commit : JSON.stringify(commit), commit : JSON.stringify(commit),
results : JSON.stringify(results), results : JSON.stringify(results),
......
...@@ -31,9 +31,9 @@ class HttpManager { ...@@ -31,9 +31,9 @@ class HttpManager {
} }
private registerRequestInterceptor() { private registerRequestInterceptor() {
axios.interceptors.request.use((config) => { axios.interceptors.request.use(config => {
if ( config.data instanceof FormData ) { if ( config.data instanceof FormData ) {
config.headers = { ...config.headers, ...(config.data as FormData).getHeaders() } as AxiosRequestHeaders; config.headers = { ...config.headers, ...config.data.getHeaders() } as AxiosRequestHeaders;
} }
if ( config.url && (config.url.indexOf(ClientsSharedConfig.apiURL) !== -1) ) { if ( config.url && (config.url.indexOf(ClientsSharedConfig.apiURL) !== -1) ) {
...@@ -54,9 +54,7 @@ class HttpManager { ...@@ -54,9 +54,7 @@ class HttpManager {
} }
private registerResponseInterceptor() { private registerResponseInterceptor() {
axios.interceptors.response.use((response) => { axios.interceptors.response.use(response => response, error => {
return response;
}, (error) => {
if ( error.response ) { if ( error.response ) {
if ( error.response.status === StatusCodes.METHOD_NOT_ALLOWED && error.response.data ) { if ( error.response.status === StatusCodes.METHOD_NOT_ALLOWED && error.response.data ) {
const data: DojoBackendResponse<void> = error.response.data; const data: DojoBackendResponse<void> = error.response.data;
......
Subproject commit 89f3579ca9009f793742170928d808ab4c35d931 Subproject commit fca59c4d155603b53d48a30401aabab82d91fc59
Subproject commit 098c6d20f6ed84240c086b979b56afd598fdfea4 Subproject commit 9e75273d4600f5f42c8be3c24bdced6844c32449
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment