APK 自動(dòng)編譯平臺(tái)搭建(gitlab+jenkins+svn+dingding)

APK 自動(dòng)編譯平臺(tái)搭建(gitlab+jenkins+svn+dingding)

搭建一個(gè)在 Jenkins 上的自動(dòng)編譯平臺(tái),將 apk 發(fā)布到 SVN,之后把編譯結(jié)果推送到釘釘。

安裝 Jenkins

這一步不贅述,網(wǎng)上的教程太多了,值的一提的是,你也可以通過 Docker 去安裝。Docker 可以理解為搭建了一個(gè)虛擬機(jī),在虛擬機(jī)里面運(yùn)行 Jenkins。

Jenkins 上編譯 APK

  1. 也有很多文檔可以參考,主要注意在Jenkins配置菜單里面增加 ANDROID_HOME 環(huán)境變量
  2. 注意 Gradle 配置。同時(shí)使用./sdkmanager --list 然后再安裝需要的一些 NDK 等

能夠成功編譯并在工作空間生成正確的APK就可以下一步了。

gitlab 觸發(fā) Jenkins 自動(dòng)編譯

需要打通這兩個(gè)平臺(tái),讓 gitlab 特定的分支收到 push 或者有 commit merge 后,主動(dòng)觸發(fā)編譯。

  1. Jenkins 安裝 Gitlab Hook Plugin 和 GitLab Plugin 兩個(gè)插件。

  2. 進(jìn)入 Jenkins 任務(wù)的配置界面

    Filter branches by name 填寫你關(guān)注的分支。

    點(diǎn)擊 Generate 按鈕 生成 Secret token。

    保存。

    image
  1. 把??URL 和 Secret token 分別填寫到 gitlab 項(xiàng)目的集成選項(xiàng)里,Trigger只勾選 push events就行,merge后也會(huì)觸發(fā)的。勾選Enable SSL verification 后 Add webhook。添加后有 Test 按鈕,選擇 Push events。如果能正常觸發(fā) Jenkins 編譯就說明 OK 了。

    image-20210903111908673

APK 發(fā)布到 SVN

因?yàn)闅v史原因,我們的待測(cè) APK 都是存放在 SVN 上的,SVN 提交 commit 需要把應(yīng)用的版本號(hào),gitSha,commit 帶上,方便追溯問題。

首先 commit 我們可以通過 Jenkins 自動(dòng)就拿到了,如下操作后會(huì)增加一個(gè)名為 “SCM_CHANGELOG”的環(huán)境變量。后續(xù)腳本讀取即可。

image-20210903113059522

其次,版本號(hào)和 gitSha 可以編譯生成 app_1.0.2_sdjfhga.apk 這種 apk 格式然后解析獲得。具體編譯生成的方式如下:

//build.gradle (app)
//我這里的versionCode versionName都是隨著commit提交自動(dòng)遞增的,比如當(dāng)前的versionCode是100 versionName是1.1.100
//當(dāng)你提交一個(gè)commit后,生成的apk的versionCode自動(dòng)變?yōu)?01,versionName為1.1.101
//可以按需使用。
def getSelfDefinedVersion(type) {//編譯不過需要配置git環(huán)境變量
    Process process = "git rev-list --count HEAD".execute()//git提交數(shù)
    process.waitFor()
    int commits = process.getText().toInteger()

    if ("code" == type) {
        commits
    } else if ("name" == type) {
        "1.1.$commits"
    }
}
def gitSha = 'git rev-parse --short HEAD'.execute().text.trim()

android {
    defaultConfig {
    //xxx
    }
    compileOptions {
    //xxx
    }
    //這里指定生成的APK文件的命名
    applicationVariants.all {variant ->
        variant.outputs.all {output ->
            if (variant.buildType.name == "debug") {
                output.outputFileName = "APP-debug.apk"
            } else if (variant.buildType.name == "release") {
                output.outputFileName = "APP"+gitSha+"_"+getSelfDefinedVersion('name')+".apk"
            }
        }
    }
}

提交內(nèi)容準(zhǔn)備好了,進(jìn)入服務(wù)器 jenkins相關(guān)目錄,建立script目錄,下面編寫SVN推送的腳本svn_push_apk.sh 。

#!/bin/bash -ilex
#Jenkins 工作目錄
WORKSPACE=$1
#編譯生成的Apk的位置。比如app/build/outputs/apk/release/*.apk
RELEASE_APK_REG=$2
#SVN上APK的存放位置。比如app/JenkinsTest/App.apk 
SVN_APK_PATH=$3
#git commit
SCM_CHANGELOG=$4

