From 487571b51d5ba04fc2f80c3481896aff711dea0c Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Mon, 29 Jun 2026 12:50:34 +0800 Subject: [PATCH] =?UTF-8?q?ci:=20=E9=87=8D=E5=86=99=20Jenkinsfile=20?= =?UTF-8?q?=E9=80=82=E9=85=8D=20Windows=20Jenkins=EF=BC=8C=E5=8E=BB?= =?UTF-8?q?=E6=8E=89=E7=BC=96=E8=AF=91=E6=AD=A5=E9=AA=A4=E5=8F=AA=E4=BF=9D?= =?UTF-8?q?=E7=95=99=20git=20=E5=8F=91=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Jenkinsfile | 207 ++++++++++++++++++---------------------------------- 1 file changed, 70 insertions(+), 137 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 5af9088..9be09fd 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,16 +1,11 @@ pipeline { - agent any // macOS agent (szyx.xuqinmin.com) + agent any // jenkins.xuqinmin.com (Windows) parameters { - // ── 发布模式 ───────────────────────────────────────────────────────── booleanParam(name: 'SNAPSHOT', defaultValue: true, - description: '勾选=SNAPSHOT(推送到 main 分支,不升版本,不打 tag;应用通过 branch:"main" 引用);不勾选=正式 Release(升版本号、打 tag、推送)') - - // ── 版本升级策略(仅 Release 时生效)─────────────────────────────── + description: '勾选=SNAPSHOT(推送 main,不升版本,不打 tag);不勾选=正式 Release(升版本、打 tag、创建 Gitea Release)') choice(name: 'VERSION_BUMP', choices: ['patch', 'minor', 'major'], - description: '版本升级策略: major(1.0.0→2.0.0) / minor(1.0.0→1.1.0) / patch(1.0.0→1.0.1)(SNAPSHOT 模式忽略)') - - // ── 模块选择(标记本次改动范围,用于 changelog — 不影响版本号)── + description: '版本升级策略(Release 时有效): patch 1.0.0→1.0.1 / minor 1.0.0→1.1.0 / major 1.0.0→2.0.0') booleanParam(name: 'MOD_CORE', defaultValue: false, description: '本次包含 XuqmCoreSDK 改动') booleanParam(name: 'MOD_IM', defaultValue: false, description: '本次包含 XuqmImSDK 改动') booleanParam(name: 'MOD_PUSH', defaultValue: false, description: '本次包含 XuqmPushSDK 改动') @@ -19,10 +14,6 @@ pipeline { booleanParam(name: 'MOD_FILE', defaultValue: false, description: '本次包含 XuqmFileSDK 改动') booleanParam(name: 'MOD_WEBVIEW', defaultValue: false, description: '本次包含 XuqmWebViewSDK 改动') booleanParam(name: 'MOD_BUGCOLLECT', defaultValue: false, description: '本次包含 XuqmBugCollectSDK 改动') - - // ── 构建选项 ──────────────────────────────────────────────────────── - booleanParam(name: 'RUN_TESTS', defaultValue: true, - description: '是否运行 swift test(在 macOS 上执行 SPM 测试)') } environment { @@ -32,9 +23,8 @@ pipeline { } options { - timeout(time: 30, unit: 'MINUTES') - buildDiscarder(logRotator(numToKeepStr: '20')) disableConcurrentBuilds() + buildDiscarder(logRotator(numToKeepStr: '20')) } stages { @@ -42,15 +32,10 @@ pipeline { // ───────────────────────────────────────────────────────────────────── stage('Checkout') { steps { - checkout([ - $class: 'GitSCM', - branches: [[name: 'main']], - extensions: [[$class: 'CleanBeforeCheckout']], - userRemoteConfigs: scm.userRemoteConfigs - ]) + checkout scm + bat 'git config user.email "jenkins@xuqm.com"' + bat 'git config user.name "Jenkins CI"' script { - env.GIT_COMMIT_SHORT = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim() - def moduleChecks = [ 'XuqmCoreSDK': params.MOD_CORE, 'XuqmImSDK': params.MOD_IM, @@ -63,10 +48,10 @@ pipeline { ] def changed = moduleChecks.findAll { k, v -> v }.collect { k, v -> k } if (changed.isEmpty()) { - error("没有勾选任何模块,请至少标记一个有改动的模块") + error('没有勾选任何模块,请至少标记一个有改动的模块') } env.CHANGED_MODULES = changed.join(', ') - echo "Changed modules: ${env.CHANGED_MODULES}" + echo "改动模块: ${env.CHANGED_MODULES}" } } } @@ -76,127 +61,77 @@ pipeline { steps { script { def propsText = readFile('version.properties') - def match = (propsText =~ /SDK_VERSION=([0-9][^\s#\r\n]*)/) - if (!match) { error("version.properties 中找不到 SDK_VERSION") } - def currentVer = match[0][1].replaceAll(/-SNAPSHOT$/, '') - - def bumpVersion = { String ver -> - def parts = ver.tokenize('.') - while (parts.size() < 3) { parts.add('0') } - def major = parts[0].toInteger() - def minor = parts[1].toInteger() - def patch = parts[2].toInteger() - if (params.VERSION_BUMP == 'major') { major++; minor = 0; patch = 0 } - else if (params.VERSION_BUMP == 'minor') { minor++; patch = 0 } - else { patch++ } - return "${major}.${minor}.${patch}" - } + def match = (propsText =~ /SDK_VERSION=(\d+)\.(\d+)\.(\d+)/) + if (!match) error('version.properties 中找不到 SDK_VERSION=x.y.z') + def major = match[0][1] as int + def minor = match[0][2] as int + def patch = match[0][3] as int if (params.SNAPSHOT) { - // SNAPSHOT:version.properties 不变,展示下一版本的 SNAPSHOT 标签 - def nextVer = bumpVersion(currentVer) - env.PUBLISH_VERSION = "${nextVer}-SNAPSHOT" + env.PUBLISH_VERSION = "${major}.${minor}.${patch}-SNAPSHOT" env.RELEASE_TAG = '' - echo "SNAPSHOT 模式 — 当前 Release: ${currentVer},本次标记: ${env.PUBLISH_VERSION}" + echo "SNAPSHOT 模式 — 标记版本: ${env.PUBLISH_VERSION}" } else { - // Release:升级并写回 - def newVer = bumpVersion(currentVer) - env.PUBLISH_VERSION = newVer - env.RELEASE_TAG = newVer - def newProps = propsText.replaceAll(/SDK_VERSION=[^\s#\r\n]+/, "SDK_VERSION=${newVer}") - writeFile(file: 'version.properties', text: newProps) - echo "Release 模式 — ${currentVer} → ${newVer}" + switch (params.VERSION_BUMP) { + case 'major': major++; minor = 0; patch = 0; break + case 'minor': minor++; patch = 0; break + default: patch++; break + } + env.RELEASE_TAG = "${major}.${minor}.${patch}" + env.PUBLISH_VERSION = env.RELEASE_TAG + def newProps = propsText.replaceAll(/SDK_VERSION=\d+\.\d+\.\d+/, "SDK_VERSION=${env.RELEASE_TAG}") + writeFile file: 'version.properties', text: newProps + echo "Release 模式 — 版本升级至 ${env.RELEASE_TAG}" } + currentBuild.description = "${params.SNAPSHOT ? 'SNAPSHOT' : 'Release'} ${env.PUBLISH_VERSION} [${env.CHANGED_MODULES}]" } } } // ───────────────────────────────────────────────────────────────────── - stage('Build Info') { + // SNAPSHOT:只推代码到 main,不改版本文件,不打 tag + stage('SNAPSHOT: Push main') { + when { expression { params.SNAPSHOT } } + steps { + withCredentials([string(credentialsId: 'GITEA_TOKEN', variable: 'TOKEN')]) { + bat "git push https://xuqinmin12:%TOKEN%@xuqinmin.com/xuqmGroup/XuqmGroup-iOSSDK.git HEAD:main" + } + echo "SNAPSHOT 已推送到 main 分支" + echo "应用端 project.yml 保持 branch: main 即可自动获取最新代码" + } + } + + // ───────────────────────────────────────────────────────────────────── + // Release:commit version.properties → 打 tag → 推送 commit + tag + stage('Release: Commit & Tag') { + when { expression { !params.SNAPSHOT } } + steps { + bat "git add version.properties" + bat """git commit -m "ci: release %RELEASE_TAG% [%CHANGED_MODULES%]" """ + bat "git tag %RELEASE_TAG%" + withCredentials([string(credentialsId: 'GITEA_TOKEN', variable: 'TOKEN')]) { + bat "git push https://xuqinmin12:%TOKEN%@xuqinmin.com/xuqmGroup/XuqmGroup-iOSSDK.git HEAD:main" + bat "git push https://xuqinmin12:%TOKEN%@xuqinmin.com/xuqmGroup/XuqmGroup-iOSSDK.git %RELEASE_TAG%" + } + } + } + + // ───────────────────────────────────────────────────────────────────── + // Release:在 Gitea 创建 Release 记录 + stage('Release: Gitea Release') { + when { expression { !params.SNAPSHOT } } steps { script { - echo "================================================" - echo " iOS SDK — ${params.SNAPSHOT ? 'SNAPSHOT' : 'Release'}" - echo " 版本 : ${env.PUBLISH_VERSION}" - echo " Tag : ${env.RELEASE_TAG ?: '不打 tag'}" - echo " Commit : ${env.GIT_COMMIT_SHORT}" - echo " 改动模块 : ${env.CHANGED_MODULES}" - echo "================================================" - } - } - } + def moduleList = env.CHANGED_MODULES.split(', ').collect { "- ${it}" }.join('\\n') + def bodyEscaped = "## 改动模块\\n${moduleList}\\n\\n## 集成方式\\n```yaml\\npackages:\\n XuqmGroupSDK:\\n url: ${env.GITEA_REPO_URL}\\n from: \\\"${env.RELEASE_TAG}\\\"\\n```" + def json = """{"tag_name":"${env.RELEASE_TAG}","name":"${env.RELEASE_TAG}","body":"${bodyEscaped}","draft":false,"prerelease":false}""" + writeFile file: 'release_payload.json', text: json - // ───────────────────────────────────────────────────────────────────── - stage('Swift Build') { - steps { - sh 'swift build -c release 2>&1' - } - } - - // ───────────────────────────────────────────────────────────────────── - stage('Swift Test') { - when { expression { return params.RUN_TESTS } } - steps { - sh 'swift test 2>&1' - } - } - - // ───────────────────────────────────────────────────────────────────── - // SNAPSHOT 分支:只推送代码到 main,不打 tag,不修改版本文件 - stage('Publish SNAPSHOT') { - when { expression { return params.SNAPSHOT } } - steps { - withCredentials([string(credentialsId: 'GITEA_TOKEN', variable: 'TOKEN')]) { - sh """ - git config user.email "jenkins@xuqm.com" - git config user.name "Jenkins CI" - git push https://xuqinmin12:\${TOKEN}@xuqinmin.com/xuqmGroup/XuqmGroup-iOSSDK.git HEAD:main - """ - } - script { - echo "SNAPSHOT 已推送到 main 分支 (${env.GIT_COMMIT_SHORT})" - echo "应用端 project.yml 使用: branch: \"main\"" - echo "Xcode: File > Packages > Update to Latest Package Versions 获取最新代码" - } - } - } - - // ───────────────────────────────────────────────────────────────────── - // Release 分支:升版本号 commit → 打 tag → 推送 commit + tag - stage('Commit & Tag Release') { - when { expression { return !params.SNAPSHOT } } - steps { - withCredentials([string(credentialsId: 'GITEA_TOKEN', variable: 'TOKEN')]) { - sh """ - git config user.email "jenkins@xuqm.com" - git config user.name "Jenkins CI" - git add version.properties - git commit -m "ci: release ${env.RELEASE_TAG} [${env.CHANGED_MODULES}]" - git tag ${env.RELEASE_TAG} - git push https://xuqinmin12:\${TOKEN}@xuqinmin.com/xuqmGroup/XuqmGroup-iOSSDK.git HEAD:main - git push https://xuqinmin12:\${TOKEN}@xuqinmin.com/xuqmGroup/XuqmGroup-iOSSDK.git ${env.RELEASE_TAG} - """ - } - } - } - - // ───────────────────────────────────────────────────────────────────── - // Release 分支:在 Gitea 上创建 Release 记录 - stage('Create Gitea Release') { - when { expression { return !params.SNAPSHOT } } - steps { - withCredentials([string(credentialsId: 'GITEA_TOKEN', variable: 'TOKEN')]) { - script { - def moduleList = env.CHANGED_MODULES.split(', ').collect { "- ${it}" }.join('\\n') - def body = "## 改动模块\\n${moduleList}\\n\\n## 集成方式\\n\\`\\`\\`yaml\\npackages:\\n XuqmGroupSDK:\\n url: ${env.GITEA_REPO_URL}\\n from: \\"${env.RELEASE_TAG}\\"\\n\\`\\`\\`" - sh """ - curl -sf -X POST "${GITEA_API_BASE}/repos/${GITEA_REPO_PATH}/releases" \\ - -H "Authorization: token \${TOKEN}" \\ - -H "Content-Type: application/json" \\ - -d "{\\\"tag_name\\\":\\\"${env.RELEASE_TAG}\\\",\\\"name\\\":\\\"v${env.RELEASE_TAG}\\\",\\\"body\\\":\\\"${body}\\\",\\\"draft\\\":false,\\\"prerelease\\\":false}" \\ - | python3 -c "import sys,json; d=json.load(sys.stdin); print('Release:', d.get('html_url','created'))" - """ + withCredentials([string(credentialsId: 'GITEA_TOKEN', variable: 'TOKEN')]) { + bat """curl -sf -X POST "${env.GITEA_API_BASE}/repos/${env.GITEA_REPO_PATH}/releases" -H "Authorization: token %TOKEN%" -H "Content-Type: application/json" -d @release_payload.json""" } + bat 'del release_payload.json' + echo "Gitea Release ${env.RELEASE_TAG} 创建完成" } } } @@ -206,17 +141,15 @@ pipeline { success { script { if (params.SNAPSHOT) { - echo "✅ SNAPSHOT ${env.PUBLISH_VERSION} 构建并推送成功 (commit: ${env.GIT_COMMIT_SHORT})" - echo " 改动模块: ${env.CHANGED_MODULES}" + echo "SNAPSHOT ${env.PUBLISH_VERSION} 推送成功 — 改动模块: ${env.CHANGED_MODULES}" } else { - echo "✅ Release ${env.RELEASE_TAG} 发布成功" - echo " 改动模块: ${env.CHANGED_MODULES}" - echo " 应用端 project.yml 更新: from: \"${env.RELEASE_TAG}\"" + echo "Release ${env.RELEASE_TAG} 发布成功 — 改动模块: ${env.CHANGED_MODULES}" + echo "应用端 project.yml 更新: from: \"${env.RELEASE_TAG}\"" } } } failure { - echo "❌ iOS SDK 构建失败,请检查日志" + echo "发布失败,请检查日志" } } }