Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:支持针对构建重放事件 #11232 #11328

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a3e0279
feat:支持针对构建重放事件 #11232
hejieehe Dec 17, 2024
b746893
feat:支持针对构建重放事件 #11232
hejieehe Dec 27, 2024
198dda3
Merge branch 'master' of https://github.com/TencentBlueKing/bk-ci int…
hejieehe Dec 27, 2024
a310355
feat:支持针对构建重放事件 #11232
hejieehe Dec 27, 2024
29eef50
feat:支持针对构建重放事件 #11232
hejieehe Dec 30, 2024
ef956d6
feat:支持针对构建重放事件 #11232
hejieehe Dec 30, 2024
e30ec0e
feat:支持针对构建重放事件 #11232
hejieehe Dec 30, 2024
3c5e0a0
feat:支持针对构建重放事件 #11232
hejieehe Dec 30, 2024
dc12f64
feat:支持针对构建重放事件 #11232
hejieehe Jan 2, 2025
0cf8808
feat:支持针对构建重放事件 #11232
hejieehe Jan 7, 2025
b6ea3b1
feat:支持针对构建重放事件 #11232
hejieehe Jan 9, 2025
9b5a855
feat:支持针对构建重放事件 #11232
hejieehe Jan 9, 2025
6cd9735
feat:支持针对构建重放事件 #11232
hejieehe Jan 9, 2025
fe9ed35
feat:支持针对构建重放事件 #11232
hejieehe Jan 9, 2025
8c26542
feat:支持针对构建重放事件 #11232
hejieehe Jan 9, 2025
764c2b1
feat:支持针对构建重放事件 #11232
hejieehe Jan 9, 2025
6f0b7fa
feat:支持针对构建重放事件 #11232
hejieehe Jan 9, 2025
dd3aad8
feat:支持针对构建重放事件 #11232
hejieehe Jan 9, 2025
122195b
feat:支持针对构建重放事件 #11232
hejieehe Jan 9, 2025
4143074
feat:支持针对构建重放事件 #11232
hejieehe Jan 10, 2025
5887ac5
feat:支持针对构建重放事件 #11232
hejieehe Jan 10, 2025
0a32036
feat:支持针对构建重放事件 #11232
hejieehe Jan 13, 2025
5f11789
feat:支持针对构建重放事件 #11232
hejieehe Jan 13, 2025
fa170b2
feat:支持针对构建重放事件 #11232
hejieehe Jan 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -701,4 +701,25 @@ interface UserBuildResource {
@QueryParam("stageId")
stageId: String
): Result<BuildStageProgressInfo>

@Operation(summary = "回放指定构建任务的触发事件")
@POST
@Path("/{projectId}/{pipelineId}/{buildId}/replayByBuild")
fun replayByBuild(
@Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE)
@HeaderParam(AUTH_HEADER_USER_ID)
userId: String,
@Parameter(description = "项目ID", required = true)
@PathParam("projectId")
projectId: String,
@Parameter(description = "流水线ID", required = true)
@PathParam("pipelineId")
pipelineId: String,
@Parameter(description = "构建ID", required = true)
@PathParam("buildId")
buildId: String,
@Parameter(description = "强制触发", required = false)
@QueryParam("forceTrigger")
forceTrigger: Boolean? = false
): Result<BuildId>
}
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ object ProcessMessageCode {
const val ERROR_PIPELINE_BUILD_START_PARAM_NO_EMPTY = "2101254" // 构建启动参数如果必填,不能为空
const val ERROR_REPEATEDLY_START_VM = "2101255" // 重复启动构建机,当前构建机的状态为:{0}
const val ERROR_PIPELINE_VARIABLES_OUT_OF_LENGTH = "2101256" // 流水线启动参数{0}超出4000长度限制
const val ERROR_TRIGGER_CONDITION_NOT_MATCH = "2101260" // 触发条件不匹配

const val BK_SUCCESSFULLY_DISTRIBUTED = "bkSuccessfullyDistributed" // 跨项目构件分发成功,共分发了{0}个文件
const val BK_SUCCESSFULLY_FAILED = "bkSuccessfullyFailed" // 跨项目构件分发失败,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,24 @@ class UserBuildResourceImpl @Autowired constructor(
)
}

override fun replayByBuild(
userId: String,
projectId: String,
pipelineId: String,
buildId: String,
forceTrigger: Boolean?
): Result<BuildId> {
return Result(
pipelineBuildFacadeService.replayBuild(
projectId = projectId,
pipelineId = pipelineId,
buildId = buildId,
userId = userId,
forceTrigger = forceTrigger ?: false
)
)
}

