865 lines
39 KiB
Groovy
865 lines
39 KiB
Groovy
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
|
||
]
|
||
}
|
||
|
||
} |