iOS自动化部署Jenkins

"自动化部署"

Posted by wanglilong on October 17, 2019

iOS自动化部署Jenkins

一、前言

之前写过一个自动化打包的shell脚本,但是老大觉得自动化程度还是不高,建议用Jenkins来搞。所以就研究一下Jenkins的自动化部署。

二、Jenkins安装

安装brew

1
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

由于jenkins依赖于java8(之上),所以需要先安装java

1
brew cask install homebrew/cask-versions/adoptopenjdk8

然后使用brew安装jenkins

1
brew install jenkins

三、启动Jenkins

命令

1
jenkins//启动

登录网址管理Jenkins

1
 http://localhost:8080/ 

四、插件

一般会选择Jenkins推荐安装的插件

另外一般会另外安装插件

1
2
Keychains and Provisioning Profiles Management//方便管理打包证书
Xcode integration//由于需要使用Xcode编译环境,因此必须要安装插件

但是这两个插件我好像都木有用到

五、组件化项目自动化打包

由于项目用了RN,并且用了组件化。普通方式的自动化打包无法使用。所以只能使用流水线的方式来打包。

(1)、配置环境变量

组件化是使用pod进行管理的,所以需要用pod命令

1
pod install

如果没有配置环境变量会提示 pod: command not found。所以需要配置环境变量

环境配置1

然后选择Environment variables。其中,PATH是固定的,值是在终端输入:$echo $PATH命令获取,将输入命令后得到的值粘贴过来就可以了。

(2)、配置Keychains and Provisioning Profiles Management

见(参考2)用流水方式打包好像并没有用

(3)、流水线

首先、创建流水线项目

设置执行脚本的时间

流水线2

设置脚本

脚本语法

点击上图中的Pipeline Syntax,可以通过生成器生成脚本

组件化项目打包方式

首先:拉下来iOS各个模块的代码

然后:pod install

最后:将项目打包并上传

1、从git服务器上拉下代码到指定的文件夹

1
2
3
4
node {
    checkout([$class: 'GitSCM', branches: [[name: '*/dev']], doGenerateSubmoduleConfigurations: false, extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: 'HelloBeijing/ios/HelloBeijing_iOS/']], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'ccb75a88-4fe2-44e7-846d-0fea1965cef4', url: 'http://git.jd.com/helloBJ/HelloBeijing_iOS.git']]])
}

branches:为分支设置

relativeTargetDir:指定导出的路径,根目录为项目目录

url:为git代码网址

credentialsId:为用户名密码生成的(目前只知道代码生成器的方式生成)

2、进行pod

1
2
3
4
5
6
7
8
node {
    sh label: '', 
    script: '''
cd /Users/用户名/.jenkins/workspace/HelloBeijingAll/HelloBeijing/ios/HelloBeijing_iOS
pod install
		'''
}

3、最后shell脚本打包并上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
node {
    sh label: '', script: '''
cd /Users/wanglilong3/.jenkins/workspace/HelloBeijingAll/HelloBeijing/ios/HelloBeijing_iOS
#工程名字(Target名字)
Project_Name_TEST="******"
#workspace的名字
Workspace_Name="******"
#配置环境,Release或者Debug,默认release
Configuration="Release"

#加载各个版本的plist文件
ADHOCExportOptionsPlist=./ADHOCExportOptionsPlist.plist
ADHOCExportOptionsPlist=${ADHOCExportOptionsPlist}

#adhoc脚本
xcodebuild -workspace $Workspace_Name.xcworkspace -scheme $Project_Name_TEST -configuration $Configuration -archivePath build/$Project_Name_TEST-adhoc.xcarchive clean archive build -allowProvisioningUpdates
xcodebuild  -exportArchive -archivePath build/$Project_Name_TEST-adhoc.xcarchive -exportOptionsPlist ${ADHOCExportOptionsPlist} -exportPath ~/Desktop/$Project_Name_TEST -allowProvisioningUpdates

#执行上传至蒲公英的命令
apiKey="蒲公英的apiKey"
IPA_PATH=~/Desktop/$Project_Name_TEST/$Project_Name_TEST.ipa
curl -F  file=@${IPA_PATH}  -F  _api_key=${apiKey}  https://www.pgyer.com/apiv2/app/upload
'''
}

shell脚本写法请见iOS自动打包

4、判断git上代码是否有更新

根据全局变量参考上说明,可根据currentBuild的changeSets,来判断git是否有更新。

1
2
3
4
currentBuild

changeSets
a list of changesets coming from distinct SCM checkouts; each has a kind and is a list of commits; each commit has a commitId, timestamp, msg, author, and affectedFiles each of which has an editType and path; the value will not generally be Serializable so you may only access it inside a method marked @NonCPS

代码如下

1
2
3
4
5
6
7
8
9
node {
     stage('build') {
          if (currentBuild.changeSets.isEmpty()) {
                echo 'no change'
          } else {
                echo 'build'
          }      
      }
}

六:参考

1、占坑!利用 JenKins 持续集成 iOS 项目时遇到的问题

2、使用jenkins实现xcode自动打包

3、最终脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
pipeline {
    agent any

    stages {
        stage('checkout') {
            steps {
                checkout([$class: 'GitSCM', branches: [[name: '*/dev']], doGenerateSubmoduleConfigurations: false, extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: 'HelloBeijing/ios/HelloBeijing_iOS/']], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'ccb75a88-4fe2-44e7-846d-0fea1965cef4', url: 'http://git.jd.com/helloBJ/HelloBeijing_iOS.git']]])
                echo 'ios'

                checkout([$class: 'GitSCM', branches: [[name: '*/dev']], doGenerateSubmoduleConfigurations: false, extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: 'iCityAppSDK/ICFoundationSDK/']], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'ccb75a88-4fe2-44e7-846d-0fea1965cef4', url: 'http://git.jd.com/iCityAppSDK/ICFoundationSDK.git']]])
                echo 'ICFoundationSDK'
                
                checkout([$class: 'GitSCM', branches: [[name: '*/dev']], doGenerateSubmoduleConfigurations: false, extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: 'iCityAppSDK/ICNetworkingSDK']], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'ccb75a88-4fe2-44e7-846d-0fea1965cef4', url: 'http://git.jd.com/iCityAppSDK/ICNetworkingSDK.git']]])
                echo 'ICNetworkingSDK'

                checkout([$class: 'GitSCM', branches: [[name: '*/dev']], doGenerateSubmoduleConfigurations: false, extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: 'iCityAppSDK/ICUIKit']], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'ccb75a88-4fe2-44e7-846d-0fea1965cef4', url: 'http://git.jd.com/iCityAppSDK/ICUIKit.git']]])
                echo 'ICUIKit'
            }
        }
        
        stage('pod') {
            steps {
    		    sh label: '', 
   		        script: '''
			        cd /Users/wanglilong3/.jenkins/workspace/HelloBeijingAll/HelloBeijing/ios/HelloBeijing_iOS
		        	pod install
		        '''
		        echo 'pod'
            }
        }
    }
}
node {
     stage('build') {
          if (currentBuild.changeSets.isEmpty()) {
                echo 'no change'
          } else {
                sh label: '', 
   		        	script: '''
			        	cd /Users/wanglilong3/.jenkins/workspace/HelloBeijingAll/HelloBeijing/ios/HelloBeijing_iOS
		        		sh xcode_Jenkins.sh
		        		'''
                echo 'build'
          }      
      }
}

4、代码判断

判断Git是否有新的提交,如果有的话拉取代码构建,如果没有不构建。Jenkins需要安装插件Conditional BuildStep。但是在流水线中无法生效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
if [ ! $GIT_PREVIOUS_SUCCESSFUL_COMMIT ];then
    echo "GIT_PREVIOUS_SUCCESSFUL_COMMIT is not exists."
    exit 0
else
    echo "GIT_COMMIT=[$GIT_COMMIT],GIT_PREVIOUS_SUCCESSFUL_COMMIT=[$GIT_PREVIOUS_SUCCESSFUL_COMMIT]"
    if [ $GIT_PREVIOUS_SUCCESSFUL_COMMIT == $GIT_COMMIT ];then
        echo "GIT_COMMIT is equals to GIT_PREVIOUS_SUCCESSFUL_COMMIT,skip build."
        exit -1
    else
        echo "GIT_COMMIT is not equals to GIT_PREVIOUS_SUCCESSFUL_COMMIT"
        exit 0
    fi
fi

4、手把手教你利用 Jenkins 持续集成 iOS 项目