#存放SVN的目錄
COMMONAPK_PATH=${WORKSPACE}/../CommonApk
RELEASE_APK_PATH=$(ls -1 ${WORKSPACE}/${RELEASE_APK_REG})
cd ${COMMONAPK_PATH}
fl=${RELEASE_APK_PATH##*/}
fileName=${fl%.*}
apkName=$(echo $fileName | cut -d _ -f 1)
gitsha=$(echo $fileName | cut -d _ -f 2)
versionName=$(echo $fileName | cut -d _ -f 3)
svn cleanup
svn up --username "autobuild" --password "xxxxxx"
#commit 超過300 說明一次提交過多。不認(rèn)為是正常的。
if [ ${#SCM_CHANGELOG} -gt 300 ];then
    echo "git commit too long"
#gitSha和上次一樣,不做提交。
elif echo $(svn log ${SVN_APK_PATH} -l 1 --username "autobuild" --password "xxxxxx") |grep -q $gitsha; then
    echo "gitsha same, Don't upload."
else
    cp -rf ${RELEASE_APK_PATH} $SVN_APK_PATH
    commitlog="${apkName} version:${versionName} gitsha:${gitsha} changeLog:${SCM_CHANGELOG}"
    svn commit -m "${commitlog}" ${COMMONAPK_PATH}/${SVN_APK_PATH} --username "autobuild" --password "xxxxxx"
    echo "svn successful"
fi

回到 Jenkins 項(xiàng)目的配置界面,先增加兩個(gè)參數(shù),后面有用。再增加構(gòu)建后操作。兩個(gè)內(nèi)容分別是推送到SVN 和 把相關(guān)結(jié)果發(fā)到釘釘?shù)哪_本。

image-20210903114507062

推送到 SVN?!癇UILD SUCCESSFUL” 是僅編譯成功才需要執(zhí)行下方腳本。

image-20210903114210646
#1-WORKSPACE 2-releaseApk位置 3-svn上apk位置 4-commitlog
if [ "$push_to_svn" = "true" ]; then   
    [ ! $custom_commit ] && SCM_CHANGELOG="$custom_commit"
    echo "$SCM_CHANGELOG"
    cd $WORKSPACE/../script 
    /bin/bash svn_push_apk.sh "$WORKSPACE" app/build/outputs/apk/release/*.apk app/JenkinsTest/App.apk "$SCM_CHANGELOG"
fi

結(jié)果發(fā)送到釘釘

  1. 到釘釘?shù)?“智能群助手” 中添加 “機(jī)器人”,選擇 “自定義”(通過Webhook接入自定義服務(wù))。安全設(shè)置選擇自定義關(guān)鍵詞,關(guān)鍵詞填寫 "點(diǎn)擊查看"。

  2. 添加機(jī)器人后,有個(gè)WebHook地址,復(fù)制下來。后續(xù)就可以通過給這個(gè)地址發(fā)消息到群里了。

  3. 回到 Jenkins 增加構(gòu)建后操作。 Log text 填寫 Build 因?yàn)闊o論編譯結(jié)果如何,都是要通知到發(fā)送到釘釘群里的。Script填寫如下:

    cd $WORKSPACE/../script
    /bin/bash jenkins_to_dingding.sh "$JOB_NAME" "$BUILD_NUMBER" "$SCM_CHANGELOG" "$push_to_svn"
    
  4. 到服務(wù)器 Jenkins 之前建的 script 目錄 編輯 jenkins_to_dingding.sh

    #!/bin/bash -ilex
    #################################################################
    # 釘釘消息變量定義
    #################################################################
    JOB_NAME=$1
    BUILD_NUMBER=$2
    SCM_CHANGELOG=$3
    PUSH_TO_SVN=$4
    
    BUILD_STATUS="<font color='#ff0000'>失敗</font>"
    #這是我的Jenkins服務(wù)器的地址,包括下方一些服務(wù)器地址,使用的話請(qǐng)自行修改。
    LAST_BUILD_BUILD_XML=`curl http://192.168.10.58:8090/job/${JOB_NAME}/lastBuild/api/xml`
    BUILD_RESULT=$(echo $LAST_BUILD_BUILD_XML | grep "<result>SUCCESS</result>") 
    if [ "${BUILD_RESULT}" ];then 
        BUILD_STATUS="<font color='#00ff00'>成功</font>"
    else
        BUILD_RESULT=$(echo $LAST_BUILD_BUILD_XML | grep "<result>FAILURE</result>") 
        if [ "${BUILD_RESULT}" ];then 
            BUILD_STATUS="<font color='#ff0000'>失敗</font>"
        else
            BUILD_STATUS="<font color='#ff0000'>無法獲取</font>"     
        fi
    fi   
    
    JENKINS_JOB_BUILD_LOG_URL="http://192.168.10.58:8090/job/${JOB_NAME}/${BUILD_NUMBER}/console"
    JENKINS_LAST_BUILD_CONSOLE=`curl http://192.168.10.58:8090/job/${JOB_NAME}/${BUILD_NUMBER}/consoleText`
    #echo $JENKINS_LAST_BUILD_CONSOLE
    if [ "$push_to_svn" = "true" ];then
        SVN_BUILD_STATUS="<font color='#ff0000'>失敗</font>"
        SVN_BUILD_RESULT=$(echo $JENKINS_LAST_BUILD_CONSOLE | grep "Committed revision") 
        if [ "${SVN_BUILD_RESULT}" ];then 
            SVN_BUILD_STATUS="<font color='#00ff00'>成功</font>"
        else
            SVN_BUILD_RESULT=$(echo $JENKINS_LAST_BUILD_CONSOLE | grep "gitsha same") 
            SVN_COMMIT_RESULT=$(echo $JENKINS_LAST_BUILD_CONSOLE | grep "git commit too long")
            if [ "${SVN_COMMIT_RESULT}" ];then
                SVN_BUILD_STATUS="<font color='#ff0000'>失敗,git commit過長,請(qǐng)點(diǎn)擊連接,自定義commit并觸發(fā)編譯。</font>"
            elif [ "${SVN_BUILD_RESULT}" ];then 
                SVN_BUILD_STATUS="<font color='#ff0000'>失敗,與上次提交gitsha相同</font>"
            else
                SVN_BUILD_STATUS="<font color='#ff0000'>失敗</font>"     
            fi
        fi 
    else
       SVN_BUILD_STATUS="<font color='#a9a9a9'>跳過</font>"
    fi
    
    # 機(jī)器人 webhook 地址(上文添加釘釘機(jī)器人結(jié)束時(shí)復(fù)制的webhook地址)
    DINGTALK_WEBHOOK_URL='https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxxxxxxxxxxxxxxxxxxx'
    # 消息標(biāo)題 # 實(shí)際不起作用,但是不能少,否則發(fā)送失敗
    DINGTALK_TITLE="Jenkins平臺(tái)有新的構(gòu)建"
    # 消息正文
    # Jenkins Job構(gòu)建日志地址
    DINGTALK_TEXT="### ${JOB_NAME} 有新的構(gòu)建\n\n>\
    **【構(gòu)建ID】:${BUILD_NUMBER}**\n\n>\
    **【編譯狀態(tài)】:${BUILD_STATUS}**\n\n>\
    **【SVN狀態(tài)】:${SVN_BUILD_STATUS}**\n\n>\
    **【commit】:** ${SCM_CHANGELOG}\n\n>\
    **【Jenkins】:[點(diǎn)擊查看更多](${JENKINS_JOB_BUILD_LOG_URL})**\n
    " 
    #  
    # 發(fā)送釘釘消息通知函數(shù)
    #################################################################
    function SEND_MESSAGE_TO_DINGTALK() {
        /usr/bin/curl "$1" -H 'Content-Type: application/json' -d "
        {
            \"markdown\": {
                \"title\": \"$2\", 
                \"text\": \"$3\"
            }, 
            \"at\": {
              \"atMobiles\": [],
              \"isAtAll\": false
            },
            \"msgtype\": \"markdown\"
        }
        " 
    }
    # 發(fā)送釘釘消息
    #################################################################
    SEND_MESSAGE_TO_DINGTALK "${DINGTALK_WEBHOOK_URL}" "${DINGTALK_TITLE}" "${DINGTALK_TEXT}"
    
  5. 最后效果如下:

    image-20210903143024939
image-20210903143103594

總結(jié)

  1. 能用 git 就盡量別用 SVN 了。 一些插件都不好用,或者滿足不了需求。只能自己寫。
  2. 上面的腳本其實(shí)也不一定就能滿足你的需求,最好的辦法就是根據(jù)需求自己改,自己定制。包括我之所以寫這兩個(gè)腳本,也是因?yàn)?Jenkins 版本比較低,插件不能滿足需求,又擔(dān)心升級(jí)出問題,只能自己編寫,或者拿網(wǎng)上的模版改。
  3. 整個(gè)流程搞定后還是挺爽的,以前要先提交merge 合并完代碼后,再用 Android Studio 編譯生成 APK 后 手動(dòng)提交到 SVN。整個(gè)流程繁瑣,且容易不符合規(guī)定導(dǎo)致出錯(cuò),比如不合代碼,直接就先提交 SVN 了。搞定完之后,只需要驗(yàn)證完 提交merge就可以了。Jenkins代替你編譯并提交。另外提 merge 推薦Android Studio 的插件-- GitLab Quick Merge Request 非常好用,在 Android Studio里面就可以用快捷鍵提交了。詳細(xì)使用方法可以找我之前的文章。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容