GitLab CI/CD庞萍,iOS項目管控實戰(zhàn)應(yīng)用

前言

Gitlab代碼管理:這里測試案例直接將項目放到官方提供的gitlab 個人賬號下拧烦,公司/團隊可在自身服務(wù)器上搭建一套GitLab代碼管理會更加安全(可將需求拋給運維同學(xué),稍具規(guī)模的公司都會搭建屬于自己的git/svn)。
CICD官網(wǎng)簡介https://docs.gitlab.com/ee/ci/README.html

CICD_Framework.png

一钝计、基本概念

1.1. CI/CD

CI恋博,Continuous Integration,為持續(xù)集成私恬。即在代碼構(gòu)建過程中持續(xù)地進行代碼的集成债沮、構(gòu)建、以及自動化測試等本鸣;有了 CI 工具疫衩,我們可以在代碼提交的過程中通過單元測試等盡早地發(fā)現(xiàn)引入的錯誤;
CD荣德,Continuous Deployment闷煤,為持續(xù)交付。在代碼構(gòu)建完畢后涮瞻,可以方便地將新版本部署上線鲤拿,這樣有利于快速迭代并交付產(chǎn)品。

1.2. GitLab CI/CD

GitLab CI/CD(后簡稱 GitLab CI)是一套基于 GitLab 的 CI/CD 系統(tǒng)署咽,可以讓開發(fā)人員通過 .gitlab-ci.yml 在項目中配置 CI/CD 流程近顷,在提交后,系統(tǒng)可以自動/手動地執(zhí)行任務(wù)宁否,完成 CI/CD 操作窒升。而且,它的配置非常簡單慕匠,CI Runner 由 Go 語言編寫饱须,最終打包成單文件,所以只需要一個 Runner 程序台谊、以及一個用于運行 jobs 的執(zhí)行平臺(如裸機+SSH冤寿,Docker 或 Kubernetes 等,我推薦用 Docker青伤,因為搭建相當(dāng)容易)即可運行一套完整的 CI/CD 系統(tǒng)。

Job

job 為任務(wù)殴瘦,是 GitLab CI 系統(tǒng)中可以獨立控制并運行的最小單位狠角。 在提交代碼后,開發(fā)者可以針對特定的 commit
完成一個或多個 job蚪腋,從而進行 CI/CD 操作丰歌。

Pipeline

Pipeline 即流水線姨蟋,可以像流水線一樣執(zhí)行多個 Job. 在代碼提交或 MR 被合并時,GitLab 可以在最新生成的 commit
上建立一個 pipeline立帖,在同一個 pipeline 上產(chǎn)生的多個任務(wù)中眼溶,所用到的代碼版本是一致的。

Stage

一般的流水線通常會分為幾段晓勇;在 pipeline中堂飞,可以將多個任務(wù)劃分在多個階段中,只有當(dāng)前一階段的所有任務(wù)都執(zhí)行成功后绑咱,下一階段的任務(wù)才可被執(zhí)行绰筛。

注:如果某一階段的任務(wù)均被設(shè)定為“允許失敗”,那這個階段的任務(wù)執(zhí)行情況描融,不會影響到下一階段的執(zhí)行铝噩。

Pipeline.png

上圖整條流水線從左向右依次執(zhí)行,每一列均為一個階段窿克,而列中的每個可操控元素均為任務(wù)骏庸。 這里五個階段的任務(wù)是自動執(zhí)行的任務(wù),在commit或request merge(根據(jù)gitlab-ci Job條件) 提交后即可自動開始運行年叮,執(zhí)行成功或失敗后具被,可以點擊任務(wù)右邊的按鈕重試;如果需要手動觸發(fā)執(zhí)行任務(wù)需要在.gitlab-ci.yml任務(wù)里添加when:manual表示該操作只允許手動觸發(fā)谋右。
一個Pipeline對應(yīng)多個Stage,每一個Stage可分成多個Job

二硬猫、Gitlab-Runner安裝/注冊

2.1. 安裝

官方安裝文檔https://docs.gitlab.com/runner/install/

