前言
时针回拨到2018年,微软宣布75亿美金收购Github,随后便发布了Github Actions 持续集成服务。我们可以使用它进行项目构建、测试、打包、部署、发布等一系列操作,能够大大简化工作的流程。他还提供了整套的服务器环境,包含Ubuntu、Windows、macOS等。最近一段时间一直在试用感觉十分强大,Github Actions 的文档有中文版本查询起来也比较方便。这是个简单的Android Github Actions使用示例,展示使用Github Actions自动发布一个Android应用到蒲公英,提交版本更新记录到服务器上并发送本次的应用更新结果到钉钉群中。
配置文件结构
要想写一个构建脚本, 首先我们要看看一个基本的脚本是什么样子的.
从中我们可以看到几个词:
-
Workflow ( 工作流 ): 表示一次持续集成的过程, 为
.github/workflows下的一个脚本执行的过程 -
on: 触发构建所需要的条件。<push|pull>.<branchs|tags> 都是触发构建的条件, 详情请看: 触发工作流程的事件
-
job ( 任务 ): 表示脚本中的任务(如上图中
build) ,一个 workflow 可以有多个jobs 构成。意味一个工作流中可以并发执行多个任务。所有的任务结束就相当于一次持续集成完成 -
step ( 步骤 ): 表示一个任务可以有很多的步骤,任务(job)依次每一个步骤(step)。
-
action ( 动作 ): 表示每个步骤所需要完成的行为, 比如一次或多次输出等
阮一峰老师有篇文章专门介绍 Github Actions的相关概念。 GitHub Actions 入门教程
用一个新东西,首先我们先看看效果!
效果展示
[示例仓库]: github.com/lumotime/Le…
-
钉钉通知
-
制品库
Android Github 持续集成示例
下面是示例 yml 脚本: package_task.yml
# 工作流程的名称, 显示在 ${github repo url}/actions/Workflows的列表
name: package_task
# 触发workflow的条件, 当前配置为: 当推送如 'v1.0.0' 格式的 tag 时
# 构建条件配置文档: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
on:
push:
tags:
- v[1-9]+.[0-9]+.[0-9]+
# 构建过程所执行的任务
jobs:
# 因为打包可能需要打多个应用的包, 也就是同一个项目下有多个 application时需要先把代码拉下来
build_project:
# 该 job 运行的系统环境, Github托管的运行器支持 ubuntu/windows/macOS
# 详细支持的版本请查看 https://docs.github.com/cn/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions
runs-on: ubuntu-latest
# 以下该 clone_project 任务的多个步骤
steps:
# 打印工作流程中的信息,定义: https://docs.github.com/en/free-pro-team@latest/actions/reference/environment-variables
- name: Run a one-line script
run: |
echo ID ${GITHUB_RUN_ID}, REF ${GITHUB_REF}
echo SHA ${GITHUB_SHA}, ACTOR ${GITHUB_REPOSITORY}, GITHUB_REPOSITORY ${GITHUB_REPOSITORY}
# 克隆当前项目, 默认为 ${GITHUB_REPOSITORY}
- name: clone project code
uses: actions/checkout@v2
# 克隆私有的密钥库, 用于打包时签名. 该仓库为私有库
- name: clone project keystore
uses: actions/checkout@v2
with:
repository: lumotime/lumotimeKeystore
path: keystore
token: ${{secrets.GIT_TOKEN}}
# 设置 JDK 环境为 JDK1.8
- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
# 使用 gradlew assembleRelease 打 release 包
- name: Build with Gradle generate modules apks
run: chmod +x gradlew &&./gradlew clean assembleRelease --stacktrace
# 上传 first apk 到 github actions 的制品库
- name: upload first app to github Actions
uses: actions/upload-artifact@v2
with:
name: example-first_app-release
path: example/build/outputs/apk/first_app/release/example-first_app-release.apk
# 上传 last apk 到 github actions的制品库
- name: upload last app to github Actions
uses: actions/upload-artifact@v2
with:
name: example-last_app-release
path: example/build/outputs/apk/last_app/release/example-last_app-release.apk
upload_first_app:
runs-on: ubuntu-latest
needs: build_project
steps:
# 从制品库中拉取得 first apk 并进行后续操作
- name: download first apk
uses: actions/download-artifact@v2
with:
name: example-first_app-release
# 获取触发构建的 tag 信息
- name: fetch github ref
id: REF
run: echo "::set-output name=ref::${GITHUB_REF}"
# 自定义的 action用于获取apk中的信息, 使用请看 https://github.com/lumotime/get-apk-info-action.
- name: get first app info
id: app_info
uses: lumotime/get-apk-info-action@v1.0.0
with:
apkPath: example-first_app-release.apk
# 上传 apk 到 蒲公英. secrets 配置请看下面 私密信息配置
# 蒲公英接口参数请看: https://www.pgyer.com/doc/view/api#paramInfo 上传 App接口部分
# action 使用示例请看 https://github.com/lumotime/upload-pgyer-apk-file
- name: upload first app to Pgyer
id: upload_pgyer
uses: lumotime/upload-pgyer-apk-file@v1.0.0
with:
forms: '{"_api_key":"${{secrets.pgyer_key}}","buildInstallType":2, "buildPassword": "${{secrets.pgyer_install_password}}"}'
fileForms: '{"file":"example-first_app-release.apk"}'
- name: dingtalk notification
uses: lumotime/webrequest-action@v1.2.4
with:
url: ${{secrets.dingtalk_webhook}}
method: POST
payload: '{"msgtype":"markdown","markdown":{"title":"应用版本更新","text":"#### **FIRST测试应用版本更新** \n\n**应用名称**: ${{ steps.app_info.outputs.name }} \n\n **包名**:${{ steps.app_info.outputs.applicationId }} \n\n**版本编号**:${{ steps.app_info.outputs.versionCode }} \n\n**版本名称**:${{ steps.app_info.outputs.versionName }} \n\n**最小版本要求**:${{ steps.app_info.outputs.minSdkVersion }} \n\n**编译目标版本**:${{ steps.app_info.outputs.targetSdkVersion }} \n\n**安装包名称**:${{ steps.upload_pgyer.outputs.filename }} \n\n**安装包大小**: ${{ steps.upload_pgyer.outputs.fileSize }}\n\n**更新时间**: ${{ steps.upload_pgyer.outputs.updatedTime }}\n\n**触发**: ${{steps.REF.outputs.ref}} \n\n**邀请函**: \n\n "}}'
headers: '{"Content-Type": "application/json"}'
upload_last_app:
runs-on: ubuntu-latest
needs: build_project
steps:
# 从制品库中拉取得 last apk 并进行后续操作
- name: download last apk
uses: actions/download-artifact@v2
with:
name: example-last_app-release
- name: fetch github ref
id: REF
run: echo "::set-output name=ref::${GITHUB_REF}"
# 自定义的 action用于获取apk中的信息, 使用请看 https://github.com/lumotime/get-apk-info-action.
- name: get last app info
id: app_info
uses: lumotime/get-apk-info-action@v1.0.0
with:
apkPath: example-last_app-release.apk
# 上传 apk 到 蒲公英. secrets 配置请看下面 私密信息配置
# 蒲公英接口参数请看: https://www.pgyer.com/doc/view/api#paramInfo 上传 App接口部分
# action 使用示例请看 https://github.com/lumotime/upload-pgyer-apk-file
- name: upload last app to Pgyer
id: upload_pgyer
uses: lumotime/upload-pgyer-apk-file@v1.0.0
with:
forms: '{"_api_key":"${{secrets.pgyer_key}}","buildInstallType":2, "buildPassword": "${{secrets.pgyer_install_password}}"}'
fileForms: '{"file":"example-last_app-release.apk"}'
- name: dingtalk notification
uses: lumotime/webrequest-action@v1.2.4
with:
url: ${{secrets.dingtalk_webhook}}
method: POST
payload: '{"msgtype":"markdown","markdown":{"title":"应用版本更新","text":"#### **LAST测试应用版本更新** \n\n**应用名称**: ${{ steps.app_info.outputs.name }} \n\n **包名**:${{ steps.app_info.outputs.applicationId }} \n\n**版本编号**:${{ steps.app_info.outputs.versionCode }} \n\n**版本名称**:${{ steps.app_info.outputs.versionName }} \n\n**最小版本要求**:${{ steps.app_info.outputs.minSdkVersion }} \n\n**编译目标版本**:${{ steps.app_info.outputs.targetSdkVersion }} \n\n**安装包名称**:${{ steps.upload_pgyer.outputs.filename }} \n\n**安装包大小**: ${{ steps.upload_pgyer.outputs.fileSize }}\n\n**更新时间**: ${{ steps.upload_pgyer.outputs.updatedTime }}\n\n**触发**: ${{steps.REF.outputs.ref}} \n\n**邀请函**: \n\n "}}'
headers: '{"Content-Type": "application/json"}'
secrets.GIT_TOKEN: 访问github私有仓库需要使用的个人访问密钥
secrets.dingtalk_webhook:钉钉自定义机器人的 webhook地址
secrets.pgyer_key: 蒲公英的 api 密钥
secrets.pgyer_install_password:蒲公英邀请的安装密码
其中有几点需要注意的地方:
-
配置Secrets (保证一些私密信息不会在公开库中显示)
官方文档: docs.github.com/cn/free-pro…
-
触发工作流程的事件
# 触发workflow的条件, 当前配置为: 当推送如 'v1.0.0' 格式的 tag 时 # 构建条件配置文档: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows on: push: tags: - v[1-9]+.[0-9]+.[0-9]+ -
打包所使用的签名使用私有仓库存储
-
使用 checkout action 克隆仓库到文件目录中
# 克隆私有的密钥库, 用于打包时签名. 该仓库为私有库 - name: clone project keystore uses: actions/checkout@v2 with: # 仓库的名称 repository: lumotime/lumotimeKeystore # 仓库克隆到的位置 path: keystore # 克隆私有仓库所使用的 token token: ${{secrets.GIT_TOKEN}}lumotimeKeystore 目录结构:
lumotime.properties 配置文件:
-
修改 app
build.gradle通过配置文件加载密钥[配置示例]: github.com/lumotime/Le…
// 加载仓库的密钥配置 def keyProps = new Properties() def keyPropsFile = rootProject.file('keystore/lumotime.properties') if (keyPropsFile.exists()) { keyProps.load(new FileInputStream(keyPropsFile)) } android { // 配置打包使用的密钥 signingConfigs { lumotime { keyAlias keyProps['keyAlias'] keyPassword keyProps['keyPassword'] storeFile keyProps['storeFile'] ? file(keyProps['storeFile']) : null storePassword keyProps['storePassword'] } } buildTypes { release { signingConfig signingConfigs.lumotime minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } debug { signingConfig signingConfigs.lumotime minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } }
-
-
多个 job 间传递数据
官方文档: [在工作流程中作业之间传递数据]
jobs: build_project: ... first_job: needs: build_project ... last_job: needs: build_project ...注意: 多个任务的运行器是隔离的, 需要在通过制品库进行数据的交互。例如 build_project.upload first app to github Actions 和 upload_first_app.download first apk.
-
自定义 Github Action
支持两种 Action的自定义方式
[创建 JavaScript 操作]: docs.github.com/cn/free-pro…
[创建 Docker 容器操作]: docs.github.com/cn/free-pro…
一些自定义的Action:
[webrequest-action]: 发送网络请求
[get-apk-info-action]: 获取 apk 的信息
[upload-pgyer-apk-file]: 上传 apk 到蒲公英
-
钉钉机器人配置
文档: ding-doc.dingtalk.com/document#/o…
参考和文档
[Github Actions 使用指南和Android 持续集成示例]