Skip to content

Commit

Permalink
Merge pull request #10529 from royalhuang/pac_github
Browse files Browse the repository at this point in the history
feat:流水线版本管理机制 #8161 优化版本列表排序
  • Loading branch information
bkci-bot authored Jun 19, 2024
2 parents ce5de7e + 54a5e1c commit ce21a22
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ data class PipelineDetail(
val baseVersionStatus: VersionStatus?,
@get:Schema(title = "基准版本的版本名称")
val baseVersionName: String?,
@get:Schema(title = "草稿或最新的发布版本")
@get:Schema(title = "最新的发布版本,如果为空则说明没有过发布版本")
val releaseVersion: Int?,
@get:Schema(title = "草稿或最新的发布版本名称")
@get:Schema(title = "最新的发布版本名称,如果为空则说明没有过发布版本")
val releaseVersionName: String?,
@get:Schema(title = "是否有编辑权限")
val hasPermission: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,7 @@ data class PipelineVersionSimple(
@get:Schema(title = "调试构建ID", required = false)
val debugBuildId: String? = null,
@get:Schema(title = "该版本的来源版本(空时一定为主路径)", required = false)
val baseVersion: Int? = null
val baseVersion: Int? = null,
@get:Schema(title = "当前最新正式版本标识", required = false)
var latestReleasedFlag: Boolean? = false
)
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import com.tencent.devops.process.pojo.setting.PipelineSettingVersion
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.jvm.isAccessible

@Suppress("ComplexMethod")
@Suppress("ComplexMethod", "ComplexCondition")
object PipelineVersionUtils {

fun getVersionNameByModel(
Expand Down Expand Up @@ -132,7 +132,11 @@ object PipelineVersionUtils {
if (this != other && this.size != other.size) return false
this.forEachIndexed { sIndex, thisStage ->
val otherStage = other[sIndex]
if (thisStage != otherStage && thisStage.containers.size != otherStage.containers.size) {
if (
thisStage != otherStage || thisStage.containers.size != otherStage.containers.size ||
thisStage.checkIn != otherStage.checkIn || thisStage.checkOut != otherStage.checkOut ||
thisStage.stageControlOption != otherStage.stageControlOption
) {
return false
}
thisStage.containers.forEachIndexed { cIndex, thisContainer ->
Expand All @@ -141,9 +145,13 @@ object PipelineVersionUtils {
return false
}
if (thisContainer is VMBuildContainer && otherContainer is VMBuildContainer) {
if (thisContainer != otherContainer) return false
if (thisContainer != otherContainer || thisContainer.dispatchType != otherContainer.dispatchType ||
thisContainer.jobControlOption != otherContainer.jobControlOption
) return false
} else if (thisContainer is NormalContainer && otherContainer is NormalContainer) {
if (thisContainer != otherContainer) return false
if (thisContainer != otherContainer ||
thisContainer.jobControlOption != otherContainer.jobControlOption
) return false
} else {
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ import com.tencent.devops.common.pipeline.container.Stage
import com.tencent.devops.common.pipeline.container.TriggerContainer
import com.tencent.devops.common.pipeline.container.VMBuildContainer
import com.tencent.devops.common.pipeline.enums.BuildScriptType
import com.tencent.devops.common.pipeline.enums.StageRunCondition
import com.tencent.devops.common.pipeline.enums.VMBaseOS
import com.tencent.devops.common.pipeline.option.StageControlOption
import com.tencent.devops.common.pipeline.pojo.element.ElementAdditionalOptions
import com.tencent.devops.common.pipeline.pojo.element.agent.LinuxScriptElement
import com.tencent.devops.common.pipeline.pojo.element.trigger.ManualTriggerElement
Expand Down Expand Up @@ -408,6 +410,99 @@ class PipelineYamlVersionUtilsTest {
assertEquals(version + 1, PipelineVersionUtils.getPipelineVersion(version, model1, model2))
assertEquals(version + 1, PipelineVersionUtils.getPipelineVersion(version, model1, model3))
}

@Test
fun testRunConditionDiffer() {
val model1 = Model(
name = "name1",
desc = "",
stages = listOf(
Stage(
id = "stage-1",
containers = listOf(
TriggerContainer(
id = "0",
name = "trigger",
elements = listOf(
ManualTriggerElement(
id = "T-1-1-1",
name = "t1"
)
)
)
)
),
Stage(
id = "stage-2",
containers = listOf(
VMBuildContainer(
baseOS = VMBaseOS.LINUX
),
NormalContainer(
elements = listOf(
LinuxScriptElement(
script = "echo 1",
continueNoneZero = true,
scriptType = BuildScriptType.SHELL,
additionalOptions = ElementAdditionalOptions(enable = true)
)
)
)
),
stageControlOption = StageControlOption(
runCondition = StageRunCondition.AFTER_LAST_FINISHED
)
)
),
pipelineCreator = "userId"
)
val model2 = Model(
name = "name1",
desc = "",
stages = listOf(
Stage(
id = "stage-1",
containers = listOf(
TriggerContainer(
id = "0",
name = "trigger",
elements = listOf(
ManualTriggerElement(
id = "T-1-1-1",
name = "t1"
)
)
)
)
),
Stage(
id = "stage-2",
containers = listOf(
VMBuildContainer(
baseOS = VMBaseOS.LINUX
),
NormalContainer(
elements = listOf(
LinuxScriptElement(
script = "echo 1",
continueNoneZero = true,
scriptType = BuildScriptType.SHELL,
additionalOptions = ElementAdditionalOptions(enable = true)
)
)
)
),
stageControlOption = StageControlOption(
runCondition = StageRunCondition.CUSTOM_VARIABLE_MATCH
)
)
),
pipelineCreator = "userId"
)
val version = 1
assertEquals(version + 1, PipelineVersionUtils.getPipelineVersion(version, model1, model2))
}

@Test
fun getSettingVersions() {
val setting = PipelineSettingVersion(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import com.tencent.devops.common.pipeline.enums.BranchVersionAction
import com.tencent.devops.common.pipeline.enums.VersionStatus
import com.tencent.devops.model.process.Tables.T_PIPELINE_RESOURCE_VERSION
import com.tencent.devops.model.process.tables.records.TPipelineResourceVersionRecord
import com.tencent.devops.process.engine.pojo.PipelineInfo
import com.tencent.devops.process.pojo.pipeline.PipelineResourceVersion
import com.tencent.devops.process.pojo.setting.PipelineVersionSimple
import com.tencent.devops.process.utils.PipelineVersionUtils
Expand Down Expand Up @@ -167,19 +168,19 @@ class PipelineResourceVersionDao {
dslContext: DSLContext,
projectId: String,
pipelineId: String,
branchName: String
branchName: String?
): PipelineResourceVersion? {
// 一定是取最新的分支版本
with(T_PIPELINE_RESOURCE_VERSION) {
return dslContext.selectFrom(this)
val select = dslContext.selectFrom(this)
.where(PIPELINE_ID.eq(pipelineId).and(PROJECT_ID.eq(projectId)))
.and(STATUS.eq(VersionStatus.BRANCH.name))
.and(
BRANCH_ACTION.ne(BranchVersionAction.INACTIVE.name)
.or(BRANCH_ACTION.isNull)
)
.and(VERSION_NAME.eq(branchName))
.orderBy(VERSION.desc()).limit(1)
branchName?.let { select.and(VERSION_NAME.eq(branchName)) }
return select.orderBy(VERSION.desc()).limit(1)
.fetchAny(mapper)
}
}
Expand Down Expand Up @@ -309,6 +310,7 @@ class PipelineResourceVersionDao {
dslContext: DSLContext,
projectId: String,
pipelineId: String,
pipelineInfo: PipelineInfo,
queryUnknownRelatedFlag: Boolean? = null,
maxQueryVersion: Int? = null,
offset: Int,
Expand Down Expand Up @@ -355,10 +357,11 @@ class PipelineResourceVersionDao {
maxQueryVersion?.let {
query.and(VERSION.le(maxQueryVersion))
}
// TODO UPDATE_TIME 需要增加索引,有慢查询风险
return query.orderBy(
val list = query.orderBy(
UPDATE_TIME.desc(), VERSION_NUM.desc(), VERSION.desc()
).limit(limit).offset(offset).fetch(sampleMapper)
list.forEach { if (it.version == pipelineInfo.version) it.latestReleasedFlag = true }
return list
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1246,13 +1246,20 @@ class PipelineRepositoryService constructor(
).map { it.key to str2model(it.value, it.key) }.toMap()
}

/**
* 获取编排版本的通用方法
* 1 如果指定了[version]则一定按照version号查询版本
* 2 如果没有指定版本,则通过[includeDraft]控制是否过滤掉草稿,获得最新版本流水线
* 3 默认情况,[version]=null 且 [includeDraft]=false 时,直接返回当前正式版本
*/
fun getPipelineResourceVersion(
projectId: String,
pipelineId: String,
version: Int? = null,
includeDraft: Boolean? = false
): PipelineResourceVersion? {
val resource = if (version == null) { // 取最新版,直接从旧版本表读
// TODO 取不到则直接从旧版本表读,待下架
val resource = if (version == null) {
if (includeDraft == true) pipelineResourceVersionDao.getDraftVersionResource(
dslContext = dslContext,
projectId = projectId,
Expand Down Expand Up @@ -1321,7 +1328,7 @@ class PipelineRepositoryService constructor(
fun getBranchVersionResource(
projectId: String,
pipelineId: String,
branchName: String
branchName: String?
): PipelineResourceVersion? {
val resource = pipelineResourceVersionDao.getBranchVersionResource(
dslContext = dslContext,
Expand Down Expand Up @@ -1399,7 +1406,7 @@ class PipelineRepositoryService constructor(
val now = LocalDateTime.now()
val newDraft = targetVersion.copy(
version = latestResource.version + 1,
versionNum = releaseResource.version + 1,
versionNum = null,
pipelineVersion = null,
triggerVersion = null,
versionName = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ class PipelineRepositoryVersionService(
dslContext = dslContext,
projectId = projectId,
pipelineId = pipelineId,
pipelineInfo = pipelineInfo,
creator = creator,
description = description,
versionName = versionName,
Expand Down Expand Up @@ -299,6 +300,7 @@ class PipelineRepositoryVersionService(
dslContext = dslContext,
projectId = projectId,
pipelineId = pipelineId,
pipelineInfo = pipelineInfo,
creator = creator,
description = description,
versionName = versionName,
Expand Down Expand Up @@ -461,6 +463,9 @@ class PipelineRepositoryVersionService(
private fun updatePipelineReferFlag(projectId: String, pipelineId: String) {
var offset = 0
val limit = PageUtil.DEFAULT_PAGE_SIZE
val pipelineInfo = pipelineInfoDao.convert(
pipelineInfoDao.getPipelineInfo(dslContext, projectId, pipelineId), null
) ?: return
val lock = PipelineModelLock(redisOperation, pipelineId)
try {
lock.lock()
Expand All @@ -470,6 +475,7 @@ class PipelineRepositoryVersionService(
dslContext = dslContext,
projectId = projectId,
pipelineId = pipelineId,
pipelineInfo = pipelineInfo,
queryUnknownRelatedFlag = true,
offset = offset,
limit = limit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,28 @@ class PipelineVersionFacadeService @Autowired constructor(
pipelineId = pipelineId,
detailInfo = detailInfo
)
val version = draftVersion?.version ?: releaseVersion.version
val versionName = draftVersion?.versionName ?: releaseVersion.versionName
val released = detailInfo.latestVersionStatus?.isNotReleased() != true
var versionName = releaseVersion.versionName?.takeIf { released }
// 配合前端的展示需要,version有以下几种情况的返回值:
// 1 发布过且有草稿:version取草稿的版本号
// 2 发布过且有分支版本:version取最新正式的版本号
// 3 未发布过仅有草稿版本:version取草稿的版本号
// 4 未发布过仅有分支版本:version取最新的分支版本号
val version = when (detailInfo.latestVersionStatus) {
VersionStatus.COMMITTING -> {
draftVersion?.version
}
VersionStatus.BRANCH -> {
val branchVersion = pipelineRepositoryService.getBranchVersionResource(
projectId, pipelineId, null
)
versionName = branchVersion?.versionName
branchVersion?.version
}
else -> {
null
}
} ?: releaseVersion.version
val permissions = pipelineListFacadeService.getPipelinePermissions(userId, projectId, pipelineId)
val yamlExist = pipelineYamlFacadeService.yamlExistInDefaultBranch(
projectId = projectId,
Expand All @@ -187,8 +207,9 @@ class PipelineVersionFacadeService @Autowired constructor(
permissions = permissions,
version = version,
versionName = versionName,
releaseVersion = releaseVersion.version,
releaseVersionName = releaseVersion.versionName,
// 前端需要缺省当前能用的版本,用于进入页面的默认展示,但没有发布过就不提供releaseVersionName
releaseVersion = releaseVersion.version.takeIf { released } ?: version,
releaseVersionName = releaseVersion.versionName?.takeIf { released },
baseVersion = baseVersion,
baseVersionStatus = baseVersionStatus,
baseVersionName = baseVersionName,
Expand Down Expand Up @@ -383,8 +404,7 @@ class PipelineVersionFacadeService @Autowired constructor(
if (versionStatus.isReleasing()) {
val existModel = pipelineRepositoryService.getPipelineResourceVersion(
projectId = projectId,
pipelineId = pipelineId,
includeDraft = true
pipelineId = pipelineId
)?.model ?: throw ErrorCodeException(
statusCode = Response.Status.NOT_FOUND.statusCode,
errorCode = ProcessMessageCode.ERROR_PIPELINE_MODEL_NOT_EXISTS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
package com.tencent.devops.process.service.webhook

import com.tencent.devops.common.api.enums.RepositoryType
import com.tencent.devops.common.api.exception.ErrorCodeException
import com.tencent.devops.common.api.util.JsonUtil
import com.tencent.devops.common.client.Client
import com.tencent.devops.common.event.dispatcher.pipeline.mq.MeasureEventDispatcher
Expand All @@ -38,7 +37,6 @@ import com.tencent.devops.common.log.utils.BuildLogPrinter
import com.tencent.devops.common.pipeline.container.TriggerContainer
import com.tencent.devops.common.pipeline.enums.ChannelCode
import com.tencent.devops.common.pipeline.enums.StartType
import com.tencent.devops.common.pipeline.enums.VersionStatus
import com.tencent.devops.common.pipeline.pojo.BuildParameters
import com.tencent.devops.common.pipeline.pojo.element.trigger.WebHookTriggerElement
import com.tencent.devops.common.pipeline.utils.PIPELINE_PAC_REPO_HASH_ID
Expand All @@ -50,7 +48,6 @@ import com.tencent.devops.common.webhook.service.code.matcher.ScmWebhookMatcher
import com.tencent.devops.common.webhook.util.EventCacheUtil
import com.tencent.devops.process.api.service.ServiceBuildResource
import com.tencent.devops.process.api.service.ServiceScmWebhookResource
import com.tencent.devops.process.constant.ProcessMessageCode
import com.tencent.devops.process.engine.service.PipelineRepositoryService
import com.tencent.devops.process.engine.service.PipelineWebHookQueueService
import com.tencent.devops.process.engine.service.PipelineWebhookService
Expand Down Expand Up @@ -492,10 +489,10 @@ class PipelineBuildWebhookService @Autowired constructor(

val pipelineInfo = pipelineRepositoryService.getPipelineInfo(projectId, pipelineId)
?: throw IllegalArgumentException("Pipeline($pipelineId) not found")
// 代码库触发支持仅有分支版本的情况
if (pipelineInfo.latestVersionStatus == VersionStatus.COMMITTING) throw ErrorCodeException(
errorCode = ProcessMessageCode.ERROR_NO_RELEASE_PIPELINE_VERSION
)
// 代码库触发支持仅有分支版本的情况,如果仅有草稿不需要在这里拦截
// if (pipelineInfo.latestVersionStatus == VersionStatus.COMMITTING) throw ErrorCodeException(
// errorCode = ProcessMessageCode.ERROR_NO_RELEASE_PIPELINE_VERSION
// )
val version = webhookCommit.version ?: pipelineInfo.version
checkPermission(pipelineInfo.lastModifyUser, projectId = projectId, pipelineId = pipelineId)

Expand Down
3 changes: 2 additions & 1 deletion support-files/sql/1001_ci_archive_process_ddl_mysql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,8 @@ CREATE TABLE IF NOT EXISTS `T_PIPELINE_RESOURCE_VERSION` (
`DESCRIPTION` text COMMENT '版本变更说明',
`UPDATER` varchar(64) DEFAULT NULL COMMENT '最近更新人',
`UPDATE_TIME` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`PIPELINE_ID`,`VERSION`)
PRIMARY KEY (`PIPELINE_ID`,`VERSION`),
KEY `INX_PIPELINE_UPDATE_TIME` (`PROJECT_ID`,`PIPELINE_ID`,`UPDATE_TIME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='流水线资源版本表';

CREATE TABLE IF NOT EXISTS `T_PIPELINE_BUILD_RECORD_CONTAINER` (
Expand Down
Loading

0 comments on commit ce21a22

Please sign in to comment.