Files
no-whatever/Jenkinsfile
T

200 lines
7.8 KiB
Groovy
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
pipeline {
agent any
options {
skipDefaultCheckout(true)
}
parameters {
booleanParam(name: 'RUN_FULL_E2E', defaultValue: false, description: '是否在部署后额外执行全量 E2E(失败仅标记 UNSTABLE')
}
environment {
APP_NAME = 'no-whatever'
CI_IMAGE = 'mcr.microsoft.com/playwright:v1.51.1-jammy'
NPM_CACHE_VOLUME = 'no-whatever-npm-cache'
NODE_MODULES_VOLUME = 'no-whatever-node-modules'
NPM_LOCK_HASH_FILE = '/npm-cache/no-whatever-package-lock.sha256'
NPM_REGISTRY = 'https://registry.npmmirror.com'
}
triggers {
GenericTrigger(tokenCredentialId: 'no-whatever-deploy-token')
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Runtime Check') {
steps {
sh 'docker --version'
}
}
stage('Prepare Test Images') {
options {
timeout(time: 15, unit: 'MINUTES')
}
steps {
retry(2) {
sh '''
set -e
if docker image inspect ${CI_IMAGE} >/dev/null 2>&1; then
echo "${CI_IMAGE} already exists, skip pull"
else
docker pull ${CI_IMAGE}
fi
'''
}
}
}
stage('CI Gate (Lint + TypeCheck + Unit + Smoke E2E)') {
options {
timeout(time: 30, unit: 'MINUTES')
}
steps {
sh '''
set -e
rm -rf playwright-report test-results
cid=$(docker create --ipc=host \
-e HOME=/tmp \
-e NPM_CONFIG_CACHE=/npm-cache \
-e NPM_CONFIG_REGISTRY=${NPM_REGISTRY} \
-v ${NPM_CACHE_VOLUME}:/npm-cache \
-v ${NODE_MODULES_VOLUME}:/workspace/node_modules \
${CI_IMAGE} \
sh -lc "cd /workspace && \
lock_hash=\$(sha256sum package-lock.json | cut -d ' ' -f1) && \
cached_hash=\$(cat ${NPM_LOCK_HASH_FILE} 2>/dev/null || true) && \
if [ \"\$lock_hash\" = \"\$cached_hash\" ] && [ -d node_modules ] && [ \"\$(ls -A node_modules 2>/dev/null)\" ]; then \
echo 'node_modules cache hit, skip npm ci'; \
else \
npm ci --prefer-offline --no-audit --progress=false && \
echo \"\$lock_hash\" > ${NPM_LOCK_HASH_FILE}; \
fi && \
npm run lint && npx tsc --noEmit && npm run test:coverage && npm run test:e2e:smoke")
cleanup() {
docker rm -f "$cid" >/dev/null 2>&1 || true
}
trap cleanup EXIT
git archive --format=tar HEAD | docker cp - "$cid":/workspace
set +e
docker start -a "$cid"
status=$?
set -e
docker cp "$cid":/workspace/playwright-report ./playwright-report 2>/dev/null || true
docker cp "$cid":/workspace/test-results ./test-results 2>/dev/null || true
exit $status
'''
}
post {
always {
archiveArtifacts artifacts: 'playwright-report/**,test-results/**', allowEmptyArchive: true
}
}
}
stage('Build Docker Image') {
steps {
withCredentials([
string(credentialsId: 'amap-api-key', variable: 'AMAP_KEY')
]) {
sh "docker build --build-arg NEXT_PUBLIC_AMAP_API_KEY=${AMAP_KEY} -t ${APP_NAME}:${BUILD_NUMBER} -t ${APP_NAME}:latest ."
}
}
}
stage('Deploy') {
steps {
withCredentials([
string(credentialsId: 'amap-api-key', variable: 'AMAP_KEY'),
string(credentialsId: 'deepseek-api-key', variable: 'DEEPSEEK_KEY')
]) {
sh """
docker stop ${APP_NAME} || true
docker rm ${APP_NAME} || true
mkdir -p /data/${APP_NAME}
chown 1001:1001 /data/${APP_NAME}
docker run -d \
--name ${APP_NAME} \
--network nginx \
-p 3721:3721 \
-v /data/${APP_NAME}:/app/data \
-e DATABASE_URL=file:/app/data/prod.db \
-e AMAP_API_KEY=${AMAP_KEY} \
-e DEEPSEEK_API_KEY=${DEEPSEEK_KEY} \
--restart unless-stopped \
${APP_NAME}:latest
"""
}
}
}
stage('Full E2E (Optional, Non-Blocking)') {
when {
expression { return params.RUN_FULL_E2E }
}
options {
timeout(time: 30, unit: 'MINUTES')
}
steps {
catchError(buildResult: 'UNSTABLE', stageResult: 'UNSTABLE') {
sh '''
set -e
rm -rf playwright-report-full test-results-full
cid=$(docker create --ipc=host \
-e HOME=/tmp \
-e NPM_CONFIG_CACHE=/npm-cache \
-e NPM_CONFIG_REGISTRY=${NPM_REGISTRY} \
-v ${NPM_CACHE_VOLUME}:/npm-cache \
-v ${NODE_MODULES_VOLUME}:/workspace/node_modules \
${CI_IMAGE} \
sh -lc "cd /workspace && \
lock_hash=\$(sha256sum package-lock.json | cut -d ' ' -f1) && \
cached_hash=\$(cat ${NPM_LOCK_HASH_FILE} 2>/dev/null || true) && \
if [ \"\$lock_hash\" = \"\$cached_hash\" ] && [ -d node_modules ] && [ \"\$(ls -A node_modules 2>/dev/null)\" ]; then \
echo 'node_modules cache hit, skip npm ci'; \
else \
npm ci --prefer-offline --no-audit --progress=false && \
echo \"\$lock_hash\" > ${NPM_LOCK_HASH_FILE}; \
fi && \
npm run test:e2e")
cleanup() {
docker rm -f "$cid" >/dev/null 2>&1 || true
}
trap cleanup EXIT
git archive --format=tar HEAD | docker cp - "$cid":/workspace
set +e
docker start -a "$cid"
status=$?
set -e
docker cp "$cid":/workspace/playwright-report ./playwright-report-full 2>/dev/null || true
docker cp "$cid":/workspace/test-results ./test-results-full 2>/dev/null || true
exit $status
'''
}
}
post {
always {
archiveArtifacts artifacts: 'playwright-report-full/**,test-results-full/**', allowEmptyArchive: true
}
}
}
}
post {
success {
echo "Deployed ${APP_NAME} build #${BUILD_NUMBER} successfully"
}
failure {
echo "Build #${BUILD_NUMBER} failed"
}
}
}