273 lines
11 KiB
Groovy
273 lines
11 KiB
Groovy
//=================================================================
|
||
// Byway Studios Inc. Confidential Information.
|
||
// Copyright Byway Studios Inc. All rights reserved
|
||
//=================================================================
|
||
|
||
import groovy.json.JsonOutput
|
||
import groovy.json.JsonSlurperClassic
|
||
import com.cloudbees.groovy.cps.NonCPS
|
||
|
||
@NonCPS
|
||
def getTriggerUser(buildCauses)
|
||
{
|
||
def triggerUser = "自动触发"
|
||
if (buildCauses && buildCauses.size() > 0 && buildCauses[0].userName) {
|
||
triggerUser = buildCauses[0].userName
|
||
}
|
||
return triggerUser
|
||
}
|
||
|
||
@NonCPS
|
||
def getFailedStage(build)
|
||
{
|
||
def failedStage = ""
|
||
if (build.currentResult == 'FAILURE') {
|
||
def stages = build.rawBuild.getAction(org.jenkinsci.plugins.workflow.job.views.FlowGraphAction)?.getNodes()
|
||
if (stages) {
|
||
for (stage in stages) {
|
||
if (stage.getError() != null) {
|
||
failedStage = "\n- 失败阶段: ${stage.getDisplayName()}"
|
||
break
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return failedStage
|
||
}
|
||
|
||
@NonCPS
|
||
def getMainRepoChangeString(changeLogSets)
|
||
{
|
||
def changeString = ""
|
||
if (changeLogSets && changeLogSets.size() > 0) {
|
||
changeString = "\n\n提交记录:\n"
|
||
for (int i = 0; i < changeLogSets.size(); i++) {
|
||
def entries = changeLogSets[i].items
|
||
for (int j = 0; j < entries.length; j++) {
|
||
def entry = entries[j]
|
||
changeString += "- ${entry.commitId.take(7)} ${entry.msg} - ${entry.author}\n"
|
||
}
|
||
}
|
||
} else {
|
||
changeString = "\n\n提交记录: 无变更"
|
||
}
|
||
return changeString
|
||
}
|
||
|
||
def call(Map config)
|
||
{
|
||
pipeline
|
||
{
|
||
agent
|
||
{
|
||
label config.winbakeLabel
|
||
}
|
||
parameters
|
||
{
|
||
booleanParam(name: 'CleanBuild', defaultValue: false, description: 'Force Clean Build to Avoid Previous Build Cache')
|
||
booleanParam(name: 'DebugBuild', defaultValue: false, description: 'To Create Debug Build for Profiling')
|
||
booleanParam(name: 'CleanCache', defaultValue: false, description: 'Force Clean Script and Package Cache')
|
||
booleanParam(name: 'CleanLibrary', defaultValue: false, description: 'Force Clean the Whole Library Folder')
|
||
}
|
||
options
|
||
{
|
||
skipDefaultCheckout(true) // ★ 关键:禁止 Jenkins 自动 checkout library
|
||
}
|
||
stages
|
||
{
|
||
stage("Checkout Unity Project")
|
||
{
|
||
options
|
||
{
|
||
timeout(30)
|
||
}
|
||
steps
|
||
{
|
||
script {
|
||
// 配置 Git 支持长路径(解决 Windows 260 字符限制)
|
||
bat 'git config --global core.longpaths true'
|
||
}
|
||
script {
|
||
// 最小化处理:checkout 前仅重置子模块,避免残留改动导致冲突
|
||
bat '''
|
||
if exist .gitmodules (
|
||
git submodule foreach --recursive git reset --hard
|
||
)
|
||
'''
|
||
}
|
||
checkout([
|
||
$class: 'GitSCM',
|
||
branches: [[name: '*/main']], // 分支名
|
||
userRemoteConfigs: [[
|
||
url: 'git@gitea.bywaystudios.com:pet_home/AplusB_Pet_nation.git',
|
||
credentialsId: '503eaa43-0676-40ac-81c0-d9c5cc8b4ff7'
|
||
]],
|
||
extensions: [
|
||
[$class: 'SubmoduleOption',
|
||
disableSubmodules: false,
|
||
parentCredentials: true,
|
||
recursiveSubmodules: true,
|
||
trackingSubmodules: true, // 关闭,避免冲突
|
||
reference: '',
|
||
timeout: 20,
|
||
threads: 1],
|
||
[$class: 'PruneStaleBranch']
|
||
]
|
||
])
|
||
|
||
}
|
||
}
|
||
stage("Build Unity Android")
|
||
{
|
||
options
|
||
{
|
||
timeout(60)
|
||
}
|
||
steps
|
||
{
|
||
BuildAndroid(config)
|
||
}
|
||
}
|
||
stage("AchiveArtifact")
|
||
{
|
||
options
|
||
{
|
||
timeout(10)
|
||
}
|
||
steps
|
||
{
|
||
archiveArtifact("Android_dev")
|
||
}
|
||
}
|
||
}
|
||
post
|
||
{
|
||
always
|
||
{
|
||
script {
|
||
// 获取触发者
|
||
def triggerUser = getTriggerUser(currentBuild.getBuildCauses())
|
||
|
||
// 获取失败阶段(仅失败时)
|
||
def failedStage = getFailedStage(currentBuild)
|
||
|
||
// 收集提交记录
|
||
def changeString = getMainRepoChangeString(currentBuild.changeSets)
|
||
|
||
// 收集子模块提交记录(与上一次构建对比)
|
||
def submoduleChangeString = ""
|
||
def submoduleStateFile = ".jenkins_submodule_state_dev.json"
|
||
def previousSubmoduleStates = [:]
|
||
def currentSubmoduleStates = [:]
|
||
|
||
if (fileExists(submoduleStateFile)) {
|
||
try {
|
||
previousSubmoduleStates = new JsonSlurperClassic().parseText(readFile(submoduleStateFile)) ?: [:]
|
||
} catch (Exception ignored) {
|
||
previousSubmoduleStates = [:]
|
||
}
|
||
}
|
||
|
||
if (fileExists('.git') && fileExists('.gitmodules')) {
|
||
try {
|
||
def submoduleStatusOutput = bat(
|
||
returnStdout: true,
|
||
script: '@echo off\r\ngit submodule status --recursive'
|
||
).trim()
|
||
|
||
def submoduleLines = submoduleStatusOutput ? submoduleStatusOutput.readLines().findAll { it?.trim() } : []
|
||
def submoduleSections = []
|
||
|
||
submoduleLines.each { rawLine ->
|
||
def line = rawLine.replace('\r', '').trim()
|
||
if (!line || line.length() < 42) {
|
||
return
|
||
}
|
||
|
||
def remainder = line.substring(1).trim()
|
||
def firstSpaceIndex = remainder.indexOf(' ')
|
||
if (firstSpaceIndex <= 0) {
|
||
return
|
||
}
|
||
|
||
def pathPart = remainder.substring(firstSpaceIndex + 1).trim()
|
||
def branchInfoIndex = pathPart.indexOf(' (')
|
||
def submodulePath = (branchInfoIndex >= 0 ? pathPart.substring(0, branchInfoIndex) : pathPart).trim()
|
||
if (!submodulePath) {
|
||
return
|
||
}
|
||
|
||
def currentSha = bat(
|
||
returnStdout: true,
|
||
script: "@echo off\r\ngit -C \"${submodulePath}\" rev-parse HEAD"
|
||
).trim()
|
||
def currentHeadMessage = bat(
|
||
returnStdout: true,
|
||
script: "@echo off\r\ngit -C \"${submodulePath}\" log -1 --pretty=format:\"%%h %%s - %%an\""
|
||
).trim()
|
||
|
||
currentSubmoduleStates[submodulePath] = [sha: currentSha]
|
||
|
||
def previousSha = previousSubmoduleStates[submodulePath]?.sha
|
||
if (previousSha && previousSha != currentSha) {
|
||
def commitLogs = ""
|
||
try {
|
||
commitLogs = bat(
|
||
returnStdout: true,
|
||
script: "@echo off\r\ngit -C \"${submodulePath}\" log --pretty=format:\"- %%h %%s - %%an\" ${previousSha}..${currentSha}"
|
||
).trim()
|
||
} catch (Exception ignored) {
|
||
commitLogs = "- ${currentHeadMessage}"
|
||
}
|
||
|
||
if (!commitLogs) {
|
||
commitLogs = "- ${currentHeadMessage}"
|
||
}
|
||
|
||
submoduleSections << "- 子模块: ${submodulePath}\n${commitLogs}"
|
||
} else if (!previousSha) {
|
||
submoduleSections << "- 子模块: ${submodulePath}\n- 首次记录: ${currentHeadMessage}"
|
||
}
|
||
}
|
||
|
||
if (submoduleSections.size() > 0) {
|
||
submoduleChangeString = "\n\n子模块提交记录:\n" + submoduleSections.join("\n")
|
||
} else {
|
||
submoduleChangeString = "\n\n子模块提交记录: 无变更"
|
||
}
|
||
|
||
writeFile(
|
||
file: submoduleStateFile,
|
||
text: JsonOutput.prettyPrint(JsonOutput.toJson(currentSubmoduleStates))
|
||
)
|
||
} catch (Exception ex) {
|
||
echo "子模块提交记录收集失败: ${ex.message}"
|
||
submoduleChangeString = "\n\n子模块提交记录: 收集失败"
|
||
}
|
||
} else {
|
||
submoduleChangeString = "\n\n子模块提交记录: 无子模块"
|
||
}
|
||
|
||
dingtalk(
|
||
robot:'dingtalk_unity_1',
|
||
type:'MARKDOWN',
|
||
title:"${currentBuild.currentResult} - dev #${env.BUILD_NUMBER}",
|
||
text: [
|
||
"### ${currentBuild.currentResult}",
|
||
"\n构建信息:",
|
||
"- 项目: ${env.JOB_NAME}",
|
||
"- 构建号: #${env.BUILD_NUMBER}",
|
||
"- 分支: main",
|
||
"- 触发者: ${triggerUser}",
|
||
"- 耗时: ${currentBuild.durationString}${failedStage}",
|
||
"\n链接:",
|
||
"- [下载链接](${env.BUILD_URL})",
|
||
changeString,
|
||
submoduleChangeString
|
||
]
|
||
)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} |