Plastic SCM 与 Jenkins 集成
May 26, 2024About 2 min
Plastic SCM 与 Jenkins 集成
记一下在 Jenkins 里拉 Plastic SCM 工作区的配置,以及一个我踩过的坑:把 Plastic 的提交描述同步到 Perforce 时出现编码问题,最后用了两种办法绕过。工作区路径、仓库名(RepoA / RepoB)、P4 路径都是占位,换成自己的。
Jenkins 拉取 Plastic 工作区
装好 Plastic SCM 的 Jenkins 插件后,在 pipeline 里用 checkout step 指定仓库、路径和分支:
checkout([$class: 'PlasticSCM',
cleanup: 'MINIMAL',
credentialsId: '',
directory: 'C:\\Users\\<user>\\wkspaces\\demowk',
pollOnController: false,
selector: '''repository "default"
path "/"
smartbranch "main"''',
useMultipleWorkspaces: false,
workingMode: 'NONE'])
selector 用三引号多行字符串描述 repository / path / smartbranch;directory 是工作区落地的本地目录。
Plastic 提交描述同步到 P4 的编码问题
需求
Plastic 的提交同步到 P4 时,要收集 Plastic 的提交描述并写入 P4 的提交描述。
###问题
如果直接用 bat 调 p4 submit,描述里的特殊字符会让 cmd 把一条命令拆成多行,导致提交描述没法正确写入。
解法一:用 API
不经过 shell 直接传字符串,绕开 cmd 对特殊字符的解析。用 cm find changeset 取描述(指定 UTF-8 编码),再用 P4 的 Groovy API 提交:
stage('test'){
steps{
script{
env.LAST_PL_CHANGELIST = "4775"
env.plastic_comment = powershell(returnStdout:true, script: """ cm find changeset "where changesetid > ${env.LAST_PL_CHANGELIST} and branch='br:/dev'" --format="{changesetid}-{date}-{comment}" """, encoding: 'UTF-8').trim()
println "plastic_comment=${env.plastic_comment}"
def p4 = p4ConnectStaticSpec(env.p4Credential, env.P4CLIENT)
myutil.runP4Cmd(p4, 'submit', '-d', "[Test]plastic comment ${env.plastic_comment}")
}
}
}
解法二:用模板文件
走 p4 change -o 拿到 changelist 模板,把描述行替换进去再 p4 submit -i 喂回去,整个过程不把描述当命令行参数,自然不会被特殊字符破坏。关键是把控制台代码页切成 UTF-8(chcp 65001),读写文件都指定 UTF-8 编码:
stage('test'){
steps{
script{
def description_file = "D:\\plastic_p4_sync_info\\description.txt"
def newchange_path = "D:\\plastic_p4_sync_info\\newchange.txt"
def newchange_path2 = "D:\\plastic_p4_sync_info\\newchange2.txt"
def desc = "[Sync]copying //myrepo_sync/Game/...@${env.p4_sync_last_CL} plastic /dev@${env.dev_merge_CL} to //myrepo/main/Z/... "
env.LAST_PL_CHANGELIST = "4760"
bat"""
chcp 65001
cm find changeset "where changesetid > ${env.LAST_PL_CHANGELIST} and branch='br:/dev'" --format="{changesetid}_{date}_{comment}" > ${description_file}
p4 change -o > ${newchange_path}
echo New change file written at: ${newchange_path}
type ${newchange_path}
"""
def newChangeLines = []
if (fileExists(newchange_path)) {
def lines = readFile(file: newchange_path, encoding: 'UTF-8').readLines()
for (line in lines) {
if (line.trim() == "<enter description here>") {
// 读取描述文件
if (fileExists(description_file)) {
def descLines = readFile(file: description_file, encoding: 'UTF-8').readLines()
descLines.add(0, " ${desc}")
newChangeLines += descLines.collect { " ${it}" }
}
} else {
newChangeLines << line
}
}
// 把新的变更列表写入临时文件
writeFile file: newchange_path2, text: newChangeLines.join("\n"), encoding: 'UTF-8'
echo "Processed file written to ${newchange_path2}"
} else {
echo "File not found: ${newchange_path}"
}
bat"""
move /Y ${newchange_path2} ${newchange_path}
p4 submit -i < ${newchange_path}
"""
}
}
}
两种办法都行:API 法更干净,模板文件法在不方便用 P4 Groovy API、只能走命令行时更实用。