Jenkins+fastlane实现持续集成,上传分发平台,企业微信通知

2,079 阅读6分钟

最近为公司项目集成了Jenkins+fastlane,实现了持续集成,本文做一个记录,其中遇到了不少问题,文章末尾都会列出,后续也会补充. 以此记录.

简单介绍:

fastlane是用Ruby语言编写的一套自动化工具,它把不同的action结合在一起,比如证书管理,编译打包等.从而形成一个完整的自动化流程. 另外Jenkins是一个开源的自动化服务器,给我们提供了一个自动化的平台,通过Jenkins远程拉取代码,并配置一些信息,实现自动化分发,通知等功能.

fastlane安装与配置

如果没有安装Xcode命令行工具的话,

xcode-select --install

确保gem sources是https://gems.ruby-china.com/

localhost:Jenkins snailsleep$ gem sources
*** CURRENT SOURCES ***

https://gems.ruby-china.com/

如果不是的话请更改:

gem sources --remove 当前的source
gem sources -a https://gems.ruby-china.com

fastlane安装:

brew cask install fastlane

安装完后查看版本

localhost:Jenkins snailsleep$ fastlane --version
fastlane installation at path:
/Library/Ruby/Gems/2.6.0/gems/fastlane-2.144.0/bin/fastlane
-----------------------------
[✔] 🚀 
fastlane 2.144.0

接下来要cd到我们的项目目录,然后执行

fastlane init

此时会询问我们用fastlane来做什么,这里可以选4

后续还会让输入AppleID和密码,最终我们会在项目目录里发现有个fastlane文件夹,里面包含Appfile和Fastfile 在Appfile文件里是一些简单的配置

app_identifier("***","***","***") # The bundle identifier of your app
apple_id("***") # Your Apple email address

team_id "***" # Developer Portal Team ID

# For more information about the Appfile, see:
#     https://docs.fastlane.tools/advanced/#appfile

主要的打包脚本配置都在Fastfile文件里编写,不同的lane就是不同的任务,我们可以新建一个lane,来做我们的打包任务(涉及隐私的内容用***代替)

  lane :qwer do

    ENV["FASTLANE_USER"] = "***"
    ENV["FASTLANE_PASSWORD"] = "***"
    cert(
	development: true,
    )

    sigh(
	app_identifier: "com.***.***",
	readonly: false, 
	cert_id: "***",
	development: true,
    )

    sigh(
	app_identifier: "com.***.appwatchkitapp",
	readonly: false, 
	cert_id: "***",
	development: true,
    )

    sigh(
	app_identifier: "com.***.appwatchkitapp.watchkitextension",
	readonly: false, 
	cert_id: "***",
        development: true,
    )

    
    
    build_app(
      scheme: "***",
      export_method: "development", 
      output_directory: "/Users/Shared/Jenkins/Home/workspace/IPAName",
      output_name: "IPAName",
      include_bitcode: false,
      configuration: "Debug",
      export_xcargs: "-allowProvisioningUpdates",
      destination: "generic/platform=iOS"
    )


   #可以使用蒲公英插件上传并制作二维码,具体可见 https://www.pgyer.com/doc/view/fastlane
   #pgyer(api_key: "***", user_key: "***")

  end

因为我们项目中还包含watch,存在三个app_identifier,所以进行了三次sigh.获取certid方法已在文章末贴出.

因为我们给这个lane命名为qwer,所以在项目目录中执行fastlane qwer即可开始打包

如果显示这样就说明你打包成功了

Jenkins安装与配置

Jenkins的官网 下载最新的 war 包, 我这里选择的是LTS的Mac OS X的版本, 下载完成后会有个jenkins-2.204.2.pkg的包,双击进行安装即可

安装成功后,我们会在Applications目录里发现有Jenkins文件夹,里面有个jenkins.war文件, 我们进入到这个文件目录内来启动Jenkins

    $ cd /Applications/Jenkins
    $ java -jar jenkins.war --httpPort=8080
    

Jenkins启动成功后,我们就可以去浏览器访问

    http://localhost:8080

我们会看到这个界面

需要输入密码,密码已经写入到了日志中,日志获取路径是

Linux
By default logs should be made available in /var/log/jenkins/jenkins.log, unless customized in /etc/default/jenkins (for *.deb) or via /etc/sysconfig/jenkins (for */rpm)

Windows
By default logs should be at %JENKINS_HOME%/jenkins.out and %JENKINS_HOME%/jenkins.err, unless customized in %JENKINS_HOME%/jenkins.xml

Mac OS X
Log files should be at /var/log/jenkins/jenkins.log, unless customized in org.jenkins-ci.plist.

按照文档中所述,我们去/var/log/jenkins 找到jenkins.log文件,打开它后可以看到

红框里就是密码

