|
|
pipeline {
|
|
|
agent any
|
|
|
|
|
|
environment {
|
|
|
JAVA_HOME = 'E:\\2025-2026\\GitAIOps\\jdk'
|
|
|
ANDROID_HOME = 'D:\\development\\Android'
|
|
|
WIX_HOME = 'C:\\Program Files (x86)\\WiX Toolset v3.11'
|
|
|
SONAR_HOST_URL = 'http://localhost:9000'
|
|
|
SONAR_PROJECT_KEY = 'slms'
|
|
|
SONAR_PROJECT_NAME = 'slms'
|
|
|
SONARQUBE_SCANNER_PARAMS = '-Dsonar.qualitygate.wait=true -Dsonar.qualitygate.timeout=300'
|
|
|
SONARQUBE_QUALITY_GATE = 'SLMS-Quality-Gate'
|
|
|
}
|
|
|
|
|
|
tools {
|
|
|
maven 'maven396'
|
|
|
jdk 'jdk21'
|
|
|
}
|
|
|
|
|
|
options {
|
|
|
skipDefaultCheckout()
|
|
|
buildDiscarder(logRotator(numToKeepStr: '10'))
|
|
|
disableConcurrentBuilds()
|
|
|
timestamps()
|
|
|
}
|
|
|
|
|
|
stages {
|
|
|
stage('1. 拉取Gitea代码') {
|
|
|
steps {
|
|
|
echo '========== 从 Gitea 拉取代码 =========='
|
|
|
|
|
|
// 清理可能被占用的文件
|
|
|
script {
|
|
|
try {
|
|
|
bat '''
|
|
|
@echo off
|
|
|
echo 清理工作空间中可能被占用的文件...
|
|
|
|
|
|
REM 只结束与当前工作空间相关的 Java 进程
|
|
|
for /f "tokens=2" %%i in ('tasklist /FI "IMAGENAME eq java.exe" /FO LIST ^| findstr /C:"PID:"') do (
|
|
|
wmic process where "ProcessId=%%i and CommandLine like '%%slms%%'" delete 2>nul
|
|
|
)
|
|
|
|
|
|
REM 等待进程结束
|
|
|
timeout /t 1 /nobreak >nul
|
|
|
|
|
|
echo ✓ 清理完成
|
|
|
'''
|
|
|
} catch (Exception e) {
|
|
|
echo "清理过程中出现警告: ${e.message}"
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 使用优化的 Git 拉取配置
|
|
|
checkout([
|
|
|
$class: 'GitSCM',
|
|
|
branches: [[name: '*/main']],
|
|
|
extensions: [
|
|
|
[$class: 'CleanBeforeCheckout'],
|
|
|
[$class: 'CleanCheckout']
|
|
|
],
|
|
|
userRemoteConfigs: [[
|
|
|
url: 'http://localhost:3000/gitea/slms.git',
|
|
|
credentialsId: 'gitea-credentials'
|
|
|
]]
|
|
|
])
|
|
|
echo '✓ 代码拉取成功'
|
|
|
}
|
|
|
}
|
|
|
|
|
|
stage('2. Maven编译') {
|
|
|
steps {
|
|
|
echo '========== Maven 编译 SLMS 项目 =========='
|
|
|
bat '''
|
|
|
set JAVA_HOME=%JAVA_HOME%
|
|
|
|
|
|
REM 强制删除 target 目录(如果存在)
|
|
|
if exist target (
|
|
|
echo 清理旧的 target 目录...
|
|
|
rmdir /S /Q target 2>nul
|
|
|
if exist target (
|
|
|
echo 警告: 无法删除 target 目录,尝试使用 Maven clean...
|
|
|
) else (
|
|
|
echo ✓ target 目录已清理
|
|
|
)
|
|
|
)
|
|
|
|
|
|
REM Maven 编译
|
|
|
mvn clean compile test-compile -DskipTests
|
|
|
'''
|
|
|
echo '✓ 项目编译成功'
|
|
|
}
|
|
|
}
|
|
|
|
|
|
stage('3. 运行Mock测试') {
|
|
|
steps {
|
|
|
echo '========== 运行单元测试 =========='
|
|
|
script {
|
|
|
try {
|
|
|
bat '''
|
|
|
set JAVA_HOME=%JAVA_HOME%
|
|
|
mvn test
|
|
|
'''
|
|
|
echo '✓ 测试执行完成'
|
|
|
} catch (Exception e) {
|
|
|
echo '⚠️ 测试失败,但继续流水线'
|
|
|
echo "错误信息: ${e.message}"
|
|
|
currentBuild.result = 'UNSTABLE'
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
post {
|
|
|
always {
|
|
|
junit allowEmptyResults: true, testResults: '**/target/surefire-reports/*.xml'
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
stage('4. Sonar质检') {
|
|
|
when {
|
|
|
expression { currentBuild.result == null || currentBuild.result == 'SUCCESS' || currentBuild.result == 'UNSTABLE' }
|
|
|
}
|
|
|
steps {
|
|
|
echo '========== 执行 SonarQube 代码质量检测 =========='
|
|
|
withSonarQubeEnv('SonarQube') {
|
|
|
bat '''
|
|
|
set JAVA_HOME=%JAVA_HOME%
|
|
|
mvn sonar:sonar -Dsonar.qualitygate.wait=true -Dsonar.qualitygate.timeout=300
|
|
|
'''
|
|
|
}
|
|
|
echo '✓ SonarQube 分析完成'
|
|
|
}
|
|
|
}
|
|
|
|
|
|
stage('5. 准备打包') {
|
|
|
when {
|
|
|
expression { currentBuild.result == null || currentBuild.result == 'SUCCESS' || currentBuild.result == 'UNSTABLE' }
|
|
|
}
|
|
|
steps {
|
|
|
echo '========== 准备并行打包 =========='
|
|
|
bat '''
|
|
|
echo 检查编译结果...
|
|
|
if exist target\\classes (
|
|
|
echo ✓ 编译完成,classes 目录存在
|
|
|
) else (
|
|
|
echo ⚠️ 警告: classes 目录不存在
|
|
|
)
|
|
|
|
|
|
echo.
|
|
|
echo 准备开始四端并行打包:
|
|
|
echo • CLI: 使用 -Pcli profile
|
|
|
echo • GUI: 使用 -Pgui-swing profile
|
|
|
echo • Web: 使用 -Pweb profile
|
|
|
echo • Android: 使用 Gradle
|
|
|
echo.
|
|
|
echo ✓ 准备完成,开始并行打包
|
|
|
'''
|
|
|
}
|
|
|
}
|
|
|
|
|
|
stage('6. 四端并行打包') {
|
|
|
when {
|
|
|
expression { currentBuild.result == null || currentBuild.result == 'SUCCESS' || currentBuild.result == 'UNSTABLE' }
|
|
|
}
|
|
|
parallel {
|
|
|
stage('6.1 CLI 打包 (JAR)') {
|
|
|
steps {
|
|
|
echo '========== 打包 CLI 应用 (JAR) =========='
|
|
|
bat '''
|
|
|
@echo off
|
|
|
set JAVA_HOME=%JAVA_HOME%
|
|
|
echo [CLI] 开始打包...
|
|
|
|
|
|
REM 手动清理 CLI 输出目录,避免 maven-clean-plugin 的锁冲突
|
|
|
if exist target\\cli rmdir /S /Q target\\cli
|
|
|
|
|
|
REM 使用 CLI profile 打包,指定独立输出目录,跳过 WAR 生成
|
|
|
REM 注意:移除 clean 目标,避免多进程并发清理 target 导致的冲突
|
|
|
mvn "-Dcustom.build.directory=target/cli" package -Pcli -DskipTests -Dmaven.war.skip=true
|
|
|
|
|
|
echo [CLI] 检查生成的文件...
|
|
|
echo [CLI] 列出 target\\cli 目录所有 JAR 文件:
|
|
|
dir target\\cli\\*.jar 2>nul || echo [CLI] 目录中没有 JAR 文件
|
|
|
echo.
|
|
|
if exist target\\cli\\slms-1.0-SNAPSHOT-cli-shaded.jar (
|
|
|
echo [CLI] ✓ CLI shaded JAR 生成成功
|
|
|
for %%F in (target\\cli\\slms-1.0-SNAPSHOT-cli-shaded.jar) do echo [CLI] 大小: %%~zF bytes
|
|
|
) else (
|
|
|
echo [CLI] ⚠️ 警告: 找不到 slms-1.0-SNAPSHOT-cli-shaded.jar
|
|
|
echo [CLI] 尝试查找其他 shaded JAR...
|
|
|
dir target\\cli\\*shaded*.jar 2>nul || echo [CLI] 没有找到 shaded JAR
|
|
|
)
|
|
|
'''
|
|
|
echo '✓ CLI JAR 打包成功'
|
|
|
}
|
|
|
}
|
|
|
|
|
|
stage('6.2 GUI 打包 (Swing JAR)') {
|
|
|
steps {
|
|
|
echo '========== 打包 GUI Swing 应用 (独立 JAR) =========='
|
|
|
bat '''
|
|
|
@echo off
|
|
|
set JAVA_HOME=%JAVA_HOME%
|
|
|
echo [GUI] 开始打包...
|
|
|
|
|
|
REM 手动清理 GUI 输出目录
|
|
|
if exist target\\gui rmdir /S /Q target\\gui
|
|
|
|
|
|
REM 使用 gui-swing profile 生成独立 JAR,指定独立输出目录,跳过 WAR 生成
|
|
|
mvn "-Dcustom.build.directory=target/gui" package -Pgui-swing -DskipTests -Dmaven.war.skip=true
|
|
|
|
|
|
echo [GUI] 检查生成的文件...
|
|
|
echo [GUI] 列出 target\\gui 目录所有 JAR 文件:
|
|
|
dir target\\gui\\*.jar 2>nul || echo [GUI] 目录中没有 JAR 文件
|
|
|
echo.
|
|
|
if exist target\\gui\\slms-1.0-SNAPSHOT-gui-swing.jar (
|
|
|
echo [GUI] ✓ GUI Swing JAR 生成成功
|
|
|
for %%F in (target\\gui\\slms-1.0-SNAPSHOT-gui-swing.jar) do echo [GUI] 大小: %%~zF bytes
|
|
|
) else (
|
|
|
echo [GUI] ⚠️ 警告: 找不到 slms-1.0-SNAPSHOT-gui-swing.jar
|
|
|
echo [GUI] 尝试查找其他 JAR...
|
|
|
dir target\\gui\\*swing*.jar 2>nul || echo [GUI] 没有找到 swing JAR
|
|
|
)
|
|
|
'''
|
|
|
echo '✓ GUI Swing JAR 打包成功'
|
|
|
}
|
|
|
}
|
|
|
|
|
|
stage('6.3 Web 打包 (WAR)') {
|
|
|
steps {
|
|
|
echo '========== 打包 Web 应用 (WAR) =========='
|
|
|
bat '''
|
|
|
@echo off
|
|
|
set JAVA_HOME=%JAVA_HOME%
|
|
|
echo [Web] 开始打包...
|
|
|
|
|
|
REM 手动清理 Web 输出目录
|
|
|
if exist target\\web rmdir /S /Q target\\web
|
|
|
|
|
|
REM 使用 Web profile 打包,指定独立输出目录
|
|
|
mvn "-Dcustom.build.directory=target/web" package -Pweb -DskipTests
|
|
|
|
|
|
echo [Web] 检查生成的文件...
|
|
|
if exist target\\web\\slms-1.0-SNAPSHOT.war (
|
|
|
echo [Web] ✓ Web WAR 生成成功
|
|
|
for %%F in (target\\web\\slms-1.0-SNAPSHOT.war) do echo [Web] 大小: %%~zF bytes
|
|
|
) else (
|
|
|
if exist target\\web\\slms-1.0-SNAPSHOT.jar (
|
|
|
echo [Web] ✓ Web JAR 生成成功 (备用)
|
|
|
for %%F in (target\\web\\slms-1.0-SNAPSHOT.jar) do echo [Web] 大小: %%~zF bytes
|
|
|
) else (
|
|
|
echo [Web] ⚠️ 错误: 找不到 Web WAR/JAR
|
|
|
echo [Web] 检查 target\\web 目录:
|
|
|
dir target\\web\\*.war
|
|
|
dir target\\web\\*.jar
|
|
|
exit /b 1
|
|
|
)
|
|
|
)
|
|
|
'''
|
|
|
echo '✓ Web WAR 打包成功'
|
|
|
}
|
|
|
}
|
|
|
|
|
|
stage('6.4 Android Gradle 打包 (APK)') {
|
|
|
steps {
|
|
|
echo '========== 打包 Android 应用 (APK) =========='
|
|
|
bat '''
|
|
|
@echo off
|
|
|
setlocal EnableDelayedExpansion
|
|
|
set JAVA_HOME=%JAVA_HOME%
|
|
|
set ANDROID_HOME=%ANDROID_HOME%
|
|
|
|
|
|
echo 打包 Android 应用...
|
|
|
|
|
|
REM 使用 Gradle 打包 Android APK(不操作 target 目录)
|
|
|
call gradlew.bat :android:assembleDebug
|
|
|
|
|
|
REM 先列出 APK 目录看文件名
|
|
|
echo 列出 APK 目录:
|
|
|
dir android\\build\\outputs\\apk\\debug\\*.apk
|
|
|
|
|
|
REM 检查并复制 APK - 如果文件名相同就跳过
|
|
|
if exist android\\build\\outputs\\apk\\debug\\SLMS-debug.apk (
|
|
|
echo ✓ 找到 SLMS-debug.apk
|
|
|
if /I "SLMS-debug.apk" NEQ "slms-debug.apk" (
|
|
|
copy /Y android\\build\\outputs\\apk\\debug\\SLMS-debug.apk android\\build\\outputs\\apk\\debug\\slms-debug.apk >nul 2>&1
|
|
|
)
|
|
|
echo ✓ Android APK 打包完成: slms-debug.apk
|
|
|
exit /b 0
|
|
|
)
|
|
|
|
|
|
if exist android\\build\\outputs\\apk\\debug\\android-debug.apk (
|
|
|
echo ✓ 找到 android-debug.apk
|
|
|
copy /Y android\\build\\outputs\\apk\\debug\\android-debug.apk android\\build\\outputs\\apk\\debug\\slms-debug.apk >nul 2>&1
|
|
|
echo ✓ Android APK 打包完成: slms-debug.apk
|
|
|
exit /b 0
|
|
|
)
|
|
|
|
|
|
REM 尝试复制第一个找到的 APK
|
|
|
echo ⚠️ 警告: 找不到预期的 APK 文件,尝试复制第一个找到的 APK
|
|
|
set APK_FOUND=0
|
|
|
for %%f in (android\\build\\outputs\\apk\\debug\\*.apk) do (
|
|
|
if !APK_FOUND! EQU 0 (
|
|
|
echo 找到 APK: %%f
|
|
|
copy /Y "%%f" android\\build\\outputs\\apk\\debug\\slms-debug.apk >nul 2>&1
|
|
|
echo ✓ 已复制 %%f 为 slms-debug.apk
|
|
|
set APK_FOUND=1
|
|
|
)
|
|
|
)
|
|
|
|
|
|
if !APK_FOUND! EQU 0 (
|
|
|
echo ✗ 错误: 完全找不到 APK 文件
|
|
|
exit /b 1
|
|
|
)
|
|
|
|
|
|
exit /b 0
|
|
|
'''
|
|
|
echo '✓ Android APK 打包成功'
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
stage('6.5 重命名和验证制品') {
|
|
|
when {
|
|
|
expression { currentBuild.result == null || currentBuild.result == 'SUCCESS' || currentBuild.result == 'UNSTABLE' }
|
|
|
}
|
|
|
steps {
|
|
|
echo '========== 重命名和验证制品 =========='
|
|
|
script {
|
|
|
bat '''
|
|
|
@echo off
|
|
|
setlocal EnableDelayedExpansion
|
|
|
echo ============================================
|
|
|
echo 文件重命名和验证阶段
|
|
|
echo ============================================
|
|
|
echo.
|
|
|
|
|
|
REM ========== 1.1 CLI JAR 重命名 ==========
|
|
|
echo [1/4] 处理 CLI JAR... (target\\cli)
|
|
|
echo 列出 target\\cli 目录:
|
|
|
dir target\\cli\\*.jar 2>nul || echo 目录为空或不存在
|
|
|
|
|
|
set CLI_JAR_FOUND=0
|
|
|
REM 尝试多种可能的文件名
|
|
|
if exist target\\cli\\slms-1.0-SNAPSHOT-cli-shaded.jar (
|
|
|
echo ✓ 找到: slms-1.0-SNAPSHOT-cli-shaded.jar
|
|
|
copy /Y target\\cli\\slms-1.0-SNAPSHOT-cli-shaded.jar target\\slms-cli.jar >nul
|
|
|
set CLI_JAR_FOUND=1
|
|
|
) else if exist target\\cli\\slms-1.0-SNAPSHOT-shaded.jar (
|
|
|
echo ✓ 找到备选: slms-1.0-SNAPSHOT-shaded.jar
|
|
|
copy /Y target\\cli\\slms-1.0-SNAPSHOT-shaded.jar target\\slms-cli.jar >nul
|
|
|
set CLI_JAR_FOUND=1
|
|
|
) else if exist target\\cli\\slms-1.0-SNAPSHOT.jar (
|
|
|
echo ✓ 找到默认JAR: slms-1.0-SNAPSHOT.jar
|
|
|
copy /Y target\\cli\\slms-1.0-SNAPSHOT.jar target\\slms-cli.jar >nul
|
|
|
set CLI_JAR_FOUND=1
|
|
|
)
|
|
|
|
|
|
if !CLI_JAR_FOUND!==1 (
|
|
|
if exist target\\slms-cli.jar (
|
|
|
for %%F in (target\\slms-cli.jar) do (
|
|
|
set SIZE=%%~zF
|
|
|
set /a SIZE_MB=%%~zF/1048576
|
|
|
)
|
|
|
echo ✓ 重命名成功: slms-cli.jar ^(!SIZE_MB! MB^)
|
|
|
) else (
|
|
|
echo ✗ 错误: 重命名失败
|
|
|
)
|
|
|
) else (
|
|
|
echo ⚠️ 警告: 找不到任何 CLI JAR 文件
|
|
|
)
|
|
|
echo.
|
|
|
|
|
|
REM ========== 1.2 GUI JAR 重命名 ==========
|
|
|
echo [2/4] 处理 GUI JAR... (target\\gui)
|
|
|
echo 列出 target\\gui 目录:
|
|
|
dir target\\gui\\*.jar 2>nul || echo 目录为空或不存在
|
|
|
|
|
|
set GUI_JAR_FOUND=0
|
|
|
REM 尝试多种可能的文件名
|
|
|
if exist target\\gui\\slms-1.0-SNAPSHOT-gui-swing.jar (
|
|
|
echo ✓ 找到: slms-1.0-SNAPSHOT-gui-swing.jar
|
|
|
copy /Y target\\gui\\slms-1.0-SNAPSHOT-gui-swing.jar target\\slms-gui.jar >nul
|
|
|
set GUI_JAR_FOUND=1
|
|
|
) else if exist target\\gui\\slms-1.0-SNAPSHOT-shaded.jar (
|
|
|
echo ✓ 找到备选: slms-1.0-SNAPSHOT-shaded.jar
|
|
|
copy /Y target\\gui\\slms-1.0-SNAPSHOT-shaded.jar target\\slms-gui.jar >nul
|
|
|
set GUI_JAR_FOUND=1
|
|
|
) else if exist target\\gui\\slms-1.0-SNAPSHOT.jar (
|
|
|
echo ✓ 找到默认JAR: slms-1.0-SNAPSHOT.jar
|
|
|
copy /Y target\\gui\\slms-1.0-SNAPSHOT.jar target\\slms-gui.jar >nul
|
|
|
set GUI_JAR_FOUND=1
|
|
|
)
|
|
|
|
|
|
if !GUI_JAR_FOUND!==1 (
|
|
|
if exist target\\slms-gui.jar (
|
|
|
for %%F in (target\\slms-gui.jar) do (
|
|
|
set SIZE=%%~zF
|
|
|
set /a SIZE_MB=%%~zF/1048576
|
|
|
)
|
|
|
echo ✓ 重命名成功: slms-gui.jar ^(!SIZE_MB! MB^)
|
|
|
|
|
|
REM 创建启动脚本
|
|
|
echo @echo off > target\\run-gui.bat
|
|
|
echo chcp 65001 ^>nul >> target\\run-gui.bat
|
|
|
echo echo ============================================ >> target\\run-gui.bat
|
|
|
echo echo SLMS GUI Application ^(Swing Version^) >> target\\run-gui.bat
|
|
|
echo echo ============================================ >> target\\run-gui.bat
|
|
|
echo echo. >> target\\run-gui.bat
|
|
|
echo echo Starting GUI application... >> target\\run-gui.bat
|
|
|
echo java -jar slms-gui.jar >> target\\run-gui.bat
|
|
|
echo if errorlevel 1 ^( >> target\\run-gui.bat
|
|
|
echo echo. >> target\\run-gui.bat
|
|
|
echo echo Error: Failed to start GUI application >> target\\run-gui.bat
|
|
|
echo echo Please ensure Java 11+ is installed >> target\\run-gui.bat
|
|
|
echo pause >> target\\run-gui.bat
|
|
|
echo ^) >> target\\run-gui.bat
|
|
|
echo ✓ 创建启动脚本: run-gui.bat
|
|
|
|
|
|
REM 创建 README 文件
|
|
|
echo SLMS GUI Application ^(Swing Version^) > target\\README-GUI.txt
|
|
|
echo. >> target\\README-GUI.txt
|
|
|
echo ========================================== >> target\\README-GUI.txt
|
|
|
echo. >> target\\README-GUI.txt
|
|
|
echo 运行方式: >> target\\README-GUI.txt
|
|
|
echo 1. 双击 run-gui.bat ^(推荐^) >> target\\README-GUI.txt
|
|
|
echo 2. 命令行: java -jar slms-gui.jar >> target\\README-GUI.txt
|
|
|
echo. >> target\\README-GUI.txt
|
|
|
echo 特点: >> target\\README-GUI.txt
|
|
|
echo - 单一 JAR 文件,无需额外依赖 >> target\\README-GUI.txt
|
|
|
echo - 使用 Swing 界面,兼容性好 >> target\\README-GUI.txt
|
|
|
echo - 包含完整功能:图书管理、借阅管理 >> target\\README-GUI.txt
|
|
|
echo - 文件大小约 36 MB >> target\\README-GUI.txt
|
|
|
echo. >> target\\README-GUI.txt
|
|
|
echo 系统要求: >> target\\README-GUI.txt
|
|
|
echo - Java 11 或更高版本 >> target\\README-GUI.txt
|
|
|
echo - Windows / Linux / macOS >> target\\README-GUI.txt
|
|
|
echo. >> target\\README-GUI.txt
|
|
|
echo 注意: >> target\\README-GUI.txt
|
|
|
echo - library.db 必须与应用文件在同一目录 >> target\\README-GUI.txt
|
|
|
echo - 首次运行会自动初始化数据库 >> target\\README-GUI.txt
|
|
|
echo. >> target\\README-GUI.txt
|
|
|
echo ========================================== >> target\\README-GUI.txt
|
|
|
echo ✓ 创建说明文档: README-GUI.txt
|
|
|
) else (
|
|
|
echo ✗ 错误: 重命名失败
|
|
|
)
|
|
|
) else (
|
|
|
echo ⚠️ 警告: 找不到任何 GUI JAR 文件
|
|
|
)
|
|
|
echo.
|
|
|
|
|
|
REM ========== 1.3 Web WAR 重命名 ==========
|
|
|
echo [3/4] 处理 Web WAR... (target\\web)
|
|
|
if exist target\\web\\slms-1.0-SNAPSHOT.war (
|
|
|
echo ✓ 找到源文件: slms-1.0-SNAPSHOT.war
|
|
|
copy /Y target\\web\\slms-1.0-SNAPSHOT.war target\\slms-web.war >nul
|
|
|
if exist target\\slms-web.war (
|
|
|
for %%F in (target\\slms-web.war) do (
|
|
|
set SIZE=%%~zF
|
|
|
set /a SIZE_MB=%%~zF/1048576
|
|
|
)
|
|
|
if !SIZE_MB! GTR 10 (
|
|
|
echo ✓ 重命名成功: slms-web.war ^(!SIZE_MB! MB^)
|
|
|
) else (
|
|
|
echo ⚠️ 警告: slms-web.war 文件大小异常 ^(!SIZE_MB! MB^),预期 ^> 10 MB
|
|
|
)
|
|
|
) else (
|
|
|
echo ✗ 错误: 重命名失败
|
|
|
)
|
|
|
) else (
|
|
|
echo ⚠️ 警告: 找不到 Web WAR 源文件 (target\\web\\slms-1.0-SNAPSHOT.war)
|
|
|
)
|
|
|
echo.
|
|
|
|
|
|
REM ========== 1.4 复制数据库文件 ==========
|
|
|
echo [4/4] 处理数据库文件...
|
|
|
if exist library.db (
|
|
|
echo ✓ 找到数据库文件: library.db
|
|
|
copy /Y library.db target\\library.db >nul
|
|
|
if exist target\\library.db (
|
|
|
echo ✓ 复制成功: target\\library.db
|
|
|
) else (
|
|
|
echo ✗ 错误: 复制失败
|
|
|
)
|
|
|
) else (
|
|
|
echo ⚠️ 警告: 找不到 library.db
|
|
|
)
|
|
|
echo.
|
|
|
|
|
|
REM ========== 1.5 文件验证和日志 ==========
|
|
|
echo ============================================
|
|
|
echo 制品验证报告
|
|
|
echo ============================================
|
|
|
echo.
|
|
|
echo [CLI 应用]
|
|
|
if exist target\\slms-cli.jar (
|
|
|
for %%F in (target\\slms-cli.jar) do (
|
|
|
set /a SIZE_MB=%%~zF/1048576
|
|
|
echo ✓ slms-cli.jar - !SIZE_MB! MB
|
|
|
)
|
|
|
) else (
|
|
|
echo ✗ slms-cli.jar - 不存在
|
|
|
)
|
|
|
echo.
|
|
|
|
|
|
echo [GUI 应用]
|
|
|
if exist target\\slms-gui.jar (
|
|
|
for %%F in (target\\slms-gui.jar) do (
|
|
|
set /a SIZE_MB=%%~zF/1048576
|
|
|
echo ✓ slms-gui.jar - !SIZE_MB! MB
|
|
|
)
|
|
|
) else (
|
|
|
echo ✗ slms-gui.jar - 不存在
|
|
|
)
|
|
|
if exist target\\run-gui.bat (
|
|
|
echo ✓ run-gui.bat - 存在
|
|
|
) else (
|
|
|
echo ✗ run-gui.bat - 不存在
|
|
|
)
|
|
|
if exist target\\README-GUI.txt (
|
|
|
echo ✓ README-GUI.txt - 存在
|
|
|
) else (
|
|
|
echo ✗ README-GUI.txt - 不存在
|
|
|
)
|
|
|
echo.
|
|
|
|
|
|
echo [Web 应用]
|
|
|
if exist target\\slms-web.war (
|
|
|
for %%F in (target\\slms-web.war) do (
|
|
|
set /a SIZE_MB=%%~zF/1048576
|
|
|
echo ✓ slms-web.war - !SIZE_MB! MB
|
|
|
)
|
|
|
) else (
|
|
|
echo ✗ slms-web.war - 不存在
|
|
|
)
|
|
|
echo.
|
|
|
|
|
|
echo [Android 应用]
|
|
|
if exist android\\build\\outputs\\apk\\debug\\slms-debug.apk (
|
|
|
for %%F in (android\\build\\outputs\\apk\\debug\\slms-debug.apk) do (
|
|
|
set /a SIZE_MB=%%~zF/1048576
|
|
|
echo ✓ slms-debug.apk - !SIZE_MB! MB
|
|
|
)
|
|
|
) else (
|
|
|
if exist android\\build\\outputs\\apk\\debug\\SLMS-debug.apk (
|
|
|
for %%F in (android\\build\\outputs\\apk\\debug\\SLMS-debug.apk) do (
|
|
|
set /a SIZE_MB=%%~zF/1048576
|
|
|
echo ✓ SLMS-debug.apk - !SIZE_MB! MB
|
|
|
)
|
|
|
) else (
|
|
|
echo ✗ APK - 不存在
|
|
|
)
|
|
|
)
|
|
|
echo.
|
|
|
|
|
|
echo [数据库]
|
|
|
if exist target\\library.db (
|
|
|
for %%F in (target\\library.db) do (
|
|
|
set /a SIZE_KB=%%~zF/1024
|
|
|
echo ✓ library.db - !SIZE_KB! KB
|
|
|
)
|
|
|
) else (
|
|
|
echo ✗ library.db - 不存在
|
|
|
)
|
|
|
echo.
|
|
|
|
|
|
echo ============================================
|
|
|
echo 重命名阶段完成
|
|
|
echo ============================================
|
|
|
|
|
|
REM 不因警告而失败构建
|
|
|
exit /b 0
|
|
|
'''
|
|
|
}
|
|
|
echo '✓ 制品重命名和验证完成'
|
|
|
}
|
|
|
}
|
|
|
|
|
|
stage('6.6 创建Windows安装包 (jpackage)') {
|
|
|
when {
|
|
|
expression { currentBuild.result == null || currentBuild.result == 'SUCCESS' || currentBuild.result == 'UNSTABLE' }
|
|
|
}
|
|
|
steps {
|
|
|
echo '========== 使用 jpackage 创建 EXE 和 MSI =========='
|
|
|
script {
|
|
|
try {
|
|
|
bat '''
|
|
|
@echo off
|
|
|
setlocal EnableDelayedExpansion
|
|
|
set JAVA_HOME=%JAVA_HOME%
|
|
|
REM 使用短路径避免 LocalSystem 权限导致的 "此时不应有" 错误
|
|
|
for %%P in ("C:\\Program Files (x86)\\WiX Toolset v3.11") do set "WIX_HOME=%%~sP"
|
|
|
set "PATH=%WIX_HOME%\\bin;%PATH%"
|
|
|
|
|
|
echo ============================================
|
|
|
echo jpackage 打包阶段
|
|
|
echo ============================================
|
|
|
echo.
|
|
|
|
|
|
REM 检查 jpackage
|
|
|
echo [1/6] 检查 jpackage 工具...
|
|
|
jpackage --version >nul 2>&1
|
|
|
if errorlevel 1 (
|
|
|
echo ✗ jpackage 不可用
|
|
|
echo 需要 JDK 14+ 才能使用 jpackage
|
|
|
exit /b 1
|
|
|
)
|
|
|
for /f "tokens=*" %%i in ('jpackage --version') do set JPACKAGE_VER=%%i
|
|
|
echo ✓ jpackage 可用: !JPACKAGE_VER!
|
|
|
echo.
|
|
|
|
|
|
REM 检查 WiX Toolset
|
|
|
echo [2/6] 检查 WiX Toolset...
|
|
|
set "WIX_AVAILABLE=0"
|
|
|
if exist "%WIX_HOME%\\bin\\candle.exe" (
|
|
|
echo ✓ WiX Toolset 已安装: %WIX_HOME%
|
|
|
set "WIX_AVAILABLE=1"
|
|
|
) else (
|
|
|
echo ⚠️ WiX Toolset 未找到,跳过 EXE/MSI,改用 ZIP 绿色版
|
|
|
)
|
|
|
echo.
|
|
|
|
|
|
REM 准备 jpackage 输入目录
|
|
|
echo [3/6] 准备 jpackage 输入目录...
|
|
|
if exist target\\jpackage-input rmdir /S /Q target\\jpackage-input
|
|
|
mkdir target\\jpackage-input
|
|
|
|
|
|
if exist target\\slms-gui.jar (
|
|
|
copy /Y target\\slms-gui.jar target\\jpackage-input\\ >nul
|
|
|
echo ✓ 复制 slms-gui.jar
|
|
|
) else (
|
|
|
echo ✗ 找不到 slms-gui.jar
|
|
|
exit /b 1
|
|
|
)
|
|
|
|
|
|
if exist library.db (
|
|
|
copy /Y library.db target\\jpackage-input\\ >nul
|
|
|
echo ✓ 复制 library.db
|
|
|
)
|
|
|
echo.
|
|
|
|
|
|
REM 创建 app-image (包含 JRE 的应用目录)
|
|
|
echo [4/6] 创建 app-image...
|
|
|
jpackage ^
|
|
|
--type app-image ^
|
|
|
--input target\\jpackage-input ^
|
|
|
--name SLMS ^
|
|
|
--main-jar slms-gui.jar ^
|
|
|
--main-class com.smartlibrary.gui.SimpleGUIApplication ^
|
|
|
--app-version 1.0 ^
|
|
|
--vendor "CHZU" ^
|
|
|
--description "Smart Library Management System" ^
|
|
|
--dest target\\jpackage-output
|
|
|
|
|
|
if errorlevel 1 (
|
|
|
echo ✗ app-image 创建失败
|
|
|
exit /b 1
|
|
|
)
|
|
|
echo ✓ app-image 创建成功
|
|
|
echo.
|
|
|
|
|
|
if "%WIX_AVAILABLE%"=="1" (
|
|
|
REM 创建 EXE 安装包
|
|
|
echo [5/6] 创建 EXE 安装包...
|
|
|
jpackage ^
|
|
|
--type exe ^
|
|
|
--app-image target\\jpackage-output\\SLMS ^
|
|
|
--name SLMS ^
|
|
|
--app-version 1.0 ^
|
|
|
--vendor "CHZU" ^
|
|
|
--description "Smart Library Management System" ^
|
|
|
--win-menu ^
|
|
|
--win-dir-chooser ^
|
|
|
--win-shortcut ^
|
|
|
--dest target
|
|
|
|
|
|
if errorlevel 1 (
|
|
|
echo ⚠️ EXE 安装包创建失败 ^(可能缺少 Inno Setup^)
|
|
|
) else (
|
|
|
REM 重命名生成的 EXE
|
|
|
if exist target\\SLMS-1.0.exe (
|
|
|
move /Y target\\SLMS-1.0.exe target\\slms-gui.exe >nul
|
|
|
for %%F in (target\\slms-gui.exe) do (
|
|
|
set /a SIZE_MB=%%~zF/1048576
|
|
|
echo ✓ EXE 安装包创建成功: slms-gui.exe ^(!SIZE_MB! MB^)
|
|
|
)
|
|
|
) else (
|
|
|
echo ⚠️ EXE 文件生成了但未找到预期文件名,列出 target 目录:
|
|
|
dir target\\*.exe
|
|
|
)
|
|
|
)
|
|
|
echo.
|
|
|
|
|
|
REM 创建 MSI 安装包
|
|
|
echo [6/6] 创建 MSI 安装包...
|
|
|
jpackage ^
|
|
|
--type msi ^
|
|
|
--app-image target\\jpackage-output\\SLMS ^
|
|
|
--name SLMS ^
|
|
|
--app-version 1.0 ^
|
|
|
--vendor "CHZU" ^
|
|
|
--description "Smart Library Management System" ^
|
|
|
--win-menu ^
|
|
|
--win-dir-chooser ^
|
|
|
--win-shortcut ^
|
|
|
--dest target
|
|
|
|
|
|
if errorlevel 1 (
|
|
|
echo ⚠️ MSI 创建失败,将保留 EXE/ZIP
|
|
|
) else (
|
|
|
REM 重命名 MSI
|
|
|
if exist target\\SLMS-1.0.msi (
|
|
|
move /Y target\\SLMS-1.0.msi target\\slms-gui-installer.msi >nul
|
|
|
for %%F in (target\\slms-gui-installer.msi) do (
|
|
|
set /a SIZE_MB=%%~zF/1048576
|
|
|
echo ✓ MSI 创建成功: slms-gui-installer.msi ^(!SIZE_MB! MB^)
|
|
|
)
|
|
|
) else (
|
|
|
echo ⚠️ MSI 文件未找到,检查其他可能的文件名...
|
|
|
dir target\\*.msi
|
|
|
)
|
|
|
)
|
|
|
echo.
|
|
|
) else (
|
|
|
echo [5/6] WiX 不可用,跳过 EXE/MSI,创建 ZIP 绿色版...
|
|
|
)
|
|
|
|
|
|
if %WIX_AVAILABLE%==0 (
|
|
|
powershell -Command "Compress-Archive -Path target\\jpackage-output\\SLMS -DestinationPath target\\slms-gui.zip -Force"
|
|
|
if exist target\\slms-gui.zip (
|
|
|
echo ✓ ZIP 绿色版创建成功: slms-gui.zip
|
|
|
) else (
|
|
|
echo ✗ ZIP 创建失败,请检查 jpackage 输出
|
|
|
)
|
|
|
)
|
|
|
echo.
|
|
|
|
|
|
REM 创建 README 文件
|
|
|
echo 创建 EXE 和 MSI 说明文档...
|
|
|
|
|
|
echo SLMS GUI Application - EXE Version > target\\README-GUI-EXE.txt
|
|
|
echo. >> target\\README-GUI-EXE.txt
|
|
|
echo 运行方式: >> target\\README-GUI-EXE.txt
|
|
|
echo 双击 slms-gui.exe 即可运行 >> target\\README-GUI-EXE.txt
|
|
|
echo. >> target\\README-GUI-EXE.txt
|
|
|
echo 特点: >> target\\README-GUI-EXE.txt
|
|
|
echo - 包含 Java 运行时,无需安装 Java >> target\\README-GUI-EXE.txt
|
|
|
echo - Windows 原生可执行文件 >> target\\README-GUI-EXE.txt
|
|
|
echo - 文件大小约 50-80 MB >> target\\README-GUI-EXE.txt
|
|
|
echo. >> target\\README-GUI-EXE.txt
|
|
|
echo 系统要求: >> target\\README-GUI-EXE.txt
|
|
|
echo - Windows 10 或更高版本 >> target\\README-GUI-EXE.txt
|
|
|
echo. >> target\\README-GUI-EXE.txt
|
|
|
|
|
|
echo SLMS GUI Application - MSI Installer > target\\README-GUI-MSI.txt
|
|
|
echo. >> target\\README-GUI-MSI.txt
|
|
|
echo 安装方式: >> target\\README-GUI-MSI.txt
|
|
|
echo 1. 双击 slms-gui-installer.msi >> target\\README-GUI-MSI.txt
|
|
|
echo 2. 按照安装向导完成安装 >> target\\README-GUI-MSI.txt
|
|
|
echo 3. 从开始菜单或桌面快捷方式启动 >> target\\README-GUI-MSI.txt
|
|
|
echo. >> target\\README-GUI-MSI.txt
|
|
|
echo 特点: >> target\\README-GUI-MSI.txt
|
|
|
echo - 标准 Windows 安装程序 >> target\\README-GUI-MSI.txt
|
|
|
echo - 自动创建开始菜单快捷方式 >> target\\README-GUI-MSI.txt
|
|
|
echo - 可选择安装目录 >> target\\README-GUI-MSI.txt
|
|
|
echo - 支持卸载 >> target\\README-GUI-MSI.txt
|
|
|
echo. >> target\\README-GUI-MSI.txt
|
|
|
echo 系统要求: >> target\\README-GUI-MSI.txt
|
|
|
echo - Windows 10 或更高版本 >> target\\README-GUI-MSI.txt
|
|
|
echo. >> target\\README-GUI-MSI.txt
|
|
|
|
|
|
echo ✓ 说明文档创建完成
|
|
|
echo.
|
|
|
|
|
|
echo ============================================
|
|
|
echo jpackage 打包完成
|
|
|
echo ============================================
|
|
|
echo.
|
|
|
echo 生成的文件:
|
|
|
if exist target\\slms-gui.exe echo ✓ slms-gui.exe
|
|
|
if exist target\\slms-gui-installer.msi echo ✓ slms-gui-installer.msi
|
|
|
if exist target\\README-GUI-EXE.txt echo ✓ README-GUI-EXE.txt
|
|
|
if exist target\\README-GUI-MSI.txt echo ✓ README-GUI-MSI.txt
|
|
|
echo.
|
|
|
'''
|
|
|
echo '✓ Windows 安装包创建成功'
|
|
|
} catch (Exception e) {
|
|
|
echo '⚠️ jpackage 打包失败,但继续构建'
|
|
|
echo "错误信息: ${e.message}"
|
|
|
currentBuild.result = 'UNSTABLE'
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
stage('7. 归档制品') {
|
|
|
when {
|
|
|
expression { currentBuild.result == null || currentBuild.result == 'SUCCESS' || currentBuild.result == 'UNSTABLE' }
|
|
|
}
|
|
|
steps {
|
|
|
echo '========== 归档构建制品 =========='
|
|
|
script {
|
|
|
// 显示当前工作目录
|
|
|
bat '''
|
|
|
@echo off
|
|
|
echo 当前工作目录:
|
|
|
cd
|
|
|
echo.
|
|
|
echo 列出 target 目录:
|
|
|
dir target\\*.jar 2>nul || echo 没有找到 JAR 文件
|
|
|
echo.
|
|
|
echo 列出 android/build/outputs/apk/debug 目录:
|
|
|
dir android\\build\\outputs\\apk\\debug\\*.apk 2>nul || echo 没有找到 APK 文件
|
|
|
echo.
|
|
|
'''
|
|
|
|
|
|
// 检查文件是否存在
|
|
|
bat '''
|
|
|
@echo off
|
|
|
echo 检查制品文件...
|
|
|
echo.
|
|
|
echo [CLI 应用]
|
|
|
if exist "target\\slms-cli.jar" (
|
|
|
echo ✓ 找到 slms-cli.jar
|
|
|
for %%F in (target\\slms-cli.jar) do echo 大小: %%~zF bytes
|
|
|
) else (
|
|
|
echo ✗ 未找到 slms-cli.jar
|
|
|
)
|
|
|
echo.
|
|
|
echo [GUI 应用]
|
|
|
if exist "target\\slms-gui.jar" (
|
|
|
echo ✓ 找到 slms-gui.jar
|
|
|
for %%F in (target\\slms-gui.jar) do echo 大小: %%~zF bytes
|
|
|
) else (
|
|
|
echo ✗ 未找到 slms-gui.jar
|
|
|
)
|
|
|
echo.
|
|
|
echo [Windows 安装包]
|
|
|
if exist "target\\slms-gui.exe" (
|
|
|
echo ✓ 找到 slms-gui.exe
|
|
|
for %%F in (target\\slms-gui.exe) do echo 大小: %%~zF bytes
|
|
|
) else (
|
|
|
echo ✗ 未找到 slms-gui.exe
|
|
|
)
|
|
|
if exist "target\\slms-gui-installer.msi" (
|
|
|
echo ✓ 找到 slms-gui-installer.msi
|
|
|
for %%F in (target\\slms-gui-installer.msi) do echo 大小: %%~zF bytes
|
|
|
) else (
|
|
|
echo ✗ 未找到 slms-gui-installer.msi
|
|
|
)
|
|
|
echo.
|
|
|
echo [Web 应用]
|
|
|
if exist "target\\slms-web.war" (
|
|
|
echo ✓ 找到 slms-web.war
|
|
|
for %%F in (target\\slms-web.war) do echo 大小: %%~zF bytes
|
|
|
) else (
|
|
|
echo ⚠️ 警告: 找不到 slms-web.war
|
|
|
)
|
|
|
echo.
|
|
|
echo [Android 应用]
|
|
|
if exist android\\build\\outputs\\apk\\debug\\slms-debug.apk (
|
|
|
echo ✓ 找到 slms-debug.apk
|
|
|
for %%F in (android\\build\\outputs\\apk\\debug\\slms-debug.apk) do echo 大小: %%~zF bytes
|
|
|
) else (
|
|
|
if exist android\\build\\outputs\\apk\\debug\\SLMS-debug.apk (
|
|
|
echo ✓ 找到 SLMS-debug.apk
|
|
|
for %%F in (android\\build\\outputs\\apk\\debug\\SLMS-debug.apk) do echo 大小: %%~zF bytes
|
|
|
) else (
|
|
|
echo ⚠️ 警告: 找不到 slms-debug.apk
|
|
|
)
|
|
|
)
|
|
|
echo.
|
|
|
echo [数据库文件]
|
|
|
if exist target\\library.db (
|
|
|
echo ✓ 找到 library.db
|
|
|
) else (
|
|
|
echo ⚠️ 未找到 library.db
|
|
|
)
|
|
|
exit /b 0
|
|
|
'''
|
|
|
|
|
|
// 归档制品 - 使用 try-catch 确保即使部分文件缺失也能继续
|
|
|
try {
|
|
|
echo '开始归档制品...'
|
|
|
// 归档所有制品: JAR、WAR 文件、数据库、文档、APK
|
|
|
archiveArtifacts artifacts: 'target/slms-*.jar,target/slms-*.war,target/slms-gui.exe,target/slms-gui-installer.msi,target/library.db,target/README-*.txt,target/run-*.bat,android/build/outputs/apk/debug/*.apk',
|
|
|
fingerprint: true,
|
|
|
allowEmptyArchive: true,
|
|
|
onlyIfSuccessful: false
|
|
|
echo '✓ 制品归档完成'
|
|
|
|
|
|
// Stash 制品供后续阶段使用
|
|
|
echo '保存制品到 stash...'
|
|
|
stash includes: 'target/slms-*.jar,target/slms-*.war,target/slms-gui.exe,target/slms-gui-installer.msi,target/library.db,target/README-*.txt,target/run-*.bat,android/build/outputs/apk/debug/*.apk', name: 'build-artifacts', allowEmpty: true
|
|
|
echo '✓ 制品已保存到 stash'
|
|
|
} catch (Exception e) {
|
|
|
echo "⚠️ 制品归档时出现问题: ${e.message}"
|
|
|
echo "继续执行流水线..."
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
stage('8. 部署到 Tomcat 11') {
|
|
|
when {
|
|
|
expression { currentBuild.result == null || currentBuild.result == 'SUCCESS' || currentBuild.result == 'UNSTABLE' }
|
|
|
}
|
|
|
steps {
|
|
|
echo '========== 部署到本地 Tomcat 11 =========='
|
|
|
script {
|
|
|
// 恢复制品(处理重启构建情况)
|
|
|
echo '恢复制品从 stash...'
|
|
|
unstash 'build-artifacts'
|
|
|
echo '✓ 制品已恢复'
|
|
|
def tomcatHome = 'E:\\2025-2026\\GitAIOps\\tomcat'
|
|
|
def tomcatWebapps = "${tomcatHome}\\webapps"
|
|
|
def tomcatBin = "${tomcatHome}\\bin"
|
|
|
def appName = 'slms'
|
|
|
|
|
|
try {
|
|
|
// 防止 Jenkins 杀死衍生进程
|
|
|
env.BUILD_ID = "dontKillMe"
|
|
|
|
|
|
bat """
|
|
|
@echo off
|
|
|
echo 正在检查端口 8080 占用...
|
|
|
for /f "tokens=5" %%a in ('netstat -ano ^| findstr :8080') do (
|
|
|
if not "%%a"=="0" (
|
|
|
echo 发现占用端口 8080 的进程 PID: %%a
|
|
|
taskkill /F /PID %%a 2>nul
|
|
|
)
|
|
|
)
|
|
|
|
|
|
echo 停止 Tomcat...
|
|
|
if exist "${tomcatBin}\\shutdown.bat" call "${tomcatBin}\\shutdown.bat" 2>nul
|
|
|
|
|
|
echo 清理旧应用...
|
|
|
if exist "${tomcatWebapps}\\${appName}.war" del /F /Q "${tomcatWebapps}\\${appName}.war"
|
|
|
if exist "${tomcatWebapps}\\${appName}" rmdir /S /Q "${tomcatWebapps}\\${appName}"
|
|
|
|
|
|
echo 部署新 WAR 包...
|
|
|
if exist "target\\slms-web.war" (
|
|
|
copy /Y "target\\slms-web.war" "${tomcatWebapps}\\${appName}.war"
|
|
|
echo ✓ 成功部署 WAR 包: target\\slms-web.war
|
|
|
) else (
|
|
|
echo ✗ 错误: 找不到 WAR 文件 (target\\slms-web.war)
|
|
|
echo 正在检查其他可能的 WAR 文件位置...
|
|
|
if exist "target\\web\\slms-1.0-SNAPSHOT.war" (
|
|
|
copy /Y "target\\web\\slms-1.0-SNAPSHOT.war" "${tomcatWebapps}\\${appName}.war"
|
|
|
echo ✓ 成功部署 WAR 包从 target\\web\\ 目录
|
|
|
) else (
|
|
|
echo ✗ 错误: 找不到任何 WAR 文件
|
|
|
exit /b 1
|
|
|
)
|
|
|
)
|
|
|
|
|
|
echo 更新数据库文件...
|
|
|
if exist "target\\library.db" (
|
|
|
copy /Y "target\\library.db" "${tomcatBin}\\library.db"
|
|
|
echo ✓ 成功复制数据库文件
|
|
|
) else (
|
|
|
if exist "library.db" (
|
|
|
copy /Y "library.db" "${tomcatBin}\\library.db"
|
|
|
echo ✓ 成功复制数据库文件从根目录
|
|
|
) else (
|
|
|
echo ⚠️ 警告: 找不到 library.db 文件,应用可能无法正常工作
|
|
|
)
|
|
|
)
|
|
|
|
|
|
echo 启动 Tomcat 11...
|
|
|
set CATALINA_HOME=${tomcatHome}
|
|
|
|
|
|
REM 检查 WAR 包内容 (调试用)
|
|
|
echo [Debug] 检查 WAR 包中的 WebApplication 类...
|
|
|
jar tf "${tomcatWebapps}\\${appName}.war" | findstr "WebApplication.class"
|
|
|
|
|
|
REM 使用 catalina.bat run 启动并重定向日志
|
|
|
REM 移除可能引起 CMD 解析错误的中文注释
|
|
|
start "Tomcat" /B "${tomcatBin}\\catalina.bat" run > "${tomcatHome}\\logs\\jenkins-tomcat.log" 2>&1
|
|
|
"""
|
|
|
|
|
|
echo '等待 Tomcat 启动 (60秒)...'
|
|
|
sleep 60
|
|
|
|
|
|
echo '验证应用访问...'
|
|
|
bat """
|
|
|
@echo off
|
|
|
powershell -NoLogo -NoProfile -Command "try { \$response = Invoke-WebRequest -Uri 'http://localhost:8080/${appName}/' -UseBasicParsing; if (\$response.StatusCode -eq 200) { Write-Host '✓ 部署成功,应用可访问'; exit 0 } else { Write-Host '✗ 访问失败,状态码: ' \$response.StatusCode; exit 1 } } catch { Write-Host '✗ 无法访问应用: ' \$_.Exception.Message; exit 1 }"
|
|
|
"""
|
|
|
} catch (Exception e) {
|
|
|
echo "⚠️ Tomcat 部署或验证失败: ${e.message}"
|
|
|
echo "读取 Tomcat 启动日志 (jenkins-tomcat.log)..."
|
|
|
bat """
|
|
|
@echo off
|
|
|
powershell -NoLogo -NoProfile -Command "if (Test-Path '${tomcatHome}\\logs\\jenkins-tomcat.log') { Get-Content '${tomcatHome}\\logs\\jenkins-tomcat.log' -Tail 500 } else { Write-Host '找不到 jenkins-tomcat.log' }"
|
|
|
"""
|
|
|
currentBuild.result = 'UNSTABLE'
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
stage('9. 推送头歌') {
|
|
|
when {
|
|
|
expression { currentBuild.result == null || currentBuild.result == 'SUCCESS' || currentBuild.result == 'UNSTABLE' }
|
|
|
}
|
|
|
parallel {
|
|
|
stage('9.1 推送源代码到 main') {
|
|
|
steps {
|
|
|
echo '========== 推送源代码到头歌 main 分支 =========='
|
|
|
script {
|
|
|
try {
|
|
|
withCredentials([usernamePassword(
|
|
|
credentialsId: 'educoder-credentials',
|
|
|
usernameVariable: 'EDUCODER_USER',
|
|
|
passwordVariable: 'EDUCODER_PASS'
|
|
|
)]) {
|
|
|
bat '''
|
|
|
@echo off
|
|
|
setlocal EnableExtensions EnableDelayedExpansion
|
|
|
|
|
|
REM URL编码用户名和密码
|
|
|
for /f %%i in ('powershell -NoLogo -NoProfile -Command "[Console]::Out.Write([uri]::EscapeDataString($env:EDUCODER_USER))"') do set USER_ENC=%%i
|
|
|
for /f %%i in ('powershell -NoLogo -NoProfile -Command "[Console]::Out.Write([uri]::EscapeDataString($env:EDUCODER_PASS))"') do set PASS_ENC=%%i
|
|
|
|
|
|
git config user.name "Jenkins CI"
|
|
|
git config user.email "ldl@chzu.edu.cn"
|
|
|
git remote remove educoder 2>nul || echo Remote educoder does not exist
|
|
|
git remote add educoder https://bdgit.educoder.net/pu6zrsfoy/slms.git
|
|
|
git fetch --unshallow 2>nul || echo Already a complete repository
|
|
|
|
|
|
REM 获取当前提交的 SHA
|
|
|
for /f %%i in ('git rev-parse HEAD') do set CURRENT_SHA=%%i
|
|
|
echo 当前提交 SHA: !CURRENT_SHA!
|
|
|
|
|
|
REM 使用 SHA 推送到 main 分支
|
|
|
git push https://%USER_ENC%:%PASS_ENC%@bdgit.educoder.net/pu6zrsfoy/slms.git !CURRENT_SHA!:refs/heads/main --force
|
|
|
'''
|
|
|
}
|
|
|
echo '✓ 源代码推送到 main 成功'
|
|
|
} catch (Exception e) {
|
|
|
echo '⚠ 推送代码到 main 失败'
|
|
|
echo "错误信息: ${e.message}"
|
|
|
currentBuild.result = 'UNSTABLE'
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
stage('9.2 推送制品到 release') {
|
|
|
steps {
|
|
|
echo '========== 推送构建制品到头歌 release 分支 =========='
|
|
|
script {
|
|
|
def releaseVersion = "v1.0.0.${env.BUILD_NUMBER}"
|
|
|
env.RELEASE_ARTIFACT_VERSION = releaseVersion
|
|
|
echo "本次 release 制品版本: ${releaseVersion}"
|
|
|
try {
|
|
|
// Unstash 制品
|
|
|
echo '恢复制品从 stash...'
|
|
|
unstash 'build-artifacts'
|
|
|
echo '✓ 制品已恢复'
|
|
|
|
|
|
withCredentials([usernamePassword(
|
|
|
credentialsId: 'educoder-credentials',
|
|
|
usernameVariable: 'EDUCODER_USER',
|
|
|
passwordVariable: 'EDUCODER_PASS'
|
|
|
)]) {
|
|
|
bat """
|
|
|
@echo off
|
|
|
setlocal EnableExtensions EnableDelayedExpansion
|
|
|
|
|
|
REM URL编码用户名和密码
|
|
|
for /f %%i in ('powershell -NoLogo -NoProfile -Command "[Console]::Out.Write([uri]::EscapeDataString(\$env:EDUCODER_USER))"') do set USER_ENC=%%i
|
|
|
for /f %%i in ('powershell -NoLogo -NoProfile -Command "[Console]::Out.Write([uri]::EscapeDataString(\$env:EDUCODER_PASS))"') do set PASS_ENC=%%i
|
|
|
set "VERSION_TAG=v1.0.0.%BUILD_NUMBER%"
|
|
|
set "ARTIFACTS_ROOT=artifacts"
|
|
|
set "ARTIFACTS_DIR=%ARTIFACTS_ROOT%\\\\!VERSION_TAG!"
|
|
|
|
|
|
REM 创建 artifacts 目录
|
|
|
if not exist "%ARTIFACTS_ROOT%" mkdir "%ARTIFACTS_ROOT%"
|
|
|
if exist "!ARTIFACTS_DIR!" rmdir /S /Q "!ARTIFACTS_DIR!"
|
|
|
mkdir "!ARTIFACTS_DIR!"
|
|
|
|
|
|
echo 复制制品到 !ARTIFACTS_DIR! 目录...
|
|
|
if exist target\\\\slms-cli.war copy /Y target\\\\slms-cli.war "!ARTIFACTS_DIR!\\\\slms-cli-!VERSION_TAG!.war" >nul
|
|
|
if exist target\\\\slms-gui.war copy /Y target\\\\slms-gui.war "!ARTIFACTS_DIR!\\\\slms-gui-!VERSION_TAG!.war" >nul
|
|
|
if exist target\\\\slms-web.war copy /Y target\\\\slms-web.war "!ARTIFACTS_DIR!\\\\slms-web-!VERSION_TAG!.war" >nul
|
|
|
if exist android\\\\build\\\\outputs\\\\apk\\\\debug\\\\slms-debug.apk copy /Y android\\\\build\\\\outputs\\\\apk\\\\debug\\\\slms-debug.apk "!ARTIFACTS_DIR!\\\\slms-debug-!VERSION_TAG!.apk" >nul
|
|
|
if exist target\\\\library.db copy /Y target\\\\library.db "!ARTIFACTS_DIR!\\\\library-!VERSION_TAG!.db" >nul
|
|
|
|
|
|
set "MANIFEST_FILE=!ARTIFACTS_DIR!\\\\manifest-!VERSION_TAG!.txt"
|
|
|
echo SLMS Release Manifest - !VERSION_TAG! > "!MANIFEST_FILE!"
|
|
|
echo Build ID: %BUILD_NUMBER% >> "!MANIFEST_FILE!"
|
|
|
echo 发布时间: %date% %time% >> "!MANIFEST_FILE!"
|
|
|
echo. >> "!MANIFEST_FILE!"
|
|
|
echo 制品列表: >> "!MANIFEST_FILE!"
|
|
|
for %%F in (!ARTIFACTS_DIR!\\\\*) do echo %%~nxF >> "!MANIFEST_FILE!"
|
|
|
echo ✓ 制品清单已生成: !MANIFEST_FILE!
|
|
|
echo 当前制品目录文件列表:
|
|
|
dir /B "!ARTIFACTS_DIR!"
|
|
|
|
|
|
REM 创建 orphan 分支,只推送制品
|
|
|
git checkout --orphan release-%BUILD_NUMBER%
|
|
|
git rm -rf . --ignore-unmatch >nul 2>&1
|
|
|
git add artifacts/
|
|
|
git commit -m "release: 发布 !VERSION_TAG! (Build #%BUILD_NUMBER%)"
|
|
|
echo 推送制品到头歌 release 分支: !VERSION_TAG! ...
|
|
|
git push https://%USER_ENC%:%PASS_ENC%@bdgit.educoder.net/pu6zrsfoy/slms.git HEAD:refs/heads/release --force
|
|
|
|
|
|
REM 切回 main 分支
|
|
|
git checkout main
|
|
|
echo ✓ release 分支已更新制品: !VERSION_TAG!
|
|
|
"""
|
|
|
}
|
|
|
echo '✓ 制品推送到 release 分支成功'
|
|
|
} catch (Exception e) {
|
|
|
echo '⚠ 推送制品到 release 失败'
|
|
|
echo "错误信息: ${e.message}"
|
|
|
currentBuild.result = 'UNSTABLE'
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
post {
|
|
|
always {
|
|
|
script {
|
|
|
echo '========== 流水线执行完成 =========='
|
|
|
echo "当前构建结果: ${currentBuild.result}"
|
|
|
echo "当前构建状态: ${currentBuild.currentResult}"
|
|
|
|
|
|
// 清理残留的 Java 进程
|
|
|
echo '========== 清理残留进程 =========='
|
|
|
try {
|
|
|
bat '''
|
|
|
@echo off
|
|
|
echo 清理与 slms 相关的残留进程...
|
|
|
for /f "tokens=2" %%i in ('tasklist /FI "IMAGENAME eq java.exe" /FO LIST ^| findstr /C:"PID:"') do (
|
|
|
wmic process where "ProcessId=%%i and CommandLine like '%%slms%%'" delete 2>nul
|
|
|
)
|
|
|
echo ✓ 进程清理完成
|
|
|
'''
|
|
|
} catch (Exception e) {
|
|
|
echo "⚠️ 清理进程时出错: ${e.message}"
|
|
|
}
|
|
|
|
|
|
// 检查制品是否存在
|
|
|
echo '========== 检查制品文件 =========='
|
|
|
try {
|
|
|
bat '''
|
|
|
@echo off
|
|
|
if exist target\\slms-cli.war (echo ✓ slms-cli.war 存在) else (echo ✗ slms-cli.war 不存在)
|
|
|
if exist target\\slms-gui.war (echo ✓ slms-gui.war 存在) else (echo ✗ slms-gui.war 不存在)
|
|
|
if exist target\\slms-web.war (
|
|
|
echo ✓ slms-web.war 存在
|
|
|
) else (
|
|
|
echo ✗ slms-web.war 不存在
|
|
|
)
|
|
|
if exist android\\build\\outputs\\apk\\debug\\slms-debug.apk (echo ✓ slms-debug.apk 存在) else (echo ✗ slms-debug.apk 不存在)
|
|
|
exit /b 0
|
|
|
'''
|
|
|
} catch (Exception e) {
|
|
|
echo "⚠️ 检查制品文件时出错: ${e.message}"
|
|
|
}
|
|
|
|
|
|
// 发送邮件 - 使用最简单的方式
|
|
|
echo '========== 发送邮件通知 =========='
|
|
|
def finalResult = currentBuild.result ?: 'SUCCESS'
|
|
|
def emailSubject = ""
|
|
|
def emailStatus = ""
|
|
|
def releaseVersion = env.RELEASE_ARTIFACT_VERSION ?: "v1.0.0.${BUILD_NUMBER}"
|
|
|
|
|
|
if (finalResult == 'SUCCESS') {
|
|
|
emailSubject = "✅ SLMS 构建成功 - ${releaseVersion} (Build #${BUILD_NUMBER})"
|
|
|
emailStatus = "成功"
|
|
|
} else if (finalResult == 'FAILURE') {
|
|
|
emailSubject = "❌ SLMS 构建失败 - ${releaseVersion} (Build #${BUILD_NUMBER})"
|
|
|
emailStatus = "失败"
|
|
|
} else if (finalResult == 'UNSTABLE') {
|
|
|
emailSubject = "⚠️ SLMS 构建不稳定 - ${releaseVersion} (Build #${BUILD_NUMBER})"
|
|
|
emailStatus = "不稳定"
|
|
|
} else {
|
|
|
emailSubject = "ℹ️ SLMS 构建完成 - ${releaseVersion} (Build #${BUILD_NUMBER})"
|
|
|
emailStatus = "完成"
|
|
|
}
|
|
|
|
|
|
echo "准备发送邮件: ${emailSubject}"
|
|
|
echo "收件人: 602924803@qq.com"
|
|
|
|
|
|
try {
|
|
|
mail to: '602924803@qq.com',
|
|
|
subject: emailSubject,
|
|
|
body: """SLMS 项目构建${emailStatus}
|
|
|
构建编号: #${BUILD_NUMBER}
|
|
|
Release 版本: ${releaseVersion}
|
|
|
构建状态: ${emailStatus}
|
|
|
构建时间: ${new Date(currentBuild.startTimeInMillis)}
|
|
|
Git 提交: ${env.GIT_COMMIT}
|
|
|
|
|
|
制品列表:
|
|
|
- slms-cli.war (命令行版本)
|
|
|
- slms-gui.war (图形界面版本)
|
|
|
- slms-web.war (Web应用版本)
|
|
|
- slms-debug.apk (Android版本)
|
|
|
- library.db (数据库文件)
|
|
|
|
|
|
查看构建详情: ${BUILD_URL}
|
|
|
查看构建日志: ${BUILD_URL}console
|
|
|
Jenkins 制品列表: ${BUILD_URL}artifact/
|
|
|
SonarQube 报告: http://localhost:9000/dashboard?id=slms:slms
|
|
|
Release 制品: https://code.educoder.net/pu6zrsfoy/slms/tree/release/artifacts/${releaseVersion}
|
|
|
|
|
|
此邮件由 Jenkins 自动发送 | Build #${BUILD_NUMBER}
|
|
|
"""
|
|
|
echo "✓ 邮件已发送到: 602924803@qq.com"
|
|
|
echo "✓ 邮件主题: ${emailSubject}"
|
|
|
} catch (Exception e) {
|
|
|
echo "❌ 邮件发送失败!"
|
|
|
echo "错误信息: ${e.message}"
|
|
|
echo "错误类型: ${e.class.name}"
|
|
|
echo "错误详情:"
|
|
|
e.printStackTrace()
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|