Github Actions 是 Github 提供的免費(fèi)自動化構(gòu)建實現(xiàn),特別適用于持續(xù)集成和持續(xù)交付的場景,它具備自動化完成許多不同任務(wù)的能力左腔,例如構(gòu)建诈泼、測試和部署等等懂拾。
一、簡單介紹
用戶只需要在自己 Github 的開源項目下創(chuàng)建 .github/workflows
腳本就可以完成接入铐达,另外針對 Github Actions 官方還提供了 marketplace 用于開發(fā)者提交或者引用別人寫好的 aciton 岖赋,所以很多時候開發(fā)者在使用 Github Actions 時,其實會變成了在 marketplace 里挑選和組合 action 的場景瓮孙。當(dāng)然唐断,這樣各有利弊,后面我們會講到 杭抠。
要在 Github 存儲庫中使用 Github Actions脸甘,首先需要創(chuàng)建目錄.github/workflows/
,然后在 workflows
文件夾里創(chuàng)建不同的 .yml
文件用于響應(yīng)或者執(zhí)行不同的事件祈争,比如 git push
斤程、pull request
等,例如:
name: GitHub Actions Demo
on: [push]
jobs:
Explore-GitHub-Actions:
runs-on: ubuntu-latest
steps:
- run: echo "?? The job was automatically triggered by a ${{ github.event_name }} event."
- run: echo "?? This job is now running on a ${{ runner.os }} server hosted by GitHub!"
- run: echo "?? The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
- name: Check out repository code
uses: actions/checkout@v2
- run: echo "?? The ${{ github.repository }} repository has been cloned to the runner."
- run: echo "??? The workflow is now ready to test your code on the runner."
- name: List files in the repository
run: |
ls ${{ github.workspace }}
- run: echo "?? This job's status is ${{ job.status }}."
上面是 Github doc 里關(guān)于 Action 的一個基本的工作流 yml 文件,具體參數(shù)含義 :
- name:這表示該工作流文件的名稱忿墅,將在 Github 的 actions 選項卡作為名稱顯示 扁藕;
-
on:這將觸發(fā)該工作流的事件名稱,它可以包含事件列表疚脐,例如這里監(jiān)聽的事
push
亿柑; - jobs:每個工作流會包含一個或多個 jobs ,在這里只有一個棍弄,主要是用于表示不同工作任務(wù)望薄;
- Explore-GitHub-Actions :這是工作 ID,你也可以根據(jù)自己的需要命名呼畸,會在 action 的執(zhí)行過程中顯示痕支;
-
runs-on:jobs 需要運(yùn)行在虛擬機(jī)上,在這里中使用了
ubuntu-latest
蛮原,當(dāng)然你也可以使用windows-latest
或者macos-latest
卧须; - steps:每個 jobs 可以將需要執(zhí)行的內(nèi)容劃分為不同步驟;
-
run:用于提供執(zhí)行命令儒陨,例如這里使用了
echo
打印日志花嘶; - name: steps 里的 name 是可選項,主要是在日志中用來做標(biāo)記的蹦漠;
-
uses :使用一些官方或者第三方的 actions 來執(zhí)行椭员,例如這里使用官方的
actions/checkout@v2
,它會check-out 我們的 repo 笛园,之后工作流可以直接訪問 repo 里的文件隘击;
在 GitHub 倉庫添加完對應(yīng)的 .github/workflows/ci.yml
文件之后,以后每次 push
都可以觸發(fā) action 的自動執(zhí)行喘沿,以此來完成可持續(xù)的自動集成和構(gòu)建能力闸度。
二、構(gòu)建 Flutter 和發(fā)布到 Github Release
簡單介紹完 Github Action 蚜印,接著我們介紹如何利用 Github Action 構(gòu)建 Flutter 和發(fā)布 apk 到 Github Release,如下代碼所示是 gsy_github_app_flutter 項目里使用到的 github action 腳本:
name: CI
on:
push:
branches:
- master
tags:
- '*'
pull_request:
paths-ignore:
- '**/*.md'
- '**/*.txt'
- '**/*.png'
- '**/*.jpg'
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v2
with:
distribution: 'zulu'
java-version: 11
- uses: subosito/flutter-action@v1
with:
flutter-version: '2.8.1'
- uses: finnp/create-file-action@master
env:
FILE_NAME: lib/common/config/ignoreConfig.dart
FILE_DATA: class NetConfig { static const CLIENT_ID = "${{ secrets.CLIENT_ID }}"; static const CLIENT_SECRET = "${{ secrets.CLIENT_SECRET }}";}
- run: flutter pub get
- run: flutter build apk --release --target-platform=android-arm64 --no-shrink
apk:
name: Generate APK
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup JDK
uses: actions/setup-java@v2
with:
distribution: 'zulu'
java-version: 8
- uses: subosito/flutter-action@v1
with:
flutter-version: '2.5.3'
- uses: finnp/create-file-action@master
env:
FILE_NAME: lib/common/config/ignoreConfig.dart
FILE_DATA: class NetConfig { static const CLIENT_ID = "${{ secrets.CLIENT_ID }}"; static const CLIENT_SECRET = "${{ secrets.CLIENT_SECRET }}";}
- run: flutter pub get
- run: flutter build apk --release --target-platform=android-arm64 --no-shrink
- name: Upload APK
uses: actions/upload-artifact@v2
with:
name: apk
path: build/app/outputs/apk/release/app-release.apk
release:
name: Release APK
needs: apk
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
- name: Download APK from build
uses: actions/download-artifact@v2
with:
name: apk
- name: Display structure of downloaded files
run: ls -R
- name: Create Release
id: create_release
uses: actions/create-release@v1.1.4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
- name: Upload Release APK
id: upload_release_asset
uses: actions/upload-release-asset@v1.0.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./app-release.apk
asset_name: app-release.apk
asset_content_type: application/zip
根據(jù)上述腳本留量,首先可以看到:
在
push
事件里我們指定了只監(jiān)聽 master 分支和 tags 相關(guān)的提交窄赋;然后在
pull_request
事件里忽略了關(guān)于 .md、 .text 和圖片相關(guān)的內(nèi)容楼熄,也就是這部分內(nèi)容提交不觸發(fā) action 忆绰,具體可以看你自己的需求;接著進(jìn)入到 jobs 里可岂,首先不管是
push
還是pull_request
都會執(zhí)行到Build
事件错敢,運(yùn)行在ubuntu-latest
虛擬機(jī)上,之后利用actions/checkout@v2
checkout 代碼;-
接著使用
actions/setup-java@v2
配置 java 環(huán)境稚茅,這里使用的是Zulu OpenJDK
版本 11 纸淮,下面表格是 setup-java 支持的可選 java 類型;Keyword Distribution Official site License temurin
Eclipse Temurin Link Link zulu
Zulu OpenJDK Link Link adopt
oradopt-hotspot
Adopt OpenJDK Hotspot Link Link adopt-openj9
Adopt OpenJDK OpenJ9 Link Link liberica
Liberica JDK Link Link microsoft
Microsoft Build of OpenJDK Link Link 接著就是使用第三方的
subosito/flutter-action@v1
配置 flutter 環(huán)境亚享,直接通過flutter-version: '2.8.1'
指定了 Flutter 版本咽块;接著是使用第三方的
finnp/create-file-action@master
創(chuàng)建文件,因為 gsy_github_app_flutter 項目有一個配置文件是需要用戶根據(jù)自己的 ID 和 SECRET 手動創(chuàng)建欺税,所以這里通過 create-file-action 創(chuàng)建文件并輸入內(nèi)容侈沪;在上述輸入內(nèi)容部分,有一個
secrets.xxx
的參數(shù)晚凿,因為構(gòu)建時需要將自己的一些密鑰信息配置到 action 里亭罪,所以如下圖所示,可以在Settings
的Secrets
里添加對應(yīng)的內(nèi)容歼秽,就可以在 action 里通過secrets.xxx
讀扔σ邸;
- 接著配置好環(huán)境之后哲银,就可以執(zhí)行
flutter pub get
和flutter build apk
執(zhí)行構(gòu)建扛吞;
完成 Build 任務(wù)的邏輯介紹之后,可以看到在 Build 任務(wù)下面還有一個 apk 任務(wù)荆责,該任務(wù)基本和 Build 任務(wù)一直滥比,不同之處在于:
- 多了一個
if: startsWith(github.ref, 'refs/tags/')
,也就是存在 tag 的時候才會觸發(fā)該任務(wù)執(zhí)行做院; - 多了一個
actions/upload-artifact@v2
用于將構(gòu)建出來的build/app/outputs/apk/release/app-release.apk
上傳盲泛,并等到 release 任務(wù)內(nèi)使用;
完成 apk 任務(wù)之后键耕,會進(jìn)入到 release 任務(wù)寺滚,該任務(wù)同樣通過 if 指定了只在 tag 提交時運(yùn)行:
- 任務(wù)首先會通過
actions/download-artifact@v2
下載剛剛上傳的 apk; - 然后就通過
actions/create-release@v1.1.4
創(chuàng)建一個 release 版本屈雄,這里使用的secrets.GITHUB_TOKEN
是官方內(nèi)置的 secrets 村视,我們直接使用就可以了; - 最后通過
actions/upload-release-asset@v1.0.1
將 apk 上傳到剛剛創(chuàng)建的 release 版本里酒奶,自此就完成了 action 的發(fā)布流程蚁孔;
可以看到整個過程其實都是在組合不同的 action ,可以很靈活方便地配置構(gòu)建邏輯惋嚎,例如如果你的項目是單純的 android sdk 項目杠氢,那同樣可以通過如下腳本進(jìn)行發(fā)布管理:
name: CI
on:
push:
branches:
- master
paths-ignore:
- '.idea/**'
- '.gitattributes'
- '.github/**.json'
- '.gitignore'
- '.gitmodules'
- '**.md'
- '**/*.txt'
- '**/*.png'
- '**/*.jpg'
- 'LICENSE'
- 'NOTICE'
pull_request:
paths-ignore:
- '.idea/**'
- '.gitattributes'
- '.github/**.json'
- '.gitignore'
- '.gitmodules'
- '**.md'
- '**/*.txt'
- '**/*.png'
- '**/*.jpg'
- 'LICENSE'
- 'NOTICE'
jobs:
publish:
name: Publish to MavenLocal
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 17
- uses: gradle/gradle-build-action@v2
with:
arguments: publishToMavenLocal
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 17
- uses: gradle/gradle-build-action@v2
with:
arguments: app:assembleDebug
當(dāng)然,如果你需要打包的是 iOS 另伍,那么你就需要使用 macos-latest
的環(huán)境鼻百,另外還需要配置相關(guān)的開發(fā)者證書,這個過程可能會比較難受,相關(guān)可以參考 《Flutter 搭建 iOS 命令行服務(wù)打包發(fā)布全保姆式流程》 温艇。
三因悲、隱私安全問題
最后,關(guān)于 Github Actions 之前存在過出現(xiàn)泄露敏感數(shù)據(jù)的問題中贝,比如 Github 的 Token 等 囤捻,舉個例子,如上面的腳本邻寿,它在執(zhí)行任務(wù)時都會需要秘鑰 蝎土,如果你使用的第三方 action 在執(zhí)行過程中獲取了你的密鑰并干了一些“非法” 的事情,就可能出現(xiàn)異常泄漏問題绣否。
所以一般情況下建議大家都要去看下非官方的腳本實現(xiàn)里是否安全誊涯,但是由于 tag 和 branch 是可以修改,所以建議不要@分支或tag蒜撮,而是應(yīng)該 checkout 對應(yīng)的提交哈希暴构,這樣有利于你審查使用時的腳本是否安全。
另外段磨,例如還有人提到可以通過 pull_request 來惡意攻擊獲取對應(yīng)隱私:
1取逾、fork 一個正在使用 GitHub Actions 的公開代碼庫;
2苹支、創(chuàng)建一個基于該項目的 pull 請求砾隅;
3、使用 pull_request_target 事件創(chuàng)建一個惡意 Actions 工作流债蜜,然后單獨向該 fork 庫 commit晴埂;
4、將第二步基分支的 pull 請求更新為第三步的 commit 哈希寻定;
之后惡意 Actions 工作流就會運(yùn)行儒洛,并從目標(biāo) repos 里獲取到執(zhí)行過程的敏感數(shù)據(jù),此時攻擊者將擁有對目標(biāo)存儲庫的寫訪問權(quán)限狼速,除此之外他們還可以通過 GitHub 訪問與倉庫之成的任何服務(wù)琅锻。
所以雖然 GitHub Action 很便捷,但是如果出于商業(yè)考慮的話向胡,還需要謹(jǐn)慎抉擇安全問題浅浮。