針對iOS項目,準備一臺空閑(團隊使用)Mac OS電腦當(dāng)做服務(wù)器改执,內(nèi)網(wǎng)服務(wù)器能訪問外網(wǎng)即可啸蜜,在此服務(wù)器上安裝Runner,后續(xù)ci/cd相關(guān)腳本亦在此運行

# MacOS
sudo brew install gitlab-ci-multi-runner

# For Debian/Ubuntu/Mint
sudo apt-get install gitlab-ci-multi-runner
 
# For RHEL/CentOS/Fedora
sudo yum install gitlab-ci-multi-runner

2.2.注冊

打開gitlab項目 -> Settings -> CI/CD -> Runners

這里創(chuàng)建Group辈挂,Group下Runner衬横,可共享其下的項目使用

Settings_CICD.png
  • 在安裝Runner的服務(wù)器上運行注冊
sudo gitlab-runner register
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com):
https://gitlab.com/
  • 輸入 注冊令牌 來注冊 Runner,這里copy上圖token
Please enter the gitlab-ci token for this runner:
wfjVq8G..我是馬賽克..LoZ
  • 輸入 Runner 說明
Please enter the gitlab-ci description for this runner:
iOSTeamRunner
  • 輸入 Runner 的 tags
Please enter the gitlab-ci tags for this runner (comma separated):
iOSTeamRunner
  • 輸入 Runner 執(zhí)行方式
Please enter the executor: ssh, docker+machine, docker-ssh+machine, kubernetes, docker, parallels, virtualbox, docker-ssh, shell:
shell

如下:

addRunner.png

三、CI/CD 在iOS工程中的應(yīng)用

下列使用到的.gitlab-ci.yml终蒂、project_build_check.sh衍锚、qiyewechat_sendMsg_api.sh等文件下載參考

3.1. 需求

需求:非項目負責(zé)人不允許對master主分支進行push、merge等修改代碼相關(guān)操作碍遍,收回相關(guān)權(quán)限渐裂。開發(fā)者只能通過master分支創(chuàng)建一個開發(fā)分支進行項目迭代,一旦迭代完成霉翔,只能發(fā)起merge request讓相關(guān)項目負責(zé)人將開發(fā)分支merge(合并)到master分支睁蕾,為了保證合并之前開發(fā)分支代碼是編譯通過且打包無異常,需進行校驗工作,讓項目負責(zé)人清晰知道代碼編譯是正常的子眶。所以引入了 Gitlab 下 CI/CD機制瀑凝。

flowChart.png

上圖"CD:版本發(fā)布流程" 我們使用了jenkins進行自動化打包發(fā)布(當(dāng)然也可以使用Gitlab來實現(xiàn)),這里就不多描述
這里主要關(guān)注上圖"CI:代碼編譯校驗"相關(guān)的.gitlab-ci.yml文件的編寫臭杰。

3.2. 環(huán)境

  • gitlab代碼管理粤咪,可以使用官網(wǎng),亦可自行搭建gitlab代碼管理服務(wù)器
  • 需要在一臺電腦或服務(wù)器安裝Runner,如何安裝Runner請看上方“二渴杆、Gitlab-Runner安裝/注冊 ”
  • 在安裝Runner的設(shè)備上安裝Xcode寥枝,因為我們的項目是iOS項目,編譯打包工作需要此環(huán)境
  • 設(shè)置Pipeline(流水線)成功才可merge
    Settings_Merge.png

3.3. .gitlab-ci.yml文件

給工程項目添加gitlab-ci.yml文件

這里執(zhí)行渠道(Pipeline)分成5個階段(stage)

#GIT_STRATEGY: none
#GIT策略将塑,定義拉取代碼的方式脉顿,有3種:clone/fetch/none,默認為clone点寥,速度最慢艾疟,每步j(luò)ob都會重新clone一次代碼。我們一般將它設(shè)置為none敢辩,在具體任務(wù)里設(shè)置為fetch就可以滿足需求蔽莱,畢竟不是每步都需要新代碼,那也不符合我們測試的流程
#在job中可以用${GIT_STRATEGY}來使用這個變量戚长。常用的預(yù)定義變量有CI_COMMIT_REF_NAME(項目所在的分支或標(biāo)簽名稱)盗冷,CI_JOB_NAME(任務(wù)名稱),CI_JOB_STAGE(任務(wù)階段)

