android 每日构建
在我目前的工作过程中,我不得不自动化构建Android应用程序的工作。 这篇文章旨在描述我遇到的痛点,以使您的读者在打算这样做时不会浪费您的时间。
环境如下:
- 自动化基础设施的
- Jenkins用于CI服务器
- Android项目
- 一个Gradle构建文件来构建它
- Robolectric作为主要测试框架
木偶和詹金斯
确实,我的出发点很不错。 同事们已经自动安装了Jenkins服务器,所需的软件包(包括Java),并为创建工作提供了可重用的Puppet类。 Jenkins作业依赖于一个config.xml
文件,该文件由不同部分组成。 每个部分均由专用模板处理。 在这一点上,我认为创建一个简单的Gradle工作类似于在公园散步,最多需要几天的时间,并且很快我将被分配另一个任务。
第一步很容易:只需更新现有的Puppet清单,即可将Gradle插件添加到Jenkins。
Gradle包装
该博客的普通读者知道我对Gradle的看法。 但是,我承认,确保Maven缺少-并且应该具有确保不管安装的工具版本如何都可以运行的构建。 为了达到这个目的,Gradle通过JAR,shell脚本和属性文件提供了所谓的包装器机制,后者包含Gradle ZIP发行版的URL。 所有这三个都需要存储在SCM中 。
这是我麻烦的开始。 必须在企业环境中下载意味着要经过代理并对其进行身份验证。 最简单的选择是在作业配置中设置所有内容...包括代理凭据。 但是,从安全的角度来看,这样做并不是很合理,因为任何有权访问Jenkins界面或文件系统的人都可以读取那些凭据。 需要另一种选择。
客户已经有一个带有配置的代理的有效Nexus存储库。 作为派,很容易将所需的Gradle发行版上传到那里,并更新gradle.properties以指向它。
Android SDK
Android SDK只是一个ZIP。 我重复了相同的策略:下载然后将其上传到Nexus。 此时,现有的Puppet脚本负责下载,提取和设置正确的权限。
但是,这一步骤是真正问题的开始。 Android开发人员知道Android SDK只是一种管理器:必须手动检查所需的平台和工具才能将其下载到本地文件系统上。 尽管有一个命令行等效于通过SDK来安装/更新软件包(带有--no-ui
参数),但对于Android开发人员而言,在其机器上执行的简单步骤确实是一场噩梦,尽管自动化。 有关完整说明,请检查此链接 。
Google工程师无法提供2个重要参数:
- 代理凭证-登录名/密码
- 接受许可协议
Web上有很多无法解决的答案,最诱人的是配置文件。 我发现他们都没有工作。 但是,我发现了使用expect
命令的创造性解决方案 。 Expect是一个漂亮的命令 ,它读取标准输出并相应地填写标准输入。 Expect的好处是它接受正则表达式。 因此,当它要求代理登录时,您键入登录名,当它要求输入密码时,您也进行同样的操作,而当它要求许可接受时,您键入“ y”。 这非常简单-尽管我花了很多时间反复尝试才能达到预期的结果。
我最初的设计是将所有必需的Android软件包与Puppet一起安装,作为服务器配置的一部分。 对于标准操作,例如文件创建或系统软件包安装,Puppet能够确定是否有必要进行配置, 例如,如果文件存在,则无需创建它,同样也可以安装软件包。 最后,Puppet在日志中报告它执行的每个操作。 首先,我尝试通过向Puppet告知在配置过程中创建了哪些软件包来实现这种缓存,因为Android SDK为每个软件包创建了一个文件夹。 第一个问题是Puppet仅接受一个文件夹进行验证。 然后,对于某些软件包,没有版本信息(例如Google Play服务就是这种情况)。
因此,一位同事想到了从Puppet设置的这一更新过渡到每个工作的前期步骤。 这解决了非幂等问题。 此外,它使每个作业都可以配置运行更新。
robolectric
在这一点上,我认为它会完成的。 不幸的是,由于图书馆-Robolectric,情况并非如此。
目前我还不了解Robolectric ,我只是知道这是Android的测试库,它提供了一种无需连接物理设备即可运行测试的方法。 在尝试在Jenkins上运行构建时,我偶然发现了一个“有趣的”问题:尽管Roboletric提供了带有依赖项的POM,但MavenDependencyResolver类对从中下载的存储库进行了硬编码。
唯一提供的解决方法是扩展上述类以破解您自己的实现。 我的使用了上面提到的企业Nexus存储库。
上传和发布任务
实施的结束相对容易。 仅缺少将工件上载到Nexus存储库以及SCM中发行版本的标记。
为了实现前者,我刚刚添加了一个自定义Gradle任务,以从settings.xml
(由Puppet提供)获取Nexus设置。 然后我设法使upload
任务依赖于这一任务。 最后,对于各种assemble
任务执行方式,我都将输出文件添加到要上传的工件集中。 这样,无论构建文件中配置了哪种风味,以下命令都将仅上传风味XXX和YYY:
./gradlew assembleXXX assembleYYY upload
对于发行版,它甚至更简单:唯一需要做的就是设置此 Gradle插件,该插件添加了一个release
任务,类似于Maven的部署。
结论
作为一名后端开发人员,我习惯了Continuous Integration的设置,并且几乎确定我可以在几天内处理Android CI过程。 我对Android生态系统在CI方面的不成熟感到惊讶。 每个步骤都是痛苦的,没有充分记录(如果有的话),解决方案似乎比其他任何事情更像黑客。 如果您想走这条路,已经被警告了...我祝您好运。
翻译自: https://blog.frankel.ch/fully-automated-android-build-pipeline/
android 每日构建