// 判断 manifest.json 中 versionCode 是否大于上一个版本则执行构建 apk eg: $.versionCode2 > $.versionCode2
// 判断 git comment 中包含 [release] 则执行构建 apk eg: feat: xxxx [release]
// 判断 git comment 中包含 [wgt] 则执行构建 wgt eg: feat: xxxx [wgt]
// 构建成功之后自动更新 ctms app 版本信息
// ===============================
// >>>>>>mamifest.json 必填参数<<<<<
// $.description 更新描述
// $.versionName 版本号
// $.versionCode 版本号
// $.uapp.type 1101:android 1103:ios
// $.uapp.forceUpdate 是否强制更新
// $.uapp.diff 最大相差版本
// ================================
import groovy.json.JsonSlurper
pipeline {
agent any
environment {
APP_NAME = "ctms"
MENTION_USERS = '"AAA BBB","小明"'
PRODD_SERVER_HOST = credentials('example-prod-host-248')
RELEASE_UPDATE_URL = "https://ctms.example.com/ctms/appVersion/add"
RELEASE_USERNAME = credentials('example-admin-username')
RELEASE_PASSWORD = credentials('example-admin-password')
}
stages {
stage('release') {
steps {
script {
// 1. 获取上一个版本号
def previousVersion = getPreviousVersion()
// 2. 获取当前版本号
def currentVersion = getCurrentVersion()
echo "Previous Version: ${previousVersion}"
echo "Current Version: ${currentVersion}"
// 3. 比较版本号 或者 提交信息中含有 [release] 字样
if (isVersionGreaterThan(currentVersion,previousVersion) || isReleaseCommit()) {
echo "🚀 Current version is greater than the previous version. Starting build..."
// 4. 执行构建
def buildCommand = """
cd android && \
chmod +x ./gradlew && \
uapp manifest ../manifest.json && \
uapp run build
"""
echo "🛠️ Executing command: ${buildCommand}"
try {
def result = sh(script: buildCommand, returnStatus: true)
if (result == 0) {
echo "✅ Build successful. "
// 设置变量 HAS_RELEASE_OUT 为 true
env.HAS_RELEASE_OUT = true
env.RELEASE_VERSION = currentVersion
echo "🎉 Release version: ${env.APP_NAME} ${env.RELEASE_VERSION} ${env.HAS_RELEASE_OUT}"
echo "🎉 Release path: ./android/app/build/outputs/apk/release/app-release.apk"
} else {
error "❌ Build failed. Exit code: $result"
}
} catch (Exception ex) {
error "❌ Error during build: $ex.message"
}
} else {
echo "⏭️ Current version is not greater than the previous version. Skipping build."
}
}
}
}
stage('upload') {
when {
// 当 HAS_RELEASE_OUT 为 true 时执行
expression { env.HAS_RELEASE_OUT.toString() == "true" }
}
steps {
script {
def remote = [:]
remote.name = "prod-server-248"
remote.host = env.PRODD_SERVER_HOST
remote.allowAnyHosts = true
withCredentials([usernamePassword(credentialsId: 'example-prod-server-248', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
remote.user = "${USERNAME}"
remote.password = "${PASSWORD}"
}
def latestVersion = env.RELEASE_VERSION
def appName = env.APP_NAME
if (isZipWgtCommit()) {
def appid = getAppid()
def wgtName = "${env.APP_NAME}_${latestVersion}.wgt"
def zipResult = zipWgt(wgtName,appid)
echo "📦 Wgt path: ${zipResult} ."
sshPut remote: remote, from: "${zipResult}", into: "/home/static/apk/${appName}/"
def latestUrl = "https://static.example.com/apk/$appName/$wgtName"
env.LATEST_URL = latestUrl
}else{
sshPut remote: remote, from: './android/app/build/outputs/apk/release/app-release.apk', into: "/home/static/apk/${appName}/${appName}_app_v${latestVersion}.apk"
def latestUrl = "https://static.example.com/apk/${appName}/${appName}_app_v${latestVersion}.apk"
env.LATEST_URL = latestUrl
}
echo "🚀 Upload successful."
}
}
}
stage('config') {
when {
// 当 LATEST_URL 不为空字符串时执行
expression { env.LATEST_URL != "" && env.HAS_RELEASE_OUT.toString() == "true"}
}
steps {
script {
echo "ℹ️ Configing..."
def paramsJson = buildReleaseJson()
def url = "${env.RELEASE_UPDATE_URL}"
def token = loginForToken()
echo "ℹ️ Config params: $paramsJson"
echo "ℹ️ Config url: $url"
echo "ℹ️ Config token: $token"
def response = httpRequest(
contentType: 'APPLICATION_JSON',
customHeaders: [
[name:"Content-Type", value:"application/json"],
[name:"Authorization",value:"Bearer $token"]
],
httpMode: 'POST',
requestBody: paramsJson,
url: url
)
echo "ℹ️ Config done response: $response ."
}
}
}
stage('notify') {
when {
// 当 LATEST_URL 不为空字符串时执行
expression { env.LATEST_URL != "" && env.HAS_RELEASE_OUT.toString() == "true" }
}
steps {
script {
def appName = "$env.APP_NAME $env.RELEASE_VERSION"
def latestUrl = "$env.LATEST_URL"
def gitCommand = "git log -1 --pretty=%B"
def commitMessage = sh(script: gitCommand, returnStdout: true).trim()
def message = "🚀 $appName\\n $commitMessage\\n发布成功\\n下载地址: $latestUrl"
def mentionUsers = "${env.MENTION_USERS}"
def wechatMessageCommand = "sh /home/shell/wechat-notify.sh xxx开发者通知群 text '$message' '$mentionUsers'"
def result = sh(script: wechatMessageCommand, returnStdout: true).trim()
echo "🚀 Notify done result: $result ."
}
}
}
}
}
// 获取上一个版本中 manifest.json 的 versionCode
def getPreviousVersion() {
// 使用 Git 命令获取上一个提交的版本号
def gitCommand = "git show HEAD^:manifest.json"
def manifestJsonContent = sh(script: gitCommand, returnStdout: true).trim()
// 解析 manifest.json 文件内容并获取 versionCode
def manifestJson = readJSON text: manifestJsonContent
def previousVersionCode = manifestJson.versionCode
return previousVersionCode.toInteger()
}
// 获取当前版本号的函数
def getCurrentVersion() {
// 从 manifest.json 文件中读取 versionName 字段
def manifestJson = readJSON file: 'manifest.json'
// 转换为 number
return manifestJson.versionCode.toInteger()
}
def isVersionGreaterThan(currentVersion,previousVerion) {
return currentVersion > previousVerion
}
// 提交信息中含有 [release] 字样
def isReleaseCommit() {
def gitCommand = "git log -1 --pretty=%B"
def commitMessage = sh(script: gitCommand, returnStdout: true).trim()
return commitMessage.contains("[release]")
}
def isZipWgtCommit() {
def gitCommand = "git log -1 --pretty=%B"
def commitMessage = sh(script: gitCommand, returnStdout: true).trim()
return commitMessage.contains("[wgt]")
}
// 从 manifest.json 文件中读取 appid 字段
def getAppid() {
def manifestJson = readJSON file: 'manifest.json'
return manifestJson.appid
}
// 构建更新配置文件
def buildReleaseJson() {
def manifestJson = readJSON file: 'manifest.json'
def latestUrl = "${env.LATEST_URL}"
def postJson = [
"diff": manifestJson.uapp.diff,
"downloadUrl": latestUrl,
"forceUpdate": manifestJson.uapp.forceUpdate,
"type": manifestJson.uapp.type,
"versionCode": manifestJson.versionCode,
"versionInfo": manifestJson.description,
"versionName": manifestJson.versionName
]
return groovy.json.JsonOutput.toJson(postJson)
}
// 打包成 zip 压缩包并将后缀改成 wgt
def zipWgt(wgtName,appid) {
def zipCommand = "cd ./unpackage/resources/$appid/www/ && zip -r -q -o $wgtName . && cd ../../../../"
def zipResult = sh(script: zipCommand, returnStdout: true).trim()
return "./unpackage/resources/${appid}/www/${wgtName}"
}
def loginForToken(){
def url = "https://sso.example.com/sso/user/token"
def response = httpRequest(
httpMode: 'POST',
contentType: 'APPLICATION_FORM',
requestBody: "username=${env.RELEASE_USERNAME}&password=${env.RELEASE_PASSWORD}&t=MD5",
url: url,
customHeaders: [
[name:"Content-Type",value:"application/x-www-form-urlencoded"],
[name:"Authorization",value:"Basic xxx=="],
]
)
def json = new JsonSlurper().parseText(response.content)
echo "ℹ️ Login response: $json ."
def token = json.data.access_token
return token
}