From 503a2ada14b53100df7863f8fd1ab1c8552d417a Mon Sep 17 00:00:00 2001
From: Joel von der Weid <joel.von-der-weid@hesge.ch>
Date: Tue, 14 May 2024 15:50:31 +0200
Subject: [PATCH] Add quality gate and profiles to assignments and exercises

---
 ExpressAPI/prisma/seed.ts                 |  6 ++++--
 ExpressAPI/src/helpers/GlobalHelper.ts    | 10 ++++++++--
 ExpressAPI/src/managers/SonarManager.ts   | 15 +++++++++++----
 ExpressAPI/src/routes/AssignmentRoutes.ts |  3 ++-
 ExpressAPI/src/routes/ExerciseRoutes.ts   |  2 +-
 5 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/ExpressAPI/prisma/seed.ts b/ExpressAPI/prisma/seed.ts
index 9154ef5..f73e71a 100644
--- a/ExpressAPI/prisma/seed.ts
+++ b/ExpressAPI/prisma/seed.ts
@@ -341,7 +341,8 @@ async function assignments() {
                                                'autoclose_referenced_issues'                     : true
                                            },
                                            gitlabLastInfoDate: new Date('2021-10-14T14:20:15.239Z'),
-                                           published         : false
+                                           published         : false,
+                                           secret            : '77B9BB29-82F8-4D1F-B6D2-A201ABFB8509'
                                        }
                                    });
         await db.assignment.upsert({
@@ -597,7 +598,8 @@ async function assignments() {
                                                'autoclose_referenced_issues'                     : true
                                            },
                                            gitlabLastInfoDate: new Date('2023-11-07T20:35:54.692Z'),
-                                           published         : true
+                                           published         : true,
+                                           secret            : '1127A3E7-4461-43B9-85DE-13C2317617AA'
                                        }
                                    });
     }
diff --git a/ExpressAPI/src/helpers/GlobalHelper.ts b/ExpressAPI/src/helpers/GlobalHelper.ts
index c34aac4..b784505 100644
--- a/ExpressAPI/src/helpers/GlobalHelper.ts
+++ b/ExpressAPI/src/helpers/GlobalHelper.ts
@@ -5,10 +5,12 @@ import DojoStatusCode            from '../shared/types/Dojo/DojoStatusCode.js';
 import { StatusCodes }           from 'http-status-codes';
 import { GitbeakerRequestError } from '@gitbeaker/requester-utils';
 import * as Gitlab               from '@gitbeaker/rest';
