Skip to content

Commit

Permalink
feat:流水线插件代码库开启默认分支保护 TencentBlueKing#9814
Browse files Browse the repository at this point in the history
  • Loading branch information
yjieliang committed Dec 15, 2023
1 parent cc3fa1a commit 16c9b6e
Show file tree
Hide file tree
Showing 6 changed files with 513 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ const val API_PERMISSION = "BK_CI_API_PERMISSION" // 请求API权限
const val REQUEST_IP = "X-Forwarded-For" // 请求IP
const val BK_CREATE = "bkCreate" // 创建
const val BK_REVISE = "bkRevise" // 修改
const val DEFAULT_PROTECTION_BRANCH_RULE_NAME = "master_branch_rule"

const val KEY_START_TIME = "startTime"
const val KEY_END_TIME = "endTime"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -684,4 +684,138 @@ open class GitApi {
}
return JsonUtil.getObjectMapper().readValue(responseBody)
}

fun listMergeRequest(
host: String,
token: String,
projectName: String,
sourceBranch: String?,
targetBranch: String?,
state: String?,
page: Int,
perPage: Int
): List<GitMrInfo> {
val queryParams =
"source_branch=$sourceBranch&target_branch=$targetBranch&state=$state&page=$page&per_page=$perPage"
val url = "projects/${urlEncode(projectName)}/merge_requests"
logger.info("list mr for project($projectName): url($url)")
val request = get(host, token, url, queryParams)
return JsonUtil.getObjectMapper().readValue<List<GitMrInfo>>(
getBody(getMessageByLocale(CommonMessageCode.OPERATION_LIST_MR), request)
)
}

fun createMergeRequest(
host: String,
token: String,
projectName: String,
gitCreateMergeRequest: GitCreateMergeRequest
): GitMrInfo {
val body = JsonUtil.getObjectMapper().writeValueAsString(gitCreateMergeRequest)
val url = "projects/${urlEncode(projectName)}/merge_requests/"
logger.info("create mr for project($projectName): url($url), $body")
val request = post(host, token, url, body)
try {
return callMethod(
operation = getMessageByLocale(CommonMessageCode.OPERATION_ADD_MR),
request = request,
classOfT = GitMrInfo::class.java
)
} catch (t: GitApiException) {
if (t.code == 403) {
throw GitApiException(t.code, getMessageByLocale(CommonMessageCode.ADD_MR_FAIL))
}
throw t
}
}

/**
* 获取项目下保护分支所属规则组ID
*/
fun getProtectBranchRuleId(
host: String,
token: String,
projectName: String,
branch: String
): Int? {
val url = "projects/${URLEncoder.encode(projectName, "UTF8")}/repository/branches/$branch/protect"
logger.info("getProtectDetail request url: $url")
val request = get(host, token, url, "")
val responseMap = callMethod(getMessageByLocale(CommonMessageCode.GET_PROTECT_BRANCH_RULE), request)
return responseMap["rule_id"] as? Int
}

/**
* 创建项目下保护分支规则组
*/
fun createProtectBranchRules(
host: String,
token: String,
projectName: String,
ruleMap: Map<String, Any>
): Int {
if (ruleMap.isEmpty()) throw ErrorCodeException(
errorCode = CommonMessageCode.ERROR_INVALID_PARAM_,
params = arrayOf("ruleMap")
)
val url = "projects/${URLEncoder.encode(projectName, "UTF8")}/protected_branch_rules"
val request = post(host, token, url, JsonUtil.toJson(ruleMap))
val responseMap = callMethod(CommonMessageCode.UPDATE_PROTECT_BRANCH_RULE, request)
return responseMap["id"] as Int
}

/**
* 将分支变为保护分支
*/
fun setupProtectBranch(
host: String,
token: String,
projectName: String,
branch: String,
ruleId: Int
): Boolean {
val url = "projects/${URLEncoder.encode(projectName, "UTF8")}/protected_branch_rules" +
"/$ruleId/branches?branch=$branch"
val request = post(host, token, url, "{}")
callMethod(CommonMessageCode.UPDATE_PROTECT_BRANCH_RULE, request)
return true
}

/**
* 修改项目下保护分支规则组规则
*/
fun updateProtectBranchRule(
host: String,
token: String,
projectName: String,
ruleId: Int,
ruleMap: Map<String, Any>
): Boolean {
if (ruleMap.isEmpty()) throw ErrorCodeException(
errorCode = CommonMessageCode.ERROR_INVALID_PARAM_,
params = arrayOf("ruleMap")
)
val url = "projects/${URLEncoder.encode(projectName, "UTF8")}/protected_branch_rules/$ruleId"
val request = put(host, token, url, JsonUtil.toJson(ruleMap))
callMethod(CommonMessageCode.UPDATE_PROTECT_BRANCH_RULE, request)
return true
}


