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)
import { TypedEmitter } from 'tiny-typed-emitter';
import AssignmentValidatorEvents from '../../types/Dojo/AssignmentValidatorEvents';
import SharedAssignmentHelper from '../../../shared/helpers/Dojo/SharedAssignmentHelper';
import path from 'node:path';
import AssignmentCheckerError from '../../../shared/types/Dojo/AssignmentCheckerError';
import fs from 'fs-extra';
import ClientsSharedConfig from '../../config/ClientsSharedConfig';
import YAML from 'yaml';
import DojoDockerCompose from '../../types/Dojo/DojoDockerCompose';
import { exec, spawn } from 'child_process';
import AssignmentFile from '../../../shared/types/Dojo/AssignmentFile';
import ExerciseDockerCompose from './ExerciseDockerCompose';
import util from 'util';
import { TypedEmitter } from 'tiny-typed-emitter';
import AssignmentValidatorEvents from '../../types/Dojo/AssignmentValidatorEvents';
import SharedAssignmentHelper from '../../../shared/helpers/Dojo/SharedAssignmentHelper';
import path from 'node:path';
import AssignmentCheckerError from '../../../shared/types/Dojo/AssignmentCheckerError';
import fs from 'fs-extra';
import ClientsSharedConfig from '../../config/ClientsSharedConfig';
import YAML from 'yaml';
import DojoDockerCompose from '../../types/Dojo/DojoDockerCompose';
import { exec, spawn } from 'child_process';
import AssignmentFile from '../../../shared/types/Dojo/AssignmentFile';
import ExerciseDockerCompose from './ExerciseDockerCompose';
import util from 'util';
import Assignment, { Language } from '../../models/Assignment';
import ClientsSharedAssignmentHelper from './ClientsSharedAssignmentHelper';
const execAsync = util.promisify(exec);
......@@ -81,7 +83,7 @@ class AssignmentValidator {
(async () => {
let dockerComposeFile: DojoDockerCompose;
let assignmentFile: AssignmentFile;
let assignment: Assignment;
/*
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 1: Check requirements
......@@ -118,11 +120,32 @@ class AssignmentValidator {
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
- 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...');
......@@ -159,13 +182,23 @@ class AssignmentValidator {
}
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);
}
/*
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 3: Docker Compose file validation
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 4: Docker Compose file validation
- Global validation
- Validation of the containers and volumes named in dojo_assignment.json
*/
......@@ -218,7 +251,7 @@ class AssignmentValidator {
/*
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 4: Dockerfiles validation
//////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 5: Dockerfiles validation
- Check if file exists
- TODO - Dockerfile structure linter - Issue #51 - https://github.com/hadolint/hadolint
*/
......@@ -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)
*/
{
......
import chalk from 'chalk';
import boxen from 'boxen';
import Icon from '../../../shared/types/Icon';
import AssignmentValidator from './AssignmentValidator';
import { existsSync, readFileSync } from 'fs';
import { join } from 'path';
import chalk from 'chalk';
import boxen from 'boxen';
import Icon from '../../../shared/types/Icon';
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 {
......@@ -21,6 +28,30 @@ class ClientsSharedAssignmentHelper {
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 User from './User';
import Exercise from './Exercise';
import SonarProjectCreation from '../../shared/types/Sonar/SonarProjectCreation';
interface Assignment {
......@@ -11,6 +12,10 @@ interface Assignment {
gitlabLastInfo: GitlabRepository;
gitlabLastInfoDate: string;
published: boolean;
useSonar: boolean;
sonarKey: string;
sonarCreationInfo: SonarProjectCreation;
language: Language;
staff: Array<User>;
exercises: Array<Exercise>;
......@@ -19,4 +24,74 @@ interface Assignment {
}
export default Assignment;
\ No newline at end of file
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;
......@@ -2,6 +2,7 @@ import GitlabRepository from '../../shared/types/Gitlab/GitlabRepository';
import { CommitSchema } from '@gitbeaker/rest';
import User from './User';
import Assignment from './Assignment';
import SonarProjectCreation from '../../shared/types/Sonar/SonarProjectCreation';
interface Exercise {
......@@ -14,6 +15,9 @@ interface Exercise {
gitlabLastInfo: GitlabRepository;
gitlabLastInfoDate: string;
sonarKey: string;
sonarCreationInfo: SonarProjectCreation;
members: Array<User> | undefined;
assignment: Assignment | undefined;
......
......@@ -4,6 +4,7 @@ enum ApiRoute {
TEST_SESSION = '/test_session',
GITLAB_CHECK_TEMPLATE_ACCESS = '/gitlab/project/{{id}}/checkTemplateAccess',
SONAR = '/sonar',
LANGUAGES = '/assignments/languages',
ASSIGNMENT_GET = '/assignments/{{nameOrUrl}}',
ASSIGNMENT_CREATE = '/assignments',
ASSIGNMENT_PUBLISH = '/assignments/{{nameOrUrl}}/publish',
......