diff --git a/ExerciseChecker/.env.vault b/ExerciseChecker/.env.vault index ffac033d93381286bf9c2644538ea0bc7244a848..a910a9ca68c28693a4ec6cc9ed064c3cde53a59b 100644 --- a/ExerciseChecker/.env.vault +++ b/ExerciseChecker/.env.vault @@ -4,11 +4,11 @@ #/--------------------------------------------------/ # development -DOTENV_VAULT_DEVELOPMENT="ISxiALlYWFJ0K1lyVqzvD8pIH4oSGofqrPkMd5Krwoh8haYUOtNXJ8KjDH3rKjNcvh5qAoBjj9RXkIDCHOeSs0xPBo3kUt9APjlMRYV4/o+KrItn8kmKWaR0oUFYQfsj7a8CJQILekfqpqGA/HCc149PXdywwEzV00uxlzyhvc4ggheigCDpOSM4X7QBHKIGMFSDpO8avaYiTaEWyzpaGbS4a2sfV391thhAUACJnI8lipG/0CsIF65p+fhDGHWHqAtyW+/Kh2mle0MBtbVHMUbN0JSEx+llBpcldjZV216nz+BHHF0YV9rFRHujn6ta4uCCH55SFEoXbiZUa8zkRg/vbDDfBSZxOaY5Ddm6rP5UXqyx4e7FMglBKksefdxqMN5YQTJLcxfc0DL8IS37sSK4JX5p4gHfqIoDdSdPA2YBVG1o9/wv4Yx8NWaJAIFYvjbr/BYZSXyaDcRhIOEZXT2V3z3eVtNjp3MOMKu1osn1FPrG5pbVp9jS8q1SE8SGMxkRwQ5iWpL8EClfI2b1Xt2sokmct1xXJ08ods9YW2eFf7rnG9j9lW8op9fTxMNbcRJ951A+uaPDaOilVOjSXtZBFke/zJFxTAmC9A25c5EXYzStlmp7Ywn8TZldfkyOAtpRbMaqz1K/fnuf1fWnhf91+Dl2eRNsbxkYtc+grc+7LEQEWeZkrx3SpCIqXrvb+vrGn3GbPvtnymxjRzqsszqFeeB0T9kVLjWZC0OCioIW8LKD3tW3oJHJMRp0ySuUuhWj0K3H3W/4x4PETWgrFi/QbjbL6hmM0iqes2AQalh/+eQ3TnONEoFObSQiqkZSMD5Q/TbTbdto2ByqUQ9ZyKg6hvbjjkefLx5gyJoF5WC8Tf3uZhrSHfnp0cECE5ZRJUY3+mu/HSFuDCvpsRO0GukCp8oSOKgKjIn826PhGcrD8F6BvevhT+kE2o1ziGouSN6ymd61BgmlzB+CJ9unv4pkjr3vC7/czvN6GUQUD49Ff0WJ63pMaIjP2PnTtscsOhjML6Ug873PD+8FuECIgBnS+b+n/G9ljFFaY4nrHpWc7Cq/tSf6X+RSn/qgFjXwJPKj0w+8Fg0=" +DOTENV_VAULT_DEVELOPMENT="9Kto4weA8WuuwXasgBAZTF5IiVEFxsl4PZpRqeLgIrfBrlhwMqDfrXq/E006zDg31/GePPa0VxwkWIkSIg4j6UrWzCdJHaYRQsiivjmcBmWk0cetgMb4A+TXfHKvL1KS5esgNuh0Tr3K9LXXFOZkYNDF9e/Mki7Qp1iTIj01q0TulzCwsooC/W+GgN9OL4ckmmnhjoy4bGw+fePln3SJ6vdVD4133GPczN6tmezfRA36f0cq9UUM01xQEe7FYps/GdH6NDc0cgRKXKJTT8ynCJTiBp5j8cMBzufNd6z4azhHo5F5cTmFONhEZ1rC6UXvpm2uRp2oHP7mvGOjwJri6Fd7fLWG3V5fwWKlpsBX/UZJix2VyuS7xOj2vgoKZ4SIZFPXGtkvIicsqLJsplYl80kswNLZxDo8u1gaKhVBalLSZ9AfciKUelg0R8eGMR9MrnXLyJHbrs6Z5vSZIsT6sAMf1oX/mmEWjtQBoCDxtXn3L2mAbKummGZuEJ2EY+nJD18L0zLwlPY1He0BOtAu0gJKOe3l9ohGMD4AoDa3qCOriMUK97Nma1hZoTv5DgPawXTqMJDNFVeB7pI8RH06ISIS2r/RToHmLI9ipgSEdvamzFMtexuWFylim+gzKj04Dboc3EgDYLRp/uMyeMxvF6mSivjKds358hDQLh+ZGQrt4Crt6vI8m8J0pZTMoTdxfWWuk6sp" # production -DOTENV_VAULT_PRODUCTION="+ftDTpuEySxt+n5fooD6Bae5BXB4AZxuF3MtNUr8BFKIk/jT6b3a7Bklv6uVK89wQ80JMbguVCqGBygCqqo75NYfyY9Q2kC8AFKTB29ruG5P4FCe7rssf01qqSLHY1cxIi7MBq/oA/KJhgadJwsk0K+DKpM0qphsPSsyAABmApq6BFQmOdFPlXLsltMIanapBIOkU24Eo8NkIKUp90MHXA10Qike3BQv8IY0LqW5ofMcWUvTr3bvhOQlU5kObzbEHxuH/zDxh8hqJEZshoHXFnFxksoqV/g3e3wpPYGV3VixaQp4bI8HvBJkyp8MbNWrTnMapbN4FuuUc+cuoMB59YwqxlVGc4PCKDymeTJa0yoKPRrYeJQdcqenti71nXtGyYwdMFU/rdPomqHWSMQ/1wHGzHZWCbC1pHfJtRuxHiHNB8Em6Oh7J61swpGdJjGbcA06EC3u/6U3NqdkCXTay89mwUPoD5Y3QxJ6cXyZdIMRmrUQOVJagFfMMlz51dmm2+4nyicY7B/RkRVDoi75F4UkOcY6EgVmHmhQnYJ1dKhMhnRnNJziEJdnzypzX1KQUoZAflMTkHZFJSWDas4nztLbc71M0N0aq2Z1+5DENK3PdozyhzK4/j3bil06cbvKYfa//ta3w4GNbntr2Oa87G1hG6mDSZj26GmXsgKkmHwV78VZAosrWRxIizQdvZLD5XCzU10LQJSHOfVGpL56wf+xzuWZxAXfzcU6cgit60kAgjmoLhTvek/uz6BtkPFamkwdejVbijbHfq54InTPJthfCqlLdmsp1oHYh36MG6VrQK6Tn9UF6Pf9hC+rguvAGb0McSy0oBEGzD24MohjAcizLw==" +DOTENV_VAULT_PRODUCTION="j0IU/R5Y1RPdYBzAiK9YVto9RMM7BxqSMoON2N1Hio+7r8eK3P4pIYB/UX40NS0LLU6gT+ivJteaHmuv2SrmBUmmn3Ro+KtCcGjJ2ei/ElHlulYaRuIkFSoI4pCpJfZE/n/IB64TACo2F4G0sbYYoPCgAzVfVB1xT5fNQL1k060ZCEBddwxfpVoOJVf8qLeANpUhJqcZEW5oS0ZQYyAFGE/e9i4t3J81rYDQAzzTU2oKmPG6eg/5dzx8ZvitQpa93RKLNKaSXxyYl9KQhWFgUIn4MQsVfcSB2dprXw3nc1x/IVFQqciPkJ4rTpON1KtmTA==" # test -DOTENV_VAULT_TEST="6XT3ZXsH9nBjG6qQCS+B3s/yn8J2dQctOUp+3Duu9QA4bK0iimACc57JjtRnUNYrWOHGz6jYbc4ouNC5kzhUF1Dq1dPtG0vnbqqmWe0ShUbQQjpY4V2SqvBOdDD7wfXSr0pRER81ZJkyMZPoYF8qCc9sWngZDy8PGrDs5E04sC4f+tfQO2Yv/i7TUJUxSxzwAZHS4OXZeZ/AwDbrEaEPHfCSyM/QodYMBd3YokqYpNdHhrMPhDzXmL9CBievvk9FqsLmxs1mKk43w3hiGQP7ngmOJZXYp1sQfWN2eJNXXpBDbecHyOfbwaHAul2uHk8nOCtZ1HISLetXv/r+Lb6YUf1lyms4yyK5gNO+e4H0etVkZxThKBs8woMTpICwRI+YxKvbdjwcTuNaRsmtIvARNErILW7fSyamBkxh0augsI9gWCphl0H81wExhO/23aqncLgnlD3I6KpWvKdjl4q/KHNyXvD7kFXv+NQFfv2OuCdqauOvOurQtNKkpIilsFQhF8vIgTzUJadEBodDVjB8OZOsNb6tb3XMeisxNfod5vUsJ0iYrYCxe+Lv+6B9uPpLX8VbLMs7FaTb82ZotuekF9GeeaWE6hDLdoj8swd1vx9QOQq1qcvgCZSvmcwSY8t2dSSSNGwwa6aCJiu+DEgZKUxbgbb2PL2RrE/ov66nYdZq16CfI2V+i+MXwznehlr0p56dIfFr5c9j9c5ZwspvsmU04PqmDyGP6xdCbJZeKYeiuG5gB1uk96LUcgU7HpNwiNd4yvdvyRO3InJm" +DOTENV_VAULT_TEST="a73sDZfILBBZTjedG41eXLeXVNd+kl7RV8KfvCggl9tSNFgzoPV7fkAx5AMkH6eJSU0oM8GNCWWcvUQHIgt65gzcCFsMIW7MZsIwaWuU/ObmRj/LlwqJs6ZyMBvVqcZ3Tu8Ndt6s94Aiwm10/qBMFKqHXGvWmvIjeFVGqSVoReLxfENPJzkRvpvhTjwMZ/txfbdoE3EZhhSvnt/jy8WoZaKaagX9g4oOxmhgp8FzoTXL/9yW5iuUSkxXfaGynKi/rw9xVqq3YnJkyl0GwyM2yUqE6Ty+rvscclejCNy23v7bf7QF7qpNTiFU/+uR5mRoReAvVQ==" diff --git a/ExerciseChecker/.idea/dataSources b/ExerciseChecker/.idea/dataSources new file mode 120000 index 0000000000000000000000000000000000000000..dad593ac636a6315d6d91992d4b1e57e31182df2 --- /dev/null +++ b/ExerciseChecker/.idea/dataSources @@ -0,0 +1 @@ +jetbrainsConfiguration/dataSources/ \ No newline at end of file diff --git a/ExerciseChecker/config.env b/ExerciseChecker/config.env new file mode 100644 index 0000000000000000000000000000000000000000..ab8d6b7331ea12578c6019ba74b2241524ec68f9 --- /dev/null +++ b/ExerciseChecker/config.env @@ -0,0 +1,15 @@ +########################### Node env vars +NODE_ENV=production + + +########################### App env vars +APP_NAME='DOJO EXERCISE CHECKER' + +# 10MB +EXERCISE_RESULTS_FOLDER_MAX_SIZE_IN_BYTES=10000000 + +LOGS_FOLDER=logs +EXERCISE_RESULTS_VOLUME=$CI_PROJECT_DIR/Results_of_exercise_$DOJO_EXERCISE_ID/ +EXERCISE_RESULTS_FILENAME=results.json + +DOCKER_COMPOSE_PROJECT_NAME=dojo \ No newline at end of file diff --git a/ExerciseChecker/package.json b/ExerciseChecker/package.json index 92cf7f7d7fd54baa1426d53346e145883bb521d3..11760dee0ff277b971cd1ff0d8d888fe4b5486ed 100644 --- a/ExerciseChecker/package.json +++ b/ExerciseChecker/package.json @@ -4,7 +4,6 @@ "version" : "5.0.0", "license" : "AGPLv3", "author" : "Michaƫl Minelli <dojo@minelli.me>", - "type" : "module", "main" : "dist/app.js", "bin" : { "dirmanager": "./dist/app.js" @@ -26,7 +25,7 @@ "lint" : "npx eslint .", "genversion" : "npx genversion -s -e src/config/Version.ts", "build" : "npm run genversion; npx tsc", - "start:dev" : "npm run genversion; npm run lint; tsc --noEmit && npx tsx dist/app.js", + "start:dev" : "npm run genversion; npm run lint; tsc --noEmit && npx tsx --no-warnings src/app.ts", "test" : "echo \"Error: no test specified\" && exit 1" }, "dependencies" : { diff --git a/ExerciseChecker/src/app.ts b/ExerciseChecker/src/app.ts index 5bacb02ace86ea811009ed3a50bdb4bb217b3280..d813a4d496335954aa8055b57dc10f6b006efdfb 100644 --- a/ExerciseChecker/src/app.ts +++ b/ExerciseChecker/src/app.ts @@ -16,6 +16,7 @@ import ExerciseAssignment from './sharedByClients/models/Exerc import ClientsSharedExerciseHelper from './sharedByClients/helpers/Dojo/ClientsSharedExerciseHelper.js'; import Icon from './shared/types/Icon.js'; import path from 'node:path'; +import SharedAssignmentHelper from './shared/helpers/Dojo/SharedAssignmentHelper'; let exerciseAssignment: ExerciseAssignment | undefined; @@ -168,6 +169,10 @@ async function displayResults() { (async () => { + await Config.init(); + + SharedAssignmentHelper.init(Config.gitlabManager); + HttpManager.registerAxiosInterceptor(); console.log(Styles.APP_NAME(`${ Config.appName } (version {{VERSION}})`)); diff --git a/ExerciseChecker/src/config/Config.ts b/ExerciseChecker/src/config/Config.ts index db117f5636d7b8b952491fb337f373727fcaa0d2..94e4e68218270841559813946b09df43a4a63402 100644 --- a/ExerciseChecker/src/config/Config.ts +++ b/ExerciseChecker/src/config/Config.ts @@ -1,43 +1,54 @@ -import fs from 'fs-extra'; -import path from 'path'; +import fs from 'fs-extra'; +import path from 'path'; +import ClientsSharedConfig from '../sharedByClients/config/ClientsSharedConfig'; +import GitlabManager from '../managers/GitlabManager'; class Config { - public readonly appName: string; + public gitlabManager!: GitlabManager; - public readonly folders: { + public appName!: string; + + public folders!: { project: string; resultsVolume: string; resultsDojo: string; resultsExercise: string; }; - public readonly exercise: { + public exercise!: { id: string; secret: string; }; - public readonly dockerhub: { + public dockerhub!: { repositories: { exerciseChecker: string } }; - constructor() { - this.appName = process.env.APP_NAME ?? ''; + async init() { + const apiUrl = process.env.API_URL ?? ''; + + await ClientsSharedConfig.init(apiUrl); + const getEnvVar = ClientsSharedConfig.envVarGetter(); + + this.gitlabManager = new GitlabManager(ClientsSharedConfig.gitlab.URL, ClientsSharedConfig.login.gitlab.client.id, ClientsSharedConfig.login.gitlab.url.redirect, ClientsSharedConfig.login.gitlab.url.token); + + this.appName = getEnvVar('APP_NAME', ''); this.folders = { - project : process.env.PROJECT_FOLDER?.convertWithEnvVars() ?? './', - resultsVolume : process.env.EXERCISE_RESULTS_VOLUME?.convertWithEnvVars() ?? '', - resultsDojo : path.join(process.env.EXERCISE_RESULTS_VOLUME?.convertWithEnvVars() ?? '', 'Dojo/'), - resultsExercise: path.join(process.env.EXERCISE_RESULTS_VOLUME?.convertWithEnvVars() ?? '', 'Exercise/') + project : getEnvVar('PROJECT_FOLDER', './').convertWithEnvVars(), + resultsVolume : getEnvVar('EXERCISE_RESULTS_VOLUME', '').convertWithEnvVars(), + resultsDojo : path.join(getEnvVar('EXERCISE_RESULTS_VOLUME', '').convertWithEnvVars(), 'Dojo/'), + resultsExercise: path.join(getEnvVar('EXERCISE_RESULTS_VOLUME', '').convertWithEnvVars(), 'Exercise/') }; this.resetResultsVolume(); this.exercise = { - id : process.env.DOJO_EXERCISE_ID ?? '', - secret: process.env.DOJO_SECRET ?? '' + id : getEnvVar('DOJO_EXERCISE_ID', ''), + secret: getEnvVar('DOJO_SECRET', '') }; this.dockerhub = { repositories: { - exerciseChecker: process.env.DOCKERHUB_EXERCISE_CHECKER_REPOSITORY ?? '' + exerciseChecker: getEnvVar('DOCKERHUB_EXERCISE_CHECKER_REPOSITORY', '') } }; } diff --git a/ExerciseChecker/src/init.ts b/ExerciseChecker/src/init.ts index cffc4332ef356ecffbeeda5606281ce33851452e..221146a1c3f9deeb712797a33b9ba9b445975555 100644 --- a/ExerciseChecker/src/init.ts +++ b/ExerciseChecker/src/init.ts @@ -7,4 +7,6 @@ import './shared/helpers/TypeScriptExtensions.js'; dotenvExpand.expand(dotenv.config({ path : path.join(__dirname, '../.env'), DOTENV_KEY: 'dotenv://:key_bebfddf18e3dd9a0bafafe0e383313f75add1da6fbe41ea5fde51f37ef1776aa@dotenv.local/vault/.env.vault?environment=development' - })); \ No newline at end of file + })); + +dotenvExpand.expand(dotenv.config({ path: path.join(__dirname, '../config.env') })); \ No newline at end of file diff --git a/ExerciseChecker/src/managers/GitlabManager.ts b/ExerciseChecker/src/managers/GitlabManager.ts index 2228decdd2acea5058098df2f78ae09145c51e27..142662c38285059584fc50f69f5d938fde473b69 100644 --- a/ExerciseChecker/src/managers/GitlabManager.ts +++ b/ExerciseChecker/src/managers/GitlabManager.ts @@ -4,10 +4,10 @@ import SharedGitlabManager from '../shared/managers/SharedGitlabManager.js'; // File present only for prevent errors from shared submodules class GitlabManager extends SharedGitlabManager { - constructor() { - super(''); + constructor(public gitlabUrl: string, clientId?: string, urlRedirect?: string, urlToken?: string) { + super(gitlabUrl, '', clientId, urlRedirect, urlToken); } } -export default new GitlabManager(); \ No newline at end of file +export default GitlabManager; \ No newline at end of file diff --git a/ExerciseChecker/src/shared b/ExerciseChecker/src/shared index bf75a99ba472386daa111c2fefbe69a4272ef48c..d9ecaee5f58b1b94413903ebf737b4d235bc2858 160000 --- a/ExerciseChecker/src/shared +++ b/ExerciseChecker/src/shared @@ -1 +1 @@ -Subproject commit bf75a99ba472386daa111c2fefbe69a4272ef48c +Subproject commit d9ecaee5f58b1b94413903ebf737b4d235bc2858 diff --git a/ExerciseChecker/src/sharedByClients b/ExerciseChecker/src/sharedByClients index 4e33e70f6035898f119369ae5db784d51d8298a0..64dc406659114f3afcbc89258afe84c8553c6b8f 160000 --- a/ExerciseChecker/src/sharedByClients +++ b/ExerciseChecker/src/sharedByClients @@ -1 +1 @@ -Subproject commit 4e33e70f6035898f119369ae5db784d51d8298a0 +Subproject commit 64dc406659114f3afcbc89258afe84c8553c6b8f diff --git a/deploy_on_dockerhub.sh b/deploy_on_dockerhub.sh new file mode 100755 index 0000000000000000000000000000000000000000..73a86991bc641d66a5fd1f223a5c4e1d1b9da6b4 --- /dev/null +++ b/deploy_on_dockerhub.sh @@ -0,0 +1,135 @@ +#!/bin/bash + +# Define color codes +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + + +DOCKERFILE=Dockerfile_ExerciseChecker + +PROJECT_FOLDER=ExerciseChecker + +test_if_command_unsuccessful() { + local status=$1 + local title=$2 + local text_if_failed=$3 + if [ "$status" -ne 0 ]; then + echo -e "${title}: ${RED}${text_if_failed}: $status${NC}\n" + exit 1 + fi +} + + +########################################################## +# Function to prompt for input if not provided +prompt_if_empty() { + local var_name=$1 + local prompt_message=$2 + local var_value=${!var_name} + + if [ -z "$var_value" ]; then + read -p "$prompt_message: " var_value + export "$var_name"="$var_value" + fi +} + +# Parse parameters +while [ "$1" != "" ]; do + case $1 in + --dockerhub-user ) shift + DOCKER_REGISTRY_USER=$1 + ;; + --dockerhub-password ) shift + DOCKER_REGISTRY_PASSWORD=$1 + ;; + --dockerhub-repo ) shift + DOCKER_REGISTRY_IMAGE=$1 + ;; + --backend-url ) shift + API_URL=$1 + ;; + * ) echo -e "${RED}Invalid parameter: $1${NC}" + exit 1 + esac + shift +done + +# Prompt for values if not provided +prompt_if_empty "DOCKER_REGISTRY_USER" "Docker Hub user" +prompt_if_empty "DOCKER_REGISTRY_PASSWORD" "Docker Hub password" +prompt_if_empty "DOCKER_REGISTRY_IMAGE" "Docker Hub repository" +prompt_if_empty "API_URL" "Backend url" + + +########################################################## +# Function to check if a command exists +check_dependency() { + local cmd=$1 + if ! command -v $cmd &> /dev/null; then + echo -e "${RED}Error: $cmd is not installed.${NC}" + exit 1 + fi +} + +# Check for dependencies +echo -e "Dependencies: ${YELLOW}Checking...${NC}" +check_dependency jq +check_dependency docker +check_dependency sed +echo -e "Dependencies: ${GREEN}OK${NC}\n" + + +VERSION=$(jq -r .version $PROJECT_FOLDER/package.json) +CONTAINER_IMAGE=$DOCKER_REGISTRY_IMAGE:$VERSION + + +########################################################## +# Login to Docker Hub +echo -e "Docker Hub: ${YELLOW}Login in...${NC}" +echo "$DOCKER_REGISTRY_PASSWORD" | docker login -u "$DOCKER_REGISTRY_USER" --password-stdin "$DOCKER_REGISTRY" > /dev/null +test_if_command_unsuccessful $? "Docker Hub" "FAILED to login in" +echo -e "Docker Hub: ${GREEN}Logged in${NC}\n" + + +########################################################## +echo -e "Project files: ${YELLOW}Configuring...${NC}" + +( + +cd $PROJECT_FOLDER || exit 1 + +sed -i -r "s/\{\{VERSION\}\}/${VERSION}/g" src/app.ts 2> /dev/null +if [ $? -ne 0 ]; then # If on macOS + sed -i -r "s/{{VERSION}}/${VERSION}/g" src/app.ts 2> /dev/null +fi + +sed -i -r "s/(DOTENV_KEY[ ]*:[ ]*[\'\"\`])[^'\"\`]*([\'\"\`])([ ]*\,)?//g" src/init.ts +sed -i -r "s/,[\ \n]*\}/\}/g" src/init.ts + +# Write the content to the file +cat <<EOL > ".env" +##################### App env vars +API_URL=${API_URL} +DOCKERHUB_EXERCISE_CHECKER_REPOSITORY=${DOCKER_REGISTRY_IMAGE} +EOL + +) + +echo -e "Project files: ${GREEN}Configured${NC}\n" + + +########################################################## +echo -e "Docker: ${YELLOW}Building/Uploading to Docker Hub...${NC}" + +docker buildx create --use --platform=linux/amd64 > /dev/null 2> /dev/null +test_if_command_unsuccessful $? "Docker" "FAILED to initialize builder" + +docker buildx build --pull --platform=linux/amd64 --file $DOCKERFILE --push --tag "$CONTAINER_IMAGE" . > /dev/null 2> /dev/null +test_if_command_unsuccessful $? "Docker" "FAILED to build" + +docker buildx imagetools create "$CONTAINER_IMAGE" --tag "$DOCKER_REGISTRY_IMAGE":latest > /dev/null 2> /dev/null +test_if_command_unsuccessful $? "Docker" "FAILED to set latest tag" + +echo -e "Docker: ${GREEN}Uploaded to Docker Hub${NC}\n" \ No newline at end of file