/**
* 修改项目组用户权限等级
*/
fun updateProjectUserAccessLevel(
userId: Int,
host: String,
token: String,
projectName: String,
accessLevel: Int
): Boolean {
val url = "projects/${URLEncoder.encode(projectName, "UTF8")}/members/$userId"
val handle = mapOf<String, Any>("access_level" to accessLevel)
val request = put(host, token, url, JsonUtil.toJson(handle))
callMethod(CommonMessageCode.UPDATE_PROJECT_USER_ACCESS_LEVEL, request)
return true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@
package com.tencent.devops.repository.service

import com.tencent.devops.common.api.constant.CommonMessageCode
import com.tencent.devops.common.api.constant.DEFAULT_PROTECTION_BRANCH_RULE_NAME
import com.tencent.devops.common.api.constant.MASTER
import com.tencent.devops.common.api.constant.coerceAtMaxLength
import com.tencent.devops.common.api.enums.FrontendTypeEnum
import com.tencent.devops.common.api.enums.RepositoryConfig
import com.tencent.devops.common.api.enums.RepositoryType
import com.tencent.devops.common.api.enums.ScmType
import com.tencent.devops.common.api.exception.ErrorCodeException
import com.tencent.devops.common.api.exception.OauthForbiddenException
import com.tencent.devops.common.api.exception.OperationException
import com.tencent.devops.common.api.exception.ParamBlankException
import com.tencent.devops.common.api.exception.PermissionForbiddenException
Expand All @@ -43,12 +46,15 @@ import com.tencent.devops.common.api.util.DHUtil
import com.tencent.devops.common.api.util.DateTimeUtil
import com.tencent.devops.common.api.util.HashUtil
import com.tencent.devops.common.api.util.MessageUtil
import com.tencent.devops.common.api.util.PageUtil
import com.tencent.devops.common.api.util.timestamp
import com.tencent.devops.common.api.util.timestampmilli
import com.tencent.devops.common.auth.api.AuthPermission
import com.tencent.devops.common.pipeline.utils.RepositoryConfigUtils
import com.tencent.devops.common.web.utils.I18nUtil
import com.tencent.devops.model.repository.tables.records.TRepositoryRecord
import com.tencent.devops.repository.constant.RepositoryMessageCode
import com.tencent.devops.repository.constant.RepositoryMessageCode.NOT_AUTHORIZED_BY_OAUTH
import com.tencent.devops.repository.constant.RepositoryMessageCode.USER_CREATE_PEM_ERROR
import com.tencent.devops.repository.dao.RepositoryCodeGitDao
import com.tencent.devops.repository.dao.RepositoryDao
Expand All @@ -72,15 +78,15 @@ import com.tencent.devops.scm.pojo.GitCommit
import com.tencent.devops.scm.pojo.GitProjectInfo
import com.tencent.devops.scm.pojo.GitRepositoryDirItem
import com.tencent.devops.scm.pojo.GitRepositoryResp
import java.time.LocalDateTime
import java.util.Base64
import javax.ws.rs.NotFoundException
import org.jooq.DSLContext
import org.jooq.impl.DSL
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import java.time.LocalDateTime
import java.util.Base64
import javax.ws.rs.NotFoundException

@Service
@Suppress("ALL")
Expand Down Expand Up @@ -1142,6 +1148,87 @@ class RepositoryService @Autowired constructor(
)
}

fun setProjectProtectionBranchDefaultRules(
userId: String,
repositoryHashId:String,
ruleMap: Map<String, Any>
): Result<Boolean> {
try {
val accessToken = gitOauthService.getAccessToken(userId) ?: throw OauthForbiddenException(
message = MessageUtil.getMessageByLocale(NOT_AUTHORIZED_BY_OAUTH, I18nUtil.getLanguage(userId))
)
val repoId = serviceGet(
"",
RepositoryConfigUtils.buildConfig(repositoryHashId, RepositoryType.ID)
).projectName
var ruleId = gitService.getProtectBranchRuleId(
token = accessToken.accessToken,
gitProjectId = repoId,
tokenType = TokenTypeEnum.OAUTH,
branch = MASTER
).data
// 设置保护分支规则组默认规则
if (ruleId == null) {
val newRuleMap = mutableMapOf<String, Any>()
newRuleMap.putAll(ruleMap)
newRuleMap["name"] = DEFAULT_PROTECTION_BRANCH_RULE_NAME
// 设置保护分支
ruleId = gitService.createProtectBranchRules(
token = accessToken.accessToken,
gitProjectId = repoId,
tokenType = TokenTypeEnum.OAUTH,
ruleMap = newRuleMap
).data!!
gitService.setupProtectBranch(
token = accessToken.accessToken,
gitProjectId = repoId,
tokenType = TokenTypeEnum.OAUTH,
ruleId = ruleId,
branch = MASTER
)
} else {
gitService.updateProtectBranchRule(
token = accessToken.accessToken,
gitProjectId = repoId,
tokenType = TokenTypeEnum.OAUTH,
ruleId = ruleId,
ruleMap = ruleMap
)
}
// 获取项目有权限的成员列表
var page = PageUtil.DEFAULT_PAGE
do {
val repoAllMembers = gitService.getMembers(
token = accessToken.accessToken,
gitProjectId = repoId,
page = page,
pageSize = PageUtil.DEFAULT_PAGE_SIZE,
tokenType = TokenTypeEnum.OAUTH,
search = null
).data
if (!repoAllMembers.isNullOrEmpty()) {
// 设置项目有MASTER权限的成员默认权限级别为DEVELOP
repoAllMembers.forEach {
if (it.accessLevel == GitAccessLevelEnum.MASTER.level) {
gitService.updateProjectUserAccessLevel(
userId = it.id,
gitProjectId = repoId,
tokenType = TokenTypeEnum.OAUTH,
token = accessToken.accessToken,
accessLevel = GitAccessLevelEnum.DEVELOPER.level
)
}
}
}
page++
} while (repoAllMembers?.size == PageUtil.DEFAULT_PAGE_SIZE)

} catch (ignore: Throwable) {
logger.error("update atom[$repositoryHashId] project protection branch default rules error", ignore)
}
return Result(true)
}

companion object {
private val logger = LoggerFactory.getLogger(RepositoryService::class.java)
const val MAX_ALIAS_LENGTH = 255
Expand Down
Loading

0 comments on commit 16c9b6e

Please sign in to comment.