拥有Fastlane的Easy CI:我们如何从运行测试到分发构建的所有iOS自动化

你好! 我是Aaptiv的iOS工程师Andrew Lection。 最近,我们为用户推出了一些很棒的新功能,例如Apple Watch应用程序和培训计划。 我们还长期认真地研究了“过去的工作方式”,以确保我们除了建立出色的新功能之外,还在构建有效,可持续的流程。

在本文中,我将与Ivan Lee(我们的首席测试工程师)合作,展示我们如何通过快速通道解决CI难题并分享经验教训,最佳实践和故障排除技巧。 这是我们团队开发过程中令人兴奋的新篇章,这仅仅是开始!

  • 开发人员在本地运行单元测试。
  • PR的审阅者看不到单元测试的结果或其他代码质量信息。
  • 工程师需要添加新的测试设备才能在Apple Developer Portal周围单击。 很多。
  • 测试人员不知道新版本何时准备就绪-有时需要使用Diawi等外部工具来安装版本。
  • 由于手动更新配置文件时出现问题,内部用户无法使用狗粮版本。

我们认为,我们的首要任务是专注于为iOS和Apple Watch应用程序实施持续集成(以及为最终为我们的Android应用程序实施CI奠定基础)。

由于以下原因,我们选择fastlane作为我们选择的CI工具:

  • 这是一个开放源代码工具集,具有强大而出色的支持。
  • 它非常灵活 ,可以让我们自动执行iOS特定任务,例如证书管理,自动增加内部版本号和设备配置。
  • 它是便携式的,因此我们不会锁定供应商。 fastlane并未与特定的CI平台耦合,因此我们可以轻松地将fastlane实施迁移到其他SaaS提供商或我们自己的自托管CI。

您将需要整理一小部分(但很重要!)所需的东西。 这将使您的快速通道实施尽可能地顺畅无阻-而且还可以确保CI流程在很长一段时间内都可维护。

你需要:

  • 电子邮件帐户-我们将创建一堆帐户(如果您也处理Android CI,那么还会更多!)。 一封不错的电子邮件(例如ios-ci@yourcompany.com)有助于使事情井井有条。
  • 具有SSH密钥对的Github(或[INSERT SCM HERE])帐户-您的CI系统将需要此帐户。 如果要自动增加内部版本号,则SSH密钥对还将自动提交更改。
  • 一个Apple Developer Admin帐户-fastlane Match为您处理所有杂乱的预配业务-您只需要为其提供一个帐户即可!
  • 密码管理-完成后,您将拥有三个帐户,一个SSH密钥对和一个匹配存储库密码。 要为本地开发设置快速通道,您需要访问Apple Developer帐户和匹配存储库密码。 我们可以使用Lastpass Enterprise与团队安全地共享密码,尽管您也可以使用免费替代方案甚至安全的消息传递平台。

SaaS与设备实验室

fastlane正在开发以移动设备为重点的开源CI工具。 这是令人振奋的消息,我们很高兴在2018年末将fastlane.ci带出一堂。

同时,您需要在内部运行移动CI(使用Jenkins或Atlassian Bamboo)或与基于云的SaaS提供商(例如CircleCI,TravisCI或Gitlab)之间进行选择。

自托管

优点

  • 超级灵活! 您可以控制移动CI实验室如何插入公司其余基础结构中-如果您在一个受到严格监管的行业中工作,这一点尤其重要。
  • 您可以将所有(所有)构建集中在一个位置。 移动不一定非得是雪花!

缺点

  • 并行构建的数量受物理设备数量的限制。
  • 一些解决方案(例如Jenkins)依赖于不经常维护的插件。
  • 较高的初始成本和持续维护的机会成本。

SaaS

优点

  • 开始运行移动CI的基础架构“规模较小”,从而使采用变得更容易,也更顺畅。
  • 构建环境更稳定(在基础结构和更新方面)。