before_script:
  - |
    ifconfig | grep "inet "
    pwd
#    export LANG="en_US.UTF-8" 
#    export
# 全局變量同廉,保證不同stage不會每次重置代碼
# 某些步驟需要可以在Job中添加(如結(jié)果回調(diào)中)

#after_script:
#  - |
#    pwd

stages:
  - 1.輸出環(huán)境變量
  - 2.設(shè)置編譯前腳本
  - 3.pod install
  - 4.編譯檢查
  - 5.結(jié)果處理

#1.輸出環(huán)境變量
#gitlab系統(tǒng)自帶環(huán)境變量:http://gitlab.code.mob.com/help/ci/variables/predefined_variables.md
print_env: 
  stage: 1.輸出環(huán)境變量
  script:
    - export LANG="en_US.UTF-8" 
    - export
    #- echo "==================================================="
    #- echo "project_name:${O2Space_ProjectName}"
    #- echo "project_workspace:${O2Space_WorkSpace}"
    #- echo "sdk_schemes:${O2Space_SDKSchemes}"
    #- echo "ipa_scheme:${O2Space_IPAScheme}"
    #- echo "==================================================="
  only:
    - merge_requests
  tags:
    - iOSTeamRunner
  variables:
    GIT_STRATEGY: none

#2.設(shè)置編譯前腳本
# 開啟自身clone項目 及 clone/fetch 相關(guān)封裝shell腳本
setup_script: 
  stage: 2.設(shè)置編譯前腳本
  script:
    - |
      if [ -d ToolScript ]; then
        #企業(yè)微信獲取token存儲時文件創(chuàng)建需要權(quán)限
        chmod u+w ToolScript
        builtin cd ToolScript
        git fetch
        git reset --hard origin/master
        chmod +x ./project_build_check.sh
        chmod +x ./qiyewechat_sendMsg_api.sh
        builtin cd ..
      else
        #添加ssh,否則git clone將無權(quán)限
        username="wukx"
        ssh_PATH="/Users/wkx/Documents/Develop/.ssh/${username}_rsa"
        eval $(ssh-agent)
        ssh-add $ssh_PATH
        #將shell腳本放到ToolScript項目里便于管理
        git clone git@gitlab.com:O2Space/ToolScript.git
        ssh-agent -k
      fi
      #當(dāng)前Gitlab賬號
      users=${GITLAB_USER_LOGIN}
      eventContent=""
      if [ ${CI_PIPELINE_SOURCE} = "merge_request_event" ]; then
        eventContent="您發(fā)起了merge請求仪糖,正在為您進行代碼校驗 \n項目:${CI_PROJECT_PATH},\n發(fā)起分支:${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}迫肖,\n目標(biāo)分支:${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}"
      fi
      #發(fā)送企業(yè)微信消息锅劝,通知發(fā)起者,開始編譯校驗 
      type=1
      builtin cd ToolScript
      source qiyewechat_sendMsg_api.sh -u "${users}" -c "${eventContent}" -y "${type}"
      builtin cd ..
  only:
    - merge_requests
  tags:
    - iOSTeamRunner
  variables:
    GIT_STRATEGY: clone

#3.pod install
pod_install:
  stage: 3.pod install
  script:
    - |
      pwd
      echo "此項目無需通過Pod集成第三方SDK"
#      source pod install
  only:
    - merge_requests
  tags:
    - iOSTeamRunner
  variables:
    GIT_STRATEGY: none

