Compare commits
No commits in common. "84df0d013f493bdf8f3ec5aaeaecfc87f19e614b" and "318c829ced084148242ff39f7167721c956f6c41" have entirely different histories.
84df0d013f
...
318c829ced
|
|
@ -1,207 +0,0 @@
|
|||
// 统一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}
|
||||
|
||||
if [ "${params.CLEAN_BUILD}" = "true" ]; then
|
||||
echo " - 执行 flutter clean..."
|
||||
fvm flutter clean
|
||||
fi
|
||||
|
||||
fvm flutter pub get
|
||||
|
||||
# 拼接附加构建参数
|
||||
EXTRA_ARGS=""
|
||||
if [ ! -z "${params.VERSION_NAME}" ]; then
|
||||
EXTRA_ARGS="\\$EXTRA_ARGS --build-name=${params.VERSION_NAME}"
|
||||
fi
|
||||
if [ ! -z "${params.BUILD_NUMBER}" ]; then
|
||||
EXTRA_ARGS="\\$EXTRA_ARGS --build-number=${params.BUILD_NUMBER}"
|
||||
fi
|
||||
|
||||
# 注入环境变量参数用于代码判断 (如需要)
|
||||
EXTRA_ARGS="\\$EXTRA_ARGS --dart-define=APP_ENV=${params.BUILD_ENVIRONMENT}"
|
||||
|
||||
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 "❌ 构建流程遇到错误并终止。请检查上方日志找出失败原由。"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,397 +0,0 @@
|
|||
// 统一Jenkins构建配置 (Melos Monorepo版本)
|
||||
// 同时支持开发和生产环境
|
||||
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
options {
|
||||
// 超时时间
|
||||
timeout(time: 45, unit: 'MINUTES')
|
||||
// 保留构建历史
|
||||
buildDiscarder(logRotator(numToKeepStr: '20'))
|
||||
// 时间戳显示
|
||||
timestamps()
|
||||
// 彩色输出
|
||||
ansiColor('xterm')
|
||||
}
|
||||
|
||||
environment {
|
||||
// 基础配置
|
||||
PROJECT_NAME = 'Learning Officer OA'
|
||||
APP_NAME = 'LearningOfficerOA'
|
||||
FVM_VERSION = '3.38.9'
|
||||
|
||||
// 构建模式 (始终使用 release 获得最佳性能)
|
||||
BUILD_MODE = 'release'
|
||||
|
||||
// 动态环境配置 (根据参数设置)
|
||||
ENVIRONMENT = "${params.BUILD_ENVIRONMENT}"
|
||||
|
||||
// 归档配置
|
||||
RELEASE_DIR = "${env.HOME}/release/oa/${params.BUILD_ENVIRONMENT}"
|
||||
|
||||
// Melos Monorepo 配置
|
||||
APP_DIR = 'apps/oa_app'
|
||||
|
||||
// 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}"
|
||||
|
||||
// 签名配置
|
||||
KEYCHAIN_PATH = "${HOME}/Library/Keychains/login.keychain-db"
|
||||
KEYCHAIN_PASSWORD = "${KEYCHAIN_PASSWORD}"
|
||||
|
||||
// 版本信息
|
||||
APP_VERSION = ''
|
||||
BUILD_NUMBER = ''
|
||||
MAIN_APK_FOUND = 'false'
|
||||
}
|
||||
|
||||
parameters {
|
||||
// 🎯 环境选择 (核心参数)
|
||||
choice(
|
||||
name: 'BUILD_ENVIRONMENT',
|
||||
choices: ['development', 'preview', 'production'],
|
||||
description: '🏗️ 构建环境: development(开发测试) | preview(预发布) | production(正式发布)'
|
||||
)
|
||||
|
||||
// 📱 平台选择
|
||||
choice(
|
||||
name: 'PLATFORM',
|
||||
choices: ['android', 'ios', 'all'],
|
||||
description: '📱 构建平台: android | ios | all'
|
||||
)
|
||||
|
||||
// 🧹 清理构建
|
||||
booleanParam(
|
||||
name: 'CLEAN_BUILD',
|
||||
defaultValue: true,
|
||||
description: '🧹 是否执行清理构建 (生产环境推荐开启)'
|
||||
)
|
||||
|
||||
// 🍎 iOS配置 (开发/预发布环境)
|
||||
booleanParam(
|
||||
name: 'UPLOAD_TESTFLIGHT',
|
||||
defaultValue: true,
|
||||
description: '🚀 是否自动上传iOS到TestFlight (仅开发/预发布环境有效)'
|
||||
)
|
||||
|
||||
// 🍎 iOS分发类型 (生产环境)
|
||||
choice(
|
||||
name: 'IOS_DISTRIBUTION_TYPE',
|
||||
choices: ['testflight', 'adhoc', 'appstore'],
|
||||
description: '🍎 iOS分发类型: adhoc(企业分发) | testflight(外部测试) | appstore(应用商店)'
|
||||
)
|
||||
}
|
||||
|
||||
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)"
|
||||
echo " - Melos: $(melos --version 2>/dev/null || echo '本地依赖')"
|
||||
else
|
||||
echo "❌ 错误: 未找到FVM环境"
|
||||
exit 1
|
||||
fi
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('📥 依赖管理') {
|
||||
steps {
|
||||
script {
|
||||
echo "📦 正在同步 Monorepo 依赖 (Bootstrap)..."
|
||||
sh '''
|
||||
#!/bin/zsh
|
||||
set +x
|
||||
[ -f "$HOME/.zshrc" ] && source "$HOME/.zshrc" > /dev/null 2>&1
|
||||
|
||||
# 使用 melos bootstrap 初始化所有包
|
||||
melos bootstrap
|
||||
echo " ✅ 依赖同步完成"
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('📝 版本与生成') {
|
||||
steps {
|
||||
script {
|
||||
sh '''
|
||||
#!/bin/zsh
|
||||
set +x
|
||||
[ -f "$HOME/.zshrc" ] && source "$HOME/.zshrc" > /dev/null 2>&1
|
||||
|
||||
# 运行版本管理 (在 app 目录)
|
||||
# 运行版本管理 (从根目录运行 Dart 脚本,避免子目录缺少依赖)
|
||||
if [ -f "scripts/version_manager.dart" ]; then
|
||||
# 确保根目录依赖已准备好 (通常在 Bootstrap 阶段完成,但在某些 CI 环境可能需要显式 pub get)
|
||||
# dart pub get # 如果需要,取消注释
|
||||
|
||||
eval $(dart scripts/version_manager.dart ci-clean --path ${APP_DIR}/pubspec.yaml)
|
||||
echo " - 目标版本: ${APP_FULL_VERSION}"
|
||||
fi
|
||||
|
||||
# 代码生成 (使用 melos run generate 覆盖所有包)
|
||||
echo " - 正在为所有包生成代码..."
|
||||
melos run generate
|
||||
echo " ✅ 代码生成完成"
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('🏗️ 编译构建') {
|
||||
steps {
|
||||
script {
|
||||
if (params.PLATFORM == 'android' || params.PLATFORM == 'all') {
|
||||
echo "🤖 正在构建 Android APK..."
|
||||
sh '''
|
||||
#!/bin/zsh
|
||||
set +x
|
||||
[ -f "$HOME/.zshrc" ] && source "$HOME/.zshrc" > /dev/null 2>&1
|
||||
cd ${APP_DIR}
|
||||
if [ "${CLEAN_BUILD}" = "true" ]; then
|
||||
echo " - 执行 flutter clean..."
|
||||
fvm flutter clean
|
||||
fi
|
||||
fvm flutter build apk --release --dart-define=APP_ENV=${ENVIRONMENT}
|
||||
'''
|
||||
echo " ✅ Android 构建成功"
|
||||
}
|
||||
|
||||
if (params.PLATFORM == 'ios' || params.PLATFORM == 'all') {
|
||||
echo "🍎 正在构建 iOS IPA (via Melos)..."
|
||||
sh '''
|
||||
#!/bin/zsh
|
||||
set -e
|
||||
[ -f "$HOME/.zshrc" ] && source "$HOME/.zshrc" > /dev/null 2>&1
|
||||
|
||||
cd ${APP_DIR}
|
||||
if [ "${CLEAN_BUILD}" = "true" ]; then
|
||||
echo " - 执行 flutter clean..."
|
||||
fvm flutter clean
|
||||
fi
|
||||
|
||||
# clean 后必须重新拉依赖,确保插件注册文件 (.dart_tool/flutter_build) 完整
|
||||
echo " - 恢复 Flutter 依赖..."
|
||||
fvm flutter pub get
|
||||
|
||||
# 统一更新 CocoaPods 仓库并按 Podfile 安装依赖
|
||||
echo " - CocoaPods: repo update + install..."
|
||||
retry=0
|
||||
until [ $retry -ge 3 ]
|
||||
do
|
||||
if (cd ios && pod install --repo-update); then
|
||||
echo " ✅ CocoaPods 依赖已就绪"
|
||||
break
|
||||
fi
|
||||
retry=$((retry+1))
|
||||
echo " ⚠️ pod install 失败,重试 ${retry}/3..."
|
||||
sleep 3
|
||||
done
|
||||
if [ $retry -ge 3 ]; then
|
||||
echo "❌ pod install 连续失败,停止构建"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd -
|
||||
# Melos 脚本会自动进入 apps/oa_app 目录并执行,通过 -- 传递额外参数
|
||||
melos run build:ipa -- --dart-define=APP_ENV=${ENVIRONMENT}
|
||||
'''
|
||||
echo " ✅ iOS 构建成功"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('🚀 上传 TestFlight') {
|
||||
when {
|
||||
allOf {
|
||||
anyOf {
|
||||
expression { params.BUILD_ENVIRONMENT == 'development' }
|
||||
expression { params.BUILD_ENVIRONMENT == 'preview' }
|
||||
}
|
||||
expression { params.UPLOAD_TESTFLIGHT == true }
|
||||
anyOf {
|
||||
expression { params.PLATFORM == 'ios' }
|
||||
expression { params.PLATFORM == 'all' }
|
||||
}
|
||||
}
|
||||
}
|
||||
steps {
|
||||
script {
|
||||
echo "📤 准备上传到 TestFlight..."
|
||||
sh '''
|
||||
#!/bin/zsh
|
||||
set +x
|
||||
[ -f "$HOME/.zshrc" ] && source "$HOME/.zshrc" > /dev/null 2>&1
|
||||
|
||||
# 清理环境变量引号
|
||||
export FASTLANE_APP_STORE_CONNECT_API_KEY_PATH=$(echo "${FASTLANE_APP_STORE_CONNECT_API_KEY_PATH}" | tr -d '"' | tr -d "'")
|
||||
export APP_STORE_CONNECT_API_KEY_KEY_ID=$(echo "${APP_STORE_CONNECT_API_KEY_KEY_ID}" | tr -d '"' | tr -d "'")
|
||||
export APP_STORE_CONNECT_API_KEY_ISSUER_ID=$(echo "${APP_STORE_CONNECT_API_KEY_ISSUER_ID}" | tr -d '"' | tr -d "'")
|
||||
|
||||
# 获取绝对路径的 IPA 文件
|
||||
ABS_IPA_PATH=$(ls -t $(pwd)/${APP_DIR}/build/ios/ipa/*.ipa 2>/dev/null | head -1)
|
||||
if [ -z "$ABS_IPA_PATH" ]; then echo "❌ 未找到IPA"; exit 1; fi
|
||||
|
||||
echo " - 产物: $(basename $ABS_IPA_PATH)"
|
||||
|
||||
if [ -f "fastlane/Gemfile" ]; then
|
||||
cd fastlane
|
||||
bundle install --quiet
|
||||
|
||||
echo " - 正在上传 (应用 Fastfile 内部补丁)..."
|
||||
|
||||
# 1. 清理环境,依赖 Fastfile 顶部的 require 解决兼容性
|
||||
unset RUBYOPT
|
||||
|
||||
# 2. 设置 Fastlane 官方环境变量
|
||||
export SPACESHIP_CONNECT_API_KEY_ID="$APP_STORE_CONNECT_API_KEY_KEY_ID"
|
||||
export SPACESHIP_CONNECT_API_ISSUER_ID="$APP_STORE_CONNECT_API_KEY_ISSUER_ID"
|
||||
export SPACESHIP_CONNECT_API_KEY_PATH="$FASTLANE_APP_STORE_CONNECT_API_KEY_PATH"
|
||||
|
||||
# 3. 执行上传 (使用绝对路径)
|
||||
bundle exec fastlane upload_to_testflight_with_key ipa:"$ABS_IPA_PATH"
|
||||
fi
|
||||
echo " ✅ TestFlight 上传完成"
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
script {
|
||||
echo "🧹 处理构建产物和清理"
|
||||
|
||||
// 根据环境归档不同的构建产物
|
||||
echo "📦 归档${params.BUILD_ENVIRONMENT}环境构建产物..."
|
||||
|
||||
// 归档 APK (仅限 Android 平台)
|
||||
if ((params.PLATFORM == 'android' || params.PLATFORM == 'all') && fileExists('apps/oa_app/build/app/outputs/flutter-apk/app-release.apk')) {
|
||||
echo " - 归档Android Release APK..."
|
||||
archiveArtifacts artifacts: 'apps/oa_app/build/app/outputs/flutter-apk/app-release.apk', fingerprint: true
|
||||
echo " ✅ Android Release APK已归档"
|
||||
}
|
||||
|
||||
// 归档 AAB (仅限 Android 平台)
|
||||
if ((params.PLATFORM == 'android' || params.PLATFORM == 'all') && fileExists('apps/oa_app/build/app/outputs/bundle/release/app-release.aab')) {
|
||||
echo " - 归档Android AAB..."
|
||||
archiveArtifacts artifacts: 'apps/oa_app/build/app/outputs/bundle/release/app-release.aab', fingerprint: true
|
||||
echo " ✅ Android AAB已归档"
|
||||
}
|
||||
|
||||
// 归档iOS IPA (仅限 iOS 平台)
|
||||
if (params.PLATFORM == 'ios' || params.PLATFORM == 'all') {
|
||||
def ipaFileCount = sh(
|
||||
script: "find apps/oa_app/build/ios/ipa -name '*.ipa' 2>/dev/null | wc -l | tr -d ' '",
|
||||
returnStdout: true
|
||||
).trim()
|
||||
if (ipaFileCount && ipaFileCount != '0') {
|
||||
echo " - 归档iOS IPA..."
|
||||
archiveArtifacts artifacts: 'apps/oa_app/build/ios/ipa/*.ipa', fingerprint: true
|
||||
echo " ✅ iOS IPA已归档 (找到 ${ipaFileCount} 个文件)"
|
||||
} else {
|
||||
echo " ⚠️ 未找到iOS IPA文件"
|
||||
}
|
||||
}
|
||||
|
||||
// 归档FVM配置
|
||||
if (fileExists('.fvmrc')) {
|
||||
archiveArtifacts artifacts: '.fvmrc', fingerprint: true, allowEmptyArchive: true
|
||||
echo " ✅ FVM配置已归档"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
success {
|
||||
script {
|
||||
echo "🎉 ${params.BUILD_ENVIRONMENT}环境构建成功!"
|
||||
echo ""
|
||||
echo "✅ 构建总结:"
|
||||
echo " - 项目: ${PROJECT_NAME}"
|
||||
echo " - 应用: ${APP_NAME}"
|
||||
echo " - 环境: ${params.BUILD_ENVIRONMENT}"
|
||||
echo " - 平台: ${params.PLATFORM}"
|
||||
echo " - 项目类型: Melos Monorepo"
|
||||
echo " - Flutter版本: ${FVM_VERSION}"
|
||||
echo " - 归档位置: ${RELEASE_DIR}"
|
||||
echo ""
|
||||
|
||||
if (params.BUILD_ENVIRONMENT == 'production') {
|
||||
echo "🏭 生产环境特性:"
|
||||
echo " - Release APK (生产签名,可发布)"
|
||||
echo " - iOS ${params.IOS_DISTRIBUTION_TYPE} IPA"
|
||||
echo " - AAB (Google Play Store)"
|
||||
echo ""
|
||||
echo "⚠️ 重要提醒:"
|
||||
echo " - 生产包仅用于正式发布"
|
||||
echo " - 发布前请进行充分测试"
|
||||
echo " - 确认版本号和更新说明"
|
||||
} else if (params.BUILD_ENVIRONMENT == 'preview') {
|
||||
echo "🔍 预发布环境特性:"
|
||||
echo " - Release APK (优化版本,连接预发布库)"
|
||||
echo " - iOS TestFlight版本"
|
||||
if (params.UPLOAD_TESTFLIGHT) {
|
||||
echo " - 已自动上传到TestFlight"
|
||||
}
|
||||
echo ""
|
||||
echo "🚀 下一步:"
|
||||
echo " - 供测试团队/产品验收"
|
||||
} else {
|
||||
echo "🛠️ 开发环境特性:"
|
||||
echo " - Release APK (优化版本,用于测试)"
|
||||
echo " - iOS TestFlight版本"
|
||||
if (params.UPLOAD_TESTFLIGHT) {
|
||||
echo " - 已自动上传到TestFlight"
|
||||
}
|
||||
echo ""
|
||||
echo "🚀 下一步:"
|
||||
echo " - 下载APK进行内部测试"
|
||||
echo " - TestFlight查看iOS测试版本"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
failure {
|
||||
script {
|
||||
echo "❌ ${params.BUILD_ENVIRONMENT}环境构建失败"
|
||||
echo ""
|
||||
echo "🔍 故障排除建议:"
|
||||
echo " 1. 检查Flutter环境配置"
|
||||
echo " 2. 验证Melos Monorepo依赖配置"
|
||||
if (params.BUILD_ENVIRONMENT == 'production') {
|
||||
echo " 3. 验证iOS Distribution/Ad-hoc证书"
|
||||
echo " 4. 确认Android Release签名配置"
|
||||
echo " 5. 检查生产环境权限和密钥"
|
||||
} else {
|
||||
echo " 3. 验证App Store Connect API密钥配置"
|
||||
echo " 4. 确认TestFlight上传权限"
|
||||
echo " 5. 检查开发/预发布证书配置"
|
||||
}
|
||||
echo " 6. 查看详细构建日志"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
import 'dart:io';
|
||||
|
||||
void main() {
|
||||
final file = File('Jenkinsfile');
|
||||
if (!file.existsSync()) {
|
||||
print('错误: 在项目根目录中找不到 Jenkinsfile。请确保在此目录下执行此脚本。');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
final flavorsDir = Directory('flavors');
|
||||
if (!flavorsDir.existsSync()) {
|
||||
print('错误: 在项目根目录中找不到 flavors 文件夹。');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
final apps = flavorsDir
|
||||
.listSync()
|
||||
.whereType<File>()
|
||||
.where((f) => f.path.endsWith('.yaml'))
|
||||
.map((f) => f.path.split(Platform.pathSeparator).last.replaceAll('.yaml', ''))
|
||||
.toList();
|
||||
|
||||
apps.sort();
|
||||
// 固定加上 'all' 的选项
|
||||
apps.add('all');
|
||||
|
||||
final choicesString = apps.map((a) => "'$a'").join(', ');
|
||||
|
||||
var content = file.readAsStringSync();
|
||||
|
||||
// 匹配形如:
|
||||
// name: 'APP_NAME',
|
||||
// choices: ['aixue', 'test', 'yunxiao', 'all'],
|
||||
final regex = RegExp(r"name:\s*'APP_NAME',\s*\n\s*choices:\s*\[.*\],");
|
||||
|
||||
if (regex.hasMatch(content)) {
|
||||
content = content.replaceFirst(
|
||||
regex,
|
||||
"name: 'APP_NAME',\n choices: [$choicesString],",
|
||||
);
|
||||
file.writeAsStringSync(content);
|
||||
print("✅ 已自动更新 Jenkinsfile 中的可选 Apps: ${apps.join(', ')}");
|
||||
} else {
|
||||
print('❌ 更换失败: 未能匹配到 Jenkinsfile 中的 APP_NAME choices 定位。如果更改过文件结构,请更新此脚本里的正则表达式。');
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue