签入版本

This commit is contained in:
gitadmin
2025-09-21 19:52:30 +08:00
commit 9a522f4284
46 changed files with 15459 additions and 0 deletions
+865
View File
@@ -0,0 +1,865 @@
package com.jdk
import com.utils.CommonUtils
import com.constants.ConfigConstants
import com.utils.ServerParser
/**
* JDK API 服务类
* 负责加载配置、管理分支和服务配置、设置环境参数
* 适配新的配置文件格式,支持多环境、多服务配置
*
* 主要功能:
* 1. 加载环境配置和主配置文件
* 2. 解析分支和服务配置
* 3. 设置Jenkins流水线参数
* 4. 提供环境相关的配置获取方法
*
* @version 2.0.0
* @since 2025-09-09
*/
class ResolverService implements Serializable {
// Jenkins流水线脚本对象,用于执行Jenkins相关操作
def script
// 主配置文件内容(解析后的YAML数据)
def config
// 组织名称
def orgName
// 环境配置文件内容
def envConfig
// 主配置文件路径
def jobConfigFile
/**
* 服务器解析器实例
* 负责解析服务器引用配置和索引处理
* 类型: ServerParser 自定义服务器解析工具类
*/
def serverParser
/**
* 构造函数
* 初始化服务类实例
*
* @param script Jenkins流水线脚本对象,提供echo、error等方法
* @param orgName 组织名称,用于标识项目归属
*/
ResolverService(script, orgName) {
this.script = script
this.orgName = orgName
this.config = [:]
this.envConfig = [:]
// 初始化服务器解析器,用于处理服务器引用和索引
this.serverParser = new ServerParser(script)
}
/**
* 加载所有配置文件
* 按顺序加载环境配置和主配置文件
*
* @throws Exception 如果配置文件加载失败
*/
void loadConfigurations() {
script.echo "🚀 开始加载配置文件..."
// 首先加载环境配置文件(.env.yml)
loadEnvConfig()
// 然后加载主配置文件(根据环境配置中的路径)
loadMainConfig()
script.echo "✅ 所有配置文件加载完成"
}
/**
* 加载环境配置文件的方法
* 从.jenkins/.env.yml读取环境配置,包含主配置文件路径等基本信息
*
* @return 返回当前对象实例,支持链式调用
* @throws Exception 如果文件存在但解析失败
*/
def loadEnvConfig() {
try {
// 环境配置文件相对路径
def envFilePath = '.jenkins/.env.yml'
script.echo "📁 环境配置文件路径: ${envFilePath}"
if (script.fileExists(envFilePath)) {
// 读取并解析YAML格式的环境配置文件
envConfig = script.readYaml(file: envFilePath)
// 从环境配置中获取主配置文件路径
jobConfigFile = ".pipeline-files/config-file/" + envConfig.jobConfigFile
script.echo "✅ 成功加载环境配置文件"
// 打印所有环境配置项(调试用)
if (!envConfig.isEmpty()) {
script.echo "📋 环境配置内容:"
envConfig.each { key, value ->
script.echo " ${key}: ${value}"
}
}
} else {
script.echo "⚠️ 警告: 未找到环境配置文件 .env.yml,使用默认配置"
}
} catch (Exception e) {
script.echo "⚠️ 警告: .env.yml 文件无效,使用默认配置: ${e.message}"
// 不抛出异常,允许继续执行
}
return this
}
/**
* 加载主配置文件的方法
* 读取新的配置文件格式,包含common、branchConfig、serviceConfig等部分
*
* @return 返回当前对象实例,支持链式调用
* @throws Exception 如果文件不存在或解析失败
*/
def loadMainConfig() {
try {
// 检查主配置文件是否存在
if (!script.fileExists(jobConfigFile)) {
script.error("❌ 错误: 配置文件不存在: ${jobConfigFile},请检查文件路径或创建配置文件")
}
// 读取并解析YAML格式的主配置文件
this.config = script.readYaml(file: jobConfigFile)
script.echo "✅ 成功加载主配置文件: ${jobConfigFile}"
// 打印配置详情(调试用)
printConfigSummary()
} catch (Exception e) {
script.error("❌ 错误: 加载配置文件失败: ${jobConfigFile}. 错误详情: ${e.message}")
}
return this
}
/**
* 打印主配置文件的详细内容
* 格式化输出所有配置信息,便于调试和验证
*/
def printConfigSummary() {
script.echo "=" * 70
script.echo "📊 主配置文件详细内容"
script.echo "=" * 70
if (!this.config) {
script.echo "⚠️ 配置文件内容为空"
return
}
// 打印通用配置信息
if (this.config.common) {
script.echo "🌐 通用配置:"
script.echo "-" * 50
script.echo " 部署脚本: ${this.config.common.deployScript ?: '未设置'}"
script.echo " 部署路径: ${this.config.common.deployPath ?: '未设置'}"
// 打印注册表配置
if (this.config.common.registry) {
script.echo " 注册表配置:"
this.config.common.registry.each { registryName, registryConfig ->
script.echo " ${registryName}: ${registryConfig.registry}"
}
}
script.echo ""
}
// 打印环境配置信息
if (this.config.common?.profiles) {
script.echo "🏭 环境配置 (共 ${this.config.common.profiles.size()} 个环境):"
script.echo "-" * 50
this.config.common.profiles.each { envName, envConfig ->
script.echo " ${envName.toUpperCase()} 环境:"
script.echo " 服务器数量: ${envConfig.servers ? envConfig.servers.size() : 0}"
script.echo " 部署策略: ${envConfig.deploymentStrategy ?: 'rolling'}"
script.echo " JVM参数: ${envConfig.envVars?.JAVA_OPTS ?: '未设置'}"
script.echo " 健康检查: ${envConfig.healthCheckPath ?: '/actuator/health'}"
script.echo ""
}
}
// 打印分支构建配置信息
if (this.config.branchConfig) {
script.echo "🌿 分支构建配置 (共 ${this.config.branchConfig.size()} 个分支):"
script.echo "-" * 50
this.config.branchConfig.each { branchName, branchConfig ->
script.echo " ${branchName} 分支:"
script.echo " Jenkins代理: ${branchConfig.jenkinsAgent ?: '未设置'}"
script.echo " Maven配置集: ${branchConfig.maven?.maven ?: '未设置'}"
}
}
// 打印服务配置信息
if (this.config.serviceConfig) {
script.echo "🔧 服务配置 (共 ${this.config.serviceConfig.size()} 个服务):"
script.echo "-" * 50
this.config.serviceConfig.each { serviceName, serviceConfig ->
script.echo " ${serviceName} 服务:"
script.echo " 编程语言: ${serviceConfig.programLang ?: '未设置'}"
script.echo " 语言版本: ${serviceConfig.programLangVersion ?: '未设置'}"
script.echo " 容器名称: ${serviceConfig.containerName ?: '未设置'}"
script.echo " POM路径: ${serviceConfig.pomFilePath ?: '未设置'}"
script.echo " 服务路径: ${serviceConfig.servicePath ?: '未设置'}"
script.echo " 容器名称: ${serviceConfig.containerName ?: '未设置'}"
script.echo " JAR包名称: ${serviceConfig.jarName ?: '未设置'}"
script.echo " 服务端口: ${serviceConfig.port ?: '未设置'}"
}
}
script.echo "=" * 70
}
/**
* 获取当前分支的配置
* 根据当前Jenkins作业的分支名称查找对应的分支配置
*
* @return 分支配置对象(Map类型)
* @throws Exception 如果分支配置不存在
*/
def getBranchConfig() {
// 获取当前Jenkins作业的分支名称
def branchName = script.env.BRANCH_NAME
if (!branchName) {
script.error("❌ 错误: 无法获取分支名称,env.BRANCH_NAME 为空。请检查流水线配置")
}
script.echo "🌿 正在查找分支配置: ${branchName}"
// 检查分支配置是否存在
if (!config.branchConfig || config.branchConfig.isEmpty()) {
script.error("❌ 错误: 分支配置列表为空或未定义。请检查配置文件结构")
}
// 根据分支名称获取配置
def branchConfig = config.branchConfig[branchName]
if (branchConfig) {
script.echo "✅ 成功匹配分支配置:"
script.echo " - Jenkins代理: ${branchConfig.jenkinsAgent ?: '未设置'}"
script.echo " - Maven配置集: ${branchConfig.mavenSet ?: '未设置'}"
script.echo " - 构建参数: ${branchConfig.buildArgs ?: '默认参数'}"
} else {
// 构建友好的错误信息,列出所有可用分支
def availableBranches = config.branchConfig.keySet().join(', ')
script.error("❌ 错误: 找不到分支 '${branchName}' 的配置。可用分支: ${availableBranches}")
}
return branchConfig
}
/**
* 获取指定服务的配置信息
* 根据服务名称从serviceConfig中查找对应的服务配置
*
* @param serviceName 服务名称,需要与配置文件中serviceConfig的键匹配
* @return 服务配置对象(Map类型)
* @throws Exception 如果服务配置不存在
*/
def getServiceConfig(serviceName) {
if (!serviceName) {
script.error("❌ 错误: 服务名称参数不能为空")
}
script.echo "🔧 正在查找服务配置: ${serviceName}"
// 检查服务配置是否存在
if (!config.serviceConfig || config.serviceConfig.isEmpty()) {
script.error("❌ 错误: 服务配置列表为空或未定义,请检查配置文件结构")
}
// 根据服务名称获取配置
def serviceConfig = config.serviceConfig[serviceName]
if (serviceConfig) {
script.echo "✅ 成功找到服务配置: ${serviceName}"
script.echo " - 容器名称: ${serviceConfig.containerName ?: '未设置'}"
script.echo " - 服务路径: ${serviceConfig.servicePath ?: '未设置'}"
script.echo " - 服务端口: ${serviceConfig.port ?: '未设置'}"
script.echo " - JAR包名称: ${serviceConfig.jarName ?: '未设置'}"
} else {
// 构建友好的错误信息,列出所有可用服务
def availableServices = config.serviceConfig.keySet().join(', ')
script.error("❌ 错误: 找不到服务 '${serviceName}' 的配置。可用服务: ${availableServices}")
}
return serviceConfig
}
/**
* 设置管道参数
* 整合分支配置、服务配置和环境配置,生成完整的流水线参数
*
* @return 参数映射表,包含所有必要的部署参数
*/
def setupParameters() {
script.echo "⚙️ 开始设置管道参数..."
// 获取当前分支配置
def branchConfig = getBranchConfig()
// 从Jenkins作业名称中提取服务名称
// 格式通常为: "组织名/服务名" 或 "服务名"
def serviceName = script.env.JOB_NAME?.tokenize('/')?.get(0)
script.echo "📦 服务名称: ${serviceName}"
// 获取服务配置
def serviceConfig = getServiceConfig(serviceName)
// 根据分支类型获取环境配置
def profiles = getBranchProfiles(branchConfig)
script.echo "🌍 环境配置: ${profiles}"
// 生成唯一的镜像标签,格式: {环境}-{构建ID}
def imageTag = CommonUtils.generateImageTag(script.env.PROFILES, script.env.BUILD_ID)
script.echo "自定义镜像标签:${imageTag}"
// 构建完整的参数映射表
def params = [
// 构建相关参数
jenkinsAgent : branchConfig.jenkinsAgent,
MAVEN_SET : branchConfig.maven?.mavenSet,
skipTests : branchConfig.maven?.skipTests,
goals : branchConfig.maven?.goals,
dockerFile : branchConfig.docker?.dockerFile ?: '.jenkins/Dockerfile',
buildOptions : branchConfig.docker?.buildOptions,
// 服务相关参数
projectName : serviceConfig.containerName,
packageName : serviceConfig?.packageName,
servicePath : serviceConfig.servicePath,
jarName : serviceConfig.jarName,
jarFile : serviceConfig.jarName,
jarFilePath : "${serviceConfig.servicePath}/target",
port : serviceConfig.port,
pomFilePath : serviceConfig.pomFilePath,
deployServer : serviceConfig.deployServer,
// 环境相关参数
PROFILES : profiles.default_profile,
availableProfiles : profiles.available_profiles,
imageTags : [imageTag],
// Git配置
gitUrl : config.common?.git?.url,
gitCredentialsId : config.common?.git?.credentialsId,
gitBranch : script.env.BRANCH_NAME,
// 钉钉配置
dingTalkCredentialsId: config.common?.dingtalk?.credentialsId,
// 其他参数
envConfig : this.envConfig,
orgName : this.orgName,
branchConfig : branchConfig,
serviceConfig : serviceConfig
]
// 获取分支环境变量配置
getEnvironmentConfig(params)
// 设置容器基础镜像
params.baseImage = "${params.registry}/${params.registryProject}-base/${params.registryImage}"
script.echo "基础参数:${params}"
// 设置Jenkins参数(仅对标准流水线)
setupJenkinsParameters(profiles.available_profiles as List<String>)
script.echo "✅ 管道参数设置完成"
// 返回参数
return params
}
/**
* 获取指定环境的全部配置参数
* 从通用配置中提取指定环境的所有参数,包括服务器列表、环境变量、部署策略等
*
* @param params 参数映射表(会被修改),用于存储提取的配置信息
* @return 包含指定环境全部参数的Map
*/
def getEnvironmentConfig(params) {
try {
// 从参数中获取环境名称,如果没有设置则使用默认值"dev"
// 使用Elvis操作符 ?: 提供默认值,避免空指针异常
def envName = params.PROFILES ?: "dev"
// 将环境名称转换为小写,确保与配置中的key匹配(配置通常使用小写)
// 例如:将"DEV"转换为"dev","Prod"转换为"prod"
def envKey = envName.toLowerCase()
script.echo "🔍 开始获取 ${envKey} 环境的全部配置参数..."
// ==========================================================================
// 添加通知配置
// ==========================================================================
if (config.common?.notification) {
params.notification = config.common.notification
script.echo "📧 通知配置已加载"
}
// ==========================================================================
// 添加短信配置 - 详细配置信息
// ==========================================================================
if (config.common?.sms) {
// 确保sms配置存在
params.sms = config.common.sms
script.echo "📱 短信服务配置详情:"
script.echo " - 服务商: ${params.sms.provider ?: '未设置'}"
script.echo " - 凭据ID: ${params.sms.credentialsId ?: '未设置'}"
script.echo " - 默认签名: ${params.sms.signName ?: '未设置'}"
// 打印所有模板配置
if (params.sms.templates) {
script.echo " - 可用模板:"
params.sms.templates.each { templateName, templateConfig ->
def templateCode = templateConfig.templateCode ?: '未设置'
def templateSign = templateConfig.signName ?: params.sms.signName ?: '未设置'
script.echo " 📋 ${templateName}: ${templateCode} (签名: ${templateSign})"
}
} else {
script.echo " - 模板: 未配置"
}
} else {
script.echo "📱 短信服务: 未配置"
}
// ==========================================================================
// 添加构建策略配置
// ==========================================================================
if (config.common?.buildStrategy) {
params.buildStrategy = config.common.buildStrategy
script.echo "⚡ 构建策略:"
script.echo " - 重试次数: ${params.buildStrategy.retryCount}"
script.echo " - 超时时间: ${params.buildStrategy.timeoutMinutes}分钟"
script.echo " - 启用缓存: ${params.buildStrategy.enableCaching}"
}
// 安全地获取环境配置 - 使用Map方式访问
// 使用安全导航操作符 ?. 避免空指针异常:
// - config.common?:如果config为null则返回null,不会抛出异常
// - .profiles?:如果common为null则返回null
// - ."${envKey}":动态访问指定环境的配置
def envConfig = config.common?.profiles?."${envKey}"
if (!envConfig) {
def availableProfiles = config?.common?.profiles?.keySet() ?: []
throw new Exception("未找到 ${envKey} 环境的配置,可用环境: ${availableProfiles.join(', ')}")
}
script.echo "✅ 找到 ${envKey} 环境配置,开始提取参数..."
// ==========================================================================
// 提取服务器配置
// ==========================================================================
// 检查环境配置是否存在且包含服务器列表,并且服务器列表不为空
// envConfig?.servers:安全访问servers属性
// !envConfig.servers.empty:检查servers列表是否非空
if (envConfig?.servers && !envConfig.servers.empty) {
// 使用环境配置中的服务器列表更新参数对象
// 将找到的服务器列表赋值给params.servers,供后续部署使用
params.servers = envConfig.servers
// 输出日志信息,显示成功找到服务器配置
// 使用表情符号增强可读性,显示服务器数量
script.echo "🖥️ 服务器配置: 共 ${envConfig.servers.size()} 台服务器"
// 打印服务器详情(用于调试和验证)
// 使用eachWithIndex迭代服务器列表,同时获取索引和服务器对象
envConfig.servers.eachWithIndex { server, index ->
// 输出每台服务器的详细信息
// ${index + 1}:显示序号(从1开始)
// ${server.serverName}:服务器名称标识
// ${server.serverIP}:${server.serverPort}:服务器的IP地址和端口号
script.echo " ${index + 1}. ${server.serverName} (${server.serverIP}:${server.serverPort})"
}
} else {
// 如果没有找到对应环境的服务器配置或服务器列表为空
// 输出警告信息,提示用户检查配置
script.echo "⚠️ 警告: 未找到 ${envName} 环境的服务器配置"
params.servers = []
// 注意:这里没有设置params.servers,调用方需要处理这种情况
// 可能的处理方式:使用默认服务器、终止部署流程或提示用户输入
}
// ==========================================================================
// 提取目标服务器配置
// ==========================================================================
// 解析部署服务器引用,获取目标服务器列表
// 使用ServerParser处理复杂的服务器引用表达式
def targetServers = serverParser.parseTargetServers(params)
params.targetServers = targetServers
script.echo "🎯 部署目标服务器数量: ${targetServers.size()}"
// ==========================================================================
// 提取环境变量配置
// ==========================================================================
if (envConfig?.envVars && !envConfig.envVars.empty) {
params.envVars = envConfig.envVars
script.echo "🌡️ 环境变量: 共 ${envConfig.envVars.size()} 个"
envConfig.envVars.each { key, value ->
script.echo " ${key}=${value}"
}
} else {
script.echo "⚠️ 警告: ${envKey} 环境没有配置环境变量"
params.envVars = [:]
}
// ==========================================================================
// 提取部署策略配置
// ==========================================================================
if (envConfig?.deploymentStrategy) {
params.deploymentStrategy = envConfig.deploymentStrategy
script.echo "🎯 部署策略: ${envConfig.deploymentStrategy}"
}
if (envConfig?.deploymentTimeout) {
params.deploymentTimeout = envConfig.deploymentTimeout
script.echo "⏱️ 部署超时: ${envConfig.deploymentTimeout} 秒"
}
if (envConfig?.maxParallel) {
params.maxParallel = envConfig.maxParallel
script.echo "🔀 最大并行数: ${envConfig.maxParallel}"
}
if (envConfig?.retryAttempts) {
params.retryAttempts = envConfig.retryAttempts
script.echo "🔄 重试次数: ${envConfig.retryAttempts}"
}
if (envConfig?.canaryPercentage) {
params.canaryPercentage = envConfig.canaryPercentage
script.echo "📊 金丝雀比例: ${envConfig.canaryPercentage}%"
}
// ==========================================================================
// 提取健康检查配置
// ==========================================================================
if (envConfig?.healthCheckEnabled) {
params.healthCheckEnabled = envConfig.healthCheckEnabled
script.echo "❤️ 启用健康检查: ${envConfig.healthCheckEnabled}"
}
if (envConfig?.healthCheckPath) {
params.healthCheckPath = envConfig.healthCheckPath
script.echo "❤️ 健康检查路径: ${envConfig.healthCheckPath}"
}
if (envConfig?.healthCheckTimeout) {
params.healthCheckTimeout = envConfig.healthCheckTimeout
script.echo "⏱️ 健康检查超时: ${envConfig.healthCheckTimeout} 秒"
}
if (envConfig?.healthCheckRetries) {
params.healthCheckRetries = envConfig.healthCheckRetries
script.echo "❤️ 健康检查重试次数: ${envConfig.healthCheckRetries}"
}
if (envConfig?.healthCheckInterval) {
params.healthCheckInterval = envConfig.healthCheckInterval
script.echo "🔄 健康检查间隔: ${envConfig.healthCheckInterval} 秒"
}
if (envConfig?.successThreshold) {
params.successThreshold = envConfig.successThreshold
script.echo "✅ 成功阈值: ${envConfig.successThreshold} 次"
}
// ==========================================================================
// 提取回滚配置(生产环境特有)
// ==========================================================================
if (envConfig?.rollbackEnabled != null) {
params.rollbackEnabled = envConfig.rollbackEnabled
script.echo "↩️ 自动回滚: ${envConfig.rollbackEnabled}"
}
if (envConfig?.rollbackOnFailure != null) {
params.rollbackOnFailure = envConfig.rollbackOnFailure
script.echo "❌ 失败时回滚: ${envConfig.rollbackOnFailure}"
}
if (envConfig?.rollbackTimeout) {
params.rollbackTimeout = envConfig.rollbackTimeout
script.echo "⏱️ 回滚超时: ${envConfig.rollbackTimeout} 秒"
}
// // ==========================================================================
// // 提取通知配置(生产环境特有)
// // ==========================================================================
// if (envConfig?.notifications) {
// params.notifications = envConfig.notifications
// script.echo "📧 通知配置:"
// if (envConfig.notifications.slackChannel) {
// script.echo " Slack频道: ${envConfig.notifications.slackChannel}"
// }
// if (envConfig.notifications.email) {
// script.echo " 邮件地址: ${envConfig.notifications.email}"
// }
// if (envConfig.notifications.recipients) {
// script.echo " 额外收件人: ${envConfig.notifications.recipients.join(', ')}"
// }
// script.echo " 通知时机: 开始=${envConfig.notifications.onStart}, 成功=${envConfig.notifications.onSuccess}, 失败=${envConfig.notifications.onFailure}"
// }
// ==========================================================================
// 添加通用配置
// ==========================================================================
params.deployScript = config.common?.deployScript
params.deployPath = config.common?.deployPath
script.echo "📜 部署脚本: ${params.deployScript}"
script.echo "📁 部署路径: ${params.deployPath}"
// ==========================================================================
// 添加镜像仓库配置
// ==========================================================================
if (config.common?.registrys) {
params.registrys = config.common?.registrys
script.echo "🐳 镜像仓库配置:"
params.registrys.each { registryName, registryConfig ->
script.echo " ${registryName}: ${registryConfig.registry}"
}
}
// ==========================================================================
// 添加环境分支镜像仓库配置
// ==========================================================================
def registryConfig = config.common?.registrys?."${envConfig.registry}"
params.registry = registryConfig?.registry ?: "192.168.10.102:8001"
params.registryCredential = registryConfig?.registryCredential ?: "xiaomayi-hub-credentials"
params.registryProject = registryConfig?.registryProject ?: "xiaomayi"
params.registryImage = registryConfig?.registryImage ?: "jdk:17.0.16-centos8-dos"
params.registryType = registryConfig.registryType ?: "harbor"
params.imageFullName = "${params.registry}/${params.registryProject}/${params.projectName}"
script.echo "✅ ${envKey} 环境全部参数获取完成"
// 返回配置
return params
} catch (Exception e) {
script.echo "❌ 获取环境配置失败: ${e.message}"
throw e
}
}
/**
* 设置 Jenkins 作业参数
* 为标准流水线作业创建环境选择参数和服务器选择参数
* 根据可用环境配置动态生成下拉选择框,支持环境和服务器的两级选择
*
* @param availableProfiles 可用的环境配置列表
* - 类型: List<String> 环境名称列表(如:['dev', 'test', 'prod'])
* - 来源: 通常从配置文件中解析得到的环境配置键值
* - 要求: 列表不能为空,且必须与配置文件中的环境名称匹配
*
* @note 在多分支流水线中会自动跳过参数设置(因为多分支通常根据分支自动确定环境)
* @note 在标准流水线中会创建用户可交互的选择参数
*
* @example 生成的参数:
* - PROFILES: 环境选择下拉框(dev/test/prod)
* - SERVERS: 服务器选择下拉框(根据选择的环境动态显示对应服务器)
*/
private void setupJenkinsParameters(List<String> availableProfiles) {
// 检查可用环境列表是否为空
if (!availableProfiles || availableProfiles.isEmpty()) {
script.echo "⚠️ 可用环境配置列表为空,跳过参数设置"
return
}
// 获取当前分支名称,用于判断流水线类型
def branchName = script.env.BRANCH_NAME ?: ''
// 判断是否为多分支流水线(分支名通常包含斜杠,如: feature/xxx)
boolean isMultibranchPipeline = branchName.contains('/')
if (isMultibranchPipeline) {
script.echo "🔧 检测到多分支流水线,跳过参数设置(分支: ${branchName})"
script.echo "💡 多分支流水线通常根据分支名称自动确定目标环境"
return
}
script.echo "🔧 标准流水线作业,设置部署环境参数"
script.echo "📋 可用环境选项: ${availableProfiles.join(', ')}"
try {
// ==========================================================================
// 创建环境选择参数
// ==========================================================================
def profileParameter = script.choice(
choices: availableProfiles.join('\n'), // 下拉选项,每行一个选择项
description: '请选择要部署的目标环境', // 参数描述,显示在Jenkins界面上
name: 'PROFILES' // 参数名称,后续通过params.PROFILES访问
)
// ==========================================================================
// 创建服务器选择参数(动态生成所有环境的服务器选项)
// ==========================================================================
def allServers = getAllServersForParameters(availableProfiles)
def serverChoices = generateServerChoices(allServers)
def serverParameter = script.choice(
choices: serverChoices.join('\n'), // 服务器下拉选项
description: '请选择要部署的目标服务器(格式:环境-服务器名-IP)', // 参数描述
name: 'SERVERS' // 参数名称
)
// ==========================================================================
// 设置Jenkins作业参数
// ==========================================================================
script.properties([
script.parameters([
profileParameter, // 环境选择参数
serverParameter // 服务器选择参数
])
])
script.echo "✅ 成功设置部署参数:"
script.echo " - PROFILES: 环境选择(${availableProfiles.size()} 个选项)"
script.echo " - SERVERS: 服务器选择(${serverChoices.size()} 个选项)"
} catch (Exception e) {
script.echo "⚠️ 设置 Jenkins 参数失败: ${e.message}"
script.echo "💡 这可能是因为没有权限修改作业配置,或者参数格式不正确"
// 不抛出异常,避免影响后续流程,参数设置失败通常不会阻断部署
}
}
/**
* 获取所有环境的服务器信息用于参数生成
* 从配置文件中提取每个环境的服务器列表,用于构建服务器选择参数
* 自动过滤空字符串和无效的环境名称
*
* @param availableProfiles 可用环境列表,可能包含空字符串或无效值
* @return Map<String, List> 各环境的服务器列表映射(只包含有效环境)
*/
private Map<String, List> getAllServersForParameters(List<String> availableProfiles) {
def allServers = [:]
// 过滤掉空字符串和null值,只处理有效的环境名称
def validProfiles = availableProfiles.findAll { profile ->
profile != null && profile.trim() != ''
}
script.echo "🔍 有效环境列表: ${validProfiles.join(', ')}"
script.echo "🗑️ 已过滤空环境: ${availableProfiles.size() - validProfiles.size()} 个"
validProfiles.each { profile ->
try {
// 安全地获取环境配置中的服务器列表
// 使用安全导航操作符避免空指针异常
def envConfig = config?.common?.profiles?."${profile}"
if (envConfig?.servers) {
allServers[profile] = envConfig.servers
script.echo " 📡 ${profile} 环境: ${envConfig.servers.size()} 台服务器"
// 可选:输出服务器详情用于调试
envConfig.servers.eachWithIndex { server, index ->
script.echo " ${index + 1}. ${server.serverName} (${server.serverIP}:${server.serverPort})"
}
} else {
script.echo " ⚠️ ${profile} 环境: 无服务器配置或服务器列表为空"
allServers[profile] = []
}
} catch (Exception e) {
script.echo " ❌ 获取 ${profile} 环境服务器失败: ${e.message}"
script.echo " 🐛 错误详情: ${e.getStackTrace().find { it.contains('getAllServersForParameters') } ?: '未知位置'}"
allServers[profile] = []
}
}
// 检查是否有任何有效环境配置了服务器
def environmentsWithServers = allServers.count { it.value && !it.value.empty }
script.echo "📊 统计: ${environmentsWithServers} 个环境配置了服务器,${allServers.size() - environmentsWithServers} 个环境无服务器"
return allServers
}
/**
* 生成服务器选择选项
* 创建格式化的服务器选择项,便于用户识别和选择
*
* @param allServers 所有环境的服务器映射
* @return List<String> 格式化后的服务器选项列表
*/
private List<String> generateServerChoices(Map<String, List> allServers) {
def choices = []
// 添加默认选项
choices.add("auto-自动选择(根据环境默认服务器)")
// 为每个环境的每台服务器生成选项
allServers.each { profile, servers ->
if (servers && !servers.empty) {
servers.each { server ->
// 格式化选项:环境-服务器名-IP:端口
def displayName = "${profile}-${server.serverName}-${server.serverIP}:${server.serverPort}"
choices.add(displayName)
}
} else {
// 如果某个环境没有服务器,添加提示选项
choices.add("${profile}-无可用服务器")
}
}
return choices
}
/**
* 根据分支配置获取对应的环境配置文件和默认配置文件
* @param branchConfig 分支配置信息,包含分支类型等
* @return Map 包含可用配置列表和默认配置
*/
private def getBranchProfiles(branchConfig) {
// 获取当前分支名称
def branchName = script.env.BRANCH_NAME ?: ''
// 1. 优先从常量配置中获取该分支类型对应的可用配置
def availableProfiles = ConfigConstants.BRANCH_PROFILES[branchName]
// 2. 如果常量配置中没有找到,根据分支类型选择不同的默认配置源
if (!availableProfiles) {
availableProfiles = (branchName == 'master') ?
envConfig.masterProfiles : // master分支使用特殊配置
envConfig.Profiles // 其他分支使用通用配置
}
// 确保availableProfiles不为null,如果是null则转为空列表
availableProfiles = availableProfiles ?: []
// 3. 获取默认配置,优先从常量配置中获取
def defaultProfile = ConfigConstants.DEFAULT_PROFILES[branchName]
// 4. 如果常量配置中没有默认配置,则从可用配置中选择
if (!defaultProfile) {
defaultProfile = availableProfiles.find { it } ? // 查找第一个非空配置
availableProfiles[0] : // 如果都为空则取第一个
null // 如果没有可用配置则返回null
}
return [
available_profiles: availableProfiles,
default_profile : defaultProfile
]
}
}