#4.編譯檢查
bulid_script:
  stage: 4.編譯檢查
  script:
    - |
      project_dir=`pwd`
      project_name=${O2Space_ProjectName}
      project_workspace=${O2Space_WorkSpace}
      sdk_schemes=${O2Space_SDKSchemes}
      ipa_scheme=${O2Space_IPAScheme}
      echo $project_dir
      echo "project_name:${project_name}"
      echo "project_workspace:${project_workspace}"
      echo "sdk_schemes:${sdk_schemes}"
      echo "ipa_scheme:${ipa_scheme}"
      chmod +x ToolScript/project_build_check.sh
      source ToolScript/project_build_check.sh "${project_dir}" "${project_name}" "${project_workspace}" "${sdk_schemes}" "${ipa_scheme}"
  only:
    - merge_requests
  tags: 
    - iOSTeamRunner
  variables:
    GIT_STRATEGY: none

#5.結(jié)果處理
fail_script:
  stage: 5.結(jié)果處理
  script:
    - |
      echo "校驗失敗"
      users=${GITLAB_USER_LOGIN}
      timeStr=$(date "+%Y-%m-%d %H:%M:%S")
      title="Gitlab操作:代碼編譯校驗結(jié)果通知"
      branchInfo=${CI_BUILD_REF_NAME}
      eventContent=""
      weblink=""
      if [ ${CI_PIPELINE_SOURCE} = "merge_request_event" ]; then
        branchInfo=${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}→${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}
        eventContent=${CI_MERGE_REQUEST_TITLE}
        weblink=${CI_MERGE_REQUEST_PROJECT_URL}/merge_requests/${CI_MERGE_REQUEST_IID}
      fi
      description="<div class='gray'>${timeStr}</div>
                  <div class='normal'>項目:${CI_PROJECT_PATH}</div>
                  <div class='normal'>事件:${CI_PIPELINE_SOURCE}</div>
                  <div class='normal'>涉及分支:${branchInfo}</div>
                  <div class='normal'>事件內(nèi)容:${eventContent}</div>
                  <div class='normal'>pipeline:${CI_PIPELINE_ID}</div>
                  <div class='highlight'>校驗結(jié)果:失敗</div>"
      type=2
      builtin cd ToolScript
      source qiyewechat_sendMsg_api.sh -u "${users}" -t "${title}" -d "${description}" -l "${weblink}" -y "${type}"
      builtin cd ..
  when: on_failure
  only: 
    - merge_requests
  tags: 
    - iOSTeamRunner
  variables:
    GIT_STRATEGY: none

#5.結(jié)果處理
success_script:
  stage: 5.結(jié)果處理
  script:
    - |
      echo "校驗成功"
      users=${GITLAB_USER_LOGIN}
      resultStr=""
      if [ ! -n "$O2Space_MergeOwner" ]; then
        echo "O2Space_MergeOwner is null"
      else
        users=${users},${O2Space_MergeOwner}
        resultStr="蟆湖,請相關(guān)人員:${O2Space_MergeOwner}故爵,進行merge操作"
      fi
      timeStr=$(date "+%Y-%m-%d %H:%M:%S")
      title="Gitlab操作:代碼編譯校驗結(jié)果通知"
      branchInfo=${CI_BUILD_REF_NAME}
      eventContent=""
      weblink=""
      if [ ${CI_PIPELINE_SOURCE} = "merge_request_event" ]; then
        branchInfo=${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}→${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}
        eventContent=${CI_MERGE_REQUEST_TITLE}
        weblink=${CI_MERGE_REQUEST_PROJECT_URL}/merge_requests/${CI_MERGE_REQUEST_IID}
      fi
      description="<div class='gray'>${timeStr}</div>
                  <div class='normal'>項目:${CI_PROJECT_PATH}</div>
                  <div class='normal'>事件:${CI_PIPELINE_SOURCE}</div>
                  <div class='normal'>涉及分支:${branchInfo}</div>
                  <div class='normal'>事件內(nèi)容:${eventContent}</div>
                  <div class='normal'>pipeline:${CI_PIPELINE_ID}</div>
                  <div class='blue'>校驗結(jié)果:成功${resultStr}</div>"
      type=2
      builtin cd ToolScript
      source qiyewechat_sendMsg_api.sh -u "${users}" -t "${title}" -d "${description}" -l "${weblink}" -y "${type}"
      builtin cd ..
  when: on_success
  only: 
    - merge_requests
  tags: 
    - iOSTeamRunner
  variables:
    GIT_STRATEGY: none

