From 0cecad9eb53f5977a9f19719f9811c7fa666c863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CAtmozo=E2=80=9D?= Date: Tue, 31 Mar 2026 18:10:23 +0200 Subject: [PATCH] Add production Jenkinsfile with parameters --- Jenkinsfile | 144 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 137 insertions(+), 7 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index ac124cf..5ae56c6 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,9 @@ +// ============================================================ +// PLAYWRIGHT TESTS - PRODUCTION PIPELINE +// ============================================================ + pipeline { + agent { docker { image 'mcr.microsoft.com/playwright:v1.48.0-jammy' @@ -6,33 +11,158 @@ pipeline { } } + parameters { + choice(name: 'ENVIRONMENT', choices: ['dev', 'staging', 'production'], description: 'Target environment') + choice(name: 'BROWSER', choices: ['chromium', 'firefox', 'webkit', 'all'], description: 'Which browser to test') + booleanParam(name: 'HEADLESS', defaultValue: true, description: 'Run tests in headless mode') + string(name: 'TEST_PATTERN', defaultValue: '**/*.spec.ts', description: 'Test file pattern') + } + + environment { + OPENWEATHER_API_KEY = credentials('openweather-api-key') + WEATHER_BASE_URL = 'https://api.openweathermap.org' + REQRES_BASE_URL = 'https://reqres.in' + DOGS_BASE_URL = 'https://dog.ceo/api' + NODE_ENV = 'test' + CI = 'true' + TEST_ENV = "${params.ENVIRONMENT}" + } + + options { + buildDiscarder(logRotator(numToKeepStr: '30', daysToKeepStr: '30', artifactNumToKeepStr: '10')) + timeout(time: 1, unit: 'HOURS') + timestamps() + disableConcurrentBuilds() + } + + triggers { + pollSCM('H/15 * * * *') + cron('0 2 * * *') + } + stages { - stage('Install') { + + stage('Pipeline Info') { steps { + script { + echo """ + ============================================ + PLAYWRIGHT TEST PIPELINE + ============================================ + Branch: ${env.BRANCH_NAME ?: 'N/A'} + Environment: ${params.ENVIRONMENT} + Browser: ${params.BROWSER} + Headless: ${params.HEADLESS} + Build: #${BUILD_NUMBER} + ============================================ + """ + } sh ''' - npm ci - npx playwright install --with-deps chromium + echo "Commit: $GIT_COMMIT" + git log -1 --pretty=format:"%h - %an: %s" ''' } } - stage('Test') { + stage('Install Dependencies') { steps { - sh 'npx playwright test' + sh 'npm ci' + script { + if (params.BROWSER == 'all') { + sh 'npx playwright install --with-deps' + } else { + sh "npx playwright install --with-deps ${params.BROWSER}" + } + } + } + } + + stage('Code Quality') { + parallel { + stage('ESLint') { + steps { sh 'npm run lint || true' } + } + stage('TypeScript') { + steps { sh 'npx tsc --noEmit || true' } + } } } - stage('Report') { + stage('Run Tests') { + steps { + script { + def browserArg = params.BROWSER == 'all' ? '' : "--project=${params.BROWSER}" + def headlessArg = params.HEADLESS ? '' : '--headed' + + def testScope = '' + if (env.BRANCH_NAME == 'main' || env.BRANCH_NAME == 'develop') { + testScope = params.TEST_PATTERN + } else if (env.BRANCH_NAME?.startsWith('feature/')) { + testScope = '--grep @smoke' + } else { + testScope = params.TEST_PATTERN + } + + sh """ + npx playwright test ${browserArg} ${headlessArg} \ + --reporter=html,json,junit \ + ${testScope} + """ + } + } + } + + stage('Security Scan') { + when { branch 'main' } + steps { sh 'npm audit --production || true' } + } + + stage('Publish Reports') { steps { publishHTML([ reportDir: 'playwright-report', reportFiles: 'index.html', - reportName: 'Playwright Report', + reportName: 'Playwright Test Report', keepAll: true, alwaysLinkToLastBuild: true, allowMissing: true ]) + + junit testResults: 'test-results/*.xml', allowEmptyResults: true + archiveArtifacts artifacts: 'test-results/**/*', allowEmptyArchive: true + } + } + + stage('Deploy') { + when { + allOf { + branch 'main' + expression { params.ENVIRONMENT == 'production' } + } + } + input { + message 'Deploy to production?' + ok 'Deploy' } + steps { + echo 'Deploying to production...' + sh './deploy.sh' + } + } + } + + post { + success { + script { + def duration = currentBuild.durationString.replace(' and counting', '') + echo "Build #${BUILD_NUMBER} succeeded in ${duration}" + } + } + failure { + echo "Build #${BUILD_NUMBER} failed" + } + always { + deleteDir() } } }