commit 4ecd596b79a2b12cbcea3e2141401faf2f0e3f29 Author: spassignat Date: Sat May 2 10:31:10 2026 +0200 patch: test 1 diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..ab1f416 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..3545ac5 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,21 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..4444b22 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..d38a978 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/test-cicd.iml b/.idea/test-cicd.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/test-cicd.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.woodpecker/build-pipeline.yml b/.woodpecker/build-pipeline.yml new file mode 100644 index 0000000..3a6636a --- /dev/null +++ b/.woodpecker/build-pipeline.yml @@ -0,0 +1,165 @@ +when: + - event: push + branch: [ main ] # ← Les tags ne sont sur aucune "branch" + - event: pull_request + - event: manual + +variables: + - &node_image node:18-alpine + - &git_image alpine/git + +steps: + # Étape 1: Nettoyage du projet, à ajuster + - name: clean_project + image: *git_image + commands: | + rm -rf dist + rm -f version.env + + - name: prepare + image: *git_image + commands: | + # Récupérer le message du commit + COMMIT_MSG=$(git log -1 --pretty=%B) + echo "📝 Message: $COMMIT_MSG" + + # Déterminer le type de version + if echo "$COMMIT_MSG" | grep -qE "^(major)(\(.*\))?!:"; then + echo "version_type=major" >> version.env + echo "🔴 MAJOR - Breaking change" + elif echo "$COMMIT_MSG" | grep -qE "^(minor)(\(.*\))?:"; then + echo "version_type=minor" >> version.env + echo "🟡 MINOR - Nouvelle fonctionnalité" + elif echo "$COMMIT_MSG" | grep -qE "^(patch)(\(.*\))?:"; then + echo "version_type=patch" >> version.env + echo "🟢 PATCH - Correction" + else + echo "version_type=none" >> version.env + echo "⚠️ Aucun changement de version" + fi + npm ci --cache .npm --prefer-offline + depends_on: [ clean_project ] + + # Étape 4: Mettre à jour la version (seulement si nécessaire) + - name: update_version + image: *node_image + commands: | + source version.env + if [ "$version_type" != "none" ]; then + CURRENT_VERSION=$(node -p "require('./package.json').version") + echo "📦 Version actuelle: $CURRENT_VERSION" + npm run update:$version_type + NEW_VERSION=$(node -p "require('./package.json').version") + echo "🆕 Nouvelle version: $NEW_VERSION" + echo "NEW_VERSION=$NEW_VERSION" >> version.env + echo "CURRENT_VERSION=$CURRENT_VERSION" >> version.env + echo "artifact=${CI_REPO_NAME}-$NEW_VERSION.tar" >> version.env + else + echo "artifact=no-artifact" >> version.env + echo "⏭️ Pas de mise à jour de version" + fi + depends_on: [ build ] + + # Étape 1: Installation des dépendances + - name: build + image: *node_image + commands: + - npm run build + depends_on: [ prepare ] + + # Étape 5: Commit et tag + - name: commit_tag + image: *git_image + environment: + GITEA_TOKEN: + from_secret: gitea_token + commands: | + # Charger les variables + more version.env + source version.env + echo "version type: $version_type" + + if [ "$version_type" != "none" ]; then + echo "http://oauth2:$GITEA_TOKEN@gitea.cicd.exygen.fr/${CI_REPO_OWNER}/${CI_REPO_NAME}.git" + git remote set-url origin http://oauth2:$GITEA_TOKEN@gitea.cicd.exygen.fr/${CI_REPO_OWNER}/${CI_REPO_NAME}.git + git config user.email "woodpecker@exygen.fr" + git config user.name "Woodpecker CI" + + # Ajouter le remote avec token + + # Ajouter le package.json modifié + git add package.json + git add ./database/src/sql/*.sql + + # Vérifier s'il y a des changements + # if ! git diff --cached --quiet; then + # Commiter la nouvelle version + git commit -m "Pipeline: update current version v$NEW_VERSION [skip ci]" + git push origin main + echo "✅ Commit new version" + + # Créer le tag + git tag -a "v$NEW_VERSION" -m "Release version v$NEW_VERSION" + git push origin "v$NEW_VERSION" + echo "🏷️ Tag v$NEW_VERSION created and pushed" + else + echo "⚠️ Aucun changement à commiter" + fi + depends_on: [ publish ] + + # Étape 6: Package des artefacts + - name: package + image: *node_image + commands: | + more version.env + source version.env + if [ "$version_type" != "none" ]; then + WDIR=/tmp/artifacts/$NEW_VERSION + echo "create work directory: $WDIR" + mkdir -p $WDIR + echo "create front artifact: $WDIR/front.tar.gz" + tar -czf $WDIR/front.tar.gz -C frontend/dist . + echo "create back artifact: $WDIR/back.tar.gz" + tar -czf $WDIR/back.tar.gz -C backend/dist . + echo "create db artifact: $WDIR/db.tar.gz" + tar -czf $WDIR/db.tar.gz -C database src *.json + echo "create final artifact: /tmp/artifacts/$artifact" + ls -als /tmp/artifacts/$artifact + tar -cf /tmp/artifacts/$artifact -C $WDIR . + fi + ls -als /tmp/artifacts/ + depends_on: [ build ] + + - name: publish + image: curlimages/curl:latest + environment: + NEXUS_USERNAME: + from_secret: nexus_username + NEXUS_PASSWORD: + from_secret: nexus_password + commands: | + source version.env + echo "📦 Publication de la version $NEW_VERSION : $artifact" + ls -als /tmp/artifacts/$artifact + + curl -v \ + -u ${NEXUS_USERNAME}:${NEXUS_PASSWORD} \ + -F "raw.directory=apps/${CI_REPO_NAME}/${NEW_VERSION}" \ + -F "raw.asset1=@/tmp/artifacts/$artifact" \ + -F "raw.asset1.filename=$artifact" \ + https://nexus.cicd.exygen.fr/service/rest/v1/components?repository=domaine-passignat + depends_on: [ package ] + + - name: trigger-deployment + image: woodpeckerci/plugin-trigger:latest + settings: + token: + from_secret: woodpecker_token + server: https://woodpecker.cicd.exygen.fr # ← Ajoute l'URL du serveur + repo: ${CI_REPO_OWNER}/${CI_REPO_NAME} + branch: main + event: deployment + deploy_id: ${CI_PIPELINE_NUMBER} # ← Peut être optionnel + deploy_to: production # ← Renommé en "environment" parfois + wait: true # ← Attend la fin du déploiement + depends_on: [ publish ] \ No newline at end of file diff --git a/.woodpecker/deploy-pipeline.yml b/.woodpecker/deploy-pipeline.yml new file mode 100644 index 0000000..c134375 --- /dev/null +++ b/.woodpecker/deploy-pipeline.yml @@ -0,0 +1,64 @@ +# Documentation: https://woodpecker-ci.org/docs/usage/workflow-syntax + +when: + - event: deployment + +steps: + - name: get-artifact + image: curlimages/curl:latest + commands: | + VERSION=${CI_COMMIT_TAG#v} + curl -o /tmp/${CI_REPO_NAME}-${VERSION}.tar \ + "https://nexus.cicd.exygen.fr/repository/domaine-passignat/apps/${CI_REPO_NAME}/${VERSION}/${CI_REPO_NAME}-${VERSION}.tar" + + # Étape 7: Transfert vers le serveur distant (SCP) + - name: transfert + image: appleboy/drone-scp + settings: + host: + from_secret: remote_host + username: + from_secret: remote_user + password: + from_secret: remote_password + port: 22 + source: /tmp/${CI_REPO_NAME}-${VERSION}.tar + target: /tmp/ + depends_on: [ get-artifact ] + + # Étape 8: Déploiement sur le serveur distant + - name: deploy + image: appleboy/drone-ssh + environment: + SUDO_PASSWORD: + from_secret: remote_password + settings: + host: + from_secret: remote_host + username: + from_secret: remote_user + password: + from_secret: remote_password + port: 22 + envs: + - SUDO_PASSWORD + script: + - echo "$${SUDO_PASSWORD}" | sudo -S systemctl stop gestion + - mkdir -p /srv/volumes/gestion/{front-binaries,back-binaries,tmpdb} + - rm -rf /srv/volumes/gestion/front-binaries/* + - rm -rf /srv/volumes/gestion/back-binaries/* + - rm -rf /srv/volumes/gestion/tmpdb/* + - tar -xvf /tmp/${CI_REPO_NAME}-${VERSION}.tar -C /tmp + - tar -xvf /tmp/front.tar.gz -C /srv/volumes/gestion/front-binaries + - tar -xzvf /tmp/back.tar.gz -C /srv/volumes/gestion/back-binaries + - tar -xzvf /tmp/db.tar.gz -C /srv/volumes/gestion/tmpdb + - rm -f /tmp/front.tar.gz + - rm -f /tmp/back.tar.gz + - rm -f /tmp/db.tar.gz + - rm -f /tmp/${CI_REPO_NAME}-${VERSION}.tar + - docker-compose up database + - cd /srv/volumes/gestion/tmpdb + - npm ci --cache .npm --prefer-offline + - npm run install-db + - echo "$${SUDO_PASSWORD}" | sudo -S systemctl start gestion + depends_on: [ transfert ] diff --git a/database/current.sql b/database/current.sql new file mode 100644 index 0000000..e69de29 diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..a486ddc --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "esnext", + "moduleResolution": "node", + "baseUrl": ".", + "paths": { + "@/*": ["front/*"] + }, + "allowSyntheticDefaultImports": true, + "jsx": "preserve" + }, + "include": [ + "frontend/**/*" + ], + "exclude": ["node_modules", "dist"] +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..9e84d3d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,17 @@ +{ + "name": "@cicd", + "version": "2.7.15", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@cicd", + "version": "2.7.15", + "license": "Exygen", + "engines": { + "node": "<=25.9.0", + "npm": "<=11.13.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..7b7d7bf --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "cicd", + "private": true, + "version": "0.0.1", + "description": "Node.js Rest Apis with Express, Sequelize & PostgreSQL", + "scripts": { + "update:patch": "node scripts/update-version.js -patch", + "update:minor": "node scripts/update-version.js -minor", + "update:major": "node scripts/update-version.js -major", + "build": "mkdir dist & touch dist/app" + }, + "engines": { + "node": "<=25.9.0", + "npm": "<=11.13.0" + }, + "keywords": [], + "author": "Stephane Passignat", + "license": "Exygen" +} \ No newline at end of file diff --git a/scripts/copy-resources.js b/scripts/copy-resources.js new file mode 100644 index 0000000..9349294 --- /dev/null +++ b/scripts/copy-resources.js @@ -0,0 +1,151 @@ +console.log(process.cwd()); +const fs = require('fs'); +const builder = require('./generators/generate-jsdoc'); +const plant = require('./generators/generate-plantuml'); +const data = require('./generators/generate-namedlist'); +const tax = require('./generators/generate-tax'); +const classesFront = require('./generators/generate-class'); +const classesBack = require('./generators/generate-class-back'); +const path = require('path'); +let path1 = path.join("dist", "back"); +if (!fs.existsSync(path1)) { + fs.mkdirSync(path1, {recursive: true}); +} + +// Fonction pour copier un fichier +function copyFile(source, destination) { + fs.mkdirSync(path.dirname(destination), {recursive: true}); + fs.copyFileSync(source, destination); +} + +function copyResources() { +// Chemins source et destination + const resources = [{ + source: path.join(__dirname, "config", `front-${env}.json`), + target: path.join(__dirname, "front", `config.json`) + }, { + source: path.join(__dirname, "config", `back-${env}.json`), + target: path.join(__dirname, "back", `config.json`) + }, { + source: path.join(__dirname, "config", `front-${env}.json`), + target: path.join(__dirname, "dist/front", `config.json`) + }, { + source: path.join(__dirname, "config", `back-${env}.json`), + target: path.join(__dirname, "dist/back", `config.json`) + }, { + source: path.join(__dirname, "package.json"), + target: path.join(__dirname, "dist", "package.json") + }, { + source: path.join(__dirname, "package-lock.json"), + target: path.join(__dirname, "dist", "package-lock.json") + }, { + source: path.join(__dirname, "vite.config.js"), + target: path.join(__dirname, "dist", "vite.config.js") + }]; + for (const resource of resources) { + copyFile(resource.source, resource.target); + } + for (const resource of resources) { + if (resource.target.endsWith("config.json")) { + setConfigVersion(resource.target); + } + } + fs.mkdirSync(path.dirname("dist/model"), {recursive: true}); + fs.mkdirSync(path.dirname("dist/back"), {recursive: true}); + fs.mkdirSync(path.dirname("dist/app"), {recursive: true}); + fs.mkdirSync(path.dirname("dist/data"), {recursive: true}); + fs.cpSync("back", "dist/back", {recursive: true}); + fs.cpSync("model", "dist/model", {recursive: true}); + fs.cpSync("app", "dist/app", {recursive: true}); + fs.cpSync("data", "dist/data", {recursive: true}); +} + + +function updateVersion(major = false, minor = false, patch = true) { + let obj; + try { + obj = JSON.parse(fs.readFileSync('./package.json', 'utf8')); + let currentVersion = obj.version; + + let versions = currentVersion.split('.'); + let majorVersion = versions[0]; + let minorVersion = versions[1]; + let patchVersion = versions[2]; + if (major) { + let number = Number.parseInt(majorVersion); + number++; + versions[0] = number; + versions[1] = 0; + versions[2] = 0; + } else if (minor) { + let number = Number.parseInt(minorVersion); + number++; + versions[0] = majorVersion; + versions[1] = number; + versions[2] = 0; + } else if (patch) { + let number = Number.parseInt(patchVersion); + number++; + versions[0] = majorVersion; + versions[1] = minorVersion; + versions[2] = number; + } + let newVersion = versions.join('.'); + obj.version = newVersion; + + fs.writeFileSync("./package.json", JSON.stringify(obj, null, "\t"), 'utf8'); + let newVar = { + oldVersion: currentVersion, + newVersion: newVersion + }; + return newVar; + } catch (e) { + } +} + +function setConfigVersion(resource) { + let src; + try { + src = JSON.parse(fs.readFileSync('./package.json', 'utf8')); + let versions = src.version; + target = JSON.parse(fs.readFileSync(resource, 'utf8')); + target.version = versions; + fs.writeFileSync(resource, JSON.stringify(target), 'utf8') + } catch (e) { + } +} + +let env = "local"; +let major = false; +let minor = false; +let patch = false; +process.argv.forEach(function (val, index, array) { + if (val === "-local") { + env = "local" + } else if (val === "-prod") { + env = "prod"; + } else if (val === "-patch") { + patch = true; + } else if (val === "-major") { + major = true; + } else if (val === "-minor") { + minor = true; + } +}); + +if (patch||minor||major) { + let updateVersion1 = updateVersion(major,minor,patch); + let src = path.join(__dirname, "back", "models", "current.sql"); + let tgt = path.join(__dirname, "back", "models", "sql", `version-${updateVersion1.oldVersion}-${updateVersion1.newVersion}.sql`); + fs.copyFileSync(src, tgt); + let writeStream = fs.createWriteStream(src); + writeStream.close(); +} + +copyResources(); +builder.generateJSDocTypes('./model/DataModel.json', './types.js'); +plant.generatePlantUML('./model/DataModel.json', './model.puml'); +// data.generateTVA("./tva_agriculture_detaillee.csv","./data/NamedList.json"); +// tax.generateTax("./tva_agriculture_detaillee.csv","./data/Tax.json"); +classesFront.generateClasses('./model/DataModel.json',"./front/data/"); +classesBack.generateClasses('./model/DataModel.json',"./back/data/"); \ No newline at end of file diff --git a/scripts/update-version.js b/scripts/update-version.js new file mode 100644 index 0000000..01dc302 --- /dev/null +++ b/scripts/update-version.js @@ -0,0 +1,81 @@ +console.log(process.cwd()); +const fs = require('fs'); + +const path = require('path'); + + +function updateVersion(major = false, minor = false, patch = true) { + let obj; + try { + obj = JSON.parse(fs.readFileSync('./package.json', 'utf8')); + let currentVersion = obj.version; + + let versions = currentVersion.split('.'); + let majorVersion = versions[0]; + let minorVersion = versions[1]; + let patchVersion = versions[2]; + if (major) { + let number = Number.parseInt(majorVersion); + number++; + versions[0] = number; + versions[1] = 0; + versions[2] = 0; + } else if (minor) { + let number = Number.parseInt(minorVersion); + number++; + versions[0] = majorVersion; + versions[1] = number; + versions[2] = 0; + } else if (patch) { + let number = Number.parseInt(patchVersion); + number++; + versions[0] = majorVersion; + versions[1] = minorVersion; + versions[2] = number; + } + let newVersion = versions.join('.'); + obj.version = newVersion; + + fs.writeFileSync("./package.json", JSON.stringify(obj, null, "\t"), 'utf8'); + let newVar = { + oldVersion: currentVersion, + newVersion: newVersion + }; + return newVar; + } catch (e) { + } +} + +function setConfigVersion(resource) { + let src; + try { + src = JSON.parse(fs.readFileSync('./package.json', 'utf8')); + let versions = src.version; + let target = JSON.parse(fs.readFileSync(resource, 'utf8')); + target.version = versions; + fs.writeFileSync(resource, JSON.stringify(target), 'utf8') + } catch (e) { + } +} + +let major = false; +let minor = false; +let patch = false; +process.argv.forEach(function (val, index, array) { + if (val === "-patch") { + patch = true; + } else if (val === "-major") { + major = true; + } else if (val === "-minor") { + minor = true; + } +}); + +if (patch||minor||major) { + let updateVersion1 = updateVersion(major,minor,patch); + let src = path.join(__dirname,"..", "database", "current.sql"); + let tgt = path.join(__dirname,"..", "database", "src", "sql", `version-${updateVersion1.oldVersion}-${updateVersion1.newVersion}.sql`); + fs.copyFileSync(src, tgt); + let writeStream = fs.createWriteStream(src); + writeStream.close(); +} diff --git a/versions.js b/versions.js new file mode 100644 index 0000000..a042826 --- /dev/null +++ b/versions.js @@ -0,0 +1,75 @@ +// copy.js +const fs = require('fs'); +const path = require('path'); +let path1 = path.join("dist", "back"); +if (!fs.existsSync(path1)) { + fs.mkdirSync(path1); +} + + +function updateVersion(major = false, minor = false, patch = true) { + let obj; + try { + obj = JSON.parse(fs.readFileSync('./package.json', 'utf8')); + let currentVersion = obj.version; + + let versions = currentVersion.split('.'); + let majorVersion = versions[0]; + let minorVersion = versions[1]; + let patchVersion = versions[2]; + if (major) { + let number = Number.parseInt(majorVersion); + number++; + versions[0] = number; + versions[1] = 0; + versions[2] = 0; + } else if (minor) { + let number = Number.parseInt(minorVersion); + number++; + versions[0] = majorVersion; + versions[1] = number; + versions[2] = patchVersion; + } else if (patch) { + let number = Number.parseInt(patchVersion); + number++; + versions[0] = majorVersion; + versions[1] = minorVersion; + versions[2] = number; + } + let newVersion = versions.join('.'); + obj.version = newVersion; + + fs.writeFileSync("./package.json", JSON.stringify(obj, null, "\t"), 'utf8'); + let newVar = { + oldVersion: currentVersion, + newVersion: newVersion + }; + return newVar; + } catch (e) { + } +} + +function setVersion() { + let src; + try { + src = JSON.parse(fs.readFileSync('./package.json', 'utf8')); + let versions = src.version; + target = JSON.parse(fs.readFileSync('./config.json', 'utf8')); + target.version = versions; + fs.writeFileSync("./package.json", JSON.stringify(target), 'utf8') + return versions.join('.'); + } catch (e) { + } +} + +let release = false; +process.argv.forEach(function (val, index, array) { + if (val === "-release") { + release = true; + } +}); + +if (release) { + updateVersion(); +} +setVersion();