Files
timeline-frontend/Jenkinsfile

253 lines
8.1 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 14:36:47 +08:00
def workspace = pwd
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 14:39:16 +08:00
sh "chmod -R 755 ${workspace}"
sh "chown -R jenkins:jenkins ${workspace}"
2025-12-26 21:18:32 +08:00
2025-12-29 14:36:47 +08:00
// 使用更健壮的Docker命令
2025-12-29 14:42:01 +08:00
sh "docker run -u \$ (id -u):\$ (id -g) -v ${workspace}:/app -w /app node:18-alpine sh -c 'npm install && npm run build'" }
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 """
docker build -t ${DOCKER_IMAGE}:${imageTag} .
docker tag ${DOCKER_IMAGE}:${imageTag} ${DOCKER_IMAGE}:latest
"""
}
}
}
stage('Push Docker Image') {
steps {
script {
withCredentials([usernamePassword(credentialsId: 'docker-registry-credentials',
usernameVariable: 'DOCKER_USER',
passwordVariable: 'DOCKER_PASS')]) {
sh 'echo $DOCKER_PASS | docker login $DOCKER_REGISTRY -u $DOCKER_USER --password-stdin'
sh "docker push ${DOCKER_IMAGE}:${env.IMAGE_TAG}"
sh "docker push ${DOCKER_IMAGE}:latest"
}
}
}
}
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}"
def imageToDeploy = "${DOCKER_IMAGE}:${env.IMAGE_TAG}"
// 停止现有容器
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
}
}