uappkit / uapp

uapp是一款基于uni-app跨平台开发的高效cli。 源自自有产品跨平台的最佳实践,通过集成 uni-app, electron, tauri,让开发者仅需维护一套代码,就能横跨所有平台。uapp助开发者无限制重构一切软件。
Apache License 2.0
845 stars 143 forks source link

分享一个测试通过的 Jenkinsfile 支持 apk,wgt 构建 #9

Open bestK opened 10 months ago

bestK commented 10 months ago
// 判断 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    
}
zencodex commented 10 months ago

👍 好东西

SunSeekerX commented 10 months ago

Good jop!

813wangyanfei commented 9 months ago

Is very very nice!