All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tencent.devops.process.yaml.modelCreate.ModelCreate.kt Maven / Gradle / Ivy

/*
 * 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.process.yaml.modelCreate

import com.tencent.devops.common.api.constant.CommonMessageCode.BK_BUILD_TRIGGER
import com.tencent.devops.common.api.constant.CommonMessageCode.BK_MANUAL_TRIGGER
import com.tencent.devops.common.api.pojo.PipelineAsCodeSettings
import com.tencent.devops.common.client.Client
import com.tencent.devops.common.pipeline.Model
import com.tencent.devops.common.pipeline.container.Stage
import com.tencent.devops.common.pipeline.container.TriggerContainer
import com.tencent.devops.common.pipeline.pojo.BuildFormProperty
import com.tencent.devops.common.pipeline.pojo.element.Element
import com.tencent.devops.common.pipeline.pojo.element.trigger.ManualTriggerElement
import com.tencent.devops.common.web.utils.I18nUtil
import com.tencent.devops.process.api.user.UserPipelineGroupResource
import com.tencent.devops.process.engine.common.VMUtils
import com.tencent.devops.process.pojo.classify.PipelineGroup
import com.tencent.devops.process.pojo.classify.PipelineGroupCreate
import com.tencent.devops.process.pojo.classify.PipelineLabelCreate
import com.tencent.devops.process.pojo.setting.PipelineModelAndSetting
import com.tencent.devops.process.pojo.setting.PipelineRunLockType
import com.tencent.devops.process.pojo.setting.PipelineSetting
import com.tencent.devops.process.yaml.modelCreate.inner.ModelCreateEvent
import com.tencent.devops.process.yaml.pojo.QualityElementInfo
import com.tencent.devops.process.yaml.v2.models.ScriptBuildYaml
import java.util.concurrent.TimeUnit
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
import com.tencent.devops.process.yaml.v2.models.stage.Stage as StreamV2Stage

@Component
class ModelCreate @Autowired constructor(
    val client: Client,
    val modelStage: ModelStage
) {

    companion object {
        private val logger = LoggerFactory.getLogger(ModelCreate::class.java)
    }

    fun createPipelineModel(
        modelName: String,
        event: ModelCreateEvent,
        yaml: ScriptBuildYaml,
        pipelineParams: List,
        asCodeSettings: PipelineAsCodeSettings?
    ): PipelineModelAndSetting {
        // 流水线插件标签设置
        val labelList = preparePipelineLabels(event, yaml)

        val stageList = mutableListOf()

        // 第一个stage,触发类
        val triggerElementList = mutableListOf()
        val manualTriggerElement = ManualTriggerElement(
            I18nUtil.getCodeLanMessage(BK_MANUAL_TRIGGER),
            "T-1-1-1"
        )
        triggerElementList.add(manualTriggerElement)

        val triggerContainer = TriggerContainer(
            id = "0",
            name = I18nUtil.getCodeLanMessage(BK_BUILD_TRIGGER),
            elements = triggerElementList,
            status = null,
            startEpoch = null,
            systemElapsed = null,
            elementElapsed = null,
            params = pipelineParams
        )

        // 蓝盾引擎会将stageId从1开始顺序强制重写,因此在生成model时保持一致
        var stageIndex = 1
        val stageId = VMUtils.genStageId(stageIndex++)
        val stage1 = Stage(listOf(triggerContainer), id = stageId, name = stageId)
        stageList.add(stage1)

        // 红线的步骤指标 xxx* 的判断,当指定多个指标时报错,所以需要维护一套List
        // list中保存
        val elementNames: MutableList = mutableListOf()

        // 其他的stage
        yaml.stages.forEach { stage ->
            stageList.add(
                modelStage.createStage(
                    stage = stage,
                    event = event,
                    // stream的stage标号从1开始,后续都加1
                    stageIndex = stageIndex++,
                    resources = yaml.resource,
                    jobBuildTemplateAcrossInfos = event.jobTemplateAcrossInfo,
                    elementNames = elementNames
                )
            )
        }
        // 添加finally
        if (!yaml.finally.isNullOrEmpty()) {
            stageList.add(
                modelStage.createStage(
                    stage = StreamV2Stage(
                        name = "Finally",
                        label = emptyList(),
                        ifField = null,
                        fastKill = false,
                        jobs = yaml.finally!!,
                        checkIn = null,
                        checkOut = null
                    ),
                    event = event,
                    stageIndex = stageIndex,
                    finalStage = true,
                    resources = yaml.resource,
                    jobBuildTemplateAcrossInfos = event.jobTemplateAcrossInfo,
                    elementNames = null
                )
            )
        }

        return PipelineModelAndSetting(
            model = Model(
                name = modelName,
                desc = "",
                stages = stageList,
                labels = labelList,
                instanceFromTemplate = false,
                pipelineCreator = event.userId
            ),
            setting = PipelineSetting(
                concurrencyGroup = yaml.concurrency?.group,
                // Cancel-In-Progress 配置group后默认为true
                concurrencyCancelInProgress = yaml.concurrency?.cancelInProgress
                    ?: yaml.concurrency?.group?.let { true }
                    ?: true,
                runLockType = when {
                    yaml.concurrency?.group != null -> PipelineRunLockType.GROUP_LOCK
                    else -> PipelineRunLockType.MULTIPLE
                },
                waitQueueTimeMinute = yaml.concurrency?.queueTimeoutMinutes ?: TimeUnit.HOURS.toMinutes(8).toInt(),
                // #6090 stream重试时均需要清理变量表
                cleanVariablesWhenRetry = true,
                maxQueueSize = yaml.concurrency?.queueLength ?: 1,
                labels = labelList,
                pipelineAsCodeSettings = asCodeSettings
            )
        )
    }

    @Suppress("NestedBlockDepth")
    private fun preparePipelineLabels(
        event: ModelCreateEvent,
        yaml: ScriptBuildYaml
    ): List {
        val gitCIPipelineLabels = mutableListOf()

        try {
            // 获取当前项目下存在的标签组
            val pipelineGroups = client.get(UserPipelineGroupResource::class)
                .getGroups(event.userId, event.projectCode)
                .data

            yaml.label?.forEach {
                // 要设置的标签组不存在,新建标签组和标签(同名)
                if (!checkPipelineLabel(it, pipelineGroups)) {
                    client.get(UserPipelineGroupResource::class).addGroup(
                        event.userId,
                        PipelineGroupCreate(
                            projectId = event.projectCode,
                            name = it
                        )
                    )

                    val pipelineGroup = getPipelineGroup(it, event.userId, event.projectCode)
                    if (pipelineGroup != null) {
                        client.get(UserPipelineGroupResource::class).addLabel(
                            userId = event.userId,
                            projectId = event.projectCode,
                            pipelineLabel = PipelineLabelCreate(
                                groupId = pipelineGroup.id,
                                name = it
                            )
                        )
                    }
                }

                // 保证标签已创建成功后,取label加密ID
                val pipelineGroup = getPipelineGroup(it, event.userId, event.projectCode)
                gitCIPipelineLabels.add(pipelineGroup!!.labels[0].id)
            }
        } catch (e: Exception) {
            logger.warn("${event.userId}|${event.projectCode} preparePipelineLabels error.", e)
        }

        return gitCIPipelineLabels
    }

    private fun checkPipelineLabel(gitciPipelineLabel: String, pipelineGroups: List?): Boolean {
        pipelineGroups?.forEach { pipelineGroup ->
            pipelineGroup.labels.forEach {
                if (it.name == gitciPipelineLabel) {
                    return true
                }
            }
        }

        return false
    }

    private fun getPipelineGroup(labelGroupName: String, userId: String, projectId: String): PipelineGroup? {
        val pipelineGroups = client.get(UserPipelineGroupResource::class)
            .getGroups(userId, projectId)
            .data
        pipelineGroups?.forEach {
            if (it.name == labelGroupName) {
                return it
            }
        }

        return null
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy