為Github倉庫添加Github Actions實現持續集成: Android apk自動編譯發布以及github pages同步推送coding.net

內容轉載自我的部落格

說明

對於普通的github倉庫,只需要在根目錄創建.github/workflows/文件夾即可自動使用Actions功能,具體執行的操作可以創建一個配置文件(命名不限),如build_apk.yml
Github Actions產品對公開倉庫是完全免費的,對私人倉庫每月有2000分鐘使用時間,詳細說明見費用。另外,github有許多官方已經實現好的actions可以供用戶直接調用,用戶只需用設置參數即可
每個配置文件稱為一個工作流程(workflow),每個工作流程可以包含多個作業(job),每個作業可以包含一系列的步驟(steps),每個step可以稱為action,可以認為這是三個層級

1. 編寫Android項目的CI配置文件

這裡以項目WhuHelper為例,介紹如何使用YAML語法和Github Actions功能

  • 原始倉庫的文件版本為c1a78da
  • 添加CI功能(自動進行build testbuild app-debug.apk)以後的文件版本為4ef2e90,只需要關注文件build_apk.yml即可,其他文件無變化
  • 最終的CI功能包括自動進行構建測試、構建app-debug.apk、創建倉庫的release(只包括程式碼,且只在push tag時觸發)、為此次release添加apk文件,文件版本為20fe364,只需要關注文件build_apk.yml即可,其他文件無變化

主要涉及到的操作為:設置workflow及以下層級的每個操作名字、設置workflow的觸發條件、創建多個job、job的條件執行、調用別人寫好的actions、自己為某個step設置輸出參數供其他步驟調用、持久化build的結果、上傳build的結果供用戶下載、下載build的結果供下一步操作使用、多個job之間傳遞數據、多個step之間傳遞數據、使用環境變數
實例build_apk.yml文件內容及解析如下:

name: Auto build debug apk

# 設置workflow的觸發條件
# 在pull和push到主分支時觸發workflow
# 在push tags時觸發workflow
on:
  pull_request:
    branches:
      - 'master'
  push:
    branches:
      - 'master'
    # 在push tag時觸發
    tags:
      - '*'

