Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • dojo_project/projects/shared/nodeclientsharedcode
1 result
Select Git revision
Show changes
Commits on Source (4)
...@@ -11,6 +11,8 @@ import { exec, spawn } from 'child_process'; ...@@ -11,6 +11,8 @@ 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 { existsSync, readFileSync } from 'fs';
import { join } from 'path';
import chalk from 'chalk'; import chalk from 'chalk';
import boxen from 'boxen'; import boxen from 'boxen';
import Icon from '../../../shared/types/Icon'; import Icon from '../../../shared/types/Icon';
import AssignmentValidator from './AssignmentValidator'; 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);
}
} }
......
import GitlabRepository from '../../shared/types/Gitlab/GitlabRepository'; import GitlabRepository from '../../shared/types/Gitlab/GitlabRepository';
import User from './User'; import User from './User';
import Exercise from './Exercise'; import Exercise from './Exercise';
import SonarProjectCreation from '../../shared/types/Sonar/SonarProjectCreation';
interface Assignment { interface Assignment {
...@@ -11,6 +12,10 @@ interface Assignment { ...@@ -11,6 +12,10 @@ interface Assignment {
gitlabLastInfo: GitlabRepository; gitlabLastInfo: GitlabRepository;
gitlabLastInfoDate: string; gitlabLastInfoDate: string;
published: boolean; published: boolean;
useSonar: boolean;
sonarKey: string;
sonarCreationInfo: SonarProjectCreation;
language: Language;
staff: Array<User>; staff: Array<User>;
exercises: Array<Exercise>; exercises: Array<Exercise>;
...@@ -19,4 +24,74 @@ interface Assignment { ...@@ -19,4 +24,74 @@ interface Assignment {
} }
export enum Language {
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; export default Assignment;
...@@ -2,6 +2,7 @@ import GitlabRepository from '../../shared/types/Gitlab/GitlabRepository'; ...@@ -2,6 +2,7 @@ import GitlabRepository from '../../shared/types/Gitlab/GitlabRepository';
import { CommitSchema } from '@gitbeaker/rest'; import { CommitSchema } from '@gitbeaker/rest';
import User from './User'; import User from './User';
import Assignment from './Assignment'; import Assignment from './Assignment';
import SonarProjectCreation from '../../shared/types/Sonar/SonarProjectCreation';
interface Exercise { interface Exercise {
...@@ -14,6 +15,9 @@ interface Exercise { ...@@ -14,6 +15,9 @@ interface Exercise {
gitlabLastInfo: GitlabRepository; gitlabLastInfo: GitlabRepository;
gitlabLastInfoDate: string; gitlabLastInfoDate: string;
sonarKey: string;
sonarCreationInfo: SonarProjectCreation;
members: Array<User> | undefined; members: Array<User> | undefined;
assignment: Assignment | undefined; assignment: Assignment | undefined;
......
...@@ -4,6 +4,7 @@ enum ApiRoute { ...@@ -4,6 +4,7 @@ enum ApiRoute {
TEST_SESSION = '/test_session', TEST_SESSION = '/test_session',
GITLAB_CHECK_TEMPLATE_ACCESS = '/gitlab/project/{{id}}/checkTemplateAccess', GITLAB_CHECK_TEMPLATE_ACCESS = '/gitlab/project/{{id}}/checkTemplateAccess',
SONAR = '/sonar', SONAR = '/sonar',
LANGUAGES = '/assignments/languages',
ASSIGNMENT_GET = '/assignments/{{nameOrUrl}}', ASSIGNMENT_GET = '/assignments/{{nameOrUrl}}',
ASSIGNMENT_CREATE = '/assignments', ASSIGNMENT_CREATE = '/assignments',
ASSIGNMENT_PUBLISH = '/assignments/{{nameOrUrl}}/publish', ASSIGNMENT_PUBLISH = '/assignments/{{nameOrUrl}}/publish',
......