Files
timeline-frontend/Jenkinsfile

278 lines
9.0 KiB
Plaintext
Raw Normal View History

2025-12-26 21:02:15 +08:00
pipeline {
2025-12-26 21:18:32 +08:00
agent any
2025-12-26 21:02:15 +08:00
environment {
// 环境变量定义
PROJECT_NAME = 'timeline-frontend'
2025-12-26 21:18:32 +08:00
DOCKER_REGISTRY = 'timeline-registry:5000'
2025-12-26 21:02:15 +08:00
DOCKER_IMAGE = "${DOCKER_REGISTRY}/${PROJECT_NAME}"
}
parameters {
// 构建参数
choice(
name: 'DEPLOY_TARGET',
choices: ['dev', 'staging', 'prod'],
description: '选择部署环境'
)
string(
name: 'GIT_COMMIT',
defaultValue: '',
description: '指定 Git Commit SHA 进行构建(留空则使用最新提交)'
)
}
stages {
stage('Checkout') {
steps {
script {
2025-12-26 21:14:40 +08:00
if (params.GIT_COMMIT) {
checkout scm
sh "git reset --hard ${params.GIT_COMMIT}"
} else {
checkout scm
}
2025-12-26 21:02:15 +08:00
}
2025-12-26 21:14:40 +08:00
echo "当前构建的 Git Commit: ${env.GIT_COMMIT}"
2025-12-26 21:02:15 +08:00
}
}
2025-12-26 21:18:32 +08:00
2025-12-26 21:08:00 +08:00
stage('Build timeline-frontend dist') {
2025-12-26 21:02:15 +08:00
steps {
script {
2025-12-29 15:13:23 +08:00
def workspace = sh(script: "pwd", returnStdout: true).trim()
2025-12-29 14:39:16 +08:00
echo "当前工作空间路径: ${workspace}"
2025-12-29 14:36:47 +08:00
// 确保路径正确
2025-12-29 14:39:16 +08:00
sh "ls -la ${workspace}"
2025-12-29 14:36:47 +08:00
2025-12-29 15:47:36 +08:00
// 修复权限问题
sh "chmod -R 755 ${workspace}"
sh "chown -R jenkins:jenkins ${workspace}"
2025-12-29 15:26:05 +08:00
2025-12-29 15:47:36 +08:00
// 使用 Jenkins Node.js 插件,并确保在工作空间目录中执行
dir(workspace) {
nodejs('NodeJS-18') {
// 检查是否存在 package.json 和 pnpm-lock.yaml
if (fileExists('package.json')) {
echo "package.json found"
if (fileExists('pnpm-lock.yaml')) {
echo "pnpm-lock.yaml found"
} else {
error('pnpm-lock.yaml not found')
}
2025-12-29 15:41:20 +08:00
2025-12-29 15:47:36 +08:00
// 安装 pnpm
sh 'npm install -g pnpm'
2025-12-29 15:41:20 +08:00
2025-12-29 15:55:25 +08:00
// 使用 pnpm 安装依赖,由于锁文件兼容性问题,不使用 --frozen-lockfile
sh 'pnpm install --no-frozen-lockfile'
2025-12-29 15:41:20 +08:00
2025-12-29 15:47:36 +08:00
// 构建项目
sh 'pnpm run build'
// 检查 dist 目录是否存在
if (!fileExists('dist')) {
error('ERROR: dist directory does not exist after build')
} else {
echo 'Build completed successfully, dist directory exists'
}
2025-12-29 15:41:20 +08:00
} else {
2025-12-29 15:47:36 +08:00
error('package.json not found')
2025-12-29 15:41:20 +08:00
}
}
}
2025-12-29 15:24:13 +08:00
}
2025-12-29 14:55:43 +08:00
}
2025-12-26 21:08:00 +08:00
}
2025-12-26 21:02:15 +08:00
2025-12-26 21:08:00 +08:00
stage('Build Docker Image') {
steps {
script {
2025-12-26 21:02:15 +08:00
def imageTag = "${BUILD_NUMBER}-${env.GIT_COMMIT.take(7)}"
env.IMAGE_TAG = imageTag
2025-12-26 21:18:32 +08:00
// 创建一个简单的 nginx 配置(可选)
sh '''
cat > nginx.conf << 'EOF'
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}
EOF
'''
2025-12-26 21:02:15 +08:00
sh """
2025-12-29 16:21:31 +08:00
docker build -t ${DOCKER_IMAGE}:latest .
2025-12-26 21:02:15 +08:00
"""
}
}
}
stage('Push Docker Image') {
steps {
script {
2025-12-29 16:17:06 +08:00
2025-12-29 16:08:27 +08:00
sh "docker push ${DOCKER_IMAGE}:latest"
2025-12-26 21:02:15 +08:00
}
}
}
stage('Deploy to Environment') {
parallel {
stage('Deploy to Dev') {
when {
expression { params.DEPLOY_TARGET == 'dev' }
}
steps {
deployToEnvironment('dev')
}
}
stage('Deploy to Staging') {
when {
anyOf {
expression { params.DEPLOY_TARGET == 'staging' }
expression { params.DEPLOY_TARGET == 'prod' }
}
}
steps {
deployToEnvironment('staging')
}
}
stage('Deploy to Production') {
when {
expression { params.DEPLOY_TARGET == 'prod' }
}
steps {
script {
input message: "确定要部署到生产环境吗?", ok: "是", parameters: [
choice(name: 'CONFIRM_DEPLOY', choices: ['yes', 'no'], description: '确认部署')
]
if (params.CONFIRM_DEPLOY == 'yes') {
deployToEnvironment('prod')
} else {
error "部署被取消"
}
}
}
}
}
}
}
post {
always {
// 清理构建产物
cleanWs()
}
success {
script {
def slackMessage = """
*✅ 构建成功*
项目: ${PROJECT_NAME}
构建: ${BUILD_NUMBER}
分支: ${env.BRANCH_NAME}
提交: ${env.GIT_COMMIT}
镜像: ${DOCKER_IMAGE}:${env.IMAGE_TAG}
"""
// 发送成功通知(如果配置了 Slack 通知)
// slackSend(channel: '#builds', color: 'good', message: slackMessage)
}
}
failure {
script {
def slackMessage = """
*❌ 构建失败*
项目: ${PROJECT_NAME}
构建: ${BUILD_NUMBER}
分支: ${env.BRANCH_NAME}
提交: ${env.GIT_COMMIT}
错误: ${currentBuild.description ?: '构建失败'}
"""
// 发送失败通知(如果配置了 Slack 通知)
// slackSend(channel: '#builds', color: 'danger', message: slackMessage)
}
}
cleanup {
// 清理 Docker 镜像
script {
sh """
docker rmi -f ${DOCKER_IMAGE}:${env.IMAGE_TAG} || true
docker rmi -f ${DOCKER_IMAGE}:latest || true
"""
}
}
}
}
// 公共函数定义
def deployToEnvironment(String env) {
script {
// 根据环境设置部署参数
def containerName = "${PROJECT_NAME}-${env}"
2025-12-29 16:17:06 +08:00
def imageToDeploy = "${DOCKER_IMAGE}:latest"
2025-12-26 21:02:15 +08:00
// 停止现有容器
sh """
docker stop ${containerName} || true
docker rm ${containerName} || true
"""
// 运行新容器
sh """
docker run -d \
--name ${containerName} \
--restart unless-stopped \
2025-12-26 21:18:32 +08:00
-p ${getPortForEnvironment(env)}:80 \
2025-12-26 21:02:15 +08:00
${imageToDeploy}
"""
// 验证部署
sh """
echo "等待容器启动..."
sleep 10
docker ps | grep ${containerName}
docker logs ${containerName}
"""
}
}
// 获取环境对应端口的辅助函数
def getPortForEnvironment(String env) {
switch(env) {
case 'dev':
return '3001'
case 'staging':
return '3002'
case 'prod':
2025-12-26 21:18:32 +08:00
return '80'
2025-12-26 21:02:15 +08:00
default:
2025-12-26 21:18:32 +08:00
return '80'
2025-12-26 21:02:15 +08:00
}
}