-import { AxiosError } from 'axios';
+import SonarProjectCreation      from '../shared/types/Sonar/SonarProjectCreation';
+import SonarManager              from '../managers/SonarManager';
+
 
 class GlobalHelper {
-    repoCreationFnExecCreator(req: express.Request, res: express.Response, gitlabError: DojoStatusCode, internalError: DojoStatusCode, repositoryToRemove?: Gitlab.ProjectSchema) {
+    repoCreationFnExecCreator(req: express.Request, res: express.Response, gitlabError: DojoStatusCode, internalError: DojoStatusCode, repositoryToRemove?: Gitlab.ProjectSchema, sonarToRemove?: SonarProjectCreation) {
         return async (toExec: () => Promise<unknown>, errorMessage?: string) => {
             try {
                 return await toExec();
@@ -21,6 +23,10 @@ class GlobalHelper {
                         if ( repositoryToRemove ) {
                             await GitlabManager.deleteRepository(repositoryToRemove.id);
                         }
+
+                        if ( sonarToRemove ) {
+                            await SonarManager.deleteProject(sonarToRemove.project.key);
+                        }
                     } catch ( deleteError ) {
                         logger.error('Repository deletion error');
                         logger.error(JSON.stringify(deleteError));
diff --git a/ExpressAPI/src/managers/SonarManager.ts b/ExpressAPI/src/managers/SonarManager.ts
index 88320a4..9c8946e 100644
--- a/ExpressAPI/src/managers/SonarManager.ts
+++ b/ExpressAPI/src/managers/SonarManager.ts
@@ -88,14 +88,14 @@ class SonarManager {
                 return await GlobalHelper.repositoryCreationError('Sonar error', undefined, req, res, DojoStatusCode.ASSIGNMENT_CREATION_SONAR_ERROR, DojoStatusCode.ASSIGNMENT_CREATION_SONAR_ERROR, gitlabRepository);
             }
         } catch ( error ) {
-            return await GlobalHelper.repositoryCreationError('Sonar project creation error', error, req, res, DojoStatusCode.ASSIGNMENT_CREATION_SONAR_ERROR, DojoStatusCode.ASSIGNMENT_CREATION_INTERNAL_ERROR, gitlabRepository);
+            return await GlobalHelper.repositoryCreationError('Sonar project creation error', error, req, res, DojoStatusCode.ASSIGNMENT_CREATION_SONAR_ERROR, DojoStatusCode.ASSIGNMENT_CREATION_INTERNAL_ERROR, gitlabRepository, sonarProject);
         }
         // Add gate and profiles to sonar project
         if ( qualityGate != undefined && qualityGate != "" ) {
             try {
                 await this.addQualityGate(sonarProject.project.key, qualityGate);
             } catch ( error ) {
-                return await GlobalHelper.repositoryCreationError('Sonar gate error', error, req, res, DojoStatusCode.ASSIGNMENT_SONAR_GATE_NOT_FOUND, DojoStatusCode.ASSIGNMENT_SONAR_GATE_NOT_FOUND, gitlabRepository);
+                return await GlobalHelper.repositoryCreationError('Sonar gate error', error, req, res, DojoStatusCode.ASSIGNMENT_SONAR_GATE_NOT_FOUND, DojoStatusCode.ASSIGNMENT_SONAR_GATE_NOT_FOUND, gitlabRepository, sonarProject);
             }
         }
 
@@ -106,10 +106,10 @@ class SonarManager {
                     if (lang.trim() != '' && name.trim() != '') {
                         await this.addQualityProfile(sonarProject.project.key, name.trim(), lang.trim());
                     } else {
-                        return await GlobalHelper.repositoryCreationError('Sonar profile invalid', undefined, req, res, DojoStatusCode.ASSIGNMENT_SONAR_PROFILE_NOT_FOUND, DojoStatusCode.ASSIGNMENT_SONAR_PROFILE_NOT_FOUND, gitlabRepository);
+                        return await GlobalHelper.repositoryCreationError('Sonar profile invalid', undefined, req, res, DojoStatusCode.ASSIGNMENT_SONAR_PROFILE_NOT_FOUND, DojoStatusCode.ASSIGNMENT_SONAR_PROFILE_NOT_FOUND, gitlabRepository, sonarProject);
                     }
                 } catch ( error ) {
-                    return await GlobalHelper.repositoryCreationError('Sonar profile not found', error, req, res, DojoStatusCode.ASSIGNMENT_SONAR_PROFILE_NOT_FOUND, DojoStatusCode.ASSIGNMENT_SONAR_PROFILE_NOT_FOUND, gitlabRepository);
+                    return await GlobalHelper.repositoryCreationError('Sonar profile not found', error, req, res, DojoStatusCode.ASSIGNMENT_SONAR_PROFILE_NOT_FOUND, DojoStatusCode.ASSIGNMENT_SONAR_PROFILE_NOT_FOUND, gitlabRepository, sonarProject);
                 }
             }
         }
@@ -117,6 +117,13 @@ class SonarManager {
         return sonarProject;
     }
 
+    async deleteProject(projectKey: string) {
+        const formData = new FormData();
+        formData.append('project', projectKey);
+
+        return await this.executePostRequest<SonarProjectCreation>(this.getApiUrl(SonarRoute.PROJECT_DELETE), formData)
+    }
+
     async getLanguages() {
         const resp = await this.executeGetRequest<{ languages: { key: string, name: string }[]}>(this.getApiUrl(SonarRoute.GET_LANGUAGES))
         return resp.languages.map(l => l.key)
diff --git a/ExpressAPI/src/routes/AssignmentRoutes.ts b/ExpressAPI/src/routes/AssignmentRoutes.ts
index e7d8c13..ee123f2 100644
--- a/ExpressAPI/src/routes/AssignmentRoutes.ts
+++ b/ExpressAPI/src/routes/AssignmentRoutes.ts
@@ -187,7 +187,7 @@ class AssignmentRoutes implements RoutesManager {
 
         try {
             await repoCreationFnExec(() => GitlabManager.protectBranch(repository.id, '*', true, Gitlab.AccessLevel.DEVELOPER, Gitlab.AccessLevel.DEVELOPER, Gitlab.AccessLevel.ADMIN), 'Branch protection modification error');
-            await repoCreationFnExec(() => GitlabManager.addRepositoryVariable(repository.id, 'DOJO_ASSIGNMENT_NAME', repository.name, false, true), 'Add repo variable "DOJO_ASSIGNMENT_NAME" error');
+            await repoCreationFnExec(() => GitlabManager.addRepositoryVariable(repository.id, 'DOJO_ASSIGNMENT_NAME', repository.name, false, false), 'Add repo variable "DOJO_ASSIGNMENT_NAME" error');
             await repoCreationFnExec(() => GitlabManager.addRepositoryVariable(repository.id, 'DOJO_ASSIGNMENT_SECRET', secret, false, true), 'Add repo variable "DOJO_ASSIGNMENT_SECRET" error');
             await repoCreationFnExec(() => GitlabManager.addRepositoryBadge(repository.id, Config.gitlab.badges.pipeline.link, Config.gitlab.badges.pipeline.imageUrl, 'Pipeline Status'), 'Pipeline badge addition error');
             await repoCreationFnExec(() => GitlabManager.deleteFile(repository.id, '.gitlab-ci.yml', 'Remove .gitlab-ci.yml'));
@@ -221,6 +221,7 @@ class AssignmentRoutes implements RoutesManager {
                                                                                                        sonarGate         : params.sonarGate,
                                                                                                        sonarProfiles     : params.sonarProfiles,
                                                                                                        language          : Language[params.language as keyof typeof Language],
+                                                                                                       secret            : secret,
                                                                                                        staff             : {
                                                                                                            connectOrCreate: [ ...params.members.map(gitlabUser => {
                                                                                                                return {
diff --git a/ExpressAPI/src/routes/ExerciseRoutes.ts b/ExpressAPI/src/routes/ExerciseRoutes.ts
index 6221ede..269cedf 100644
--- a/ExpressAPI/src/routes/ExerciseRoutes.ts
+++ b/ExpressAPI/src/routes/ExerciseRoutes.ts
@@ -245,6 +245,7 @@ class ExerciseRoutes implements RoutesManager {
         const exerciseId: string = uuidv4();
         const secret: string = uuidv4();
         const repository: Gitlab.ProjectSchema | undefined = await this.createExerciseRepository(assignment, params.members, exerciseId, req, res);
+        let sonarProject: SonarProjectCreation | undefined = undefined;
 
         if ( !repository ) {
             return;
@@ -269,7 +270,6 @@ class ExerciseRoutes implements RoutesManager {
             await repoCreationFnExec(async () => Promise.all([ ...new Set([ ...assignment.staff, ...params.members ].map(member => member.id)) ].map(GlobalHelper.addRepoMember(repository.id))), 'Add repository members error');
 
             // Create Sonar project
-            let sonarProject: SonarProjectCreation | undefined = undefined;
             if ( assignment.useSonar && assignment.sonarProfiles != null ) {
                 const profiles: string[] = JSON.parse(assignment.sonarProfiles as string);
                 sonarProject = await GlobalHelper.repoCreationFnExecCreator(req, res, DojoStatusCode.EXERCISE_CREATION_SONAR_ERROR, DojoStatusCode.EXERCISE_CREATION_INTERNAL_ERROR, repository)(() => SonarManager.createProjectWithQualities(repository, assignment.sonarGate, profiles, req, res), 'Sonar project creation error') as SonarProjectCreation;
-- 
GitLab