# workflow的所有作業job
jobs:
  # 單個job的名字:測試Android項目
  # 每個job執行完畢會默認刪除所有文件等
  #   可通過cache來保留特定文件夾和文件
  #   也可使用upload-artifact上傳來實現保留文件,再配合download-artifact實現多job之間的數據傳遞
  test:
    # test這個作業的實際名字
    # 也是執行build時Actions監控處顯示的名字
    name: Run Unit Tests
    # job的運行平台,還有windows、macos及不同版本可供選擇
    runs-on: ubuntu-18.04
    # test任務的具體步驟,可以有很多個步驟,都寫在這裡
    steps:
      # 使用別人寫好的指定版本的actions腳本,名稱是checkout
      # 這是步驟1,即每個'-'符號到下一個'-'符號之間的部分是一個步驟
      - uses: actions/checkout@v2
      # 這是步驟2,創建java環境,with裡面填寫actions的輸入參數
      - name: set up JDK 1.8
        uses: actions/setup-java@v1
        # 設置setup-java腳本的輸入參數
        with:
          java-version: 1.8
      # 步驟3,執行shell命令
      - name: Unit tests
        run: bash ./gradlew test --stacktrace

  apk:
    name: Generate APK
    runs-on: ubuntu-18.04

    steps:
      - uses: actions/checkout@v2
      - name: set up JDK 1.8
        uses: actions/setup-java@v1
        with:
          java-version: 1.8
      - name: Build debug APK
        run: bash ./gradlew assembleDebug --stacktrace
      # 利用upload-artifact實現build結果的保存(可以在Actions的控制台下載壓縮文件)
      - name: Upload APK
        uses: actions/upload-artifact@v2
        with:
          # 設置壓縮文件的名稱,在控制台會得到WhuHelper-debug.zip文件的下載鏈接
          # 下載後解壓縮,裡面直接可以看到app-debug.apk,沒有其他東西
          name: WhuHelper-debug
          path: app/build/outputs/apk/debug/app-debug.apk

  deploy:
    name: Upload Release Asset
    # 依賴上一個job
    needs: apk
    runs-on: ubuntu-latest
    # 只在tag時執行,即在自己終端運行以下程式碼後才會觸發
    # git tag -a v0.1.0 -m "release 0.1.0 version"
    # git push origin –-tags
    if: contains(github.ref, 'tags/')
    steps:
      # 自己編寫的shell命令
      # 學習如何設置單個任務的輸出來被其他任務調用
      - name: Prepare Release
        # 設置id一般是為了其他step調用本步驟的輸出
        id: prepare_release
        run: |
          TAG_NAME=`echo $GITHUB_REF | cut -d / -f3`
          echo ::set-output name=tag_name::$TAG_NAME
      - name: Download build result for job apk
        # 只有上一步獲取到tag_name才繼續,下載前面apk任務裡面的WhuHelper-debug.zip文件
        # 自動解壓縮到當前文件夾,自動刪除原壓縮文件
        # 多任務之間的數據交換
        if: steps.prepare_release.outputs.tag_name
        uses: actions/download-artifact@v2
        with:
          name: WhuHelper-debug
      - shell: bash
        # 手動更改apk名字
        run: |
          mv app-debug.apk  app-debug-${{steps.prepare_release.outputs.tag_name}}.apk 
      # 發布release,版本號是用戶git push的tag裡面的版本號,發布的只有程式碼壓縮包(與手動默認發布一致)
      - name: Create Release
        id: create_release
        # 只有上一步獲取到tag_name才繼續
        if: steps.prepare_release.outputs.tag_name
        uses: actions/create-release@v1
        env:
          # GitHub 會自動創建 GITHUB_TOKEN 密碼以在工作流程中使用
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          # 設置時區,默認是格林尼治時間
          # TZ: Asia/Shanghai
        with:
          tag_name: ${{steps.prepare_release.outputs.tag_name}}
          release_name: Release ${{steps.prepare_release.outputs.tag_name}} by zfb
          draft: false
          prerelease: false
      # 這一步是對上一步發布的release文件的補充,調用github api上傳一個apk文件
      - name: Upload Release Asset
        id: upload-release-asset 
        # 只有create_release成功得到輸出才繼續
        if: steps.create_release.outputs.upload_url
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }} 
          asset_path: ./app-debug-${{steps.prepare_release.outputs.tag_name}}.apk
          asset_name: app-debug-${{steps.prepare_release.outputs.tag_name}}.apk
          asset_content_type: application/vnd.android.package-archive

2. 編寫Jekyll項目的CI配置文件

2.1 配置coding.net

