diff --git a/.htmlhintrc b/.htmlhintrc new file mode 100644 index 0000000..dfa6e3d --- /dev/null +++ b/.htmlhintrc @@ -0,0 +1,6 @@ +{ + "attr-value-double-quotes": false, + "tag-pair": true, + "id-unique": true, + "tagname-lowercase": false +} diff --git a/.lighthouserc.cjs b/.lighthouserc.cjs new file mode 100644 index 0000000..aaaf112 --- /dev/null +++ b/.lighthouserc.cjs @@ -0,0 +1,24 @@ +module.exports = { + ci: { + collect: { + staticDistDir: './html', + settings: { + chromeFlags: '--no-sandbox --disable-setuid-sandbox --headless=new --disable-gpu --disable-dev-shm-usage', + targets: ['filesystem'], + }, + numberOfRuns: 1 + }, + assert: { + assertions: { + 'categories:performance': ['error', {minScore: 0.9}], + 'categories:accessibility': ['error', {minScore: 0.9}], + 'categories:best-practices': ['error', {minScore: 0.9}], + 'categories:seo': ['error', {minScore: 0.9}], + }, + }, + upload: { + target: 'filesystem', + outputDir: './.lighthouseci', // C'est ici que Jenkins ira chercher les fichiers + }, + }, +}; \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..3c86a32 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,117 @@ +pipeline { + agent any + environment { + GITEA_REPO_PATH = "lucas/site-veloboomboom" + GITEA_API_URL = "https://gitea.lucasroyer.fr/api/v1" + DOCKER_HOST = "unix:///run/user/1001/docker.sock" + + TOOLBOX_PATH ="/home/lucas/services/static-sites/static-toolbox" + SOURCE_DIR = "html" + DEPLOY_PATH = "/home/lucas/services/static-sites/site-veloboomboom/html-prod" + } + stages { + stage('Check toolbox') { + steps { + sh """ + if ! docker image inspect static-toolbox >/dev/null 2>&1; then + echo "Missing toolbox, rebuild using Docker socket..." + # On crée l'image à la volée car Jenkins ne voit pas le script 'build' + echo "FROM node:25-alpine\nRUN npm install -g htmlhint\nWORKDIR /apps\nENTRYPOINT [\"htmlhint\"]" | docker build -t static-toolbox - + fi + """ + // sh """ + // if ! docker image inspect static-toolbox >/dev/null 2>&1; then + // echo "Missing toolbox, rebuild..." + // ${env.TOOLBOX_PATH}/build + // fi + // """ + } + } + stage('Lint HTML') { + steps { + echo "Check HTML files..." + sh "docker run --rm --volumes-from jenkins -w \$(pwd) static-toolbox '${env.SOURCE_DIR}/**/*.html' --config .htmlhintrc" + } + } + stage('Lighthouse Audit') { + steps { + echo "Running Lighthouse audit..." + sh "docker rm -f lighthouse-audit || true" + + // Utilisation de l'image officielle Chrome, plus prévisible + sh """ + docker run --name lighthouse-audit \ + --volumes-from jenkins \ + -w \$(pwd) \ + --user "0:0" \ + -v /home/lucas/.npm-cache:/root/.npm \ + -e CHROME_PATH=/usr/bin/chromium-browser \ + --entrypoint "" \ + zenika/alpine-chrome:with-node \ + npx --prefer-offline -p @lhci/cli@0.13.0 lhci autorun \ + --collect.settings.chromeFlags='--no-sandbox --disable-dev-shm-usage --disable-gpu --headless' \ + --config=./.lighthouserc.cjs + """ + sh "docker rm -f lighthouse-audit" + } + } + + stage('Deploy') { + steps { + echo "Deploying via Docker mount..." + // On utilise un petit conteneur alpine pour faire le rsync + // en montant le dossier de destination du VPS + sh """ + docker run --rm \ + --volumes-from jenkins \ + -v ${env.DEPLOY_PATH}:${env.DEPLOY_PATH} \ + -w \$(pwd) \ + alpine:latest \ + sh -c "mkdir -p ${env.DEPLOY_PATH} && cp -R ${env.SOURCE_DIR}/* ${env.DEPLOY_PATH}/" + """ + + echo "Reloading Caddy..." + sh "docker exec caddy-reverse-proxy caddy reload --config /etc/caddy/Caddyfile" + } + } + } + post { + always { + echo "Publish Lighthouse audit..." + publishHTML([ + allowMissing: true, + alwaysLinkToLastBuild: true, + keepAll: false, + reportDir: '.lighthouseci', + reportFiles: '*.html', + reportName: 'Lighthouse Report' + ]) + script { + echo "Waiting for Gitea to be online..." + + echo "Send Gitea check..." + // Get and store SHA + def commitSha = sh(script: 'git rev-parse HEAD', returnStdout: true).trim() + + // Convert from Jenkins to Gitea API + def buildState = (currentBuild.currentResult == 'SUCCESS') ? 'success' : 'failure' + def buildDesc = (currentBuild.currentResult == 'SUCCESS') ? 'Build successful' : 'Build failed' + + // Send it to Gitea API with secret 'gitea-token' + withCredentials([string(credentialsId: 'gitea-token', variable: 'GITEA_TOKEN')]) { + // Use \$TOKEN to avoid jenkins to print token in logs + sh """ + curl -f -X POST "${GITEA_API_URL}/repos/${GITEA_REPO_PATH}/statuses/${commitSha}" \ + -H "Authorization: token \$GITEA_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"state": "${buildState}", "target_url": "${env.BUILD_URL}", "description": "${buildDesc}", "context": "jenkins-ci"}' + """ + } + } + echo "Clean unused image" + sh "docker image prune -f" + } + success { echo "Success !" } + failure { echo "Failed." } + } +}