gitlab系統(tǒng)自帶環(huán)境變量、自定義的變量隅津。
自定義變量配置:

CusParam.png

通知:
通過企業(yè)微信Api接口發(fā)送通知到開發(fā)者微信上诬垂,這里通知功能封裝在qiyewechat_sendMsg_api.sh的shell文件里,此文件在項目“ToolScripts”里伦仍,所以腳本任務(wù)中執(zhí)行g(shù)it clone項目
qiyewechat_sendMsg_api.sh文件:

#!/bin/bash

#用法提示
usage() {
    echo "Usage:"
    echo "  qiyewechat_sendMsg_api.sh [-u USER] [-t TITLE] [-c CONTENT] [-d DETAIL] [-p PICTURE] [-l LINK] [-y TYPE]"
    echo "Description:"
    echo "    USER, 用戶."
    echo "    TITLE, 標(biāo)題."
    echo "    CONTENT, 內(nèi)容."
    echo "    DETAIL, 細節(jié)."
    echo "    PICTURE, 圖片."
    echo "    LINK, 鏈接."
    echo "    TYPE, 內(nèi)容類型."
    exit -1
}


# 獲取腳本執(zhí)行時的選項
while getopts u:t:c:d:p:l:y: option
do
   case "${option}"  in
                u) USER=${OPTARG};;
                t) TITLE=${OPTARG};;
                c) CONTENT=${OPTARG};;
                d) DETAIL=${OPTARG};;
                p) PICTURE=${OPTARG};;
                l) LINK=${OPTARG};;
                y) TYPE=${OPTARG};;
                h) usage;;
                ?) usage;;
   esac
   echo $option
   echo $OPTARG

done