主要包括以下步驟:

  • 首先新建一個空項目(如果已經有了的話就不需要再新建,但是要保證與Github的對應倉庫版本一致,防止無法commit)
  • coding.net的程式碼倉庫新建訪問令牌,授予倉庫許可權,假設名字為GITHUB_AUTO_DEPLOY,複製顯示的token備用
  • 在該程式碼倉庫,找到設置-->倉庫設置,即可看到設置本倉庫地址的方法,本例子顯示為(格式為//e.coding.net/團隊名/項目名/倉庫名.git
    git remote set-url origin //e.coding.net/zfbin/zfbin/zfbin.git

使用token來讀寫遠程倉庫(格式為//用戶名:[email protected]/團隊名/項目名/倉庫名.git),使用如下命令自己測試一下,用戶名(默認是手機號碼)為13677888877,上一步得到的token是cdd0b865cdd0b865cdd0b865cdd0b865cf87ce84,團隊名稱是zfbin,項目的名稱是zfbin,程式碼倉庫的名稱是zfbin(這裡所有配置的敏感資訊都是示例):

 ~/work/github/zfbin > git push  "//13677888877:[email protected]/zfbin/zfbin/zfbin.git" master:master
Everything up-to-date
 ~/work/github/zfbin >

2.2 配置github

打開Github的此倉庫的Secrets選項,新建以下秘鑰:

DEPLOY_CODING    cdd0b865cdd0b865cdd0b865cdd0b865cf87ce84
CODING_USERNAME  13677888877
CODING_REF       e.coding.net/zfbin/zfbin/zfbin.git

2.3 自動部署到coding.net

github的倉庫的原始文件版本為8570167,最終添加github actions之後的文件版本為0462a89e,不需要關注其他文件,只考慮.github/workflows/deploy_to_coding.yml文件,其內容如下:

name: Auto deploy to coding pages

# 在push主分支時觸發構建
on:
  push:
    branches:
      - 'master'

jobs:
  # job的名字:推送到coding
  deploy:
    name: Deploy to Coding
    # job的運行平台
    runs-on: ubuntu-18.04
    # test任務的步驟
    steps:
      # 使用別人寫好的指定版本的actions腳本,名稱是checkout,下載本倉庫
      - uses: actions/checkout@v2
      - name: 設置提交者的個人資訊
        # 這三個變數的值都放在 //github.com/zfb132/zfb132.github.com/settings/secrets
        env:
          # 設置時區
          TZ: Asia/Shanghai
          # 在coding.net的某個倉庫新建訪問令牌出現的秘鑰
          coding_token: ${{ secrets.DEPLOY_CODING }}
          # 團隊中的某個人的用戶名,一般默認是本人手機號碼
          coding_username: ${{ secrets.CODING_USERNAME }}
          # 格式為:e.coding.net/組織名/項目名/倉庫名.git
          coding_ref: ${{ secrets.CODING_REF }}
        run: |
          export message=$(git log --pretty=format:"%s" -1)
          [ -f CNAME ] && rm CNAME || echo "CNAME doesn't exist"
          rm -rf .github
          rm -rf .git
          git clone //${coding_username}:${coding_token}@${coding_ref} coding_dir
          cd coding_dir && mv .git ../ && cd ../ && rm -rf coding_dir
          git config --local user.email "[email protected]"
          git config --local user.name "zfb"
          git config core.filemode false
          git remote set-url origin //${coding_ref}
          git add .
          git commit -m "$message"
          git push --force --quiet "//${coding_username}:${coding_token}@${coding_ref}" master:master

具體運行的命令的解釋:

  • export message=$(git log --pretty=format:"%s" -1)是獲取github的提交的message
  • rm CNAME是刪除github倉庫的CNAME文件,因為coding.net不需要此文件
  • rm -rf .github是刪除github actions的配置文件,因為coding.net不需要進行CI
  • rm -rf .git是刪除github倉庫時的git資訊,為後面使用coding.net的git清理空間
  • git clone //${coding_username}:${coding_token}@${coding_ref} coding_dir是克隆coding.net的對應倉庫,主要為了.git文件夾,所以只是把此倉庫下載到一個臨時文件夾coding_dir
  • cd coding_dir && mv .git ../ && cd ../ && rm -rf coding_dir是把coding.net的.git文件夾替換掉原來的,並且刪除臨時文件夾
  • git config --local user.email "[email protected]"是設置提交者的電子郵箱地址
  • git config --local user.name "zfb"是設置提交者的名字
  • git config core.filemode false忽略文件屬性的問題,因為github的文件模式(許可權)不一定與coding.net的相同
  • git remote set-url origin //${coding_ref}是設置遠程倉庫的地址為coding.net的倉庫
  • git add .是添加文件到暫存區
  • git commit -m "$message"設置commit的資訊與github一致
  • git push --force --quiet "//${coding_username}:${coding_token}@${coding_ref}" master:master是強制推送到遠程倉庫