java_demo/Jenkinsfile

321 lines
11 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 {
buildDiscarder(logRotator(numToKeepStr: '10'))
timeout(time: 30, unit: 'MINUTES')
timestamps()
}
environment {
JAVA_HOME = '/usr/lib/jvm/java-17-openjdk'
MAVEN_HOME = '/opt/maven'
PATH = "${MAVEN_HOME}/bin:${JAVA_HOME}/bin:${env.PATH}"
// Docker相关环境变量
DOCKER_REGISTRY = 'your-registry.com'
IMAGE_NAME = 'jenkins-demo'
IMAGE_TAG = "${BUILD_NUMBER}"
// SonarQube配置
SONAR_HOST_URL = 'http://your-sonar-server:9000'
SONAR_PROJECT_KEY = 'jenkins-demo'
}
tools {
maven 'Maven-3.9.3'
jdk 'JDK-17'
}
stages {
stage('Checkout') {
steps {
echo '🔄 开始检出代码...'
checkout scm
script {
env.GIT_COMMIT_SHORT = sh(
script: "git rev-parse --short HEAD",
returnStdout: true
).trim()
}
echo "📋 Git提交ID: ${env.GIT_COMMIT_SHORT}"
}
}
stage('环境检查') {
steps {
echo '🔍 检查构建环境...'
sh '''
echo "Java版本:"
java -version
echo "Maven版本:"
mvn -version
echo "Git版本:"
git --version
'''
}
}
stage('编译') {
steps {
echo '🔨 开始编译项目...'
sh 'mvn clean compile -DskipTests=true'
}
}
stage('单元测试') {
steps {
echo '🧪 运行单元测试...'
sh 'mvn test'
}
post {
always {
// 发布测试结果
publishTestResults testResultsPattern: 'target/surefire-reports/*.xml'
// 发布代码覆盖率报告
step([$class: 'JacocoPublisher',
execPattern: 'target/jacoco.exec',
classPattern: 'target/classes',
sourcePattern: 'src/main/java',
exclusionPattern: '**/*Test*.class'
])
}
}
}
stage('代码质量扫描') {
steps {
echo '🔍 运行SonarQube代码扫描...'
script {
try {
withSonarQubeEnv('SonarQube') {
sh '''
mvn sonar:sonar \
-Dsonar.projectKey=${SONAR_PROJECT_KEY} \
-Dsonar.host.url=${SONAR_HOST_URL} \
-Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml
'''
}
// 等待质量门检查结果
timeout(time: 5, unit: 'MINUTES') {
def qg = waitForQualityGate()
if (qg.status != 'OK') {
error "质量门检查失败: ${qg.status}"
}
}
} catch (Exception e) {
echo "⚠️ SonarQube扫描失败继续构建流程: ${e.getMessage()}"
}
}
}
}
stage('打包') {
steps {
echo '📦 开始打包应用程序...'
sh 'mvn package -DskipTests=true'
}
post {
success {
// 归档构建产物
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
}
stage('构建Docker镜像') {
steps {
echo '🐳 构建Docker镜像...'
script {
def image = docker.build("${IMAGE_NAME}:${IMAGE_TAG}")
// 也创建latest标签
sh "docker tag ${IMAGE_NAME}:${IMAGE_TAG} ${IMAGE_NAME}:latest"
echo "✅ Docker镜像构建完成: ${IMAGE_NAME}:${IMAGE_TAG}"
}
}
}
stage('推送Docker镜像') {
when {
anyOf {
branch 'main'
branch 'master'
branch 'develop'
}
}
steps {
echo '📤 推送Docker镜像到仓库...'
script {
docker.withRegistry("https://${DOCKER_REGISTRY}", 'docker-registry-credentials') {
def image = docker.image("${IMAGE_NAME}:${IMAGE_TAG}")
image.push()
image.push("latest")
}
echo "✅ Docker镜像推送完成"
}
}
}
stage('部署到测试环境') {
when {
anyOf {
branch 'develop'
branch 'feature/*'
}
}
steps {
echo '🚀 部署到测试环境...'
script {
// 部署到测试服务器
sshagent(['test-server-ssh']) {
sh '''
ssh -o StrictHostKeyChecking=no user@test-server << EOF
# 停止现有容器
docker stop jenkins-demo-test || true
docker rm jenkins-demo-test || true
# 运行新容器
docker run -d --name jenkins-demo-test \\
-p 8080:8080 \\
--restart unless-stopped \\
${IMAGE_NAME}:${IMAGE_TAG}
echo "✅ 测试环境部署完成"
EOF
'''
}
}
}
}
stage('部署到生产环境') {
when {
anyOf {
branch 'main'
branch 'master'
}
}
steps {
echo '🎯 部署到生产环境...'
script {
// 需要手动确认
input message: '确认部署到生产环境?', ok: '部署',
parameters: [choice(name: 'DEPLOY_ENV', choices: ['prod'], description: '选择部署环境')]
// 部署到生产服务器
sshagent(['prod-server-ssh']) {
sh '''
ssh -o StrictHostKeyChecking=no user@prod-server << EOF
# 备份当前版本
docker tag ${IMAGE_NAME}:latest ${IMAGE_NAME}:backup-$(date +%Y%m%d-%H%M%S) || true
# 停止现有容器
docker stop jenkins-demo-prod || true
docker rm jenkins-demo-prod || true
# 运行新容器
docker run -d --name jenkins-demo-prod \\
-p 80:8080 \\
--restart unless-stopped \\
-e SPRING_PROFILES_ACTIVE=prod \\
${IMAGE_NAME}:${IMAGE_TAG}
echo "✅ 生产环境部署完成"
EOF
'''
}
}
}
}
stage('健康检查') {
steps {
echo '🏥 执行应用健康检查...'
script {
// 等待应用启动
sleep(time: 30, unit: 'SECONDS')
// 检查应用健康状态
def healthCheckUrl = "http://localhost:8080/api/health"
def response = sh(
script: "curl -s -o /dev/null -w '%{http_code}' ${healthCheckUrl}",
returnStdout: true
).trim()
if (response == "200") {
echo "✅ 应用健康检查通过"
} else {
error "❌ 应用健康检查失败HTTP状态码: ${response}"
}
}
}
}
}
post {
always {
echo '🧹 清理工作空间...'
// 清理Docker镜像
sh '''
docker image prune -f
docker system prune -f
'''
}
success {
echo '✅ 流水线执行成功!'
// 发送成功通知
script {
def message = """
🎉 Jenkins构建成功
📋 项目: ${env.JOB_NAME}
🔢 构建号: ${env.BUILD_NUMBER}
🌿 分支: ${env.BRANCH_NAME}
📝 提交: ${env.GIT_COMMIT_SHORT}
⏱️ 持续时间: ${currentBuild.durationString}
🔗 构建链接: ${env.BUILD_URL}
"""
// 可以集成钉钉、企业微信、邮件等通知
echo message
}
}
failure {
echo '❌ 流水线执行失败!'
// 发送失败通知
script {
def message = """
💥 Jenkins构建失败
📋 项目: ${env.JOB_NAME}
🔢 构建号: ${env.BUILD_NUMBER}
🌿 分支: ${env.BRANCH_NAME}
📝 提交: ${env.GIT_COMMIT_SHORT}
⏱️ 持续时间: ${currentBuild.durationString}
🔗 构建链接: ${env.BUILD_URL}
📄 查看日志: ${env.BUILD_URL}console
"""
echo message
}
}
unstable {
echo '⚠️ 构建不稳定,可能存在测试失败'
}
cleanup {
// 清理工作空间
cleanWs()
}
}
}