#gitlab用戶 匹配 企業(yè)微信通訊錄用戶賬號
function getQiyewechatUserId(){
  local str=(`cat ./user_table.txt | awk -F ' ' '{print $1}'`)
  local userid=""
  local params=$@
  for i in ${!str[@]}
  do
    arr=(${str[i]//:/ })
    
    if [ ${arr[0]} == ${params[0]} ]; then
      echo ${arr[1]}
    fi 
  done

  echo ${userid}
}

function getQiyewechatUserIds(){
  local params=$@
  local userids=""
  arr=(${params//,/ })
  for i in ${!arr[@]}
  do
    tmp_str=$(getQiyewechatUserId ${arr[i]})
    if [[ $i != 0 ]]; then
      tmp_str=\|${tmp_str}
    fi
    userids=${userids}${tmp_str}
  done
  echo ${userids}
}

userids=$(getQiyewechatUserIds $USER)
echo userids:${userids}
# exit 0

#api的相關(guān)參數(shù)
#企業(yè)id
corpid='ww93f2060b7af1b265'
#企業(yè)下創(chuàng)建應(yīng)用id
agentId=1000002
corpsecret='kaoVjgw1Qi2lnvqjBJbbxAl3mTkYCKq7sk7eOZyFA7Y'



#RESTFUL API 接口相關(guān)參數(shù)
HOST=https://qyapi.weixin.qq.com


#獲取token
wechat_api_token=${HOST}/cgi-bin/gettoken
#例子:
#GET:https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=""&corpsecret=""
#返回內(nèi)容:
#{
#       "errcode":0
#       "errmsg": ok
#       "access_token":"",
#       "expires_in": 7200,
#}


#發(fā)送消息
wechat_api_sendText=${HOST}/cgi-bin/message/send
#例子:
#POST: https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN
#文本消息:
#{
#   "touser" : "UserID1|UserID2|UserID3"
#   "toparty" : "PartyID1|PartyID2",
#   "totag" : "TagID1 | TagID2",
#   "msgtype" : "text",
#   "agentid" : 1,
#   "text" : {
#       "content" : "你的快遞已到结窘,請攜帶工卡前往郵件中心領(lǐng)取。\n出發(fā)前可查看<a href=\"http://work.weixin.qq.com\">郵件中心視頻實況</a>充蓝,聰明避開排隊晦鞋。"
#   },
#   "safe":0,
#   "enable_id_trans": 0
#}
#
#文本卡片消息:
#{
#   "touser" : "UserID1|UserID2|UserID3",
#   "toparty" : "PartyID1 | PartyID2",
#   "totag" : "TagID1 | TagID2",
#   "msgtype" : "textcard",
#   "agentid" : 1,
#   "textcard" : {
#            "title" : "領(lǐng)獎通知",
#            "description" : "<div class=\"gray\">2016年9月26日</div> <div class=\"normal\">恭喜你抽中iPhone 7一臺,領(lǐng)獎碼:xxxx</div><div class=\"highlight\">請于2016年10月10日前聯(lián)系行政同事領(lǐng)取</div>",
#            "url" : "URL",
#            "btntxt":"更多"
#    },
#   "enable_id_trans": 0
#}
#
#圖文消息:
# {
#   "touser" : "UserID1|UserID2|UserID3",
#   "toparty" : "PartyID1 | PartyID2",
#   "totag" : "TagID1 | TagID2",
#   "msgtype" : "news",
#   "agentid" : 1,
#   "news" : {
#       "articles" : [
#           {
#               "title" : "中秋節(jié)禮品領(lǐng)取",
#               "description" : "今年中秋節(jié)公司有豪禮相送",
#               "url" : "URL",
#               "picurl" : "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png"
#           }
#        ]
#   },
#   "enable_id_trans": 0
# }

#返回內(nèi)容:
#{
#   "errcode" : 0,
#   "errmsg" : "ok",
#   "invaliduser" : "userid1|userid2", // 不區(qū)分大小寫,返回的列表都統(tǒng)一轉(zhuǎn)為小寫
#   "invalidparty" : "partyid1|partyid2",
#   "invalidtag": "tagid1|tagid2"
# }


# 獲取token
function getAccessToken {
   token_url="${wechat_api_token}?corpid=${corpid}&corpsecret=${corpsecret}"
   curl -d "" -X GET $token_url > token.json
   token=$(cat token.json | python -c "import sys, json; print(json.load(sys.stdin)['access_token'])")
   echo $token
}

token=$(getAccessToken)
echo token:$token

send_content=""
  
if [ $TYPE -eq 1 ] 
  then
    send_content="{
      \"touser\":\"$userids\",
      \"agentid\":\"$agentId\",
      \"msgtype\":\"text\",
      \"text\":{\"content\":\"$CONTENT\"},
      \"safe\":0,
      \"enable_id_trans\":0
      }"
elif [ $TYPE -eq 2 ] 
  then
    send_content="{
      \"touser\":\"$userids\",
      \"agentid\":\"$agentId\",
      \"msgtype\":\"textcard\",
      \"textcard\":{
            \"title\":\"$TITLE\",
            \"description\":\"$DETAIL\",
            \"url\":\"$LINK\",
            \"btntxt\":\"更多\"
      },
      \"enable_id_trans\":0
    }"
elif [ $TYPE -eq 3 ] 
  then
   send_content="{
      \"touser\":\"$userids\",
      \"agentid\":\"$agentId\",
      \"msgtype\":\"news\",
      \"news\":{
          \"articles\":[{
              \"title\":\"$TITLE\",
              \"description\":\"$DETAIL\",
              \"url\":\"$LINK\",
              \"picurl\":\"$PICTURE\"
          }]
      },
    \"enable_id_trans\":0
    }"
fi


echo -e $send_content > "send_content.json"
send_url="${wechat_api_sendText}?access_token=${token}"
echo $send_url
curl  --write-out %{http_code} -d '@send_content.json' -X POST ${send_url} > sendResult.json


用戶對應(yīng)企業(yè)微信賬號,user_table.txt文件:
gitlab賬號:企業(yè)微信賬號

wukexiu:WuKeXiu

