使用 act 快速调试 Github Actions

5,659 阅读1分钟

GitHub Actions 是 GitHub 在 2018 年推出的持续集成服务。

image.png

最近在项目上使用下来的感觉是,非常好上手,也很灵活易用。而且大多数的构建和部署需要的插件都能够在 Github Actions 的 marketplace 里面找到。

on: push
jobs:
  test:
    strategy:
      matrix:
        platform: [ubuntu-latest, macos-latest, windows-latest]
    runs-on: ${{ matrix.platform }}
    steps:
    - uses: actions/checkout@v1
    - uses: actions/setup-node@v1
      with:
        version: 12
    - run: npm install-ci-test
    - uses:


  publish:
    needs: [build]
    steps:
    - uses: actions/checkout@v1

不过对于新手来说,如果每次都要修改代码后推到远端才能测试新的或修改后的 GitHub Actions 代码的话,效率就太低了,最好能在本地调试 GitHub Actions 代码以便快速验证。

Act 就是这样一个工具,正如它的 slogan 所说的:

"Think globally, act locally"

它可以让我们在本地运行 GitHub Actions 代码来获得快速的反馈,极大地方便了我们调试代码。

用 act 本地运行 Github Actions,快速验证调试

注意:act 使用有一个前提条件是必需安装 docker。

首先,让我们用 brew 安装 act (其它系统可以参考 act 的安装文档

brew install act

下面的命令可以列出当前目录下的所有 actions

act -l

假设我们本地有一个写好的 deploy.yml 文件(位于/.github/workflows/deploy.yml),那么运行下面的命令就能在本地将 deploy actions 跑起来了。

act -j deploy --bind . --secret-file .env
--bind . 是把本地的目录绑定到 docker 容器,可以提高效率(比如,可以省掉每次运行重新安装 npm 依赖的时间)
--secret-file 可以用来指定 actions 里面需要的环境变量,比如上面的例子就是把需要的环境变量放在 .env 文件里面

.env文件里内容的格式参考如下:

BASE_URL=http://www.test.com/
GCS_BUCKET=test_bucket
...

用 act 的一个坑

image.png

第一次用 act 运行 actions 的时候没注意,选了一个 micro docker image 作为 runner,结果一直报错,后来才发现是因为 act micro 的 image 里的环境是不全的,没有 Python 等运行时,所以一般还是推荐用 medium 的,因为 large 的有点儿太大了。不过 medium 的 docker image 不支持 yarn,大家可以根据自己项目的情况选择。

下面列举两个例子供大家参考

1、将 React 项目部署到 Google Cloud Storage

name: Deploy

on:
  push:
    branches:
      - develop

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Use Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '14'
      - name: Run CI
        run: |
          npm install
          npm run lint
          npm test
      - name: Build
        run: |
          REACT_APP_BASE_URL=${{secrets.BASE_URL}} npm run build
      - name: Set up Cloud SDK
        uses: google-github-actions/setup-gcloud@master
        with:
          project_id: ${{ secrets.GCP_PROJECT }}
          service_account_key: ${{ secrets.GCP_SA_KEY }}
          export_default_credentials: true
      - name: Upload files
        run: |
          gsutil -m rsync -r -d build/ gs://${{ secrets.GCS_BUCKET }}/
          gsutil -m setmeta -h "Cache-Control:no-store" gs://${{ secrets.GCS_BUCKET }}/*
          gsutil -m setmeta -r -h "Cache-Control:max-age=31536000" gs://${{ secrets.GCS_BUCKET }}/static/*

2、将 react native 项目打包发布到 Google Play Store

name: Deploy

on:
  workflow_dispatch:
    inputs:
      deploy:
        description: 'Do you want to deploy to Google Play Store?'
        required: true
        default: "yes"

jobs:
  build:
    runs-on: ubuntu-latest
    name: Build
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - uses: actions/setup-node@master
      - uses: c-hive/gha-yarn-cache@v1

      - name: Install node modules
        run: |
          yarn install
      - name: Run lint and test
        run: |
          yarn lint
          yarn test

      - name: Cache Gradle Wrapper
        uses: actions/cache@v2
        with:
          path: ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}

      - name: Cache Gradle Dependencies
        uses: actions/cache@v2
        with:
          path: ~/.gradle/caches
          key: ${{ runner.os }}-gradle-caches-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
          restore-keys: |
            ${{ runner.os }}-gradle-caches-
      - name: Make Gradlew Executable
        run: cd android && chmod +x ./gradlew

      - name: set up JDK 1.8
        uses: actions/setup-java@v1
        with:
          java-version: 1.8
      - name: Bump version
        uses: chkfung/android-version-actions@v1.1
        with:
          gradlePath: android/app/build.gradle
          versionCode: ${{github.run_number}}

      - name: Build Android App Bundle
        run: |
          cd android && ./gradlew bundleRelease --no-daemon

      - name: Sign App Bundle
        id: sign_app
        uses: r0adkll/sign-android-release@v1
        with:
          releaseDirectory: android/app/build/outputs/bundle/release
          signingKeyBase64: ${{ secrets.ANDROID_SIGNING_KEY }}
          alias: ${{ secrets.ANDROID_SIGNING_ALIAS }}
          keyStorePassword: ${{ secrets.ANDROID_SIGNING_KEYSTORE_PASSWORD }}
          keyPassword: ${{ secrets.ANDROID_SIGNING_KEY_PASSWORD }}

      - name: Upload Artifact
        uses: actions/upload-artifact@v2
        with:
          name: signed-app-bundle
          path: ${{steps.sign_app.outputs.signedReleaseFile}}

      - name: Deploy to Google Play Store
        uses: r0adkll/upload-google-play@v1
        with:
          serviceAccountJsonPlainText: ${{ secrets.ANDROID_SERVICE_ACCOUNT }}
          packageName: com.projecttest
          releaseFiles: ${{steps.sign_app.outputs.signedReleaseFile}}
          track: internal