private fun checkParam(userId: String, projectId: String, pipelineId: String) {
if (userId.isBlank()) {
throw ParamBlankException("Invalid userId")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class SubPipelineStartUpService @Autowired constructor(

companion object {
private val logger = LoggerFactory.getLogger(SubPipelineStartUpService::class.java)
private const val SYNC_RUN_MODE = "syn"
const val SYNC_RUN_MODE = "syn"
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import com.tencent.devops.common.pipeline.pojo.BuildFormProperty
import com.tencent.devops.common.pipeline.pojo.BuildFormValue
import com.tencent.devops.common.pipeline.pojo.BuildParameters
import com.tencent.devops.common.pipeline.pojo.StageReviewRequest
import com.tencent.devops.common.pipeline.pojo.element.EmptyElement
import com.tencent.devops.common.pipeline.pojo.element.agent.ManualReviewUserTaskElement
import com.tencent.devops.common.pipeline.pojo.element.atom.ManualReviewParam
import com.tencent.devops.common.pipeline.pojo.element.atom.ManualReviewParamType
Expand Down Expand Up @@ -88,6 +89,7 @@ import com.tencent.devops.process.engine.control.lock.PipelineRefreshBuildLock
import com.tencent.devops.process.engine.interceptor.InterceptData
import com.tencent.devops.process.engine.interceptor.PipelineInterceptorChain
import com.tencent.devops.process.engine.pojo.BuildInfo
import com.tencent.devops.process.engine.pojo.PipelineInfo
import com.tencent.devops.process.engine.pojo.event.PipelineBuildContainerEvent
import com.tencent.devops.process.engine.service.PipelineBuildDetailService
import com.tencent.devops.process.engine.service.PipelineBuildQualityService
Expand Down Expand Up @@ -123,24 +125,34 @@ import com.tencent.devops.process.pojo.pipeline.PipelineResourceVersion
import com.tencent.devops.process.service.BuildVariableService
import com.tencent.devops.process.service.ParamFacadeService
import com.tencent.devops.process.service.PipelineTaskPauseService
import com.tencent.devops.process.service.SubPipelineStartUpService
import com.tencent.devops.process.service.pipeline.PipelineBuildService
import com.tencent.devops.process.service.template.TemplateFacadeService
import com.tencent.devops.process.strategy.context.UserPipelinePermissionCheckContext
import com.tencent.devops.process.strategy.factory.UserPipelinePermissionCheckStrategyFactory
import com.tencent.devops.process.util.TaskUtils
import com.tencent.devops.process.utils.BK_CI_MATERIAL_ID
import com.tencent.devops.process.utils.BK_CI_MATERIAL_NAME
import com.tencent.devops.process.utils.BK_CI_MATERIAL_URL
import com.tencent.devops.process.utils.PIPELINE_BUILD_MSG
import com.tencent.devops.process.utils.PIPELINE_NAME
import com.tencent.devops.process.utils.PIPELINE_RETRY_ALL_FAILED_CONTAINER
import com.tencent.devops.process.utils.PIPELINE_RETRY_BUILD_ID
import com.tencent.devops.process.utils.PIPELINE_RETRY_COUNT
import com.tencent.devops.process.utils.PIPELINE_RETRY_START_TASK_ID
import com.tencent.devops.process.utils.PIPELINE_SKIP_FAILED_TASK
import com.tencent.devops.process.utils.PIPELINE_START_PARENT_BUILD_ID
import com.tencent.devops.process.utils.PIPELINE_START_PARENT_BUILD_TASK_ID
import com.tencent.devops.process.utils.PIPELINE_START_PARENT_EXECUTE_COUNT
import com.tencent.devops.process.utils.PIPELINE_START_PARENT_PIPELINE_ID
import com.tencent.devops.process.utils.PIPELINE_START_PARENT_PROJECT_ID
import com.tencent.devops.process.utils.PIPELINE_START_SUB_RUN_MODE
import com.tencent.devops.process.utils.PIPELINE_START_TASK_ID
import com.tencent.devops.process.utils.PipelineVarUtil.recommendVersionKey
import com.tencent.devops.process.yaml.PipelineYamlFacadeService
import com.tencent.devops.quality.api.v2.pojo.ControlPointPosition
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Lazy
import org.springframework.stereotype.Service
import java.util.concurrent.TimeUnit
import javax.ws.rs.core.Response
Expand Down Expand Up @@ -177,7 +189,8 @@ class PipelineBuildFacadeService(
private val pipelineRetryFacadeService: PipelineRetryFacadeService,
private val webhookBuildParameterService: WebhookBuildParameterService,
private val pipelineYamlFacadeService: PipelineYamlFacadeService,
private val templateFacadeService: TemplateFacadeService
@Lazy
private val subPipelineStartUpService: SubPipelineStartUpService
) {

@Value("\${pipeline.build.cancel.intervalLimitTime:60}")
Expand Down Expand Up @@ -834,7 +847,9 @@ class PipelineBuildFacadeService(
startType: StartType = StartType.WEB_HOOK,
startValues: Map<String, String>? = null,
userParameters: List<BuildParameters>? = null,
triggerReviewers: List<String>? = null
triggerReviewers: List<String>? = null,
pipelineResource: PipelineResourceVersion? = null,
pipelineInfo: PipelineInfo? = null,
): String? {

if (checkPermission) {
Expand All @@ -849,8 +864,10 @@ class PipelineBuildFacadeService(
)
)
}
val readyToBuildPipelineInfo = pipelineRepositoryService.getPipelineInfo(projectId, pipelineId)
?: return null
val readyToBuildPipelineInfo = pipelineInfo ?: pipelineRepositoryService.getPipelineInfo(
projectId = projectId,
pipelineId = pipelineId
) ?: return null
if (readyToBuildPipelineInfo.locked == true) {
throw ErrorCodeException(errorCode = ProcessMessageCode.ERROR_PIPELINE_LOCK)
}
Expand All @@ -859,8 +876,11 @@ class PipelineBuildFacadeService(
)
val startEpoch = System.currentTimeMillis()
try {

val resource = getPipelineResourceVersion(projectId, pipelineId, readyToBuildPipelineInfo.version)
val resource = pipelineResource ?: getPipelineResourceVersion(
projectId = projectId,
pipelineId = pipelineId,
version = readyToBuildPipelineInfo.version
)
val model = resource.model

/**
Expand Down Expand Up @@ -2683,6 +2703,185 @@ class PipelineBuildFacadeService(
)
}

fun replayBuild(
projectId: String,
pipelineId: String,
buildId: String,
userId: String,
forceTrigger: Boolean
): BuildId {
pipelinePermissionService.validPipelinePermission(
userId = userId,
projectId = projectId,
pipelineId = pipelineId,
permission = AuthPermission.EXECUTE,
message = MessageUtil.getMessageByLocale(
CommonMessageCode.USER_NOT_PERMISSIONS_OPERATE_PIPELINE,
I18nUtil.getLanguage(userId),
arrayOf(
userId,
projectId,
AuthPermission.EXECUTE.getI18n(I18nUtil.getLanguage(userId)),
pipelineId
)
)
)
val buildInfo = checkPipelineInfo(projectId, pipelineId, buildId)
// 按原有的启动参数组装启动参数(排除重试次数)
val startParameters = buildInfo.buildParameters?.filter {
it.key != PIPELINE_RETRY_COUNT
}?.associate {
it.key to it.value.toString()
}?.toMutableMap() ?: mutableMapOf()
val startType = StartType.toStartType(buildInfo.trigger)
val pipelineInfo = pipelineRepositoryService.getPipelineInfo(projectId, pipelineId)
?: throw ErrorCodeException(errorCode = ProcessMessageCode.ERROR_PIPELINE_NOT_EXISTS)
if (pipelineInfo.locked == true) {
throw ErrorCodeException(errorCode = ProcessMessageCode.ERROR_PIPELINE_LOCK)
}
if (pipelineInfo.latestVersionStatus?.isNotReleased() == true) throw ErrorCodeException(
errorCode = ProcessMessageCode.ERROR_NO_RELEASE_PIPELINE_VERSION
)
val pipelineResourceVersion = getPipelineResourceVersion(projectId, pipelineId, pipelineInfo.version)
val model = pipelineResourceVersion.model
val triggerContainer = model.getTriggerContainer()
// 检查触发器是否存在
val checkTriggerResult = forceTrigger || when (startType) {
StartType.WEB_HOOK -> {
triggerContainer.elements.find { it.id == startParameters[PIPELINE_START_TASK_ID] }
}

StartType.MANUAL, StartType.SERVICE -> {
triggerContainer.elements.find { it is ManualTriggerElement }
}

StartType.REMOTE -> {
triggerContainer.elements.find { it is RemoteTriggerElement }
}

StartType.TIME_TRIGGER -> {
triggerContainer.elements.find { it.id == startParameters[PIPELINE_START_TASK_ID] }
}

StartType.PIPELINE -> {
EmptyElement()
}
} != null
if (!checkTriggerResult) {
throw ErrorCodeException(
errorCode = ProcessMessageCode.ERROR_TRIGGER_CONDITION_NOT_MATCH,
params = arrayOf(pipelineResourceVersion.versionName ?: "")
)
}
return triggerPipeline(
userId = buildInfo.startUser,
projectId = projectId,
pipelineId = pipelineId,
buildId = buildId,
startParameters = startParameters,
startType = startType,
pipelineInfo = pipelineInfo,
pipelineResourceVersion = pipelineResourceVersion
)
}

private fun triggerPipeline(
startType: StartType,
projectId: String,
pipelineId: String,
buildId: String,
startParameters: MutableMap<String, String>,
pipelineInfo: PipelineInfo? = null,
pipelineResourceVersion: PipelineResourceVersion? = null,
userId: String
) = when (startType) {
StartType.WEB_HOOK -> {
// webhook触发
webhookBuildParameterService.getBuildParameters(buildId = buildId)?.forEach { param ->
startParameters[param.key] = param.value.toString()
}
// webhook触发
BuildId(
webhookTriggerPipelineBuild(
userId = userId,
projectId = projectId,
pipelineId = pipelineId,
parameters = startParameters,
checkPermission = false,
startType = startType,
pipelineInfo = pipelineInfo,
pipelineResource = pipelineResourceVersion
)!!
)
}

StartType.MANUAL, StartType.SERVICE, StartType.REMOTE -> {
startParameters.putAll(
// 自定义触发源材料参数
buildVariableService.getAllVariable(
projectId = projectId,
pipelineId = pipelineId,
buildId = buildId,
keys = setOf(BK_CI_MATERIAL_ID, BK_CI_MATERIAL_NAME, BK_CI_MATERIAL_URL)
)
)
buildManualStartup(
userId = userId,
projectId = projectId,
pipelineId = pipelineId,
channelCode = ChannelCode.BS,
values = startParameters,
startType = startType
)
}

StartType.TIME_TRIGGER -> {
BuildId(
timerTriggerPipelineBuild(
userId = userId,
projectId = projectId,
pipelineId = pipelineId,
parameters = startParameters,
checkPermission = false
) ?: ""
)
}

StartType.PIPELINE -> {
// 父子流水线核心参数
startParameters.putAll(
buildVariableService.getAllVariable(
projectId = projectId,
pipelineId = pipelineId,
buildId = buildId,
keys = setOf(
PIPELINE_START_PARENT_PROJECT_ID,
PIPELINE_START_PARENT_PIPELINE_ID,
PIPELINE_START_PARENT_BUILD_ID,
PIPELINE_START_PARENT_BUILD_TASK_ID,
PIPELINE_START_SUB_RUN_MODE,
PIPELINE_START_PARENT_EXECUTE_COUNT
)
)
)
BuildId(
subPipelineStartUpService.callPipelineStartup(
projectId = startParameters[PIPELINE_START_PARENT_PROJECT_ID]!!,
parentPipelineId = startParameters[PIPELINE_START_PARENT_PIPELINE_ID]!!,
buildId = startParameters[PIPELINE_START_PARENT_BUILD_ID]!!,
callProjectId = projectId,
callPipelineId = pipelineId,
atomCode = "SubPipelineExec",
taskId = startParameters[PIPELINE_START_PARENT_BUILD_TASK_ID]!!,
channelCode = ChannelCode.BS,
values = startParameters,
runMode = startParameters[PIPELINE_START_SUB_RUN_MODE] ?: SubPipelineStartUpService.SYNC_RUN_MODE,
executeCount = startParameters[PIPELINE_START_PARENT_EXECUTE_COUNT]?.toInt()
).data!!.id
)
}
}

private fun buildRestartPipeline(
projectId: String,
pipelineId: String,
Expand Down
2 changes: 1 addition & 1 deletion support-files/i18n/process/message_en_US.properties
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@
2101254=Parameter {0} is required and cannot be empty
2101255=Start the build machine repeatedly. The current status of the build machine is: {0}
2101256=pipeline build parameter {0} value exceeds 4000 length limit

2101260=Same trigger parameters, no longer meet the trigger conditions of the current pipeline latest version {0}. Continuing to run may produce errors. Confirm to continue?
ATOM_POST_EXECUTE_TIP=###Tip:this is the post-action hooked by [step{0}]{1}###
# 公共变量
ci.build-no=Build number. Only available when the recommended version number is enabled.
Expand Down
2 changes: 1 addition & 1 deletion support-files/i18n/process/message_zh_CN.properties
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@
2101254=构建入参[{0}]必填,不能为空
2101255=重复启动构建机,当前构建机的状态为:{0}
2101256=流水线变量{0}值超出4000长度限制

2101260=同样的触发参数, 已不满足当前流水线最新版本 {0} 的触发条件, 继续运行可能会产生错误, 确认继续吗
ATOM_POST_EXECUTE_TIP=###Tip:this is the post-action hooked by [step{0}]{1}###
ci.build-no=构建号,开启推荐版本号时有效
ci.build_num=当前构建的唯一标示ID,从1开始自增
Expand Down