首次进入Jenkins配置首页后,会询问你自定义插件还是直接用推荐的,这里直接选的一键集成推荐插件

install suggested plusgins省事省心省时间

正在配置插件..好慢..

我要重试,必须都安上!

经过了几次重试,终于成功,会到下面这个界面

创建完用户,需要配置Jenkins URL

最终Jenkins安装完成!

搞定

Jenkins配置首页
新创建个任务,这里选择Jenkins的核心功能"Freestyle project"

创建完任务后,我们需要对它进行一些配置,其中在源码管理里,我们需要配置Repository URL和Credentials(凭据)来告诉Jenkins去哪里找到我们的代码

这里我选择的是SSH Username with private key 然后把私钥填写好(~/.ssh/id_rsa这里复制私钥内容),当然前提是得在代码托管平台配置好SSH,我这是在Gitee已经配置好了.

⚠️注意"-----BEGIN OPENSSH PRIVATE KEY-----"和"-----END OPENSSH PRIVATE KEY-----"不要去掉,里面内容全部复制粘贴即可

在"构建"栏目里,通过"增加构建步骤--Execute shell" 可以添加一些脚本,如下图

这里的qwer就是lane的名字,是在Fastfile文件里我们定义好的,配置好脚本后,点击Build Now即可开始编译打包

打包完成

我们还可以通过蒲公英Jenkins插件来上传包并生成二维码,并且通过以下脚本,用企业微信机器人,来通知群里每个人

curl '这里是企业微信群机器人的Webhook地址'
   -H 'Content-Type: application/json' \
   -d '
   {
    "msgtype": "news",
    "news": {
       "articles" : [
           {
               "title" : "iOS 测试包",
               "description" : "修复***问题\n修复***问题",
               "url" : "***",
               "picurl" : "***",
           }
        ]
    }
}'

✨ 可能遇到的问题与解决办法

1. 执行完fastlane init后,在bundle update卡住了

如果按照文章开头的方式已经更换了gem source,但是依然卡住,可以进到项目目录找到Gemfile文件,打开后发现是这样的

source "https://rubygems.org"

gem "fastlane"

在这里我们再改一次source

source "https://gems.ruby-china.com"

gem "fastlane"

然后在当前目录下执行bundle update就可以啦

2. 出现 fastlane: command not found 怎么办?

这个情况一般是由于 jenkins 没有设置正确的 $PATH 环境变量导致的。正确设置的方法为:

在命令行下执行 echo $PATH,记录下输出的结果, 在 jenkins 中系统管理-系统设置中,找到 环境变量(Environment variables) 在 key 中填写 PATH,在 value 中填写第一步中输出的结果 保存即可。

3. fastfile里明明配置好了pp文件,可是总说找不到pp文件?

例如:

Exit status: 70
[11:24:53]: No provisioning profile provided
[11:24:53]: Make sure to pass a valid provisioning for each required target
[11:24:53]: Check out the docs on how to fix this: https://docs.fastlane.tools/actions/gym/#export-options

build_app里加上export_xcargs: "-allowProvisioningUpdates" (见文章中fastfile的lane部分)

4.certid怎么获取?

require 'spaceship'

Spaceship.login('***')
Spaceship.select_team

Spaceship.certificate.all.each do |cert|
  cert_type = Spaceship::Portal::Certificate::CERTIFICATE_TYPE_IDS[cert.type_display_id].to_s.split("::")[-1]
  puts "Cert id: #{cert.id}, name: #{cert.name}, expires: #{cert.expires.strftime("%Y-%m-%d")}, type: #{cert_type}"
end

以上脚本内容存好放在桌面,比如getcertID.rb,记得在Spaceship.login里改一下自己的开发者账号, 然后在命令行cd到桌面,执行

ruby getcertID.rb

输入开发者密码,即可获取所有certid

5. 启动Jenkins时候报错,端口号被占用

