我正在参加「启航计划」
布景
关于 CI/CD
,在2023年的今日,基本一切技能团队或多或少都会运用,其很大程度上减轻了咱们的冗余重复作业,然后简化咱们的作业流程。
不过关于大多数客户端工程师而言,其实 CI
这个词还是比较陌生。当然并不是说,CI/CD
有什么高大上或许门槛很高,由于毕竟不是一切人会去保护开源库或许搞基建,或许说少有场景去触摸到。但关于一个 工程师 而言,这严厉意义上其实属于 基本技能点 ,或许说在现在这个时代,这种小技能应该没有太多边界之分。
相应的,假如运用 Github Action
,这个难度就更低了,其相比传统的 Jenkins
,容易上手了更多,简化了 环境 、装备 等等。并且,在这个进程中,咱们也将逐渐触摸到一些 cmd
、python
等其他东西运用方法或许语法,然后探究出更多可玩性。
写在开端
留意: 本篇不会讲 Github Action
根底语法,这些官网有更详细的文档,没有意义去做二次转移♂️。
本篇更多是围绕要处理的实践问题进行剖析,并在中心对关键语法进行解说,然后便于更快的运用 Github CI
;
个人建议关于这种东西类的技能,不需求学的很详细,只需求了解基本准则:自己要处理什么问题,即可。
故此,学完本篇,你将学会 Github CI
的根底运用,以及一些常见的实用操作,如:
-
主动化打包以及上传;
-
主动化版别号与code;
-
主动化发布release;
-
逐渐解开传统思想圈套,体会
CI
在日常开发中的妙用;
好了,让咱们开端吧 !
什么是 CI/CD?
CI/CD
是指继续集成(Continuous Integration)和继续布置/交给(Continuous Deployment/Delivery)的缩写。
- 继续集成(
CI
)是一种软件开发实践,指的是将代码集成到骨干分支中并进行构建和测验的进程,以便尽早发现和处理问题。CI 东西能够主动履行这个进程,例如 1、Travis CI、CircleCI 等。每次提交代码时,CI 东西会主动构建和运转测验,并给出构建和测验成果的反应。 - 继续布置/交给(
CD
)是指主动化地将代码布置到生产环境或发布到运用商铺的进程。继续布置/交给能够让开发团队更加快速和可靠地将新功用交给给用户。CD
东西能够主动化履行布置和发布进程,例如Ansible
、Kubernetes
、Docker
等。在继续布置/交给的进程中,需求进行主动化测验、版别操控、继续监控等操作,以保证代码质量和运用稳定性。
CI/CD
的长处包含加速软件开发、进步代码质量、降低危险、进步作业功率 等。然后能够让开发团队更加专心于代码编写,而不必花费许多时刻进行 手动构建 、测验 和 布置 等重复性作业。
什么是 Github CI?
由于本篇,主要是讲 Github CI
的运用,故还是要简单说一下 Github CI
的简介及功用。
GitHub CI
(GitHub Actions)是GitHub
供给的一项主动化东西,用于 构建 、 测验 和 布置GitHub
上保管的代码库房。GitHub CI
供给了一种界说主动化作业流程的方法,能够依据代码库房的变化主动触发作业流程。一组作业流程能够包含多个过程,例如编译代码、运转测验、构建镜像、布置运用等。其长处包含与GitHub
渠道紧密集成、易于装备、支撑多种语言和环境、供给丰厚的集成能力等。它能够帮助开发团队主动化构建和测验进程,进步代码质量和开发功率。
详细运转示例中如下图所示:
CI 能够做什么?
简直能够简化任何咱们能在本地做的一切 人工 操作,甚至主动编码。
为了更好的便于理解,咱们切换到 Android工程师 视角,运用一个示例来说明。
比方咱们现在有个 下厨房 Android工程,假如在没有 CI
时,咱们最根底的流程通常如下:
- 开发: 本地开发、调试、push;
- 测验:本地打包、发给测验同学;
- 打包: 改版别号、打tag、本地打包、发给运营同学;
上面的流程看上去好像没有什么问题,关于本地开发而言,浓缩下来也就上面三步,这也是小团队常见流程。
但仔细观察的话,其间许多过程都是冗余,比方每次 本地打包 、改版别号 、 打tag 、 发给指定人 ,这些过程都显得很机械(或许比较呆),特别是假如是在 bug fix
阶段,更是繁琐。
那假如凭借 CI
,咱们应该怎样优化上述过程呢?
- 当咱们每次提一个
PR
或许push
时,就主动去打测验包,并履行一些咱们自界说的一些check
,如 代码查看 、 包巨细查看 、主动化测验 等等,并将最后打出的 apk 上传到fir
或许其他当地。并凭借webhook
,然后完成 飞书、钉钉 等方法告诉相关同学; - 发布新的 release版别 前,改版别号时,也能够支撑主动化版别号。比方能够运用
git tag
作为版别号,commit
记录作为code,并与CI
联动,完成动态指定; - 而当咱们每次发布
release
版别时,通常情况下,咱们都会打一个tag
,然后push
。所以咱们也能够运用CI
,发现有新的tag
时,则触发作业流履行,然后去主动发布一个release
版别,并且履行一遍打包,将相关产物上传到咱们指定的方位;并依据项意图规矩总结出相应的release
更改信息,并更新描绘,最后再将版别信息告诉到相关运营同学; - 在运用包上传的进程中,人工必不可少会呈现传错包的情况,此刻也能够凭借
CI
完成打包完成后主动上传运用商铺,比方 华为、小米、Gogole 现在就支撑 api 上传;
假如上述过程,你们团队都现已完成了,那就证明关于 Android工程 而言,你们的根底 CI/CD
设备现已做的很不错了,无妨为自己点点赞。
换个角度而言,CI
简直能够完成大多数重复项作业,然后为咱们节省时刻。而运用 Github Action
完成上述过程,如虎添翼,更为方便。
快速入门教程
关于 GitHub Action
而言,官方规定了作业流文件有必要存储在代码库房的 .github/workflows
目录中,文件名有必要以 .yml
或 .yaml
结束,然后便于 Github
辨认这是一个作业流程。
创立新的作业流
要创立一个作业流,有两种方法:
-
在线创立:
Github-Reposity-actions
里去创立,创立进程中能够随时增加其他作业流; -
本地创立: 在项目目录里创立
.github/workflows
文件夹,并在其间创立你的作业流文件,Github
会主动依照规矩辨认;
1. 在线创立
咱们直接去相应的 Github
库房底下,点击 Actions
,此刻有两种挑选:
- 在现有的作业流模版上进行创立;
- 新创立自己的作业流文件;
比方下面的示例中,咱们查找 Android
,并挑选 Android CI
模版进行创立,如下所示:
在上面的图2里,这是官方给咱们的 根底Android CI
模版,详细的逻辑咱们下面再解说。图中箭头所指的是一些比较热门的 Action
,能够挑选其间一个,快速仿制(引用)到咱们自己的作业流中,即相当于增加一个新的子过程。
2. 本地创立
咱们以方才上面截图中的 Android CI
为示例,直接仿制到本地新建的 android.yml
中,如下所示:
创立作业流 | 作业流运转效果 |
---|---|
将相应的作业流 push
之后,如图所示,咱们会发现,咱们新 push
的作业流现已被触发了多次(原因下面解说),而列表最顶部的,也是最新的,即正在运转的作业流。
点击进去看一下,如下图所示:
作业流运转成果 | 作业流详细履行过程 |
---|---|
左面的图表明这是本次的运转成果,以及一些工件的上传或许日志输出方位;而右图则代表这个作业流详细履行子过程列表,咱们也能够点击去查看每一个过程做的成果。
示例作业流剖析
如下所示,这是咱们上面过程创立的 Android CI
作业流,其意图是用于每次 push
代码后,履行一次 build
,详细代码如下:
name: Android CI
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: gradle
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
相应的,其内部的意义如下所示:
-
name:
表明当时作业流的名字是什么。
-
on:
表明当时作业流在什么情况下被触发。
比方这个示例中,咱们触发的机遇有两个,即
push
||pr
时,并且限制了有必要是在main分支
。再解说的浅显点便是:当咱们在main分支push了代码,或许提了一个新的PR,要合并到main分支时,此刻就会触发这个作业流。
ps: 这也是为什么咱们上面的截图里,创立一个新的作业流后,为什么会呈现运转多次(首次创立时main分支触发+push行为触发)。
-
jobs:
指的是当时使命列表。比方上述示例中咱们只有一个使命,名为
build
,当然也能够运用 name: 进行重命名。 -
runs-on:
指定当时使命运转的环境。比方上述示例中使命是在 ubuntu-latest 系统下运转。
-
steps:
指定当时使命的过程列表。比方当时示例中,咱们有多个使命,别离如下:
- -拉代码;
- -设置
jdk
与Gradle
环境; - -为
Gradle
设置运转权限; - -履行
Gradle
指令:build
;
uses:
用于导入开源的
Action
或许自界说的Action
,然后在自己的作业流中进行运用;run:
在
shell
环境中履行一段指令,常用于履行cmd
指令;
需求留意:
yml
文件,严厉操控阶段间的缩进,所以假如IDE
提示异常,或许摆放不齐时,常常会呈现作业流运转时报错。
常用的环境变量
在运用 Github Action
时,咱们常常会遇到需求运用一些环境变量的情况,比方最常用的 Github.token
等等,关于每一个作业流,默许供给了以下环境变量用于运用:
-
GITHUB_ACTION
当时运转的操作的称号,或
id
过程的称号; -
GITHUB_RUN_ID
当时运转的作业流ID,这个 id 是固定的;
-
更多环境变量见文档
当然,咱们也能够自界说一些环境变量,然后将其保存到 Github Action
里的 secrets
中,然后完成安全的存储与运用,而非硬编码的方法。
如下所示,咱们将fir.im 的api token保存到secrets里,并取名为FIR_TOKEN:
在详细运用时,如下所示:
- name: echo token
run: |
echo "-token: ${{ secrets.FIR_TOKEN }}"
这儿咱们尝试去打印一下 token
,可是成果必定是 [**] 。由于 Github Action
默许会对其进行躲藏,然后避免其被意外泄漏。
小操练
主动化打包
在开发中,咱们日常触摸最多的无非便是 [fix bug]
& [create new bug]
,而假如每次假如都要手动打包,再转发给测验同学,无疑是一件及其糟蹋时刻和无聊的工作。
本末节示例代码见:Android CI
这儿咱们以打包并上传fir 为例,如下所示:
上述流程如下:
- 拉代码;
- 装置 && 装备gradle环境;
- 打debug包;
- 装置
fir-cli
& 上传apk;
上面内部运用的
FIR_TOKEN
正是咱们上面在介绍环境变量部分时,自己界说的。
当然做的更详细点,这儿还能够加上打包成功后webhook到飞书或许钉钉等,以飞书为例,能够运用我司另一个小伙伴写的这个 xiachufang/action-feishu,碍于篇幅,这儿就不做解说了。
主动化版别号
本末节示例代码见:settings.gradle、release.yml
在日常发版其他进程中,咱们都有打 tag
的阅历,比方每周在发布新的版别之前,打 新版别tag ,一起打新的线上包。这个时分,假如每次都要去再改一次硬编码里的 versionName
以及 versionCode
,无疑有点烦人,并且人工操作,依然存在改错的问题。
此刻,常见的方法是运用 tag
作为 versionName
,git commit
数作为 versionCode
。这种方法固然好用,可是还是不行谨慎,关于常见的团队而言,一般有更一致的称号,如 版别名@版别号,示例:2.1.1@807,当然这都是后话了。
要完成上面的根底需求,需求咱们对 Gradle
与 Git
有一丢丢运用经历。比方,怎样获取 最新tag 呢?怎样获取 commit
数呢?
处理方法如下所示:
如上所示,咱们直接在 settings.gradle
中新增了以下代码。意图是当 Gradle
加载完当时项目信息之后,此刻就运用 cmd
去获取一下当时的 最新tag 与 commit数,并将其设置给 ext
,然后便于咱们在其他当地引用。
外部运用方法:
rootProject.versionCode
此刻 build
咱们的项目, build
日志部分就会打印下面句子:
versionName:xxx,versionCode:x
ps: 假如你的
versionName
是空,请留意是否打过tag
。 [git tag xxx]
上面的方法看着好像没什么问题,可是假如你实践用几回就会发现,假如你 两个tag之间并没有任何变化的话,此刻 gitVersionTag() 取出的 tag
永久不是最新的那一条(不知道该怎样处理)。
这个时分,咱们就能够运用 Github Action
,获取最新 release.tag
,然后将其以 gradle传参
的方法传递到咱们本次编译中,然后完成主动化版别号。
如下所示:
咱们从头调整下上述的写法,每次优先获取外部传入的参数 versionName
以及 versionCode
,一起对其check。假如没传递或许为null,则本地从头运用Git去获取,否则就运用指定的参数。
release.yml
在详细的作业流脚本这儿,咱们的触发机遇挑选为每次发布新的 release
时,此刻就去获取本次 release
对应的 tag_name
,并在打包时,通过 Gradle
指令行传参的方法,将其传递给咱们本次的打包流程。
上面的
env:
,用于设置一个或多个环境变量。比方在这个示例里,咱们界说了一个名为
VERSION_NAME
的变量,其的值取自 本次release所对应的tag_name ,而 {{ xx }} 这种取值方法,则是Github Action
中的一个规范。而在shell里,咱们能够不加 {{ }} ,直接$xx
。
主动化发布release
本末节示例代码见:create_release.yml
每个版别发布 release
时,咱们一般都要去写一遍描绘,但假如每个版别都去写一遍,无疑非常呆。
所以,那能不能把两个版别之间的 PR
主动收集下来,然后写到 release
的描绘里呢?
回答必定是能够的,并且 Github
也供给了默许的方法,如下所示:
创立新的release | 终究成果页 |
---|---|
看着效果还不错,省事不少。
那能不能我每次 push tag
时,就主动触发 release创立
呢?
: 你最好别懒死。
当然是能够的,Github Action
作业流供给了许多触发机遇,所以咱们只需求设置触发机遇为 push tag
时,然后再去新建 release
即可。
示例代码如下:
这儿运用开源的 action,ncipollo/release-action,然后更简单的完成上述需求,当然也能够挑选运用 Github Api
。
效果如下所示:
Github Action | Github release |
---|---|
一些经历共享
关于 Github Action
,由于其自身上手难度很低,所以当咱们想处理某个问题时,只需求考虑清下面的几个问题:
- 当时问题 到底 是什么?
- 有没有开源的
Action
? - 假如问题比较复杂,那能不能拆解为多个过程呢?
-
Github API
能不能处理,能不能调配其他方法呢?如shell
、python
、jar
、gradle
;
当然假如你想再探究一点,此刻能够考虑以下:
- 作业流复用,作业流依靠履行,作业流成果传递,作业流并发等等。
常用的一些资料:
- Github Action开源库查找;
- Github Action文档;
总结
本篇,咱们从 CI/CD
是什么开端,叨叨絮絮,一直到处理常见开发中的一些问题。纵观这些问题或许场景,尽管并不是特别繁琐,但也构成了 CI
的基本运用单元。希望通过这些场景,能让大家关于 Github CI
有快速的了解及上手体会。
当然我本人也不是一个娴熟的 CI工程师 ,更多是个半吊子,所以文章里必定也有模糊不清的当地,此刻就建议大家多搜多试验,或许谈论区问我。但关于这些东西方面,我个人的准则一直是,会用即可。当然更好的是,当问题不能直线处理时,咱们能不能拆分过程去逐一处理。
咱们生在一个幸运的时代,许多工作,都能很简单的去处理,比方有问题问 GPT
,不懂就翻翻源码,而关于一些繁琐的重复项作业,此刻无妨交给CI/CD
或许其他 主动化东西。
关于开发者的咱们而言,咱们只需求理解一个准则:当下要处理什么问题,即可。
把时刻糟蹋在更有意思的工作上,真的 泰库辣 :)
见字如面,咱们下篇文章再会
参考
- GitHub Actions文档
关于我
我是 Petterp ,一个 Android工程师。假如本文,你觉得写的还不错,无妨点个赞或许收藏,你的支撑,是我继续创造的最大鼓励!
欢迎关注我的 公众号(Petterp) ,等待与你一起行进 :)