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
  • jw_sonar
  • jw_sonar_backup
  • main
  • move-to-esm-only
  • open_tool_for_self_hosting
  • v5.0
  • v4.1
  • v4.2
8 results

Target

Select target project
  • dojo_project/projects/shared/nodesharedcode
1 result
Select Git revision
  • jw_sonar
  • jw_sonar_backup
  • main
  • move-to-esm-only
  • open_tool_for_self_hosting
  • v5.0
  • v4.1
  • v4.2
8 results
Show changes
Commits on Source (14)
......@@ -6,10 +6,11 @@ This repo contains some code that can be shared across node projects of Dojo.
These packages are needed :
- `ajv`
- `json5`
- `tar-stream`
- `winston`
- `zod`
- `zod-validation-error`
## How to use it
......
class SharedConfig {
public readonly production: boolean;
public debug: boolean = false;
public readonly logsFolder: string;
......
import Ajv, { ErrorObject, JTDSchemaType } from 'ajv/dist/jtd';
import fs from 'fs';
import JSON5 from 'json5';
import AssignmentFile from '../../types/Dojo/AssignmentFile';
import GitlabPipelineStatus from '../../types/Gitlab/GitlabPipelineStatus';
import DojoStatusCode from '../../types/Dojo/DojoStatusCode';
import GitlabPipeline from '../../types/Gitlab/GitlabPipeline';
import SharedGitlabManager from '../../managers/SharedGitlabManager';
import AssignmentFile from '../../types/Dojo/AssignmentFile';
import GitlabPipelineStatus from '../../types/Gitlab/GitlabPipelineStatus';
import DojoStatusCode from '../../types/Dojo/DojoStatusCode';
import GitlabPipeline from '../../types/Gitlab/GitlabPipeline';
import SharedGitlabManager from '../../managers/SharedGitlabManager';
import Json5FileValidator from '../Json5FileValidator';
class SharedAssignmentHelper {
private validateDescriptionFileV1(resultsFilePathOrStr: string, isFile: boolean = true): { results: AssignmentFile | undefined, isValid: boolean, errors: Array<ErrorObject | string> | null | undefined } {
const ajv = new Ajv();
const schema: JTDSchemaType<AssignmentFile> = {
properties : {
dojoAssignmentVersion: { type: 'uint32' },
version : { type: 'uint32' },
immutable: {
elements: {
properties : {
path: { type: 'string' }
},
optionalProperties: {
description: { type: 'string' },
isDirectory: { type: 'boolean' }
}
}
},
result: {
properties : {
container: { type: 'string' }
},
optionalProperties: {
volume: { type: 'string' }
}
}
},
additionalProperties: false
};
const validator = ajv.compile(schema);
try {
const results = JSON5.parse(isFile ? fs.readFileSync(resultsFilePathOrStr, 'utf8') : resultsFilePathOrStr);
const isValid = validator(results);
return {
results: isValid ? results : results as AssignmentFile,
isValid: isValid,
errors : validator.errors
};
} catch ( error ) {
return {
results: undefined,
isValid: false,
errors : [ `JSON5 invalid : ${ JSON.stringify(error) }` ]
};
}
}
validateDescriptionFile(resultsFilePathOrStr: string, isFile: boolean = true, version: number = 1): { results: AssignmentFile | undefined, isValid: boolean, errors: Array<ErrorObject | string> | null | undefined } {
validateDescriptionFile(filePathOrStr: string, isFile: boolean = true, version: number = 1): { content: AssignmentFile | undefined, isValid: boolean, error: string | null } {
switch ( version ) {
case 1:
return this.validateDescriptionFileV1(resultsFilePathOrStr, isFile);
return Json5FileValidator.validateFile(AssignmentFile, filePathOrStr, isFile);
default:
return {
results: undefined,
content: undefined,
isValid: false,
errors : [ `Version ${ version } not supported` ]
error : `Version ${ version } not supported`
};
}
}
......
import Ajv, { ErrorObject, JTDSchemaType } from 'ajv/dist/jtd';
import fs from 'fs';
import ExerciseResultsFile from '../../types/Dojo/ExerciseResultsFile';
import JSON5 from 'json5';
class SharedExerciseHelper {
validateResultFile(resultsFilePathOrStr: string, isFile: boolean = true): { results: ExerciseResultsFile | undefined, isValid: boolean, errors: Array<ErrorObject | string> | null | undefined } {
const ajv = new Ajv();
const schema: JTDSchemaType<ExerciseResultsFile> = {
properties : {},
optionalProperties : {
success: { type: 'boolean' },
containerExitCode: { type: 'uint32' },
successfulTests: { type: 'uint32' },
failedTests : { type: 'uint32' },
successfulTestsList: {
elements: {
type: 'string'
}
},
failedTestsList : {
elements: {
type: 'string'
}
}
},
additionalProperties: false
};
const validator = ajv.compile(schema);
try {
const results = JSON5.parse(isFile ? fs.readFileSync(resultsFilePathOrStr, 'utf8') : resultsFilePathOrStr);
const isValid = validator(results);
if ( isValid ) {
if ( results.successfulTests === undefined && results.successfulTestsList !== undefined ) {
results.successfulTests = results.successfulTestsList.length;
}
if ( results.failedTests === undefined && results.failedTestsList !== undefined ) {
results.failedTests = results.failedTestsList.length;
}
}
return {
results: isValid ? results : results as ExerciseResultsFile,
isValid: isValid,
errors : validator.errors
};
} catch ( error ) {
return {
results: undefined,
isValid: false,
errors : [ `JSON5 invalid : ${ JSON.stringify(error) }` ]
};
}
}
}
class SharedExerciseHelper {}
export default new SharedExerciseHelper();
\ No newline at end of file
import JSON5 from 'json5';
import fs from 'fs';
import { z, ZodError } from 'zod';
import { fromZodError } from 'zod-validation-error';
class Json5FileValidator {
validateFile<T>(schema: z.ZodType<T>, filePathOrStr: string, isFile: boolean = true, resultSanitizer: (value: T) => T = value => value): { content: T | undefined, isValid: boolean, error: string | null } {
let parsedInput: T;
try {
parsedInput = JSON5.parse(isFile ? fs.readFileSync(filePathOrStr, 'utf8') : filePathOrStr);
} catch ( error ) {
return {
content: undefined,
isValid: false,
error : `JSON5 invalid : ${ JSON.stringify(error) }`
};
}
try {
return {
content: resultSanitizer(schema.parse(parsedInput) as unknown as T),
isValid: true,
error : null
};
} catch ( error ) {
if ( error instanceof ZodError ) {
return {
content: parsedInput,
isValid: false,
error : fromZodError(error).toString()
};
}
return {
content: parsedInput,
isValid: false,
error : `Unknown error : ${ JSON.stringify(error) }`
};
}
}
}
export default new Json5FileValidator();
\ No newline at end of file
import ImmutableFileDescriptor from './ImmutableFileDescriptor';
import { z } from 'zod';
interface AssignmentFile {
dojoAssignmentVersion: number,
version: number,
const AssignmentFile = z.object({
dojoAssignmentVersion: z.number(),
version : z.number(),
immutable : z.array(ImmutableFileDescriptor.transform(value => value as ImmutableFileDescriptor)),
result : z.object({
container: z.string(),
volume : z.string().optional()
})
}).strict();
immutable: Array<ImmutableFileDescriptor>
result: {
container: string, volume?: string
}
}
type AssignmentFile = z.infer<typeof AssignmentFile>;
export default AssignmentFile;
\ No newline at end of file
......@@ -5,7 +5,8 @@ enum ExerciseCheckerError {
DOCKER_COMPOSE_DOWN_ERROR = 203,
EXERCISE_RESULTS_FOLDER_TOO_BIG = 204,
EXERCISE_RESULTS_FILE_SCHEMA_NOT_VALID = 206,
UPLOAD = 207
UPLOAD = 207,
DOCKER_COMPOSE_REMOVE_DANGLING_ERROR = 208
}
......
interface ExerciseResultsFile {
success?: boolean;
import Icon from '../Icon';
import { z } from 'zod';
containerExitCode?: number;
successfulTests?: number;
failedTests?: number;
const ExerciseResultsFile = z.object({
success: z.boolean().optional(),
successfulTestsList?: Array<string>;
failedTestsList?: Array<string>;
}
containerExitCode: z.number().optional(),
successfulTests: z.number().optional(),
failedTests : z.number().optional(),
successfulTestsList: z.array(z.string()).optional(),
failedTestsList : z.array(z.string()).optional(),
otherInformations: z.array(z.object({
name : z.string(),
description : z.string().optional(),
icon : z.enum(Object.keys(Icon) as [ firstKey: string, ...otherKeys: Array<string> ]).optional(),
itemsOrInformations: z.union([ z.array(z.string()), z.string() ])
}))
.optional()
}).strict().transform(value => {
if ( value.successfulTests === undefined && value.successfulTestsList !== undefined ) {
value.successfulTests = value.successfulTestsList.length;
}
if ( value.failedTests === undefined && value.failedTestsList !== undefined ) {
value.failedTests = value.failedTestsList.length;
}
return value;
});
type ExerciseResultsFile = z.infer<typeof ExerciseResultsFile>;
export default ExerciseResultsFile;
\ No newline at end of file
interface ImmutableFileDescriptor {
description?: string,
path: string,
isDirectory?: boolean,
}
import { z } from 'zod';
const ImmutableFileDescriptor = z.object({
description: z.string().optional(),
path : z.string(),
isDirectory: z.boolean().optional()
});
type ImmutableFileDescriptor = z.infer<typeof ImmutableFileDescriptor>;
export default ImmutableFileDescriptor;
\ No newline at end of file
interface GitlabCommit {
id: string;
short_id: string;
created_at: string;
parent_ids: Array<string>;
title: string;
message: string;
author_name: string;
author_email: string;
authored_date: string;
committer_name: string;
committer_email: string;
committed_date: string;
}
export default GitlabCommit;
\ No newline at end of file
interface GitlabMilestone {
id: number;
iid: number;
project_id: number;
title: string;
description: string;
state: string;
created_at: string;
updated_at: string;
due_date: string;
start_date: string;
web_url: string;
issue_stats: {
total: number; closed: number;
};
}
export default GitlabMilestone;
\ No newline at end of file
import GitlabUser from './GitlabUser';
import GitlabCommit from './GitlabCommit';
import GitlabMilestone from './GitlabMilestone';
interface GitlabRelease {
tag_name: string;
description: string;
created_at: string;
released_at: string;
author: GitlabUser;
commit: GitlabCommit;
milestones: Array<GitlabMilestone>;
commit_path: string;
tag_path: string;
assets: {
count: number; sources: Array<{
format: string; url: string;
}>; links: Array<{
id: number; name: string; url: string; link_type: string;
}>; evidence_file_path: string;
};
evidences: Array<{
sha: string; filepath: string; collected_at: string;
}>;
}
export default GitlabRelease;
\ No newline at end of file
......@@ -9,6 +9,7 @@ enum GitlabRoute {
REPOSITORY_FORK = '/projects/{{id}}/fork',
REPOSITORY_MEMBER_ADD = '/projects/{{id}}/members',
REPOSITORY_MEMBERS_GET = '/projects/{{id}}/members/all',
REPOSITORY_RELEASES_GET = '/projects/{{id}}/releases',
REPOSITORY_BADGES_ADD = '/projects/{{id}}/badges',
REPOSITORY_VARIABLES_ADD = '/projects/{{id}}/variables',
REPOSITORY_BRANCHES_PROTECT = '/projects/{{id}}/protected_branches',
......
const Icon = {
CAT_INFO : '▶️',
INFO : 'ℹ️',
ERROR : '⛔️',
SUCCESS : '',
FAILURE : '',
VOMIT : '🤮',
YUCK : '🤢',
WELL_DONE: '👍',
NULL : '',
NONE : '',
BADMINTON: '🏸'
} as { [index: string]: string };
export default Icon;
\ No newline at end of file