(base) localhost:Jenkins snailsleep$ java -jar jenkins.war --httpPort=8080
Running from: /Applications/Jenkins/jenkins.war
webroot: $user.home/.jenkins
2020-04-02 07:49:53.939+0000 [id=1]	INFO	org.eclipse.jetty.util.log.Log#initialized: Logging initialized @328ms to org.eclipse.jetty.util.log.JavaUtilLog
2020-04-02 07:49:54.051+0000 [id=1]	INFO	winstone.Logger#logInternal: Beginning extraction from war file
2020-04-02 07:49:55.387+0000 [id=1]	WARNING	o.e.j.s.handler.ContextHandler#setContextPath: Empty contextPath
2020-04-02 07:49:55.442+0000 [id=1]	INFO	org.eclipse.jetty.server.Server#doStart: jetty-9.4.z-SNAPSHOT; built: 2019-05-02T00:04:53.875Z; git: e1bc35120a6617ee3df052294e433f3a25ce7097; jvm 1.8.0_242-b08
2020-04-02 07:49:55.714+0000 [id=1]	INFO	o.e.j.w.StandardDescriptorProcessor#visitServlet: NO JSP Support for /, did not find org.eclipse.jetty.jsp.JettyJspServlet
2020-04-02 07:49:55.766+0000 [id=1]	INFO	o.e.j.s.s.DefaultSessionIdManager#doStart: DefaultSessionIdManager workerName=node0
2020-04-02 07:49:55.767+0000 [id=1]	INFO	o.e.j.s.s.DefaultSessionIdManager#doStart: No SessionScavenger set, using defaults
2020-04-02 07:49:55.769+0000 [id=1]	INFO	o.e.j.server.session.HouseKeeper#startScavenging: node0 Scavenging every 660000ms
2020-04-02 07:49:56.112+0000 [id=1]	INFO	hudson.WebAppMain#contextInitialized: Jenkins home directory: /Users/snailsleep/.jenkins found at: $user.home/.jenkins
2020-04-02 07:49:57.139+0000 [id=1]	INFO	o.e.j.s.handler.ContextHandler#doStart: Started w.@782a4fff{Jenkins v2.204.5,/,file:///Users/snailsleep/.jenkins/war/,AVAILABLE}{/Users/snailsleep/.jenkins/war}
2020-04-02 07:49:57.154+0000 [id=1]	INFO	o.e.j.server.AbstractConnector#doStop: Stopped ServerConnector@723ca036{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2020-04-02 07:49:57.155+0000 [id=1]	INFO	o.e.j.server.session.HouseKeeper#stopScavenging: node0 Stopped scavenging
2020-04-02 07:49:57.157+0000 [id=1]	INFO	hudson.WebAppMain#contextDestroyed: Shutting down a Jenkins instance that was still starting up
java.lang.Throwable: reason
	at hudson.WebAppMain.contextDestroyed(WebAppMain.java:388)

端口号被占用,换个端口号即可:

$ cd /Applications/Jenkins
$ java -jar jenkins.war --httpPort=8080

6. 启动Jenkins时候报错,java版本不对

2020-02-27 16:50:30.475 defaults[94179:3383577] 
The domain/default pair of (/Library/Preferences/org.jenkins-ci, httpsKeyStore) does not exist
2020-02-27 16:50:30.486 defaults[94180:3383580] 
The domain/default pair of (/Library/Preferences/org.jenkins-ci, httpsKeyStorePassword) does not exist
JENKINS_HOME=/Users/Shared/Jenkins/Home
Jenkins command line for execution:
/usr/bin/java -Dfile.encoding=UTF-8 -XX:PermSize=256m -XX:MaxPermSize=512m -Xms256m -Xmx512m -Djava.io.tmpdir=/Users/Shared/Jenkins/tmp -jar /Applications/Jenkins/jenkins.war --httpPort=8080
OpenJDK 64-Bit Server VM warning: Ignoring option PermSize; support was removed in 8.0
OpenJDK 64-Bit Server VM warning: Ignoring option MaxPermSize; support was removed in 8.0
2月 27, 2020 4:50:30 下午 Main verifyJavaVersion
严重: Running with Java class version 57 which is not in the list of supported versions: [52, 55]. Run with the --enable-future-java flag to enable such behavior. See https://jenkins.io/redirect/java-support/
java.lang.UnsupportedClassVersionError: 57.0
	at Main.verifyJavaVersion(Main.java:174)
	at Main.main(Main.java:142)

Jenkins requires Java versions [8, 11] but you are running with Java 13 from /Library/Java/JavaVirtualMachines/openjdk-13.0.2.jdk/Contents/Home
java.lang.UnsupportedClassVersionError: 57.0
	at Main.verifyJavaVersion(Main.java:174)
	at Main.main(Main.java:142)
2020-02-27 16:50:40.839 defaults[94183:3383671] 

注意 "Jenkins requires Java versions [8, 11] but you are running with Java 13" , Jenkins要求Java版本是8~11,我们需要去这个路径/Library/Java/JavaVirtualMachines/openjdk-13.0.2.jdk/Contents/Home,把openjdk-13.0.2.jdk删掉,然后我们再安装个Java8即可

安装Java8

$ brew tap AdoptOpenJDK/openjdk
$ brew cask install adoptopenjdk8

OK!搞定! 我们再次启动Jenkins,就会发现Jenkins is fully up and running ~

7. Jenkins跑项目的时候报错,need password

(见文章中fastfile文件的lane里) 打包脚本里需要添加以下内容,即为你的开发者账号和密码

    ENV["FASTLANE_USER"] = "***"
    ENV["FASTLANE_PASSWORD"] = "***"