diff --git a/src/backend/ci/core/common/common-api/src/main/kotlin/com/tencent/devops/common/api/constant/CommonConstants.kt b/src/backend/ci/core/common/common-api/src/main/kotlin/com/tencent/devops/common/api/constant/CommonConstants.kt index 72b788f9323..1dd590018db 100644 --- a/src/backend/ci/core/common/common-api/src/main/kotlin/com/tencent/devops/common/api/constant/CommonConstants.kt +++ b/src/backend/ci/core/common/common-api/src/main/kotlin/com/tencent/devops/common/api/constant/CommonConstants.kt @@ -104,6 +104,7 @@ const val OR = "or" // 或 const val TIMETOSELECT = "timetoSelect" // 时必选 const val MASTER = "master" // 主干 const val SYSTEM = "system" // 系统 +const val IN_READY_TEST = "IN_READY_TEST" // 正在测试中 const val BUILD_RUNNING = "buildRunning" // 运行中 const val BUILD_QUEUE = "buildQueue" // 构建排队中 const val BUILD_REVIEWING = "buildReviewing" // 构建待审核 @@ -154,6 +155,7 @@ const val KEY_UPDATED_TIME = "updatedTime" const val KEY_DEFAULT_LOCALE_LANGUAGE = "defaultLocaleLanguage" const val KEY_PROJECT_ID = "projectId" const val KEY_PIPELINE_NUM = "pipelineNum" +const val KEY_BRANCH_TEST_FLAG = "branchTestFlag" const val BK_BUILD_ENV_START_FAILED = "bkBuildEnvStartFailed" // 构建环境启动失败 const val BK_START_PULL_IMAGE = "bkStartPullImage" // 开始拉取镜像,镜像名称: diff --git a/src/backend/ci/core/log/api-log/src/main/kotlin/com/tencent/devops/log/api/print/BuildLogPrintResource.kt b/src/backend/ci/core/log/api-log/src/main/kotlin/com/tencent/devops/log/api/print/BuildLogPrintResource.kt index 3e17a790c1e..cd254968258 100644 --- a/src/backend/ci/core/log/api-log/src/main/kotlin/com/tencent/devops/log/api/print/BuildLogPrintResource.kt +++ b/src/backend/ci/core/log/api-log/src/main/kotlin/com/tencent/devops/log/api/print/BuildLogPrintResource.kt @@ -28,17 +28,23 @@ package com.tencent.devops.log.api.print import com.tencent.devops.common.api.auth.AUTH_HEADER_DEVOPS_BUILD_ID +import com.tencent.devops.common.api.auth.AUTH_HEADER_USER_ID +import com.tencent.devops.common.api.auth.AUTH_HEADER_USER_ID_DEFAULT_VALUE import com.tencent.devops.common.api.pojo.Result +import com.tencent.devops.common.log.pojo.QueryLogs import com.tencent.devops.common.log.pojo.TaskBuildLogProperty +import com.tencent.devops.common.log.pojo.enums.LogType import com.tencent.devops.common.log.pojo.message.LogMessage import io.swagger.annotations.Api import io.swagger.annotations.ApiOperation import io.swagger.annotations.ApiParam import javax.ws.rs.Consumes +import javax.ws.rs.GET import javax.ws.rs.HeaderParam import javax.ws.rs.POST import javax.ws.rs.PUT import javax.ws.rs.Path +import javax.ws.rs.PathParam import javax.ws.rs.Produces import javax.ws.rs.QueryParam import javax.ws.rs.core.MediaType @@ -162,4 +168,79 @@ interface BuildLogPrintResource { @ApiParam("所有插件的日志存储结果", required = true) propertyList: List ): Result + + @ApiOperation("根据构建ID获取初始化所有日志") + @GET + @Path("/{projectId}/{pipelineId}/{buildId}/") + fun getInitLogs( + @ApiParam("用户ID", required = true, defaultValue = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @HeaderParam(AUTH_HEADER_USER_ID) + userId: String, + @ApiParam("项目ID", required = true) + @PathParam("projectId") + projectId: String, + @ApiParam("流水线ID", required = true) + @PathParam("pipelineId") + pipelineId: String, + @ApiParam("构建ID", required = true) + @PathParam("buildId") + buildId: String, + @ApiParam("是否包含调试日志", required = false) + @QueryParam("debug") + debug: Boolean? = false, + @ApiParam("过滤日志级别", required = false) + @QueryParam("logType") + logType: LogType? = null, + @ApiParam("对应elementId", required = false) + @QueryParam("tag") + tag: String?, + @ApiParam("指定subTag", required = false) + @QueryParam("subTag") + subTag: String?, + @ApiParam("对应jobId", required = false) + @QueryParam("jobId") + jobId: String?, + @ApiParam("执行次数", required = false) + @QueryParam("executeCount") + executeCount: Int? + ): Result + + @ApiOperation("获取某行后的日志") + @GET + @Path("/{projectId}/{pipelineId}/{buildId}/after") + fun getAfterLogs( + @ApiParam("用户ID", required = true, defaultValue = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @HeaderParam(AUTH_HEADER_USER_ID) + userId: String, + @ApiParam("项目ID", required = true) + @PathParam("projectId") + projectId: String, + @ApiParam("流水线ID", required = true) + @PathParam("pipelineId") + pipelineId: String, + @ApiParam("构建ID", required = true) + @PathParam("buildId") + buildId: String, + @ApiParam("起始行号", required = true) + @QueryParam("start") + start: Long, + @ApiParam("是否包含调试日志", required = false) + @QueryParam("debug") + debug: Boolean? = false, + @ApiParam("过滤日志级别", required = false) + @QueryParam("logType") + logType: LogType? = null, + @ApiParam("对应elementId", required = false) + @QueryParam("tag") + tag: String?, + @ApiParam("指定subTag", required = false) + @QueryParam("subTag") + subTag: String?, + @ApiParam("对应jobId", required = false) + @QueryParam("jobId") + jobId: String?, + @ApiParam("执行次数", required = false) + @QueryParam("executeCount") + executeCount: Int? + ): Result } diff --git a/src/backend/ci/core/log/biz-log/src/main/kotlin/com/tencent/devops/log/resources/BuildLogPrintResourceImpl.kt b/src/backend/ci/core/log/biz-log/src/main/kotlin/com/tencent/devops/log/resources/BuildLogPrintResourceImpl.kt index 279b69a07c5..8f5cab0cc75 100644 --- a/src/backend/ci/core/log/biz-log/src/main/kotlin/com/tencent/devops/log/resources/BuildLogPrintResourceImpl.kt +++ b/src/backend/ci/core/log/biz-log/src/main/kotlin/com/tencent/devops/log/resources/BuildLogPrintResourceImpl.kt @@ -28,8 +28,10 @@ package com.tencent.devops.log.resources import com.tencent.devops.common.api.pojo.Result +import com.tencent.devops.common.log.pojo.QueryLogs import com.tencent.devops.common.log.pojo.TaskBuildLogProperty import com.tencent.devops.common.log.pojo.enums.LogStorageMode +import com.tencent.devops.common.log.pojo.enums.LogType import com.tencent.devops.common.log.pojo.message.LogMessage import com.tencent.devops.common.web.RestResource import com.tencent.devops.log.api.print.BuildLogPrintResource @@ -37,6 +39,7 @@ import com.tencent.devops.log.event.LogOriginEvent import com.tencent.devops.log.event.LogStatusEvent import com.tencent.devops.log.meta.Ansi import com.tencent.devops.log.service.BuildLogPrintService +import com.tencent.devops.log.service.BuildLogQueryService import com.tencent.devops.log.service.IndexService import com.tencent.devops.log.service.LogStatusService import io.micrometer.core.annotation.Timed @@ -55,7 +58,8 @@ class BuildLogPrintResourceImpl @Autowired constructor( private val buildLogPrintService: BuildLogPrintService, private val logStatusService: LogStatusService, private val indexService: IndexService, - private val meterRegistry: MeterRegistry + private val meterRegistry: MeterRegistry, + private val buildLogQueryService: BuildLogQueryService ) : BuildLogPrintResource { @Value("\${spring.application.name:#{null}}") @@ -190,6 +194,65 @@ class BuildLogPrintResourceImpl @Autowired constructor( return Result(true) } + override fun getInitLogs( + userId: String, + projectId: String, + pipelineId: String, + buildId: String, + debug: Boolean?, + logType: LogType?, + tag: String?, + subTag: String?, + jobId: String?, + executeCount: Int? + ): Result { + val initLogs = buildLogQueryService.getInitLogs( + userId = userId, + projectId = projectId, + pipelineId = pipelineId, + buildId = buildId, + debug = debug, + logType = logType, + tag = tag, + subTag = subTag, + jobId = jobId, + executeCount = executeCount + ) + recordMultiLogCount(initLogs.data?.logs?.size ?: 0) + return initLogs + } + + override fun getAfterLogs( + userId: String, + projectId: String, + pipelineId: String, + buildId: String, + start: Long, + debug: Boolean?, + logType: LogType?, + tag: String?, + subTag: String?, + jobId: String?, + executeCount: Int? + ): Result { + val afterLogs = buildLogQueryService.getAfterLogs( + userId = userId, + projectId = projectId, + pipelineId = pipelineId, + buildId = buildId, + start = start, + debug = debug, + logType = logType, + tag = tag, + subTag = subTag, + jobId = jobId, + executeCount = executeCount + ) + recordMultiLogCount(afterLogs.data?.logs?.size ?: 0) + + return afterLogs + } + /** * 记录日志列表函数 */ diff --git a/src/backend/ci/core/quality/api-quality/src/main/kotlin/com/tencent/devops/quality/api/v2/ServiceQualityControlPointMarketResource.kt b/src/backend/ci/core/quality/api-quality/src/main/kotlin/com/tencent/devops/quality/api/v2/ServiceQualityControlPointMarketResource.kt index 890d453f72f..6235904fb82 100644 --- a/src/backend/ci/core/quality/api-quality/src/main/kotlin/com/tencent/devops/quality/api/v2/ServiceQualityControlPointMarketResource.kt +++ b/src/backend/ci/core/quality/api-quality/src/main/kotlin/com/tencent/devops/quality/api/v2/ServiceQualityControlPointMarketResource.kt @@ -27,6 +27,7 @@ package com.tencent.devops.quality.api.v2 +import com.tencent.devops.common.api.constant.IN_READY_TEST import com.tencent.devops.common.api.pojo.Result import com.tencent.devops.quality.api.v2.pojo.QualityControlPoint import io.swagger.annotations.Api @@ -52,6 +53,8 @@ interface ServiceQualityControlPointMarketResource { fun setTestControlPoint( @QueryParam("userId") userId: String, + @QueryParam("tag") + tag: String = IN_READY_TEST, controlPoint: QualityControlPoint ): Result @@ -68,6 +71,8 @@ interface ServiceQualityControlPointMarketResource { @DELETE fun deleteTestControlPoint( @QueryParam("elementType") - elementType: String + elementType: String, + @QueryParam("tag") + tag: String = IN_READY_TEST ): Result } diff --git a/src/backend/ci/core/quality/api-quality/src/main/kotlin/com/tencent/devops/quality/api/v2/ServiceQualityIndicatorMarketResource.kt b/src/backend/ci/core/quality/api-quality/src/main/kotlin/com/tencent/devops/quality/api/v2/ServiceQualityIndicatorMarketResource.kt index 0aa06ccc9e1..8721816b807 100644 --- a/src/backend/ci/core/quality/api-quality/src/main/kotlin/com/tencent/devops/quality/api/v2/ServiceQualityIndicatorMarketResource.kt +++ b/src/backend/ci/core/quality/api-quality/src/main/kotlin/com/tencent/devops/quality/api/v2/ServiceQualityIndicatorMarketResource.kt @@ -27,6 +27,7 @@ package com.tencent.devops.quality.api.v2 +import com.tencent.devops.common.api.constant.IN_READY_TEST import com.tencent.devops.common.api.pojo.Result import com.tencent.devops.quality.api.v2.pojo.op.IndicatorUpdate import io.swagger.annotations.Api @@ -54,6 +55,8 @@ interface ServiceQualityIndicatorMarketResource { userId: String, @QueryParam("atomCode") atomCode: String, + @QueryParam("tag") + tag: String = IN_READY_TEST, indicatorUpdateList: Collection ): Result @@ -71,6 +74,8 @@ interface ServiceQualityIndicatorMarketResource { @DELETE fun deleteTestIndicator( @QueryParam("elementType") - elementType: String + elementType: String, + @QueryParam("extra") + extra: String = IN_READY_TEST ): Result } diff --git a/src/backend/ci/core/quality/api-quality/src/main/kotlin/com/tencent/devops/quality/api/v2/ServiceQualityMetadataMarketResource.kt b/src/backend/ci/core/quality/api-quality/src/main/kotlin/com/tencent/devops/quality/api/v2/ServiceQualityMetadataMarketResource.kt index f1f5b8e0c6d..f04497d7b82 100644 --- a/src/backend/ci/core/quality/api-quality/src/main/kotlin/com/tencent/devops/quality/api/v2/ServiceQualityMetadataMarketResource.kt +++ b/src/backend/ci/core/quality/api-quality/src/main/kotlin/com/tencent/devops/quality/api/v2/ServiceQualityMetadataMarketResource.kt @@ -27,6 +27,7 @@ package com.tencent.devops.quality.api.v2 +import com.tencent.devops.common.api.constant.IN_READY_TEST import com.tencent.devops.common.api.pojo.Result import com.tencent.devops.quality.api.v2.pojo.op.QualityMetaData import io.swagger.annotations.Api @@ -46,7 +47,7 @@ import javax.ws.rs.core.MediaType @Consumes(MediaType.APPLICATION_JSON) interface ServiceQualityMetadataMarketResource { - @ApiOperation("注册插件指标的元数据") + @ApiOperation("注册插件指标的测试元数据") @Path("/setMetadata") @POST fun setTestMetadata( @@ -54,6 +55,8 @@ interface ServiceQualityMetadataMarketResource { userId: String, @QueryParam("atomCode") atomCode: String, + @QueryParam("extra") + extra: String = IN_READY_TEST, metadataList: List ): Result> @@ -70,6 +73,8 @@ interface ServiceQualityMetadataMarketResource { @DELETE fun deleteTestMetadata( @QueryParam("elementType") - elementType: String + elementType: String, + @QueryParam("extra") + extra: String = IN_READY_TEST ): Result } diff --git a/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/dao/v2/QualityControlPointDao.kt b/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/dao/v2/QualityControlPointDao.kt index a1b86856e3d..f40e9b06acd 100644 --- a/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/dao/v2/QualityControlPointDao.kt +++ b/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/dao/v2/QualityControlPointDao.kt @@ -27,6 +27,7 @@ package com.tencent.devops.quality.dao.v2 +import com.tencent.devops.common.api.constant.IN_READY_TEST import com.tencent.devops.common.api.util.HashUtil import com.tencent.devops.common.api.util.PageUtil import com.tencent.devops.model.quality.tables.TQualityControlPoint @@ -63,7 +64,7 @@ class QualityControlPointDao { val sqlLimit = PageUtil.convertPageSizeToSQLLimit(page, pageSize) with(TQualityControlPoint.T_QUALITY_CONTROL_POINT) { return dslContext.selectFrom(this) - .where((TAG.isNull).or(TAG.ne("IN_READY_TEST"))) + .where((TAG.isNull).or(TAG.notContains(IN_READY_TEST))) .orderBy(CREATE_TIME.desc()) .limit(sqlLimit.offset, sqlLimit.limit) .fetch() @@ -82,7 +83,7 @@ class QualityControlPointDao { fun count(dslContext: DSLContext): Long { with(TQualityControlPoint.T_QUALITY_CONTROL_POINT) { return dslContext.selectCount().from(this) - .where((TAG.isNull).or(TAG.ne("IN_READY_TEST"))) + .where((TAG.isNull).or(TAG.notContains(IN_READY_TEST))) .fetchOne(0, Long::class.java)!! } } @@ -110,7 +111,7 @@ class QualityControlPointDao { fun getStages(dslContext: DSLContext): Result> { return with(TQualityControlPoint.T_QUALITY_CONTROL_POINT) { dslContext.select(STAGE).from(this) - .where(STAGE.isNotNull.and(TAG.ne("IN_READY_TEST"))) + .where(STAGE.isNotNull.and(TAG.notContains(IN_READY_TEST))) .groupBy(STAGE) .fetch() } @@ -123,17 +124,22 @@ class QualityControlPointDao { fun getElementNames(dslContext: DSLContext): Result> { return with(TQualityControlPoint.T_QUALITY_CONTROL_POINT) { dslContext.select(ELEMENT_TYPE, NAME).from(this) - .where(NAME.isNotNull.and(TAG.ne("IN_READY_TEST"))) + .where(NAME.isNotNull.and(TAG.notContains(IN_READY_TEST))) .groupBy(ELEMENT_TYPE, NAME) .fetch() } } - fun setTestControlPoint(dslContext: DSLContext, userId: String, controlPoint: QualityControlPoint): Long { + fun setTestControlPoint( + dslContext: DSLContext, + userId: String, + tag: String, + controlPoint: QualityControlPoint + ): Long { var pointId = 0L with(TQualityControlPoint.T_QUALITY_CONTROL_POINT) { val testControlPoint = dslContext.selectFrom(this) - .where(ELEMENT_TYPE.eq(controlPoint.type).and(TAG.eq("IN_READY_TEST"))) + .where(ELEMENT_TYPE.eq(controlPoint.type).and(TAG.eq(tag))) .fetchOne() if (testControlPoint != null) { dslContext.update(this) @@ -177,7 +183,7 @@ class QualityControlPointDao { LocalDateTime.now(), controlPoint.atomVersion, controlPoint.testProject, - "IN_READY_TEST" + tag ).returning(ID).fetchOne()!!.id val hashId = HashUtil.encodeLongId(pointId) dslContext.update(this) @@ -197,8 +203,8 @@ class QualityControlPointDao { .where(ELEMENT_TYPE.eq(elementType)) .fetch() - val testControlPoint = controlPoints.firstOrNull { it.tag == "IN_READY_TEST" } - val prodControlPoint = controlPoints.firstOrNull { it.tag != "IN_READY_TEST" } + val testControlPoint = controlPoints.firstOrNull { it.tag == IN_READY_TEST } + val prodControlPoint = controlPoints.firstOrNull { it.tag != IN_READY_TEST } // 测试为空,代表quality.json被删了,直接把生产的也删了 if (testControlPoint == null) { @@ -227,10 +233,10 @@ class QualityControlPointDao { return 0 } - fun deleteTestControlPoint(dslContext: DSLContext, elementType: String): Int { + fun deleteTestControlPoint(dslContext: DSLContext, elementType: String, tag: String): Int { return with(TQualityControlPoint.T_QUALITY_CONTROL_POINT) { dslContext.deleteFrom(this) - .where(ELEMENT_TYPE.eq(elementType).and(TAG.eq("IN_READY_TEST"))) + .where(ELEMENT_TYPE.eq(elementType).and(TAG.eq(tag))) .execute() } } diff --git a/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/resources/v2/ServiceQualityControlPointMarketResourceImpl.kt b/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/resources/v2/ServiceQualityControlPointMarketResourceImpl.kt index b707dec692e..339d526fdfc 100644 --- a/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/resources/v2/ServiceQualityControlPointMarketResourceImpl.kt +++ b/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/resources/v2/ServiceQualityControlPointMarketResourceImpl.kt @@ -39,15 +39,15 @@ class ServiceQualityControlPointMarketResourceImpl @Autowired constructor( private val controlPointService: QualityControlPointService ) : ServiceQualityControlPointMarketResource { - override fun setTestControlPoint(userId: String, controlPoint: QualityControlPoint): Result { - return Result(controlPointService.setTestControlPoint(userId, controlPoint)) + override fun setTestControlPoint(userId: String, tag: String, controlPoint: QualityControlPoint): Result { + return Result(controlPointService.setTestControlPoint(userId, tag, controlPoint)) } override fun refreshControlPoint(elementType: String): Result { return Result(controlPointService.refreshControlPoint(elementType)) } - override fun deleteTestControlPoint(elementType: String): Result { - return Result(controlPointService.deleteTestControlPoint(elementType)) + override fun deleteTestControlPoint(elementType: String, tag: String): Result { + return Result(controlPointService.deleteTestControlPoint(elementType, tag)) } } diff --git a/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/resources/v2/ServiceQualityIndicatorMarketResourceImpl.kt b/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/resources/v2/ServiceQualityIndicatorMarketResourceImpl.kt index a245b0118b5..3e04cb20a06 100644 --- a/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/resources/v2/ServiceQualityIndicatorMarketResourceImpl.kt +++ b/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/resources/v2/ServiceQualityIndicatorMarketResourceImpl.kt @@ -41,16 +41,22 @@ class ServiceQualityIndicatorMarketResourceImpl @Autowired constructor( override fun setTestIndicator( userId: String, atomCode: String, + tag: String, indicatorUpdateList: Collection ): Result { - return Result(qualityIndicatorService.setTestIndicator(userId, atomCode, indicatorUpdateList)) + return Result(qualityIndicatorService.setTestIndicator( + userId = userId, + elementType = atomCode, + tag = tag, + indicatorUpdateList = indicatorUpdateList + )) } override fun refreshIndicator(elementType: String, metadataMap: Map): Result { return Result(qualityIndicatorService.serviceRefreshIndicator(elementType, metadataMap)) } - override fun deleteTestIndicator(elementType: String): Result { - return Result(qualityIndicatorService.serviceDeleteTestIndicator(elementType)) + override fun deleteTestIndicator(elementType: String, extra: String): Result { + return Result(qualityIndicatorService.serviceDeleteTestIndicator(elementType, extra)) } } diff --git a/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/resources/v2/ServiceQualityMetadataMarketResourceImpl.kt b/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/resources/v2/ServiceQualityMetadataMarketResourceImpl.kt index 41c21242058..1f657c46b88 100644 --- a/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/resources/v2/ServiceQualityMetadataMarketResourceImpl.kt +++ b/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/resources/v2/ServiceQualityMetadataMarketResourceImpl.kt @@ -41,16 +41,22 @@ class ServiceQualityMetadataMarketResourceImpl @Autowired constructor( override fun setTestMetadata( userId: String, atomCode: String, + extra: String, metadataList: List ): Result> { - return Result(qualityMetadataService.serviceSetTestMetadata(userId, atomCode, metadataList)) + return Result(qualityMetadataService.serviceSetTestMetadata( + userId = userId, + elementType = atomCode, + extra = extra, + metadataList = metadataList + )) } override fun refreshMetadata(elementType: String): Result> { return Result(qualityMetadataService.serviceRefreshMetadata(elementType)) } - override fun deleteTestMetadata(elementType: String): Result { - return Result(qualityMetadataService.serviceDeleteTestMetadata(elementType)) + override fun deleteTestMetadata(elementType: String, extra: String): Result { + return Result(qualityMetadataService.serviceDeleteTestMetadata(elementType, extra)) } } diff --git a/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/service/v2/QualityControlPointService.kt b/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/service/v2/QualityControlPointService.kt index 89ceda93a86..04cd379569e 100644 --- a/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/service/v2/QualityControlPointService.kt +++ b/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/service/v2/QualityControlPointService.kt @@ -113,13 +113,11 @@ class QualityControlPointService @Autowired constructor( ): List? { val filterResult = mutableListOf() // 获取生产跑的,或者测试项目对应的 - controlPointRecords.groupBy { it.elementType }.forEach { elementType, list -> - val testControlPoint = list.firstOrNull { it.testProject == projectId } - val prodControlPoint = list.firstOrNull { it.testProject.isNullOrBlank() } - if (testControlPoint != null) { - filterResult.add(testControlPoint) + controlPointRecords.forEach { + if (it.testProject == projectId) { + filterResult.add(it) } else { - if (prodControlPoint != null) filterResult.add(prodControlPoint) + if (it.testProject.isNullOrBlank()) filterResult.add(it) } } return filterResult @@ -235,9 +233,14 @@ class QualityControlPointService @Autowired constructor( return controlPoint != null && controlPoint.atomVersion <= atomVersion } - fun setTestControlPoint(userId: String, controlPoint: QualityControlPoint): Long { - logger.info("QUALITY|setTestControlPoint userId: $userId, controlPoint: ${controlPoint.type}") - return controlPointDao.setTestControlPoint(dslContext, userId, controlPoint) + fun setTestControlPoint(userId: String, tag: String, controlPoint: QualityControlPoint): Long { + logger.info("QUALITY|setTestControlPoint userId: $userId, controlPoint: ${controlPoint.type} | tag:$tag") + return controlPointDao.setTestControlPoint( + dslContext = dslContext, + userId = userId, + controlPoint = controlPoint, + tag = tag + ) } fun refreshControlPoint(elementType: String): Int { @@ -245,9 +248,9 @@ class QualityControlPointService @Autowired constructor( return controlPointDao.refreshControlPoint(dslContext, elementType) } - fun deleteTestControlPoint(elementType: String): Int { - logger.info("QUALITY|deleteTestControlPoint controlPoint: $elementType") - return controlPointDao.deleteTestControlPoint(dslContext, elementType) + fun deleteTestControlPoint(elementType: String, tag: String): Int { + logger.info("QUALITY|deleteTestControlPoint controlPoint: $elementType | tag:$tag") + return controlPointDao.deleteTestControlPoint(dslContext, elementType, tag) } fun deleteControlPoint(id: Long): Int { diff --git a/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/service/v2/QualityIndicatorService.kt b/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/service/v2/QualityIndicatorService.kt index 1c785807ed5..294cfa06b7e 100644 --- a/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/service/v2/QualityIndicatorService.kt +++ b/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/service/v2/QualityIndicatorService.kt @@ -30,6 +30,7 @@ package com.tencent.devops.quality.service.v2 import com.fasterxml.jackson.core.type.TypeReference import com.google.common.collect.Maps import com.tencent.devops.common.api.constant.DEVELOP +import com.tencent.devops.common.api.constant.IN_READY_TEST import com.tencent.devops.common.api.exception.OperationException import com.tencent.devops.common.api.pojo.Page import com.tencent.devops.common.api.util.HashUtil @@ -515,10 +516,15 @@ class QualityIndicatorService @Autowired constructor( return convertRecord(record, metadata) } - fun setTestIndicator(userId: String, elementType: String, indicatorUpdateList: Collection): Int { + fun setTestIndicator( + userId: String, + elementType: String, + tag: String, + indicatorUpdateList: Collection + ): Int { logger.info("QUALITY|setTestIndicator userId: $userId, elementType: $elementType") val testIndicatorList = indicatorDao.listByElementType(dslContext, elementType, IndicatorType.MARKET) - ?.filter { isTestIndicator(it) } ?: listOf() + ?.filter { isTestIndicator(tag, it) } ?: listOf() val testIndicatorMap = testIndicatorList.map { it.enName to it }.toMap() val lastIndicatorName = testIndicatorList.map { it.enName } val newIndicatorName = indicatorUpdateList.map { it.enName } @@ -544,8 +550,8 @@ class QualityIndicatorService @Autowired constructor( fun serviceRefreshIndicator(elementType: String, metadataMap: Map): Int { logger.info("QUALITY|refreshIndicator elementType: $elementType") val data = indicatorDao.listByElementType(dslContext, elementType, IndicatorType.MARKET) - val testData = data?.filter { isTestIndicator(it) } ?: listOf() - val prodData = data?.filter { !isTestIndicator(it) } ?: listOf() + val testData = data?.filter { isTestIndicator(IN_READY_TEST, it) } ?: listOf() + val prodData = data?.filter { !isTestIndicator(IN_READY_TEST, it) } ?: listOf() val userId = testData.firstOrNull()?.createUser ?: "" // 有则update @@ -615,10 +621,10 @@ class QualityIndicatorService @Autowired constructor( return testData.size } - fun serviceDeleteTestIndicator(elementType: String): Int { + fun serviceDeleteTestIndicator(elementType: String, extra: String): Int { logger.info("QUALITY|deleteTestIndicator elementType: $elementType") val data = indicatorDao.listByElementType(dslContext, elementType) - val testData = data?.filter { isTestIndicator(it) } ?: listOf() + val testData = data?.filter { isTestIndicator(extra, it) } ?: listOf() return indicatorDao.delete(testData.map { it.id }, dslContext) } @@ -649,8 +655,8 @@ class QualityIndicatorService @Autowired constructor( return result.filter { it.enable } } - private fun isTestIndicator(qualityIndicator: TQualityIndicatorRecord): Boolean { - return qualityIndicator.type == IndicatorType.MARKET.name && qualityIndicator.tag == "IN_READY_TEST" + private fun isTestIndicator(tag: String, qualityIndicator: TQualityIndicatorRecord): Boolean { + return qualityIndicator.type == IndicatorType.MARKET.name && qualityIndicator.tag == tag } private fun convertRecord( @@ -872,4 +878,8 @@ class QualityIndicatorService @Autowired constructor( "BKCHECK-CPP" to I18nUtil.getCodeLanMessage(BK_TOOL_NAME_BKCHECK_CPP), "BKCHECK-OC" to I18nUtil.getCodeLanMessage(BK_TOOL_NAME_BKCHECK_OC)) } + + private fun isTestIndicator(qualityIndicator: TQualityIndicatorRecord): Boolean { + return qualityIndicator.type == IndicatorType.MARKET.name && qualityIndicator.tag.startsWith(IN_READY_TEST) + } } diff --git a/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/service/v2/QualityMetadataService.kt b/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/service/v2/QualityMetadataService.kt index 5309c9dbefc..b1b3dcddd23 100644 --- a/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/service/v2/QualityMetadataService.kt +++ b/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/service/v2/QualityMetadataService.kt @@ -28,6 +28,7 @@ package com.tencent.devops.quality.service.v2 import com.fasterxml.jackson.core.type.TypeReference +import com.tencent.devops.common.api.constant.IN_READY_TEST import com.tencent.devops.common.api.pojo.Page import com.tencent.devops.common.api.util.HashUtil import com.tencent.devops.common.api.util.JsonUtil @@ -185,10 +186,11 @@ class QualityMetadataService @Autowired constructor( fun serviceSetTestMetadata( userId: String, elementType: String, + extra: String, metadataList: List ): Map { logger.info("QUALITY|setTestMetadata userId: $userId, elementType: $elementType") - val data = metadataDao.listByElementType(dslContext, elementType)?.filter { it.extra == "IN_READY_TEST" } + val data = metadataDao.listByElementType(dslContext, elementType)?.filter { it.extra == extra } val lastMetadataIdMap = data?.map { it.dataId to it.id }?.toMap() ?: mapOf() val newDataId = metadataList.map { it.dataId!! } val lastDataId = lastMetadataIdMap.keys @@ -213,8 +215,8 @@ class QualityMetadataService @Autowired constructor( fun serviceRefreshMetadata(elementType: String): Map { logger.info("QUALITY|refreshMetadata elementType: $elementType") val data = metadataDao.listByElementType(dslContext, elementType) - val testData = data?.filter { it.extra == "IN_READY_TEST" } ?: listOf() - val prodData = data?.filter { it.extra != "IN_READY_TEST" } ?: listOf() + val testData = data?.filter { it.extra == IN_READY_TEST } ?: listOf() + val prodData = data?.filter { it.extra != IN_READY_TEST } ?: listOf() val userId = testData.firstOrNull()?.createUser ?: "" val resultMap = mutableMapOf() @@ -266,10 +268,10 @@ class QualityMetadataService @Autowired constructor( return resultMap } - fun serviceDeleteTestMetadata(elementType: String): Int { - logger.info("QUALITY|deleteTestMetadata elementType: $elementType") + fun serviceDeleteTestMetadata(elementType: String, extra: String): Int { + logger.info("QUALITY|deleteTestMetadata elementType: $elementType | extra:$extra") val data = metadataDao.listByElementType(dslContext, elementType) - val testData = data?.filter { it.extra == "IN_READY_TEST" } ?: listOf() + val testData = data?.filter { it.extra == extra } ?: listOf() return metadataDao.delete(testData.map { it.id }, dslContext) } diff --git a/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/api/atom/BuildAtomResource.kt b/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/api/atom/BuildAtomResource.kt index 7fbd840fb64..d1341737c90 100644 --- a/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/api/atom/BuildAtomResource.kt +++ b/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/api/atom/BuildAtomResource.kt @@ -27,16 +27,22 @@ package com.tencent.devops.store.api.atom +import com.tencent.devops.common.api.auth.AUTH_HEADER_USER_ID import com.tencent.devops.common.api.pojo.Result +import com.tencent.devops.store.pojo.atom.MarketAtomUpdateRequest +import com.tencent.devops.store.pojo.common.StoreProcessInfo import com.tencent.devops.store.pojo.common.VersionInfo import io.swagger.annotations.Api import io.swagger.annotations.ApiOperation import io.swagger.annotations.ApiParam import javax.ws.rs.Consumes import javax.ws.rs.GET +import javax.ws.rs.HeaderParam +import javax.ws.rs.POST import javax.ws.rs.Path import javax.ws.rs.PathParam import javax.ws.rs.Produces +import javax.ws.rs.QueryParam import javax.ws.rs.core.MediaType @Api(tags = ["BUILD_PIPELINE_ATOM"], description = "流水线-插件") @@ -56,4 +62,42 @@ interface BuildAtomResource { @PathParam("atomCode") atomCode: String ): Result + + @ApiOperation("使用分支创建插件测试版本") + @POST + @Path("/test/version/create") + fun createAtomBranchTestVersion( + @ApiParam("userId", required = true) + @HeaderParam(AUTH_HEADER_USER_ID) + userId: String, + @ApiParam("新增插件请求报文体", required = true) + marketAtomUpdateRequest: MarketAtomUpdateRequest + ): Result + + @ApiOperation("结束插件分支测试版本测试") + @GET + @Path("/atoms/{atomCode}/test/version/end") + fun endBranchVersionTest( + @ApiParam("userId", required = true) + @HeaderParam(AUTH_HEADER_USER_ID) + userId: String, + @ApiParam("插件分支", required = true) + @PathParam("atomCode") + atomCode: String, + @ApiParam("插件分支", required = true) + @QueryParam("branch") + branch: String + ): Result + + @ApiOperation("根据插件版本ID获取插件版本进度") + @GET + @Path("/desk/atom/release/ids/{atomId}") + fun getProcessInfo( + @ApiParam("userId", required = true) + @HeaderParam(AUTH_HEADER_USER_ID) + userId: String, + @ApiParam("atomId", required = true) + @PathParam("atomId") + atomId: String + ): Result } diff --git a/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/constant/StoreMessageCode.kt b/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/constant/StoreMessageCode.kt index 067bd913a06..b7fb40a045c 100644 --- a/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/constant/StoreMessageCode.kt +++ b/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/constant/StoreMessageCode.kt @@ -150,6 +150,9 @@ object StoreMessageCode { const val BUILD_VISIT_NO_PERMISSION = "2120923" // 接口请求中的插件【{0}】不是当前当前构建运行的插件 const val VERSION_PUBLISHED = "2120924" // 组件{0}版本({1})已发布 const val NO_COMPONENT_ADMIN_AND_CREATETOR_PERMISSION = "2120925" // 无组件{0}管理员或当前版本创建者权限,请联系组件管理员。 + const val USER_NOT_IS_STORE_MEMBER = "2120926" // 研发商店:用户{0}不是组件成员 + const val GET_BRANCH_COMMIT_INFO_ERROR = "2120927" // 获取分支提交信息异常 + const val STORE_BRANCH_NO_NEW_COMMIT = "2120928" // 代码未变更,分支测试版本生成失败 const val BK_OTHER = "bkOther" // 其他 const val BK_PIPELINED_JOB = "bkPipelinedJob" // 流水线Job diff --git a/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/atom/MarketAtomUpdateRequest.kt b/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/atom/MarketAtomUpdateRequest.kt index aa91648f4f1..b15eb881091 100644 --- a/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/atom/MarketAtomUpdateRequest.kt +++ b/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/atom/MarketAtomUpdateRequest.kt @@ -57,7 +57,7 @@ data class MarketAtomUpdateRequest( @ApiModelProperty("logo地址", required = false) val logoUrl: String?, @ApiModelProperty("版本号", required = true) - val version: String, + var version: String, @ApiModelProperty( "发布类型,NEW:新上架 INCOMPATIBILITY_UPGRADE:非兼容性升级 COMPATIBILITY_UPGRADE:兼容性功能更新 COMPATIBILITY_FIX:兼容性问题修正", required = true @@ -74,5 +74,7 @@ data class MarketAtomUpdateRequest( @ApiModelProperty(value = "插件字段校验确认标识", required = false) val fieldCheckConfirmFlag: Boolean? = false, @ApiModelProperty("分支", required = false) - val branch: String? = null + val branch: String? = null, + @ApiModelProperty("是否属于分支测试版本", required = false) + var isBranchTestVersion: Boolean = false ) diff --git a/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/atom/UpdateAtomPackageInfo.kt b/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/atom/UpdateAtomPackageInfo.kt new file mode 100644 index 00000000000..ead4559f600 --- /dev/null +++ b/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/atom/UpdateAtomPackageInfo.kt @@ -0,0 +1,44 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.tencent.devops.store.pojo.atom + +import com.tencent.devops.store.pojo.common.enums.PackageSourceTypeEnum +import io.swagger.annotations.ApiModel +import io.swagger.annotations.ApiModelProperty + +@ApiModel("升级插件包信息") +data class UpdateAtomPackageInfo( + @ApiModelProperty("插件ID") + val atomId: String, + @ApiModelProperty("国际化资源目录路径") + val i18nDir: String, + @ApiModelProperty("包路径") + val packagePath: String?, + @ApiModelProperty("插件包资源类型") + val atomPackageSourceType: PackageSourceTypeEnum +) diff --git a/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/atom/enums/AtomStatusEnum.kt b/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/atom/enums/AtomStatusEnum.kt index bfae30d3e73..dd8fc20485e 100644 --- a/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/atom/enums/AtomStatusEnum.kt +++ b/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/atom/enums/AtomStatusEnum.kt @@ -41,7 +41,8 @@ enum class AtomStatusEnum(val status: Int) { UNDERCARRIAGING(9), // 下架中 UNDERCARRIAGED(10), // 已下架 CODECCING(11), // 代码检查中 - CODECC_FAIL(12); // 代码检查失败 + CODECC_FAIL(12), // 代码检查失败 + TESTED(13); // 测试结束(仅分支测试使用) companion object { diff --git a/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/common/StoreConstants.kt b/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/common/StoreConstants.kt index c2ae548dbce..1951eb9134b 100644 --- a/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/common/StoreConstants.kt +++ b/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/common/StoreConstants.kt @@ -67,6 +67,7 @@ const val ATOM_NAMESPACE = "namespace" // 插件命名空间 const val ATOM_UPLOAD_ID_KEY_PREFIX = "ATOM_UPLOAD_ID" // 插件包上传ID值Key前缀 const val STORE_PUBLIC_FLAG_KEY_PREFIX = "STORE_PUBLIC_FLAG_KEY" // 公共组件Key前缀 const val STORE_NORMAL_PROJECT_RUN_INFO_KEY_PREFIX = "STORE_NORMAL_PROJECT_RUN_INFO_KEY" // 组件对应普通项目的运行时信息Key前缀 +const val STORE_LATEST_TEST_FLAG_KEY_PREFIX = "STORE_LATEST_TEST_FLAG" const val SERVICE_COLLABORATOR_APPLY_MOA_TEMPLATE = "SERIVCE_COLLABORATOR_APPLY_MOA_TEMPLATE" // 扩展服务协作开发申请MOA审批消息通知模板 const val SERVICE_COLLABORATOR_APPLY_REFUSE_TEMPLATE = "SERIVCE_COLLABORATOR_APPLY_REFUSE" // 扩展服务协作开发申请被拒的消息通知模板 diff --git a/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/atom/StoreI18nConfig.kt b/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/common/StoreI18nConfig.kt similarity index 93% rename from src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/atom/StoreI18nConfig.kt rename to src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/common/StoreI18nConfig.kt index c1380c78177..21db2947634 100644 --- a/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/atom/StoreI18nConfig.kt +++ b/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/common/StoreI18nConfig.kt @@ -25,7 +25,7 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.tencent.devops.store.pojo.atom +package com.tencent.devops.store.pojo.common import io.swagger.annotations.ApiModel import io.swagger.annotations.ApiModelProperty @@ -45,5 +45,7 @@ data class StoreI18nConfig( @ApiModelProperty("map字段在db中key的前缀") val dbKeyPrefix: String? = null, @ApiModelProperty("代码库哈希ID") - val repositoryHashId: String? = null + val repositoryHashId: String? = null, + @ApiModelProperty("代码库分支") + val branch: String? = null ) diff --git a/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/common/enums/ReleaseTypeEnum.kt b/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/common/enums/ReleaseTypeEnum.kt index ed92dcb299a..1e648311a53 100644 --- a/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/common/enums/ReleaseTypeEnum.kt +++ b/src/backend/ci/core/store/api-store/src/main/kotlin/com/tencent/devops/store/pojo/common/enums/ReleaseTypeEnum.kt @@ -33,7 +33,8 @@ enum class ReleaseTypeEnum(val releaseType: Int) { COMPATIBILITY_UPGRADE(2), // 兼容性功能更新 COMPATIBILITY_FIX(3), // 兼容性问题修正 CANCEL_RE_RELEASE(4), // 取消发布后重新发布 - HIS_VERSION_UPGRADE(5); // 历史大版本下的小版本更新 + HIS_VERSION_UPGRADE(5), // 历史大版本下的小版本更新 + BRANCH_TEST(6); // 分支测试 fun isDefaultShow(): Boolean = this == COMPATIBILITY_UPGRADE || this == COMPATIBILITY_FIX diff --git a/src/backend/ci/core/store/biz-store-sample/src/main/kotlin/com/tencent/devops/store/service/atom/impl/SampleAtomReleaseServiceImpl.kt b/src/backend/ci/core/store/biz-store-sample/src/main/kotlin/com/tencent/devops/store/service/atom/impl/SampleAtomReleaseServiceImpl.kt index 00d3afed22c..7ae9503de5a 100644 --- a/src/backend/ci/core/store/biz-store-sample/src/main/kotlin/com/tencent/devops/store/service/atom/impl/SampleAtomReleaseServiceImpl.kt +++ b/src/backend/ci/core/store/biz-store-sample/src/main/kotlin/com/tencent/devops/store/service/atom/impl/SampleAtomReleaseServiceImpl.kt @@ -42,7 +42,6 @@ import com.tencent.devops.common.api.constant.TEST import com.tencent.devops.common.api.constant.UNDO import com.tencent.devops.common.api.pojo.Result import com.tencent.devops.common.web.utils.I18nUtil -import com.tencent.devops.model.store.tables.records.TAtomRecord import com.tencent.devops.store.constant.StoreMessageCode import com.tencent.devops.store.constant.StoreMessageCode.NO_COMPONENT_ADMIN_AND_CREATETOR_PERMISSION import com.tencent.devops.store.pojo.atom.AtomReleaseRequest @@ -95,7 +94,7 @@ class SampleAtomReleaseServiceImpl : SampleAtomReleaseService, AtomReleaseServic override fun validateUpdateMarketAtomReq( userId: String, marketAtomUpdateRequest: MarketAtomUpdateRequest, - atomRecord: TAtomRecord + repositoryHashId: String? ): Result { // 开源版升级插件暂无特殊参数需要校验 return Result(true) @@ -219,4 +218,15 @@ class SampleAtomReleaseServiceImpl : SampleAtomReleaseService, AtomReleaseServic return if (validateFlag) Triple(true, "", null) else Triple(false, StoreMessageCode.USER_ATOM_RELEASE_STEPS_ERROR, null) } + + override fun creatAtomBranchTestVersion( + userId: String, + marketAtomUpdateRequest: MarketAtomUpdateRequest + ): Result = Result("") + + override fun endBranchVersionTest( + userId: String, + atomCode: String, + branch: String + ): Result = Result(true) } diff --git a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/dao/atom/AtomBaseDao.kt b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/dao/atom/AtomBaseDao.kt index 86ba45bfa14..54c245b2a19 100644 --- a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/dao/atom/AtomBaseDao.kt +++ b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/dao/atom/AtomBaseDao.kt @@ -74,10 +74,10 @@ abstract class AtomBaseDao { } } - fun getNewestAtomByCode(dslContext: DSLContext, atomCode: String): TAtomRecord? { + fun getNewestAtomByCode(dslContext: DSLContext, atomCode: String, branchTestFlag: Boolean = false): TAtomRecord? { return with(TAtom.T_ATOM) { dslContext.selectFrom(this) - .where(ATOM_CODE.eq(atomCode)) + .where(ATOM_CODE.eq(atomCode).and(BRANCH_TEST_FLAG.eq(branchTestFlag))) .orderBy(CREATE_TIME.desc()) .limit(1) .fetchOne() diff --git a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/dao/atom/AtomDao.kt b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/dao/atom/AtomDao.kt index ae1bf703dc3..7b70f8d0e80 100644 --- a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/dao/atom/AtomDao.kt +++ b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/dao/atom/AtomDao.kt @@ -29,6 +29,7 @@ package com.tencent.devops.store.dao.atom import com.tencent.devops.common.api.constant.INIT_VERSION import com.tencent.devops.common.api.constant.KEY_ALL +import com.tencent.devops.common.api.constant.KEY_BRANCH_TEST_FLAG import com.tencent.devops.common.api.constant.KEY_DESCRIPTION import com.tencent.devops.common.api.constant.KEY_DOCSLINK import com.tencent.devops.common.api.constant.KEY_OS @@ -260,6 +261,16 @@ class AtomDao : AtomBaseDao() { } } + fun getAtomByVersionPrefix(dslContext: DSLContext, atomCode: String, versionPrefix: String): TAtomRecord? { + return with(TAtom.T_ATOM) { + dslContext.selectFrom(this) + .where(ATOM_CODE.eq(atomCode).and(VERSION.startsWith(versionPrefix))) + .orderBy(UPDATE_TIME.desc()) + .limit(1) + .fetchOne() + } + } + fun getPipelineAtom( dslContext: DSLContext, atomCode: String, @@ -331,6 +342,7 @@ class AtomDao : AtomBaseDao() { ): MutableList { val conditions = mutableListOf() conditions.add(tAtom.ATOM_CODE.eq(atomCode)) + conditions.add(tAtom.ATOM_STATUS.notEqual(AtomStatusEnum.TESTED.status.toByte())) if (version != null) { conditions.add(tAtom.VERSION.like(VersionUtils.generateQueryVersion(version))) } @@ -470,7 +482,8 @@ class AtomDao : AtomBaseDao() { val tStoreProjectRel = TStoreProjectRel.T_STORE_PROJECT_REL val baseStep = dslContext.select( tAtom.VERSION.`as`(KEY_VERSION), - tAtom.ATOM_STATUS.`as`(KEY_ATOM_STATUS) + tAtom.ATOM_STATUS.`as`(KEY_ATOM_STATUS), + tAtom.BRANCH_TEST_FLAG.`as`(KEY_BRANCH_TEST_FLAG) ).from(tAtom) val t = if (defaultFlag) { val conditions = generateGetPipelineAtomCondition( @@ -512,14 +525,21 @@ class AtomDao : AtomBaseDao() { delim = ".", count = -1 ) + val branchTestFlagField = t.field(KEY_BRANCH_TEST_FLAG) as Field val queryStep = dslContext.select( t.field(KEY_VERSION), t.field(KEY_ATOM_STATUS), firstVersion, secondVersion, - thirdVersion + thirdVersion, + branchTestFlagField ).from(t) - .orderBy(firstVersion.plus(0).desc(), secondVersion.plus(0).desc(), thirdVersion.plus(0).desc()) + .orderBy( + branchTestFlagField.desc(), + firstVersion.plus(0).desc(), + secondVersion.plus(0).desc(), + thirdVersion.plus(0).desc() + ) limitNum?.let { queryStep.limit(it) } return queryStep.skipCheck().fetch() } @@ -624,6 +644,7 @@ class AtomDao : AtomBaseDao() { getPipelineAtomBaseStep(dslContext, ta, tc, taf, tst).where(defaultAtomCondition) ) if (queryInitTestAtomStep != null && initTestAtomCondition != null) { + initTestAtomCondition.add(ta.LATEST_TEST_FLAG.eq(true)) queryAtomStep.union( getPipelineAtomBaseStep(dslContext, ta, tc, taf, tst) .join(tspr) @@ -676,6 +697,7 @@ class AtomDao : AtomBaseDao() { ta.BUILD_LESS_RUN_FLAG.`as`(KEY_BUILD_LESS_RUN_FLAG), ta.WEIGHT.`as`(KEY_WEIGHT), ta.HTML_TEMPLATE_VERSION.`as`(KEY_HTML_TEMPLATE_VERSION), + ta.BRANCH_TEST_FLAG.`as`(KEY_BRANCH_TEST_FLAG), taf.RECOMMEND_FLAG.`as`(KEY_RECOMMEND_FLAG), tsst.SCORE_AVERAGE.`as`(KEY_AVG_SCORE), tsst.RECENT_EXECUTE_NUM.`as`(KEY_RECENT_EXECUTE_NUM), @@ -785,6 +807,7 @@ class AtomDao : AtomBaseDao() { .where(defaultAtomCondition).fetchOne(0, Long::class.java)!! val normalAtomCount = queryNormalAtomStep.where(normalAtomConditions).fetchOne(0, Long::class.java)!! val initTestAtomCount = if (initTestAtomCondition != null && queryInitTestAtomStep != null) { + initTestAtomCondition.add(ta.LATEST_TEST_FLAG.eq(true)) queryInitTestAtomStep.where(initTestAtomCondition).fetchOne(0, Long::class.java)!! } else { 0 diff --git a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/dao/atom/MarketAtomDao.kt b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/dao/atom/MarketAtomDao.kt index 37b9ea09d72..6576304ddff 100644 --- a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/dao/atom/MarketAtomDao.kt +++ b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/dao/atom/MarketAtomDao.kt @@ -48,6 +48,8 @@ import com.tencent.devops.store.pojo.atom.enums.AtomTypeEnum import com.tencent.devops.store.pojo.atom.enums.MarketAtomSortTypeEnum import com.tencent.devops.store.pojo.common.enums.StoreTypeEnum import com.tencent.devops.store.utils.VersionUtils +import java.math.BigDecimal +import java.time.LocalDateTime import org.jooq.Condition import org.jooq.DSLContext import org.jooq.Record @@ -56,8 +58,6 @@ import org.jooq.SelectOnConditionStep import org.jooq.UpdateSetFirstStep import org.jooq.impl.DSL import org.springframework.stereotype.Repository -import java.math.BigDecimal -import java.time.LocalDateTime @Suppress("ALL") @Repository @@ -509,7 +509,8 @@ class MarketAtomDao : AtomBaseDao() { PUBLISHER, WEIGHT, CREATOR, - MODIFIER + MODIFIER, + BRANCH_TEST_FLAG ) .values(id, atomRequest.name, @@ -542,7 +543,8 @@ class MarketAtomDao : AtomBaseDao() { atomRequest.publisher, atomRecord.weight, userId, - userId + userId, + atomRequest.isBranchTestVersion ) .execute() } @@ -579,6 +581,7 @@ class MarketAtomDao : AtomBaseDao() { return with(TAtom.T_ATOM) { val baseStep = dslContext.selectFrom(this) .where(ATOM_CODE.eq(atomCode)) + .and(BRANCH_TEST_FLAG.eq(false)) .orderBy(CREATE_TIME.desc()) if (null != page && null != pageSize) { baseStep.limit((page - 1) * pageSize, pageSize).fetch() @@ -611,6 +614,21 @@ class MarketAtomDao : AtomBaseDao() { } } + fun getAtomBranchTestVersion( + dslContext: DSLContext, + atomCode: String, + versionPrefix: String + ): TAtomRecord? { + with(TAtom.T_ATOM) { + return dslContext.selectFrom(this) + .where(ATOM_CODE.eq(atomCode)) + .and(VERSION.startsWith(versionPrefix)) + .and(ATOM_STATUS.eq(AtomStatusEnum.TESTING.status.toByte())) + .orderBy(UPDATE_TIME.desc()) + .fetchOne() + } + } + fun getAtomById(dslContext: DSLContext, atomId: String): Record? { val tAtom = TAtom.T_ATOM val tAtomVersionLog = TAtomVersionLog.T_ATOM_VERSION_LOG @@ -713,6 +731,39 @@ class MarketAtomDao : AtomBaseDao() { } } + fun setupAtomLatestTestFlag(dslContext: DSLContext, userId: String, atomCode: String, atomId: String) { + with(TAtom.T_ATOM) { + dslContext.update(this) + .set( + LATEST_TEST_FLAG, + DSL.case_().`when`(ID.eq(atomId), true).otherwise(false) + ) + .set(MODIFIER, userId) + .where(ATOM_CODE.eq(atomCode)) + .execute() + } + } + + fun queryAtomLatestTestVersionId(dslContext: DSLContext, atomCode: String): String? { + with(TAtom.T_ATOM) { + return dslContext.select(ID).from(this) + .where(ATOM_CODE.eq(atomCode)) + .and(ATOM_STATUS.`in`( + listOf(AtomStatusEnum.TESTING.status.toByte(), AtomStatusEnum.AUDITING.status.toByte()) + )) + .orderBy(UPDATE_TIME.desc()) + .limit(1) + .fetchOne(0, String::class.java) + } + } + + fun isAtomLatestTestVersion(dslContext: DSLContext, atomId: String): Int { + with(TAtom.T_ATOM) { + return dslContext.select(ID).from(this) + .where(ID.eq(atomId).and(LATEST_TEST_FLAG.eq(true))).execute() + } + } + fun updateAtomInfoByCode(dslContext: DSLContext, userId: String, atomCode: String, updateAtomInfo: UpdateAtomInfo) { with(TAtom.T_ATOM) { val baseStep = dslContext.update(this) diff --git a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/dao/atom/MarketAtomVersionLogDao.kt b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/dao/atom/MarketAtomVersionLogDao.kt index 9dc116b8952..9d39243ea03 100644 --- a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/dao/atom/MarketAtomVersionLogDao.kt +++ b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/dao/atom/MarketAtomVersionLogDao.kt @@ -31,10 +31,11 @@ import com.tencent.devops.common.api.util.UUIDUtil import com.tencent.devops.model.store.tables.TAtom import com.tencent.devops.model.store.tables.TAtomVersionLog import com.tencent.devops.model.store.tables.records.TAtomVersionLogRecord +import com.tencent.devops.store.pojo.common.enums.ReleaseTypeEnum +import java.time.LocalDateTime import org.jooq.DSLContext import org.jooq.Result import org.springframework.stereotype.Repository -import java.time.LocalDateTime @Suppress("ALL") @Repository @@ -81,11 +82,18 @@ class MarketAtomVersionLogDao { } } - fun getAtomVersions(dslContext: DSLContext, atomIds: List): Result? { + fun getAtomVersions( + dslContext: DSLContext, + atomIds: List, + getTestVersionFlag: Boolean = false + ): Result? { with(TAtomVersionLog.T_ATOM_VERSION_LOG) { - return dslContext.selectFrom(this) + val step = dslContext.selectFrom(this) .where(ATOM_ID.`in`(atomIds)) - .fetch() + val conditionStep = if (!getTestVersionFlag) { + step.and(RELEASE_TYPE.notEqual(ReleaseTypeEnum.BRANCH_TEST.releaseType.toByte())) + } else { step } + return conditionStep.fetch() } } diff --git a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/resources/atom/BuildAtomResourceImpl.kt b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/resources/atom/BuildAtomResourceImpl.kt index a2fff1e44de..917c9142e85 100644 --- a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/resources/atom/BuildAtomResourceImpl.kt +++ b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/resources/atom/BuildAtomResourceImpl.kt @@ -29,16 +29,35 @@ package com.tencent.devops.store.resources.atom import com.tencent.devops.common.api.pojo.Result import com.tencent.devops.common.web.RestResource import com.tencent.devops.store.api.atom.BuildAtomResource +import com.tencent.devops.store.pojo.atom.MarketAtomUpdateRequest +import com.tencent.devops.store.pojo.common.StoreProcessInfo import com.tencent.devops.store.pojo.common.VersionInfo +import com.tencent.devops.store.service.atom.AtomReleaseService import com.tencent.devops.store.service.atom.AtomService import org.springframework.beans.factory.annotation.Autowired @RestResource class BuildAtomResourceImpl @Autowired constructor( - private val atomService: AtomService + private val atomService: AtomService, + private val atomReleaseService: AtomReleaseService ) : BuildAtomResource { override fun getAtomDefaultValidVersion(projectCode: String, atomCode: String): Result { return atomService.getAtomDefaultValidVersion(projectCode, atomCode) } + + override fun createAtomBranchTestVersion( + userId: String, + marketAtomUpdateRequest: MarketAtomUpdateRequest + ): Result { + return atomReleaseService.creatAtomBranchTestVersion(userId, marketAtomUpdateRequest) + } + + override fun endBranchVersionTest(userId: String, atomCode: String, branch: String): Result { + return atomReleaseService.endBranchVersionTest(userId, atomCode, branch) + } + + override fun getProcessInfo(userId: String, atomId: String): Result { + return atomReleaseService.getProcessInfo(userId, atomId) + } } diff --git a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/AtomReleaseService.kt b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/AtomReleaseService.kt index 564646a4d41..1ff3dd2e241 100644 --- a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/AtomReleaseService.kt +++ b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/AtomReleaseService.kt @@ -49,7 +49,7 @@ interface AtomReleaseService { userId: String, projectCode: String, marketAtomUpdateRequest: MarketAtomUpdateRequest - ): Result + ): Result /** * 获取插件版本发布进度 @@ -95,4 +95,17 @@ interface AtomReleaseService { repositoryHashId: String?, branch: String? ) + + /** + * 创建分支测试版本 + */ + fun creatAtomBranchTestVersion( + userId: String, + marketAtomUpdateRequest: MarketAtomUpdateRequest + ): Result + + /** + * 结束分支版本测试 + */ + fun endBranchVersionTest(userId: String, atomCode: String, branch: String): Result } diff --git a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/AtomHandleBuildResultServiceImpl.kt b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/AtomHandleBuildResultServiceImpl.kt index def642f852d..5aed1bd4fa6 100644 --- a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/AtomHandleBuildResultServiceImpl.kt +++ b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/AtomHandleBuildResultServiceImpl.kt @@ -30,11 +30,13 @@ package com.tencent.devops.store.service.atom.impl import com.tencent.devops.common.api.constant.CommonMessageCode import com.tencent.devops.common.api.pojo.Result import com.tencent.devops.common.pipeline.enums.BuildStatus +import com.tencent.devops.common.redis.RedisLock import com.tencent.devops.common.redis.RedisOperation import com.tencent.devops.common.web.utils.I18nUtil import com.tencent.devops.store.dao.atom.MarketAtomDao import com.tencent.devops.store.pojo.atom.enums.AtomStatusEnum import com.tencent.devops.store.pojo.common.ATOM_POST_VERSION_TEST_FLAG_KEY_PREFIX +import com.tencent.devops.store.pojo.common.STORE_LATEST_TEST_FLAG_KEY_PREFIX import com.tencent.devops.store.pojo.common.StoreBuildResultRequest import com.tencent.devops.store.service.atom.AtomReleaseService import com.tencent.devops.store.service.atom.MarketAtomService @@ -84,6 +86,19 @@ class AtomHandleBuildResultServiceImpl @Autowired constructor( msg = null ) if (atomStatus == AtomStatusEnum.TESTING) { + RedisLock( + redisOperation, + "$STORE_LATEST_TEST_FLAG_KEY_PREFIX:$atomCode", + 60L + ).use { redisLock -> + redisLock.lock() + marketAtomDao.setupAtomLatestTestFlag( + dslContext = dslContext, + userId = storeBuildResultRequest.userId, + atomCode = atomCode, + atomId = atomId + ) + } // 插件errorCodes.json文件数据入库 atomReleaseService.syncAtomErrorCodeConfig( atomCode = atomCode, diff --git a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/AtomQualityServiceImpl.kt b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/AtomQualityServiceImpl.kt index a5cc1ec067d..fc027fc096f 100644 --- a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/AtomQualityServiceImpl.kt +++ b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/AtomQualityServiceImpl.kt @@ -27,6 +27,7 @@ package com.tencent.devops.store.service.atom.impl +import com.tencent.devops.common.api.constant.IN_READY_TEST import com.tencent.devops.common.client.Client import com.tencent.devops.common.redis.RedisLock import com.tencent.devops.common.redis.RedisOperation @@ -71,9 +72,9 @@ class AtomQualityServiceImpl @Autowired constructor( client.get(ServiceQualityControlPointMarketResource::class).refreshControlPoint(atomCode) } // 删除测试数据 - client.get(ServiceQualityMetadataMarketResource::class).deleteTestMetadata(atomCode) - client.get(ServiceQualityIndicatorMarketResource::class).deleteTestIndicator(atomCode) - client.get(ServiceQualityControlPointMarketResource::class).deleteTestControlPoint(atomCode) + client.get(ServiceQualityMetadataMarketResource::class).deleteTestMetadata(atomCode, IN_READY_TEST) + client.get(ServiceQualityIndicatorMarketResource::class).deleteTestIndicator(atomCode, IN_READY_TEST) + client.get(ServiceQualityControlPointMarketResource::class).deleteTestControlPoint(atomCode, IN_READY_TEST) } finally { lock.unlock() } diff --git a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/AtomReleaseServiceImpl.kt b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/AtomReleaseServiceImpl.kt index a8cb9b97a42..4f0328eff23 100644 --- a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/AtomReleaseServiceImpl.kt +++ b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/AtomReleaseServiceImpl.kt @@ -32,6 +32,7 @@ import com.tencent.devops.common.api.constant.CommonMessageCode import com.tencent.devops.common.api.constant.DEFAULT_LOCALE_LANGUAGE import com.tencent.devops.common.api.constant.DEPLOY import com.tencent.devops.common.api.constant.DEVELOP +import com.tencent.devops.common.api.constant.IN_READY_TEST import com.tencent.devops.common.api.constant.KEY_DEFAULT_LOCALE_LANGUAGE import com.tencent.devops.common.api.constant.KEY_REPOSITORY_HASH_ID import com.tencent.devops.common.api.constant.MASTER @@ -46,6 +47,7 @@ import com.tencent.devops.common.api.util.UUIDUtil import com.tencent.devops.common.client.Client import com.tencent.devops.common.pipeline.pojo.element.market.MarketBuildAtomElement import com.tencent.devops.common.pipeline.pojo.element.market.MarketBuildLessAtomElement +import com.tencent.devops.common.redis.RedisLock import com.tencent.devops.common.redis.RedisOperation import com.tencent.devops.common.service.prometheus.BkTimed import com.tencent.devops.common.web.utils.I18nUtil @@ -85,8 +87,8 @@ import com.tencent.devops.store.pojo.atom.GetAtomConfigResult import com.tencent.devops.store.pojo.atom.GetAtomQualityConfigResult import com.tencent.devops.store.pojo.atom.MarketAtomCreateRequest import com.tencent.devops.store.pojo.atom.MarketAtomUpdateRequest -import com.tencent.devops.store.pojo.atom.StoreI18nConfig import com.tencent.devops.store.pojo.atom.UpdateAtomInfo +import com.tencent.devops.store.pojo.atom.UpdateAtomPackageInfo import com.tencent.devops.store.pojo.atom.enums.AtomStatusEnum import com.tencent.devops.store.pojo.common.ATOM_POST_VERSION_TEST_FLAG_KEY_PREFIX import com.tencent.devops.store.pojo.common.ATOM_UPLOAD_ID_KEY_PREFIX @@ -103,7 +105,9 @@ import com.tencent.devops.store.pojo.common.KEY_RELEASE_INFO import com.tencent.devops.store.pojo.common.KEY_VERSION_INFO import com.tencent.devops.store.pojo.common.QUALITY_JSON_NAME import com.tencent.devops.store.pojo.common.ReleaseProcessItem +import com.tencent.devops.store.pojo.common.STORE_LATEST_TEST_FLAG_KEY_PREFIX import com.tencent.devops.store.pojo.common.StoreErrorCodeInfo +import com.tencent.devops.store.pojo.common.StoreI18nConfig import com.tencent.devops.store.pojo.common.StoreProcessInfo import com.tencent.devops.store.pojo.common.StoreReleaseCreateRequest import com.tencent.devops.store.pojo.common.TASK_JSON_NAME @@ -326,7 +330,7 @@ abstract class AtomReleaseServiceImpl @Autowired constructor() : AtomReleaseServ userId: String, projectCode: String, marketAtomUpdateRequest: MarketAtomUpdateRequest - ): Result { + ): Result { logger.info("updateMarketAtom userId is :$userId,marketAtomUpdateRequest is :$marketAtomUpdateRequest") val atomCode = marketAtomUpdateRequest.atomCode val version = marketAtomUpdateRequest.version @@ -386,7 +390,8 @@ abstract class AtomReleaseServiceImpl @Autowired constructor() : AtomReleaseServ i18nDir = i18nDir, propertiesKeyPrefix = KEY_RELEASE_INFO, dbKeyPrefix = StoreUtils.getStoreFieldKeyPrefix(StoreTypeEnum.ATOM, atomCode, version), - repositoryHashId = atomRecord.repositoryHashId + repositoryHashId = atomRecord.repositoryHashId, + branch = branch ), version = version ).toMutableMap() @@ -416,158 +421,26 @@ abstract class AtomReleaseServiceImpl @Autowired constructor() : AtomReleaseServ if (validateAtomVersionResult.isNotOk()) { return Result(status = validateAtomVersionResult.status, message = validateAtomVersionResult.message ?: "") } - val taskDataMap = storeI18nMessageService.parseJsonMapI18nInfo( - userId = userId, - jsonMap = getAtomConfResult.taskDataMap.toMutableMap(), - storeI18nConfig = StoreI18nConfig( - projectCode = projectCode, - storeCode = atomCode, - fileDir = "$atomCode/$version", - i18nDir = i18nDir, - dbKeyPrefix = StoreUtils.getStoreFieldKeyPrefix(StoreTypeEnum.ATOM, atomCode, version), - repositoryHashId = atomRecord.repositoryHashId - ), - version = version - ) - // 校验插件发布类型 - marketAtomCommonService.validateReleaseType( - atomId = atomRecord.id, - atomCode = atomCode, - version = version, - releaseType = releaseType, - taskDataMap = taskDataMap, - fieldCheckConfirmFlag = convertUpdateRequest.fieldCheckConfirmFlag - ) - val validateResult = validateUpdateMarketAtomReq(userId, convertUpdateRequest, atomRecord) - logger.info("validateUpdateMarketAtomReq validateResult is :$validateResult") - if (validateResult.isNotOk()) { - return Result(validateResult.status, validateResult.message, null) - } - var atomId = if (atomPackageSourceType == PackageSourceTypeEnum.UPLOAD) { + val atomId = if (atomPackageSourceType == PackageSourceTypeEnum.UPLOAD) { redisOperation.get("$ATOM_UPLOAD_ID_KEY_PREFIX:$atomCode:$version") ?: throw ErrorCodeException(errorCode = USER_UPLOAD_PACKAGE_INVALID) } else { UUIDUtil.generate() } - - // 解析quality.json - val getAtomQualityResult = getAtomQualityConfig( - projectCode = projectCode, - atomCode = atomCode, - atomName = convertUpdateRequest.name, - atomVersion = version, + val newVersionFlag = !(releaseType == ReleaseTypeEnum.NEW || releaseType == ReleaseTypeEnum.CANCEL_RE_RELEASE) + return updateAtomVersionInfo( userId = userId, - i18nDir = i18nDir, - repositoryHashId = atomRecord.repositoryHashId, - branch = branch - ) - logger.info("update market atom, getAtomQualityResult: $getAtomQualityResult") - if (getAtomQualityResult.errorCode == StoreMessageCode.USER_REPOSITORY_PULL_QUALITY_JSON_FILE_FAIL) { - logger.info("quality.json not found , skip...") - } else if (getAtomQualityResult.errorCode != "0") { - return I18nUtil.generateResponseDataObject( - messageCode = getAtomQualityResult.errorCode, - params = getAtomQualityResult.errorParams, - language = I18nUtil.getLanguage(userId) - ) - } - - val atomEnvRequests = getAtomConfResult.atomEnvRequests ?: return I18nUtil.generateResponseDataObject( - messageCode = StoreMessageCode.USER_REPOSITORY_TASK_JSON_FIELD_IS_NULL, - params = arrayOf(KEY_EXECUTION), - language = I18nUtil.getLanguage(userId) + projectCode = projectCode, + newVersionFlag = newVersionFlag, + updateAtomPackageInfo = UpdateAtomPackageInfo( + atomId = if (newVersionFlag) atomId else newestAtomRecord.id, + i18nDir = i18nDir, + packagePath = executionInfoMap[KEY_PACKAGE_PATH] as? String, + atomPackageSourceType = atomPackageSourceType + ), + convertUpdateRequest = convertUpdateRequest, + getAtomConfResult = getAtomConfResult ) - - val packagePath = executionInfoMap[KEY_PACKAGE_PATH] as? String - val classType = if (packagePath.isNullOrBlank() && atomPackageSourceType == PackageSourceTypeEnum.UPLOAD) { - // 没有可执行文件的插件是老的内置插件,插件的classType为插件标识 - atomCode - } else if (convertUpdateRequest.os.isEmpty()) { - MarketBuildLessAtomElement.classType - } else { - MarketBuildAtomElement.classType - } - val propsMap = mutableMapOf() - val inputDataMap = taskDataMap[KEY_INPUT] as? Map - if (convertUpdateRequest.frontendType == FrontendTypeEnum.HISTORY) { - inputDataMap?.let { propsMap.putAll(inputDataMap) } - } else { - propsMap[KEY_INPUT_GROUPS] = taskDataMap[KEY_INPUT_GROUPS] - propsMap[KEY_INPUT] = inputDataMap - propsMap[KEY_OUTPUT] = taskDataMap[KEY_OUTPUT] - propsMap[KEY_CONFIG] = taskDataMap[KEY_CONFIG] - } - convertUpdateRequest.os.sort() // 给操作系统排序 - val atomStatus = - if (atomPackageSourceType == PackageSourceTypeEnum.REPO) { - AtomStatusEnum.COMMITTING - } else AtomStatusEnum.TESTING - dslContext.transaction { t -> - val context = DSL.using(t) - val props = JsonUtil.toJson(propsMap, formatted = false) - if (releaseType == ReleaseTypeEnum.NEW || releaseType == ReleaseTypeEnum.CANCEL_RE_RELEASE) { - // 首次创建版本或者取消发布后不变更版本号重新上架,则在该版本的记录上做更新操作 - atomId = newestAtomRecord.id - updateMarketAtom( - context = context, - userId = userId, - atomId = atomId, - atomStatus = atomStatus, - classType = classType, - props = props, - releaseType = releaseType.releaseType.toByte(), - marketAtomUpdateRequest = convertUpdateRequest, - atomEnvRequests = atomEnvRequests, - repositoryHashId = atomRecord.repositoryHashId - ) - } else { - // 升级插件 - upgradeMarketAtom( - marketAtomUpdateRequest = convertUpdateRequest, - context = context, - userId = userId, - atomId = atomId, - atomStatus = atomStatus, - classType = classType, - props = props, - atomEnvRequests = atomEnvRequests, - atomRecord = atomRecord - ) - } - if (atomStatus == AtomStatusEnum.TESTING) { - // 插件大版本内有测试版本则写入缓存 - redisOperation.hset( - key = "$ATOM_POST_VERSION_TEST_FLAG_KEY_PREFIX:$atomCode", - hashKey = VersionUtils.convertLatestVersion(version), - values = "true" - ) - } - // 更新标签信息 - val labelIdList = convertUpdateRequest.labelIdList?.filter { !it.isNullOrBlank() } - if (null != labelIdList) { - atomLabelRelDao.deleteByAtomId(context, atomId) - if (labelIdList.isNotEmpty()) { - atomLabelRelDao.batchAdd(context, userId = userId, atomId = atomId, labelIdList = labelIdList) - } - } - - // 更新红线标识 - val qualityFlag = getAtomQualityResult.errorCode == "0" - marketAtomFeatureDao.updateAtomFeature( - dslContext = context, - userId = userId, - atomFeatureRequest = AtomFeatureRequest(atomCode = atomCode, qualityFlag = qualityFlag) - ) - asyncHandleUpdateAtom( - context = context, - atomId = atomId, - userId = userId, - branch = branch, - validOsNameFlag = marketAtomCommonService.getValidOsNameFlag(atomEnvRequests), - validOsArchFlag = marketAtomCommonService.getValidOsArchFlag(atomEnvRequests) - ) - } - return Result(atomId) } /** @@ -576,7 +449,7 @@ abstract class AtomReleaseServiceImpl @Autowired constructor() : AtomReleaseServ abstract fun validateUpdateMarketAtomReq( userId: String, marketAtomUpdateRequest: MarketAtomUpdateRequest, - atomRecord: TAtomRecord + repositoryHashId: String? ): Result /** @@ -591,7 +464,7 @@ abstract class AtomReleaseServiceImpl @Autowired constructor() : AtomReleaseServ validOsArchFlag: Boolean? = null ) - private fun updateMarketAtom( + protected fun updateMarketAtom( context: DSLContext, userId: String, atomId: String, @@ -678,7 +551,8 @@ abstract class AtomReleaseServiceImpl @Autowired constructor() : AtomReleaseServ fileDir = "$atomCode/$atomVersion", i18nDir = StoreUtils.getStoreI18nDir(atomLanguage, getAtomPackageSourceType(repositoryHashId)), dbKeyPrefix = "${StoreTypeEnum.ATOM.name}.$atomCode.$atomVersion", - repositoryHashId = repositoryHashId + repositoryHashId = repositoryHashId, + branch = branch ) ) val storeErrorCodeInfo = StoreErrorCodeInfo( @@ -723,7 +597,8 @@ abstract class AtomReleaseServiceImpl @Autowired constructor() : AtomReleaseServ fileDir = "$atomCode/$atomVersion", i18nDir = i18nDir, dbKeyPrefix = StoreUtils.getStoreFieldKeyPrefix(StoreTypeEnum.ATOM, atomCode, atomVersion), - repositoryHashId = repositoryHashId + repositoryHashId = repositoryHashId, + branch = branch ), version = atomVersion ) @@ -741,7 +616,8 @@ abstract class AtomReleaseServiceImpl @Autowired constructor() : AtomReleaseServ userId = userId, atomCode = atomCode, atomName = atomName, - indicators = indicators + indicators = indicators, + version = if (branch == MASTER) null else atomVersion ) // 再注册指标 @@ -768,10 +644,16 @@ abstract class AtomReleaseServiceImpl @Autowired constructor() : AtomReleaseServ GetAtomQualityConfigResult("0", arrayOf("")) } else { + val extra = if (atomVersion.startsWith("$TEST-$atomVersion-")) { + "$IN_READY_TEST($atomVersion)" + } else { + IN_READY_TEST + } try { - client.get(ServiceQualityIndicatorMarketResource::class).deleteTestIndicator(atomCode) - client.get(ServiceQualityMetadataMarketResource::class).deleteTestMetadata(atomCode) - client.get(ServiceQualityControlPointMarketResource::class).deleteTestControlPoint(atomCode) + client.get(ServiceQualityIndicatorMarketResource::class) + .deleteTestIndicator(atomCode, extra) + client.get(ServiceQualityMetadataMarketResource::class).deleteTestMetadata(atomCode, extra) + client.get(ServiceQualityControlPointMarketResource::class).deleteTestControlPoint(atomCode, extra) } catch (ignored: Throwable) { logger.warn("clear atom:$atomCode test quality data fail", ignored) } @@ -811,7 +693,10 @@ abstract class AtomReleaseServiceImpl @Autowired constructor() : AtomReleaseServ projectId: String ) { client.get(ServiceQualityControlPointMarketResource::class).setTestControlPoint( - userId, QualityControlPoint( + userId = userId, + tag = + if (atomVersion.startsWith("$TEST-$atomVersion-")) "$IN_READY_TEST($atomVersion)" else IN_READY_TEST, + controlPoint = QualityControlPoint( hashId = "", type = atomCode, name = atomName, @@ -839,6 +724,8 @@ abstract class AtomReleaseServiceImpl @Autowired constructor() : AtomReleaseServ metadataResultMap: Map, indicators: Map ) { + val tag = + if (atomVersion.startsWith("$TEST-$atomVersion-")) "$IN_READY_TEST($atomVersion)" else IN_READY_TEST val indicatorsList = indicators.map { val map = it.value as Map val type = map["type"] as String? @@ -859,13 +746,18 @@ abstract class AtomReleaseServiceImpl @Autowired constructor() : AtomReleaseServ readOnly = map["readOnly"] as Boolean? ?: false, stage = stage, range = projectId, - tag = "IN_READY_TEST", + tag = tag, enable = true, type = IndicatorType.MARKET, logPrompt = map["logPrompt"] as? String ?: "" ) } - client.get(ServiceQualityIndicatorMarketResource::class).setTestIndicator(userId, atomCode, indicatorsList) + client.get(ServiceQualityIndicatorMarketResource::class).setTestIndicator( + userId = userId, + atomCode = atomCode, + tag = tag, + indicatorUpdateList = indicatorsList + ) } @Suppress("UNCHECKED_CAST") @@ -873,8 +765,10 @@ abstract class AtomReleaseServiceImpl @Autowired constructor() : AtomReleaseServ userId: String, atomCode: String, atomName: String, - indicators: Map + indicators: Map, + version: String? ): Map { + val extra = version?.let { "$IN_READY_TEST($version)" } ?: IN_READY_TEST // 标注是正在测试中的 val metadataList = indicators.map { val map = it.value as Map val type = map["type"] as String? @@ -887,12 +781,13 @@ abstract class AtomReleaseServiceImpl @Autowired constructor() : AtomReleaseServ elementDetail = if (type.isNullOrBlank()) atomCode else type, valueType = map["valueType"] as String? ?: "INT", desc = map["desc"] as String? ?: "", - extra = "IN_READY_TEST" // 标注是正在测试中的 + extra = extra ) } return client.get(ServiceQualityMetadataMarketResource::class).setTestMetadata( userId = userId, atomCode = atomCode, + extra = extra, metadataList = metadataList ).data ?: mapOf() } @@ -1072,13 +967,14 @@ abstract class AtomReleaseServiceImpl @Autowired constructor() : AtomReleaseServ hashKey = VersionUtils.convertLatestVersion(record.version), values = "false" ) + checkUpdateAtomLatestTestFlag(userId, atomCode, atomId) doCancelReleaseBus(userId, atomId) // 通过websocket推送状态变更消息 storeWebsocketService.sendWebsocketMessage(userId, atomId) // 删除质量红线相关数据 - client.get(ServiceQualityIndicatorMarketResource::class).deleteTestIndicator(atomCode) - client.get(ServiceQualityMetadataMarketResource::class).deleteTestMetadata(atomCode) - client.get(ServiceQualityControlPointMarketResource::class).deleteTestControlPoint(atomCode) + client.get(ServiceQualityIndicatorMarketResource::class).deleteTestIndicator(atomCode, IN_READY_TEST) + client.get(ServiceQualityMetadataMarketResource::class).deleteTestMetadata(atomCode, IN_READY_TEST) + client.get(ServiceQualityControlPointMarketResource::class).deleteTestControlPoint(atomCode, IN_READY_TEST) return Result(true) } @@ -1146,6 +1042,7 @@ abstract class AtomReleaseServiceImpl @Autowired constructor() : AtomReleaseServ doAtomReleaseBus(userId, atomReleaseRequest) // 更新质量红线信息 atomQualityService.updateQualityInApprove(atomCode, atomStatus) + checkUpdateAtomLatestTestFlag(userId, atomCode, atomId) dslContext.transaction { t -> val context = DSL.using(t) // 记录发布信息 @@ -1381,4 +1278,188 @@ abstract class AtomReleaseServiceImpl @Autowired constructor() : AtomReleaseServ } } } + + protected fun updateAtomVersionInfo( + userId: String, + projectCode: String, + newVersionFlag: Boolean, + updateAtomPackageInfo: UpdateAtomPackageInfo, + convertUpdateRequest: MarketAtomUpdateRequest, + getAtomConfResult: GetAtomConfigResult + ): Result { + val atomId = updateAtomPackageInfo.atomId + val atomCode = convertUpdateRequest.atomCode + val version = convertUpdateRequest.version + val branch = convertUpdateRequest.branch + val atomRecord = atomDao.getMaxVersionAtomByCode(dslContext, atomCode)!! + val releaseType = convertUpdateRequest.releaseType + val taskDataMap = storeI18nMessageService.parseJsonMapI18nInfo( + userId = userId, + jsonMap = getAtomConfResult.taskDataMap.toMutableMap(), + storeI18nConfig = StoreI18nConfig( + projectCode = projectCode, + storeCode = atomCode, + fileDir = "$atomCode/$version", + i18nDir = updateAtomPackageInfo.i18nDir, + dbKeyPrefix = StoreUtils.getStoreFieldKeyPrefix(StoreTypeEnum.ATOM, atomCode, version), + repositoryHashId = atomRecord.repositoryHashId, + branch = branch + ), + version = version + ) + if (!convertUpdateRequest.isBranchTestVersion) { + // 校验插件发布类型 + marketAtomCommonService.validateReleaseType( + atomId = atomRecord.id, + atomCode = atomCode, + version = version, + releaseType = releaseType, + taskDataMap = taskDataMap, + fieldCheckConfirmFlag = convertUpdateRequest.fieldCheckConfirmFlag + ) + } + val validateResult = validateUpdateMarketAtomReq(userId, convertUpdateRequest, atomRecord.repositoryHashId) + logger.info("validateUpdateMarketAtomReq validateResult is :$validateResult") + if (validateResult.isNotOk()) { + return Result(validateResult.status, validateResult.message, null) + } + + // 解析quality.json + val getAtomQualityResult = getAtomQualityConfig( + projectCode = projectCode, + atomCode = atomCode, + atomName = convertUpdateRequest.name, + atomVersion = version, + userId = userId, + i18nDir = updateAtomPackageInfo.i18nDir, + repositoryHashId = atomRecord.repositoryHashId, + branch = branch + ) + logger.info("update market atom, getAtomQualityResult: $getAtomQualityResult") + if (getAtomQualityResult.errorCode == StoreMessageCode.USER_REPOSITORY_PULL_QUALITY_JSON_FILE_FAIL) { + logger.info("quality.json not found , skip...") + } else if (getAtomQualityResult.errorCode != "0") { + return I18nUtil.generateResponseDataObject( + messageCode = getAtomQualityResult.errorCode, + params = getAtomQualityResult.errorParams, + language = I18nUtil.getLanguage(userId) + ) + } + + val atomEnvRequests = getAtomConfResult.atomEnvRequests ?: return I18nUtil.generateResponseDataObject( + messageCode = StoreMessageCode.USER_REPOSITORY_TASK_JSON_FIELD_IS_NULL, + params = arrayOf(KEY_EXECUTION), + language = I18nUtil.getLanguage(userId) + ) + val packagePath = updateAtomPackageInfo.packagePath + val atomPackageSourceType = updateAtomPackageInfo.atomPackageSourceType + val classType = if (packagePath.isNullOrBlank() && atomPackageSourceType == PackageSourceTypeEnum.UPLOAD) { + // 没有可执行文件的插件是老的内置插件,插件的classType为插件标识 + atomCode + } else if (convertUpdateRequest.os.isEmpty()) { + MarketBuildLessAtomElement.classType + } else { + MarketBuildAtomElement.classType + } + val propsMap = mutableMapOf() + val inputDataMap = taskDataMap[KEY_INPUT] as? Map + if (convertUpdateRequest.frontendType == FrontendTypeEnum.HISTORY) { + inputDataMap?.let { propsMap.putAll(inputDataMap) } + } else { + propsMap[KEY_INPUT_GROUPS] = taskDataMap[KEY_INPUT_GROUPS] + propsMap[KEY_INPUT] = inputDataMap + propsMap[KEY_OUTPUT] = taskDataMap[KEY_OUTPUT] + propsMap[KEY_CONFIG] = taskDataMap[KEY_CONFIG] + } + convertUpdateRequest.os.sort() // 给操作系统排序 + val atomStatus = + if (atomPackageSourceType == PackageSourceTypeEnum.REPO) { + AtomStatusEnum.COMMITTING + } else AtomStatusEnum.TESTING + dslContext.transaction { t -> + val context = DSL.using(t) + val props = JsonUtil.toJson(propsMap, formatted = false) + if (!newVersionFlag) { + updateMarketAtom( + context = context, + userId = userId, + atomId = atomId, + atomStatus = atomStatus, + classType = classType, + props = props, + releaseType = releaseType.releaseType.toByte(), + marketAtomUpdateRequest = convertUpdateRequest, + atomEnvRequests = atomEnvRequests, + repositoryHashId = atomRecord.repositoryHashId + ) + } else { + // 升级插件 + upgradeMarketAtom( + marketAtomUpdateRequest = convertUpdateRequest, + context = context, + userId = userId, + atomId = atomId, + atomStatus = atomStatus, + classType = classType, + props = props, + atomEnvRequests = atomEnvRequests, + atomRecord = atomRecord + ) + } + if (!convertUpdateRequest.isBranchTestVersion && atomStatus == AtomStatusEnum.TESTING) { + // 插件大版本内有测试版本则写入缓存 + redisOperation.hset( + key = "$ATOM_POST_VERSION_TEST_FLAG_KEY_PREFIX:$atomCode", + hashKey = VersionUtils.convertLatestVersion(version), + values = "true" + ) + } + // 更新标签信息 + val labelIdList = convertUpdateRequest.labelIdList?.filter { !it.isNullOrBlank() } + if (!convertUpdateRequest.isBranchTestVersion && null != labelIdList) { + atomLabelRelDao.deleteByAtomId(context, atomId) + if (labelIdList.isNotEmpty()) { + atomLabelRelDao.batchAdd(context, userId = userId, atomId = atomId, labelIdList = labelIdList) + } + } + + // 更新红线标识 + val qualityFlag = getAtomQualityResult.errorCode == "0" + marketAtomFeatureDao.updateAtomFeature( + dslContext = context, + userId = userId, + atomFeatureRequest = AtomFeatureRequest(atomCode = atomCode, qualityFlag = qualityFlag) + ) + asyncHandleUpdateAtom( + context = context, + atomId = atomId, + userId = userId, + branch = branch, + validOsNameFlag = marketAtomCommonService.getValidOsNameFlag(atomEnvRequests), + validOsArchFlag = marketAtomCommonService.getValidOsArchFlag(atomEnvRequests) + ) + } + return Result(atomId) + } + + fun checkUpdateAtomLatestTestFlag(userId: String, atomCode: String, atomId: String) { + RedisLock( + redisOperation, + "$STORE_LATEST_TEST_FLAG_KEY_PREFIX:$atomCode", + 60L + ).use { redisLock -> + redisLock.lock() + if (marketAtomDao.isAtomLatestTestVersion(dslContext, atomId) > 0) { + val latestTestVersionId = marketAtomDao.queryAtomLatestTestVersionId(dslContext, atomCode) + latestTestVersionId?.let { + marketAtomDao.setupAtomLatestTestFlag( + dslContext = dslContext, + userId = userId, + atomCode = atomCode, + atomId = atomId + ) + } + } + } + } } diff --git a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/AtomServiceImpl.kt b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/AtomServiceImpl.kt index f477c9db88b..1fb93e55383 100644 --- a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/AtomServiceImpl.kt +++ b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/AtomServiceImpl.kt @@ -29,6 +29,7 @@ package com.tencent.devops.store.service.atom.impl import com.github.benmanes.caffeine.cache.Caffeine import com.tencent.devops.common.api.constant.CommonMessageCode +import com.tencent.devops.common.api.constant.KEY_BRANCH_TEST_FLAG import com.tencent.devops.common.api.constant.KEY_DESCRIPTION import com.tencent.devops.common.api.constant.KEY_DOCSLINK import com.tencent.devops.common.api.constant.KEY_OS @@ -36,6 +37,7 @@ import com.tencent.devops.common.api.constant.KEY_SUMMARY import com.tencent.devops.common.api.constant.KEY_VERSION import com.tencent.devops.common.api.constant.KEY_WEIGHT import com.tencent.devops.common.api.constant.NAME +import com.tencent.devops.common.api.constant.TEST import com.tencent.devops.common.api.constant.VERSION import com.tencent.devops.common.api.enums.FrontendTypeEnum import com.tencent.devops.common.api.enums.SystemModuleEnum @@ -114,7 +116,6 @@ import com.tencent.devops.store.pojo.common.enums.StoreTypeEnum import com.tencent.devops.store.service.atom.AtomLabelService import com.tencent.devops.store.service.atom.AtomService import com.tencent.devops.store.service.atom.MarketAtomCommonService -import com.tencent.devops.store.service.common.action.StoreDecorateFactory import com.tencent.devops.store.service.common.ClassifyService import com.tencent.devops.store.service.common.StoreCommonService import com.tencent.devops.store.service.common.StoreHonorService @@ -122,6 +123,7 @@ import com.tencent.devops.store.service.common.StoreI18nMessageService import com.tencent.devops.store.service.common.StoreIndexManageService import com.tencent.devops.store.service.common.StoreProjectService import com.tencent.devops.store.service.common.StoreUserService +import com.tencent.devops.store.service.common.action.StoreDecorateFactory import com.tencent.devops.store.utils.StoreUtils import com.tencent.devops.store.utils.VersionUtils import java.math.BigDecimal @@ -342,7 +344,12 @@ abstract class AtomServiceImpl @Autowired constructor() : AtomService { val name = it[NAME] as String val atomCode = it[KEY_ATOM_CODE] as String val version = it[VERSION] as String - val defaultVersion = VersionUtils.convertLatestVersion(version) + val branchTestFlag = it[KEY_BRANCH_TEST_FLAG] as Boolean + val defaultVersion = if (branchTestFlag) { + version + } else { + VersionUtils.convertLatestVersion(version) + } val classType = it[KEY_CLASS_TYPE] as String val serviceScopeStr = it[KEY_SERVICE_SCOPE] as? String val honorInfos = atomHonorInfoMap[atomCode] @@ -713,7 +720,7 @@ abstract class AtomServiceImpl @Autowired constructor() : AtomService { versionName = "$atomVersion ($atomStatusMsg)" latestVersionName = "$latestVersionName ($atomStatusMsg)" } - if (tmpVersionPrefix != versionPrefix) { + if (tmpVersionPrefix != versionPrefix && (it[KEY_BRANCH_TEST_FLAG] as Boolean) != true) { versionList.add(VersionInfo(latestVersionName, "$versionPrefix*")) // 添加大版本号的通用最新模式(如1.*) tmpVersionPrefix = versionPrefix } diff --git a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/MarketAtomArchiveServiceImpl.kt b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/MarketAtomArchiveServiceImpl.kt index fad1637d1fa..af04ee704b6 100644 --- a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/MarketAtomArchiveServiceImpl.kt +++ b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/MarketAtomArchiveServiceImpl.kt @@ -46,7 +46,7 @@ import com.tencent.devops.store.pojo.atom.AtomConfigInfo import com.tencent.devops.store.pojo.atom.AtomPkgInfoUpdateRequest import com.tencent.devops.store.pojo.atom.GetAtomConfigResult import com.tencent.devops.store.pojo.atom.ReleaseInfo -import com.tencent.devops.store.pojo.atom.StoreI18nConfig +import com.tencent.devops.store.pojo.common.StoreI18nConfig import com.tencent.devops.store.pojo.common.KEY_CONFIG import com.tencent.devops.store.pojo.common.KEY_EXECUTION import com.tencent.devops.store.pojo.common.KEY_INPUT diff --git a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/MarketAtomServiceImpl.kt b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/MarketAtomServiceImpl.kt index 7a4512b05eb..6067ac6f29f 100644 --- a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/MarketAtomServiceImpl.kt +++ b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/atom/impl/MarketAtomServiceImpl.kt @@ -69,8 +69,8 @@ import com.tencent.devops.repository.pojo.Repository import com.tencent.devops.repository.pojo.enums.TokenTypeEnum import com.tencent.devops.repository.pojo.enums.VisibilityLevelEnum import com.tencent.devops.store.constant.StoreMessageCode -import com.tencent.devops.store.constant.StoreMessageCode.NO_COMPONENT_ADMIN_PERMISSION import com.tencent.devops.store.constant.StoreMessageCode.GET_INFO_NO_PERMISSION +import com.tencent.devops.store.constant.StoreMessageCode.NO_COMPONENT_ADMIN_PERMISSION import com.tencent.devops.store.constant.StoreMessageCode.TASK_JSON_CONFIGURE_FORMAT_ERROR import com.tencent.devops.store.dao.atom.AtomApproveRelDao import com.tencent.devops.store.dao.atom.AtomDao @@ -583,7 +583,8 @@ abstract class MarketAtomServiceImpl @Autowired constructor() : MarketAtomServic // 获取插件处于流程中的版本信息 var processingVersionInfoMap: MutableMap>? = null processingAtomRecords?.forEach { processingAtomRecord -> - if (processingAtomRecord.version == INIT_VERSION || processingAtomRecord.version.isNullOrBlank()) { + if (processingAtomRecord.version == INIT_VERSION || processingAtomRecord.version.isNullOrBlank() || + processingAtomRecord.branchTestFlag) { return@forEach } if (processingVersionInfoMap == null) { diff --git a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/common/StoreI18nMessageService.kt b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/common/StoreI18nMessageService.kt index 53fda888446..b603bbe3289 100644 --- a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/common/StoreI18nMessageService.kt +++ b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/common/StoreI18nMessageService.kt @@ -27,7 +27,7 @@ package com.tencent.devops.store.service.common -import com.tencent.devops.store.pojo.atom.StoreI18nConfig +import com.tencent.devops.store.pojo.common.StoreI18nConfig @Suppress("LongParameterList") interface StoreI18nMessageService { diff --git a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/common/impl/StoreI18nMessageServiceImpl.kt b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/common/impl/StoreI18nMessageServiceImpl.kt index 586d595cd3e..8f9f19409ee 100644 --- a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/common/impl/StoreI18nMessageServiceImpl.kt +++ b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/service/common/impl/StoreI18nMessageServiceImpl.kt @@ -39,7 +39,7 @@ import com.tencent.devops.common.client.Client import com.tencent.devops.common.service.config.CommonConfig import com.tencent.devops.common.web.service.ServiceI18nMessageResource import com.tencent.devops.common.web.utils.I18nUtil -import com.tencent.devops.store.pojo.atom.StoreI18nConfig +import com.tencent.devops.store.pojo.common.StoreI18nConfig import com.tencent.devops.store.pojo.common.TextReferenceFileDownloadRequest import com.tencent.devops.store.service.common.StoreFileService import com.tencent.devops.store.service.common.StoreFileService.Companion.BK_CI_PATH_REGEX @@ -104,7 +104,8 @@ abstract class StoreI18nMessageServiceImpl : StoreI18nMessageService { fileDir = fileDir, i18nDir = i18nDir, fileName = fileName, - repositoryHashId = repositoryHashId + repositoryHashId = repositoryHashId, + branch = storeI18nConfig.branch ) val fieldLocaleInfos = if (jsonLocaleLanguage == devopsDefaultLocaleLanguage) { // 如果map集合中默认字段值对应的语言和蓝盾默认语言一致,则无需替换 @@ -209,7 +210,8 @@ abstract class StoreI18nMessageServiceImpl : StoreI18nMessageService { projectCode = storeI18nConfig.projectCode, fileDir = storeI18nConfig.fileDir, i18nDir = storeI18nConfig.i18nDir, - repositoryHashId = storeI18nConfig.repositoryHashId + repositoryHashId = storeI18nConfig.repositoryHashId, + branch = storeI18nConfig.branch ) logger.info("parseJsonMap propertiesFileNames:$propertiesFileNames") val regex = MESSAGE_NAME_TEMPLATE.format("(.*)").toRegex() @@ -222,13 +224,15 @@ abstract class StoreI18nMessageServiceImpl : StoreI18nMessageService { fileDir = storeI18nConfig.fileDir, i18nDir = storeI18nConfig.i18nDir, fileName = propertiesFileName, - repositoryHashId = storeI18nConfig.repositoryHashId + repositoryHashId = storeI18nConfig.repositoryHashId, + branch = storeI18nConfig.branch ) ?: return@forEach val textReferenceContentMap = getTextReferenceFileContent( projectCode = storeI18nConfig.projectCode, properties = fileProperties, repositoryHashId = storeI18nConfig.repositoryHashId, - fileDir = storeI18nConfig.fileDir + fileDir = storeI18nConfig.fileDir, + branch = storeI18nConfig.branch ) var textReferenceFileDirPath: String? = null val allFileNames = textReferenceContentMap.values.flatten().toSet() @@ -306,13 +310,15 @@ abstract class StoreI18nMessageServiceImpl : StoreI18nMessageService { fileDir: String, i18nDir: String, fileName: String, - repositoryHashId: String? + repositoryHashId: String?, + branch: String? = null ): Properties? { val fileStr = getFileStr( projectCode = projectCode, fileDir = fileDir, fileName = "$i18nDir/$fileName", - repositoryHashId = repositoryHashId + repositoryHashId = repositoryHashId, + branch = branch ) return if (fileStr.isNullOrBlank()) { null diff --git a/support-files/i18n/store/message_en_US.properties b/support-files/i18n/store/message_en_US.properties index b79301eaa1e..c0909068968 100644 --- a/support-files/i18n/store/message_en_US.properties +++ b/support-files/i18n/store/message_en_US.properties @@ -93,6 +93,9 @@ 2120923=The atom 【{0}】 in the interface request is not the atom running in the current build. 2120924=Component {0} version ({1}) has been published. 2120925=You do not have admin or current version creator permissions for component {0}. Please contact the component admin. +2120926=store:The user {0} is not a member of the component +2120927=Failed to retrieve branch commit information. +2120928=The branch test version generation failed without any code changes. ATOM.classify.common=Others ATOM.classify.compileBuild=Compile ATOM.classify.deploy=Deploy diff --git a/support-files/i18n/store/message_zh_CN.properties b/support-files/i18n/store/message_zh_CN.properties index 3e97dac58bd..86b36f8c8e7 100644 --- a/support-files/i18n/store/message_zh_CN.properties +++ b/support-files/i18n/store/message_zh_CN.properties @@ -93,6 +93,9 @@ 2120923=接口请求中的插件【{0}】不是当前当前构建运行的插件 2120924=组件{0}版本({1})已发布 2120925=无组件{0}管理员或当前版本创建者权限,请联系组件管理员。 +2120926=研发商店:用户{0}不是组件成员 +2120927=获取分支提交信息失败 +2120928=代码未变更,分支测试版本生成失败 ATOM.classify.common=其它 ATOM.classify.compileBuild=编译 ATOM.classify.deploy=部署 diff --git a/support-files/sql/1001_ci_process_ddl_mysql.sql b/support-files/sql/1001_ci_process_ddl_mysql.sql index 1737a0f3c7f..579a182d2c2 100644 --- a/support-files/sql/1001_ci_process_ddl_mysql.sql +++ b/support-files/sql/1001_ci_process_ddl_mysql.sql @@ -363,7 +363,7 @@ CREATE TABLE IF NOT EXISTS `T_PIPELINE_MODEL_TASK` ( `OS` varchar(45) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '操作系统', `ADDITIONAL_OPTIONS` mediumtext CHARACTER SET utf8mb4 COMMENT '其他选项', `ATOM_CODE` varchar(32) COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '插件的唯一标识', - `ATOM_VERSION` varchar(20) COMMENT '插件版本号', + `ATOM_VERSION` varchar(30) COMMENT '插件版本号', `CREATE_TIME` datetime(3) COMMENT '创建时间', `UPDATE_TIME` datetime(3) COMMENT '更新时间', PRIMARY KEY (`PIPELINE_ID`,`PROJECT_ID`,`STAGE_ID`,`CONTAINER_ID`,`TASK_ID`), diff --git a/support-files/sql/1001_ci_quality_ddl_mysql.sql b/support-files/sql/1001_ci_quality_ddl_mysql.sql index 05d0103a1ae..2eb30ce97a0 100644 --- a/support-files/sql/1001_ci_quality_ddl_mysql.sql +++ b/support-files/sql/1001_ci_quality_ddl_mysql.sql @@ -183,7 +183,7 @@ CREATE TABLE IF NOT EXISTS `T_QUALITY_CONTROL_POINT` `UPDATE_USER` varchar(64) DEFAULT NULL COMMENT '更新用户', `CREATE_TIME` datetime DEFAULT NULL COMMENT '创建时间', `UPDATE_TIME` datetime DEFAULT NULL COMMENT '更新时间', - `ATOM_VERSION` varchar(16) DEFAULT '1.0.0' COMMENT '插件版本', + `ATOM_VERSION` varchar(30) DEFAULT '1.0.0' COMMENT '插件版本', `TEST_PROJECT` varchar(64) NOT NULL DEFAULT '' COMMENT '测试的项目', `CONTROL_POINT_HASH_ID` varchar(64) DEFAULT NULL COMMENT '哈希ID', `TAG` VARCHAR(64) NULL, @@ -261,7 +261,7 @@ CREATE TABLE IF NOT EXISTS `T_QUALITY_INDICATOR` `UPDATE_USER` varchar(64) DEFAULT NULL COMMENT '更新用户', `CREATE_TIME` datetime DEFAULT NULL COMMENT '创建时间', `UPDATE_TIME` datetime DEFAULT NULL COMMENT '更新时间', - `ATOM_VERSION` varchar(16) NOT NULL DEFAULT '1.0.0' COMMENT '插件版本号', + `ATOM_VERSION` varchar(30) NOT NULL DEFAULT '1.0.0' COMMENT '插件版本号', `LOG_PROMPT` varchar(1024) NOT NULL DEFAULT '' COMMENT '日志提示', PRIMARY KEY (`ID`) ) ENGINE = InnoDB diff --git a/support-files/sql/1001_ci_store_ddl_mysql.sql b/support-files/sql/1001_ci_store_ddl_mysql.sql index 3052979d14a..ba7ab06f66c 100644 --- a/support-files/sql/1001_ci_store_ddl_mysql.sql +++ b/support-files/sql/1001_ci_store_ddl_mysql.sql @@ -61,7 +61,7 @@ CREATE TABLE IF NOT EXISTS `T_ATOM` ( `SUMMARY` varchar(256) DEFAULT NULL COMMENT '简介', `DESCRIPTION` text COMMENT '描述', `CATEGROY` tinyint(4) NOT NULL DEFAULT '1' COMMENT '类别', - `VERSION` varchar(20) NOT NULL COMMENT '版本号', + `VERSION` varchar(30) NOT NULL COMMENT '版本号', `LOGO_URL` varchar(256) DEFAULT NULL COMMENT 'LOGO URL地址', `ICON` text COMMENT '插件图标', `DEFAULT_FLAG` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否为默认原子', @@ -84,6 +84,8 @@ CREATE TABLE IF NOT EXISTS `T_ATOM` ( `PRIVATE_REASON` varchar(256) DEFAULT NULL COMMENT '插件代码库不开源原因', `DELETE_FLAG` bit(1) DEFAULT b'0' COMMENT '是否删除', `BRANCH` VARCHAR(128) DEFAULT 'master' COMMENT '代码库分支', + `BRANCH_TEST_FLAG` bit(1) DEFAULT b'0' COMMENT '是否是分支测试版本', + `LATEST_TEST_FLAG` bit(1) DEFAULT b'0' COMMENT '是否为最新测试版本原子, TRUE:最新 FALSE:非最新', PRIMARY KEY (`ID`), UNIQUE KEY `uni_inx_tpca_code_version` (`ATOM_CODE`,`VERSION`), KEY `inx_tpca_service_code` (`SERVICE_SCOPE`(255)), diff --git a/support-files/sql/2003_v2.x/2020_ci_process-update_v2.0_mysql.sql b/support-files/sql/2003_v2.x/2020_ci_process-update_v2.0_mysql.sql index 9e8b2a08b5e..f14bf53bfd4 100644 --- a/support-files/sql/2003_v2.x/2020_ci_process-update_v2.0_mysql.sql +++ b/support-files/sql/2003_v2.x/2020_ci_process-update_v2.0_mysql.sql @@ -113,6 +113,14 @@ BEGIN END IF; + IF EXISTS(SELECT 1 + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = db + AND TABLE_NAME = 'T_PIPELINE_MODEL_TASK' + AND COLUMN_NAME = 'ATOM_VERSION') THEN + ALTER TABLE T_PIPELINE_MODEL_TASK MODIFY COLUMN ATOM_VERSION varchar(30) NULL COMMENT '插件版本号'; + END IF; + COMMIT; END DELIMITER ; diff --git a/support-files/sql/2003_v2.x/2020_ci_quality-update_v2.0_mysql.sql b/support-files/sql/2003_v2.x/2020_ci_quality-update_v2.0_mysql.sql new file mode 100644 index 00000000000..2b4a68d6f48 --- /dev/null +++ b/support-files/sql/2003_v2.x/2020_ci_quality-update_v2.0_mysql.sql @@ -0,0 +1,34 @@ +USE devops_ci_quality; +SET NAMES utf8mb4; + +DROP PROCEDURE IF EXISTS ci_quality_schema_update; + +DELIMITER + +CREATE PROCEDURE ci_quality_schema_update() +BEGIN + + DECLARE db VARCHAR(100); + SET AUTOCOMMIT = 0; + SELECT DATABASE() INTO db; + + IF EXISTS(SELECT 1 + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = db + AND TABLE_NAME = 'T_QUALITY_CONTROL_POINT' + AND COLUMN_NAME = 'ATOM_VERSION') THEN + ALTER TABLE T_QUALITY_CONTROL_POINT MODIFY COLUMN ATOM_VERSION varchar(30) DEFAULT '1.0.0' COMMENT '插件版本'; + END IF; + IF EXISTS(SELECT 1 + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = db + AND TABLE_NAME = 'T_QUALITY_INDICATOR' + AND COLUMN_NAME = 'ATOM_VERSION') THEN + ALTER TABLE T_QUALITY_INDICATOR MODIFY COLUMN ATOM_VERSION varchar(30) DEFAULT '1.0.0' COMMENT '插件版本号'; + END IF; + + COMMIT; +END +DELIMITER ; +COMMIT; +CALL ci_quality_schema_update(); diff --git a/support-files/sql/2003_v2.x/2020_ci_store-update_v2.0_mysql.sql b/support-files/sql/2003_v2.x/2020_ci_store-update_v2.0_mysql.sql new file mode 100644 index 00000000000..4a5ab839a88 --- /dev/null +++ b/support-files/sql/2003_v2.x/2020_ci_store-update_v2.0_mysql.sql @@ -0,0 +1,43 @@ +USE devops_ci_store; +SET NAMES utf8mb4; + +DROP PROCEDURE IF EXISTS ci_store_schema_update; + +DELIMITER + +CREATE PROCEDURE ci_store_schema_update() +BEGIN + + DECLARE db VARCHAR(100); + SET AUTOCOMMIT = 0; + SELECT DATABASE() INTO db; + + IF EXISTS(SELECT 1 + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = db + AND TABLE_NAME = 'T_ATOM' + AND COLUMN_NAME = 'VERSION') THEN + ALTER TABLE T_ATOM MODIFY COLUMN VERSION varchar(30) NOT NULL COMMENT '版本号'; + END IF; + + IF NOT EXISTS(SELECT 1 + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = db + AND TABLE_NAME = 'T_ATOM' + AND COLUMN_NAME = 'BRANCH_TEST_FLAG') THEN + ALTER TABLE T_ATOM ADD BRANCH_TEST_FLAG bit(1) DEFAULT b'0' NULL COMMENT '是否是分支测试版本'; + END IF; + + IF NOT EXISTS(SELECT 1 + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = db + AND TABLE_NAME = 'T_ATOM' + AND COLUMN_NAME = 'LATEST_TEST_FLAG') THEN + ALTER TABLE T_ATOM ADD LATEST_TEST_FLAG bit(1) DEFAULT b'0' NULL COMMENT '是否为最新测试版本原子, TRUE:最新 FALSE:非最新'; + END IF; + + COMMIT; +END +DELIMITER ; +COMMIT; +CALL ci_store_schema_update();