缺点

  • 解决Xcode /代码签名问题很困难。
  • 根据平台和团队实践的不同,随着时间的推移,月租费可能变得昂贵。
  1. 当开发人员打开PR时,CircleCI将自动构建iOS项目。
  2. CircleCI将自动将代码签名证书和供应配置文件安装到本地钥匙串中(使用setup_circle_ci操作进行配置)。
  • 有关Fastlane和代码签名的更多信息,请参阅match action文档并在此处阅读有关该方法的更多信息。

3. fastlane运行SwiftLint,运行单元测试,并生成代码覆盖率报告。

4. fastlane构建IPA和* .dsym文件。

我们可以选择使用fastlane-plugin-s3插件(针对QA)或Crashlytics(针对内部用户)通过AWS分发构建。

当事态发展异常(例如,构建失败)或成功超越了我们最疯狂的梦想(即,构建已准备好进行质量检查)时,我们将使用fastlane的宽松支持来通知我们的团队。 这里肯定存在警报疲劳的风险-与您的团队合作,找出多少条通知“正确”!

用于开发,测试和生产的Xcode方案:面向所有用户的一个Xcode项目配置

为了促进我们的日常开发活动以及每晚的Beta版构建,我们需要修改Xcode项目方案结构以与Fastlane Match配合使用。

我们使用三个独立的构建配置来组织Xcode项目:

  • 调试:用于本地开发(指向我们的暂存环境)。 配备了开发资料和开发证书,以便工程师构建开发设备。
  • Beta:用于内部分发(也指向我们的暂存环境)。 配备了临时配置文件和分发证书,以构建和部署内部狗粮。
  • 发布:用于存档生产构建以提交到App Store。

首先,我们停用了Automatically manage signing Xcode中的Automatically manage signing 。 然后,我们将Xcode签名(位于“常规”选项卡下)中的供应配置文件设置为Development和Ad Hoc的每个匹配的供应配置文件。 通过使用match和共享的Xcode设置设置,我们确保iOS设置和代码签名得到一致的处理(并且可重复!)

然后,我们创建了三个单独的Xcode方案,每个构建配置都一个,并且在Xcode中创建新方案时,通过选中Shared框(在Scheme编辑窗口中),确保将这些方案签入版本控制。 然后,将Scheme的运行配置设置为其各自的构建配置(即Debug,Beta或Release)。

现在,使用这种共享的Xcode方案结构,每个工程师只需运行fastlane匹配即可确保本地配置文件是最新的:

  $ fastlane匹配开发-只读 

对于我们的移动CI,我们可以轻松地指定fastlane以使用Beta方案部署Ad Hoc构建,而无需指定任何其他Xcode配置。

为WatchKit扩展设置快速通道匹配

除了主要的iOS应用程序目标之外,我们的项目还包含Apple Watch应用程序的Watch和WatchExtension目标。 我们使用fastlane匹配为每个Watch目标生成一个Development和Ad Hoc供应配置文件,而fastlane match可以轻松处理多个Xcode目标的供应配置文件。

以与我们为主应用程序目标设置Xcode签名相同的方式,为Watch和WatchExtension目标停用Automatically manage signing ,然后将Provisioning Profile设置为Debug,Beta和Release的每个匹配配置文件。

瞧! 现在,我们可以使用fastlane健身房构建和部署iOS和Apple Watch应用程序。 如果我们想使用Beta运行配置来部署一个临时构建,我们可以简单地配置一个beta通道来运行Gym命令:

 车道:beta do 
