211 lines
8.3 KiB
Groovy
211 lines
8.3 KiB
Groovy
// 统一Jenkins构建配置 (单仓多App定制版)
|
||
// 专注 Android APK 构建,支持多应用与版本动态传参
|
||
|
||
pipeline {
|
||
agent any
|
||
|
||
options {
|
||
// 超时时间
|
||
timeout(time: 45, unit: 'MINUTES')
|
||
// 保留构建历史
|
||
buildDiscarder(logRotator(numToKeepStr: '20'))
|
||
// 时间戳显示
|
||
timestamps()
|
||
// 彩色输出
|
||
ansiColor('xterm')
|
||
}
|
||
|
||
environment {
|
||
// 基础配置
|
||
PROJECT_NAME = 'Web Android Shell'
|
||
|
||
// 此项目不使用 Melos,但通过 dart run tool/generate_app.dart 生成 App 工程
|
||
FVM_VERSION = '3.41.2'
|
||
|
||
// 动态环境配置 (根据参数设置)
|
||
ENVIRONMENT = "${params.BUILD_ENVIRONMENT}"
|
||
|
||
// Fastlane和Flutter配置
|
||
LC_ALL = 'en_US.UTF-8'
|
||
LANG = 'en_US.UTF-8'
|
||
CI = 'true'
|
||
FLUTTER_SUPPRESS_ANALYTICS = 'true'
|
||
FLUTTER_NO_ANALYTICS = 'true'
|
||
|
||
// PATH配置(使用环境变量,避免硬编码用户路径)
|
||
PATH = "${env.HOME ?: '/Users/yuanxuan'}/.pub-cache/bin:/opt/homebrew/bin:/usr/local/bin:${env.PATH}"
|
||
}
|
||
|
||
parameters {
|
||
// 🎯 目标应用 (可由 tool/update_jenkins_apps.dart 动态更新内容)
|
||
choice(
|
||
name: 'APP_NAME',
|
||
choices: ['aixue', 'test', 'yunxiao', 'all'],
|
||
description: '📱 选择要打包的应用 (从 flavors 目录生成)'
|
||
)
|
||
|
||
// 🎯 环境选择
|
||
choice(
|
||
name: 'BUILD_ENVIRONMENT',
|
||
choices: ['development', 'preview', 'production'],
|
||
description: '🏗️ 构建环境: development(开发测试) | preview(预发布) | production(正式发布)'
|
||
)
|
||
|
||
// 🎯 版本相关参数
|
||
string(
|
||
name: 'VERSION_NAME',
|
||
defaultValue: '',
|
||
description: '🏷️ 覆盖版本名称 (例如 1.0.0)。留空则使用默认配置中的版本名。'
|
||
)
|
||
|
||
string(
|
||
name: 'BUILD_NUMBER',
|
||
defaultValue: '',
|
||
description: '🔢 覆盖构建编号 (例如 1)。留空则使用默认配置中的构建版本号。'
|
||
)
|
||
|
||
// 🧹 清理构建
|
||
booleanParam(
|
||
name: 'CLEAN_BUILD',
|
||
defaultValue: true,
|
||
description: '🧹 是否执行清理构建 (生产环境推荐开启)'
|
||
)
|
||
}
|
||
|
||
stages {
|
||
stage('🔧 环境初始化') {
|
||
steps {
|
||
script {
|
||
echo "🚀 开始构建: ${PROJECT_NAME} [${params.BUILD_ENVIRONMENT}]"
|
||
}
|
||
|
||
sh '''
|
||
#!/bin/zsh
|
||
set +x
|
||
# 静默加载环境
|
||
[ -f "$HOME/.zshrc" ] && source "$HOME/.zshrc" > /dev/null 2>&1
|
||
|
||
if command -v fvm &> /dev/null; then
|
||
echo " - Flutter: $(fvm flutter --version | head -1)"
|
||
else
|
||
echo "❌ 错误: 未找到FVM环境"
|
||
exit 1
|
||
fi
|
||
'''
|
||
}
|
||
}
|
||
|
||
stage('🏗️ 生成与构建') {
|
||
steps {
|
||
script {
|
||
def appsToBuild = []
|
||
if (params.APP_NAME == 'all') {
|
||
// 动态读取 flavors 目录下的所有 yaml 文件
|
||
def flavorFiles = sh(script: "ls flavors/*.yaml | awk -F'/' '{print \$2}' | awk -F'.' '{print \$1}'", returnStdout: true).trim().split('\n')
|
||
appsToBuild = flavorFiles.toList()
|
||
} else {
|
||
appsToBuild = [params.APP_NAME]
|
||
}
|
||
|
||
for (int i = 0; i < appsToBuild.size(); i++) {
|
||
def currentApp = appsToBuild[i]
|
||
if (!currentApp) continue
|
||
|
||
echo "🤖 开始处理应用: ${currentApp}..."
|
||
|
||
// 步骤1:生成 App 工程 (如果不存在)
|
||
sh """
|
||
#!/bin/zsh
|
||
set +x
|
||
[ -f "\\$HOME/.zshrc" ] && source "\\$HOME/.zshrc" > /dev/null 2>&1
|
||
|
||
if [ ! -d "apps/${currentApp}" ]; then
|
||
echo " - 应用目录 apps/${currentApp} 不存在,正在执行 generate_app 脚本生成项目..."
|
||
dart run tool/generate_app.dart ${currentApp}
|
||
else
|
||
echo " - 应用目录 apps/${currentApp} 已存在,跳过生成工程阶段。"
|
||
fi
|
||
"""
|
||
|
||
// 步骤2:执行 Flutter 构建
|
||
echo " - 正在为 ${currentApp} 构建 Android APK..."
|
||
sh """
|
||
#!/bin/zsh
|
||
set +x
|
||
[ -f "\\$HOME/.zshrc" ] && source "\\$HOME/.zshrc" > /dev/null 2>&1
|
||
cd apps/${currentApp}
|
||
|
||
# 先写入 shell 变量,避免 GString 里出现 "\${params.xxx}" 触发 Groovy 解析错误
|
||
CLEAN_BUILD='${params.CLEAN_BUILD}'
|
||
VERSION_NAME='${params.VERSION_NAME}'
|
||
BUILD_NUMBER='${params.BUILD_NUMBER}'
|
||
BUILD_ENV='${params.BUILD_ENVIRONMENT}'
|
||
|
||
if [ "\$CLEAN_BUILD" = "true" ]; then
|
||
echo " - 执行 flutter clean..."
|
||
fvm flutter clean
|
||
fi
|
||
|
||
fvm flutter pub get
|
||
|
||
EXTRA_ARGS=""
|
||
if [ -n "\$VERSION_NAME" ]; then
|
||
EXTRA_ARGS="\$EXTRA_ARGS --build-name=\$VERSION_NAME"
|
||
fi
|
||
if [ -n "\$BUILD_NUMBER" ]; then
|
||
EXTRA_ARGS="\$EXTRA_ARGS --build-number=\$BUILD_NUMBER"
|
||
fi
|
||
EXTRA_ARGS="\$EXTRA_ARGS --dart-define=APP_ENV=\$BUILD_ENV"
|
||
|
||
echo " - 开始构建 APK 参数: \$EXTRA_ARGS"
|
||
fvm flutter build apk --release \$EXTRA_ARGS
|
||
"""
|
||
echo " ✅ ${currentApp} Android APK 构建完成"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
post {
|
||
always {
|
||
script {
|
||
echo "🧹 处理构建产物"
|
||
// 仅归档 APK 产物
|
||
def findCount = sh(
|
||
script: "find apps/*/build/app/outputs/flutter-apk -name 'app-release.apk' 2>/dev/null | wc -l | tr -d ' '",
|
||
returnStdout: true
|
||
).trim()
|
||
|
||
if (findCount && findCount != '0') {
|
||
echo " - 归档Android Release APK..."
|
||
archiveArtifacts artifacts: 'apps/*/build/app/outputs/flutter-apk/app-release.apk', fingerprint: true
|
||
echo " ✅ 归档完成 (找到 ${findCount} 个 APK 文件)"
|
||
} else {
|
||
echo " ⚠️ 未找到任何构建的 APK"
|
||
}
|
||
|
||
// 归档FVM配置便于追踪环境记录
|
||
if (fileExists('.fvmrc')) {
|
||
archiveArtifacts artifacts: '.fvmrc', fingerprint: true, allowEmptyArchive: true
|
||
}
|
||
}
|
||
}
|
||
|
||
success {
|
||
script {
|
||
echo "🎉 构建流程成功完成!"
|
||
echo "✅ 详情:"
|
||
echo " - 目标: ${params.APP_NAME}"
|
||
echo " - 环境: ${params.BUILD_ENVIRONMENT}"
|
||
if (params.VERSION_NAME) echo " - 版本名: ${params.VERSION_NAME}"
|
||
if (params.BUILD_NUMBER) echo " - 构建号: ${params.BUILD_NUMBER}"
|
||
}
|
||
}
|
||
|
||
failure {
|
||
echo "❌ 构建流程遇到错误并终止。请检查上方日志找出失败原由。"
|
||
}
|
||
}
|
||
}
|