這里才是正在的編譯校驗任務(wù)悠垛,當(dāng)然真正校驗的實現(xiàn)在project_build_check.sh中(里面有對xcode的項目進行編譯,打包)
project_build_check.sh文件:

##!/bin/sh

######################
#此shell用于項目編譯校驗#
######################

#in other shell, source project_build_check.sh 在同一個shell下執(zhí)行共享參數(shù)
echo "PROJECTNAME:${O2Space_ProjectName}"
echo "WORKSPACE:${O2Space_WorkSpace}"
echo "SDK_SCHEMES:${O2Space_SDKSchemes}"
echo "IPA_SCHEME:${O2Space_IPAScheme}"

# 第一步
echo "第一步 變量配置" 

pwd

project_path=$1

project_name=$2

# workspace名
project_workspace=$3

#多個Scheme名用“,”分割
sdk_schemes=$4

ipa_scheme=$5
if [ -z "$ipa_scheme" ]; then
    ipa_scheme=$project_name
fi

# archive_path        eg:$project_path/$project_name.xcarchive
archive_path=$project_path/$ipa_scheme.xcarchive

# ipa文件存放路徑        eg:$project_path/$project_name.ipa
export_ipa_path=$project_path/$ipa_scheme.ipa

# exportOptions plist       eg:$project_path/ExportOptions.plist
# 打包導(dǎo)出ipa的時候會生成記錄了這次導(dǎo)出時的證書及關(guān)鍵配置
export_options_plist=$project_path/ExportOptions.plist

# 編譯模式
build_type=Release

# 第二步
echo "第二步 清理工程-打包-導(dǎo)出"


#echo "選擇Xcode版本" | sudo -S xcode-select -s /Applications/Xcode10.1.app

