ticktakclockの日記

技術ポエムを綴ったりします。GitHub idも同じです (@ticktakclock)

GitHubActionsとCircleCIを使い分ける

こんにちは、tkyです。

今私が携わっているAndroidプロジェクトのCIは基本的にCircleCIを採用しています。

そんな中、同時にGitHubActionsも採用した経緯とどんなことをしているのか、ちょっとハマったことを書き留めておこうと思います。

また、本記事は「こうしたら良い」というわけではなく、「とある課題から解決策を模索した」結果なだけなので

皆さんのプロジェクトに合わせて最適な形を模索するための材料の1つとなれば幸いです。

今までのCIの運用

コードはGitHubで管理しており、PullRequestをトリガーにCIが回るようになってます。

※コミット単位にするとCIの作動回数が多くなるので節約の目的があります。

  • UnitTest
  • Lint
  • DangerでTestとLint結果を報告
  • DeoloyGateのdebug apkアップロード

[課題]developブランチとapkが一致しない

pull requestごとにdebug apkが作られるため最新Developブランチとapkが一致せず、debug用のapkはPRの動作確認用になっていました。

しかも実際はブランチをチェックアウトして自分でビルドして動作確認しており現状のapkは事実上形骸化していました。

チームメンバーと会話して「develop最新と紐付いているapkを常に確認できる状況作っておきたいよね」ということで

DeoloyGateのdebug apkアップロード のワークフローのトリガーを developブランチにマージされた時(developにコミットされた時)に変更します。

Circle CIの設定見直し

現在CircleCIの管理画面ではこの2がONになっています。

developブランチにマージされた時にしたい場合 Only build pull requests をOFFにしてfilterでdevelopのみ動作するワークフローを作ればよいのですが

そうするとPR以外のリモートへのコミットでもCIが回るのでそれもなぁ・・・という感じです。

上記をを許容できるならGitHubActions使う必要ないのでこの話は終わりですw

もう少し頑張りたいよね、というところでdevelopブランチにコミットされた時のトリガーだけをGitHubActionで切り出すことにしました。

実際に検討で使った図です

f:id:ticktakclock:20201121141635p:plain:w400
検討図

そんなこんなで以下のように話をまとめて現在のプロジェクトで2つのCIツールを運用している、という話でした。

  • CircleCI: PRした時に処理したい場合
  • GitHubActions: (特定ブランチに)コミットされた時に処理したい場合

なぜGitHubActionsにすべて移動しないのか?

GitHubの各トリガーに柔軟に対応できるGitHubActionsを使えばやりたいことは全部できるでしょう。

しかしながら後述するskip-buildの機能やSSHデバッグなどCircleCIがデフォでできる機能は各々でアクションを定義する必要があります。

ローカルCLIもないため実際にPR上げてtry&errorで動作確認になるのでコストも高いです。(一応CLI実行できるnodeプロジェクトがあったような気がする)

仮に私がaction全部作れたとして、ほかメンバーがそれを管理運用できるか、という問題も浮上してきます。

そういう部分もあり、いきなり全てをGitHubActionsにして逆にコストがかかることを考慮して一部だけ切り出しただけなので、今後の状況によってはありえるかなと思っています。(当分先になりそうですが・・・)

GitHubActions導入してみた

こんな感じのymlを作成します。これがDeploygateにアップロードする(gradleタスクを実行する)ワークフローとなります。

色んな人がAndroidのビルドしていたりするのでコピペで色々貼り付けてます。

.github/workflows/upload_apk.yml

name: upload_apk
# CIツールの使い分け
# ・CircleCI: PRした時に処理したい場合
# ・GitHubActions: (特定ブランチに)コミットされた時に処理したい場合
on:
  push:
    branches:
      - develop

jobs:
  build_canceller:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: stop old workflow
        uses: yellowmegaman/gh-build-canceller@master
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          workflows_filter: "upload_apk"
  deploygate-develop:
    name: Upload apk to deploygate for developDebug
    runs-on: ubuntu-latest
    needs: build_canceller
    steps:
      - name: Check out
        uses: actions/checkout@v2
      - name: set up JDK 1.8
        uses: actions/setup-java@v1
        with:
          java-version: 1.8
      - name: NDK cache
        id: cache-primes
        uses: actions/cache@v2
        with:
          path: ${ANDROID_HOME}
          # GithubActionsコンテナに入っているNDKバージョンとプロジェクトの必要NDKバージョンが異なるため
          # コンテナに必要NDKバージョンをインストールする
          # ビルドエラーが出た場合cacheステップとInstallステップに記述のバージョンを更新してください
          key: ${ANDROID_HOME}/ndk/21.0.6113669
          restore-keys: |
            ${{ runner.os }}-ndk-
      - name: Install NDK
        run: echo "y" | sudo $ANDROID_HOME/tools/bin/sdkmanager --install "ndk;21.0.6113669" --sdk_root=${ANDROID_SDK_ROOT}
      - name: Gradle cache
        uses: actions/cache@v2
        with:
          path: ~/.gradle
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
          restore-keys: |
            ${{ runner.os }}-gradle-
      - name: Upload DeployGateDevelopDebug
        run: |
          ./gradlew uploadDeployGateDevelopDebug

[ハマったこと]古いビルドはキャンセルされない

CircleCIのskip-buildと同じような機能はGitHubActionsにはないので自力でなんとかする必要があります。

そういうActionがあるのでありがたく使わせていただくことにします。

GitHubActionsを無料稼働枠内で使うための節約テクニックみたいな感じです・・・

※2020/11/21現在最新は

  build_canceller:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: stop old workflow
        uses: yellowmegaman/gh-build-canceller@master
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          workflows_filter: "upload_apk"

以上です。