体育馆(方案:“测试版”,
配置:“测试版”,
export_method:“临时”

结束

提示 :使用有用的(建议使用!)increment_build_number操作时,请确保Watch和Watch Extension目标的Xcode项目plist路径是相对路径,以便通过确保从plist路径中删除$(SRCROOT)来简化plist编辑。在两个监视目标的“构建设置”中指定。

单元测试,代码覆盖率和通知策略

在Aaptiv的产品和流程(包括我们的iOS和Android代码库)的整个开发周期中,测试是重要且有价值的一步。 具体来说,对于我们的iOS单元测试套件,我们添加了逻辑测试以防止在新分支中引入回归,并在重构代码库中的组件时提供额外的验证。

我们使用fastlane扫描对开放的PR运行XCTest套件,然后PR将报告单元测试的结果和代码覆盖率。 为了运行单元测试并生成报告,我们只需在Fastfile的测试通道中包装对scan命令的调用即可。 由于我们在Scanfile中设置了参数默认值,包括Xcode方案,设备类型字符串数组以及所生成报告的输出类型,因此实际的扫描命令参数非常少。

有了这个反馈环,我们应该在何时以及如何准确地得出单元测试结果,同时避免警报疲劳?

首先,我们创建了一个专门用于与iOS相关的测试和构建通知的Slack频道,以及一个相应的Slack webhook URL,我们可以使用fastlane SLACK_URL环境变量将其插入fastlane的内置slack操作中。 接下来,我们作为团队决定了一种通知策略,该策略将在以下情况下将通知发送到我们的iOS通知频道:

  • 单元测试失败
  • 每晚构建失败/成功
  • 车道发生错误

通过仅针对我们感兴趣的场景传播警报并在集中式渠道中显示通知,此通知策略对我们的团队而言效果很好。 当然,根据团队的工作流程,此通知策略因团队而异。

此外,我们确保当使用fastlane的is_ci操作在移动CI中运行fastlane 时才广播通知(我们不想每次在本地运行单元测试时都发送通知!)

为了限制何时发布有关单元测试结果的通知,扫描工具具有两个非常方便的参数:

  • skip_slack ,用于在本地运行单元测试时阻止发布通知。
  • slack_only_on_failure ,我们仅在单元测试在我们的移动CI中运行失败时用于发布通知。

有了周到的通知策略,我们现在可以将成功和失败的结果集中到Slack,以及在已打开的PR中显示单元测试状态。 太棒了!

提示 :SwiftLint在fastlane.swift文件上出错吗? 通过添加以下内容,在swiftlint.yml配置文件中排除捆绑路径,即供应商/捆绑销售商

 排除: 
-供应商/捆绑

您还需要添加CocoaPods路径,以将SwiftLint从错误中排除在项目生成的任何依赖项之外:

 排除: 
-豆荚

最佳实践

(出色的)官方通道文档以及网络上的各种知识点都有大量资源。 为了在Aaptiv进行开发,以下最佳实践帮助我们开发了Fastlane和CI解决方案:

  • 泳道的单一职责 :确保每个Fastfile泳道都有一个职责。 在添加其他要求或要在管道中添加步骤时,请将这些通道视为单独的单元,然后可以在CI工作流程配置中将它们链接在一起。 这将在将来提供灵活性,而不会膨胀单个通道(并且在将来花费更少的时间进行重构或重新构造通道!)
  • 在Fastfile之外指定默认值:通过在各自的Deliverfile,Gymfile,Matchfile和Scanfile中指定Delivery,Gym,Match和Scan的参数默认值,减少Fastfile中的混乱情况。
  • 回购中的Gemfile:我们建议将Gemfile添加到iOS项目的根目录,以确保所有本地开发环境都指定并使用相同的fastlane gem版本。
  • 快速文件可发现性 :在每个通道上添加说明以提高可发现性。 这可能只是对一个通道的单一职责(即“构建临时IPA文件”或“递增iOS内部版本号”)一样简洁:
  desc(“增加iOS内部版本号”) 
车道:build_bump do
...
结束

在我们的上一个大型项目(运行了大约两个半月)中,fastlane帮助我们自信地进行了编码,测试和发布。 总体而言,我们使用CI流程构建了10个临时版本,22个夜间版本和4个Beta版本。

尽管我们对CI流程感到非常满意,但总有改进的余地! 在接下来的几个月中,我们希望解决一些增强功能:

  • 将应用程序自动提交到Apple App Store。
  • 允许开发人员为内部版本添加发行说明,以便我们的Beta测试人员永远知道发生了什么!
  • 加快项目构建时间! (缓存CocoaPods,调查新的Xcode Build System,缓存项目文件,仅构建更改的文件)

对我们如何使用Jenkins,fastlane和Docker为Android设置CI感兴趣吗? 敬请关注…