if [ -n "$sdk_schemes" ]; then
  sdk_scheme_array=(${sdk_schemes//,/ })
  echo "http:///-----------"
  echo "http:/// 正在打包SDK"
  echo "http:///-----------"
  for scheme in ${sdk_scheme_array[@]}
  do
    echo "http:///------------------------"
    echo "http:/// 正在編譯$scheme"
    echo "http:///------------------------"
    # 安裝xcpretty 可以讓編譯輸出格式化
    #xcodebuild clean -project ${project_name}.xcodeproj -scheme $scheme | xcpretty
    #-derivedDataPath build,編譯路徑為當(dāng)前build文件
    xcodebuild -workspace ${project_workspace}.xcworkspace -scheme $scheme -configuration $build_type -derivedDataPath build build -quiet || exit
  done
fi

if [ -z "$ipa_scheme" ]; then
  echo "打包ipa的scheme為nil"
  exit 1
fi

echo "http:///---------------"
echo "http:/// 正在清理Demo工程"
echo "http:///---------------"
xcodebuild clean -workspace ${project_workspace}.xcworkspace -scheme $ipa_scheme -configuration $build_type -quiet || exit


## 打IPA方式一: xcodebuild archive + xcodebuild -exportArchive,需要exportOptionsPlist娜谊,(可以手動打包一次确买,將exportOptionsPlist拷貝一份)
# echo "http:///------------------------"
# echo "http:/// 正在編譯Demo工程: Release"
# echo "http:///------------------------"
# xcodebuild archive -workspace ${project_workspace}.xcworkspace -scheme ${ipa_scheme} -configuration Debug -archivePath $archive_path -quiet || exit


# echo "http:///-------------------------------"
# echo "http:/// 開始導(dǎo)出ipa: ${export_ipa_path}"
# echo "http:///-------------------------------"
# export_options_plist這個需要手動打包一次將ExportOptions.plist拷貝出來
# xcodebuild -exportArchive -archivePath $archive_path -exportPath ${export_ipa_path} -exportOptionsPlist ${export_options_plist} -quiet || exit

# 打IPA方式二: xcodebuild build + xcrun
xcodebuild -workspace ${project_workspace}.xcworkspace -scheme $ipa_scheme -configuration $build_type -derivedDataPath build build -quiet || exit

#Xcode升級到8.3后 用命令進行打包 提示下面這個錯誤
#xcrun: error: unable to find utility "PackageApplication", not a developer tool or in PATH
#新版的Xcode少了這個PackageApplication
#從舊版copy一份到“/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/”下
xcrun -sdk iphoneos PackageApplication -v build/Build/Products/Release-iphoneos/$ipa_scheme.app -o $export_ipa_path || exit


if [[ -e $export_ipa_path ]]; then
    echo "http:///-----------"
    echo "http:/// ipa包已導(dǎo)出"
    echo "http:///-----------"
    #open $export_ipa_path
fi


# echo "第三步 發(fā)布到蒲公英或app store" 

# echo "http:///--------------------"
# echo "http:/// 開始發(fā)布到 app store"
# echo "http:///--------------------"
# altoolPath=/Applications/Xcode.app/Contents/Applications/Application\ Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool
# "$altoolPath" --validate-app -f $export_ipa_path\
#               -u <你的開發(fā)者賬號> -p <你的開發(fā)者賬號密碼>\
#               --output-format xml
# "$altoolPath" --upload-app -f $export_ipa_path\
#               -u <你的開發(fā)者賬號> -p <你的開發(fā)者賬號密碼>\
#               --output-format xml


# echo "http:///--------------------"
# echo "http:/// 開始上傳ipa包到蒲公英"
# echo "http:///--------------------"
# curl -F "file=@${export_ipa_path}"\
#      -F "_api_key=5f36a500df15a2b22a195c1583cb8421" https://www.pgyer.com/apiv2/app/upload


# echo "http:///--------------------"
# echo "http:/// 開始上傳ipa包到Fir"
# echo "http:///--------------------"
# fir login -T <你的token>
# fir publish $export_ipa_path

# 成功退出
exit 0

流程中任務(wù)發(fā)起和執(zhí)行失敗都會通過企業(yè)微信通知到發(fā)起者,全部執(zhí)行成功通知發(fā)起者和Merge權(quán)限擁有者

3.4. 相關(guān)效果圖

  • 圖一:發(fā)起merge request

    圖一

  • 圖二:觸發(fā)CI,執(zhí)行.gitlab-ci.yml中相關(guān)merge_request任務(wù)

    圖二

  • 圖三:任務(wù)執(zhí)行完結(jié)果

    圖三

  • 圖四:查看Pipeline

    圖四

  • 圖五:微信通知信息

通過“企業(yè)微信”api發(fā)送通知到用戶的“企業(yè)微信應(yīng)用”纱皆,如何讓微信也能接收呢湾趾?用微信關(guān)注對應(yīng)的“企業(yè)微信”

微信關(guān)注企業(yè)微信

微信內(nèi)收到關(guān)注該“企業(yè)微信”的消息

圖五

四、完

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末派草,一起剝皮案震驚了整個濱河市搀缠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌近迁,老刑警劉巖艺普,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鉴竭,居然都是意外死亡歧譬,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門搏存,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瑰步,“玉大人,你說我怎么就攤上這事璧眠∷踅梗” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵责静,是天一觀的道長袁滥。 經(jīng)常有香客問我,道長泰演,這世上最難降的妖魔是什么呻拌? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮睦焕,結(jié)果婚禮上藐握,老公的妹妹穿的比我還像新娘。我一直安慰自己垃喊,他們只是感情好猾普,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著本谜,像睡著了一般初家。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天溜在,我揣著相機與錄音陌知,去河邊找鬼。 笑死掖肋,一個胖子當(dāng)著我的面吹牛仆葡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播志笼,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼沿盅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了纫溃?” 一聲冷哼從身側(cè)響起腰涧,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎紊浩,沒想到半個月后窖铡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡郎楼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年万伤,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呜袁。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡敌买,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出阶界,到底是詐尸還是另有隱情虹钮,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布膘融,位于F島的核電站芙粱,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏氧映。R本人自食惡果不足惜春畔,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望岛都。 院中可真熱鬧律姨,春花似錦、人聲如沸臼疫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽烫堤。三九已至荣赶,卻和暖如春凤价,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拔创。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工利诺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人剩燥。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓立轧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親躏吊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345