Files
jenkins-share-library/src/com/jdk/ResolverService.groovy
T
2025-09-21 20:59:25 +08:00

865 lines
39 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.
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()
// 然后加载主配置文件(根据环境配置中的路径)
loadJobConfig()
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 loadJobConfig() {
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
]
}
}