GitHub ActionsでファイルAが更新されているがファイルBが更新されていない時だけ実行する、を実現する

GitHub Actionsの on: pushon: pull_rerequest のトリガーには paths/paths_ignore という機能があり、特定のファイルパスが変更された時だけワークフローを実行できます。

# 例えばiOSとAndroidのmonorepoで、ios以下が変更された時だけiOSのテストを実行したい
on:
  push:
    paths:
      - 'ios/**'

paths/paths_ignoreには配列で複数のパス指定・globパターン指定ができ、そのうちのどれか1つにでもマッチするとワークフローが実行されます。しかしこの機能には1つ弱点があり、pathspaths_ignore を同時に使うことができません。つまり、ファイルAが変更され・かつ・ファイルBが変更されていない、という条件が記述できません(と認識しています)。

You can exclude paths using two types of filters. You cannot use both of these filters for the same event in a workflow.

今回はこれを乗り越える方法の紹介です。trilom/file-changes-actionというアクションを使用して、ジョブ内で自分でファイル差分をチェックしてみましょう。ここではiOSアプリのリポジトリで、Podfileが更新されているがPodfile.lockが更新されていない時、ということにしてみます。

name: Update Podfile.lock

on:
  pull_request:
    paths:
      - Podfile

jobs:
  precheck:
    runs-on: ubuntu-latest
    outputs:
      files_changed: ${{ steps.file_changes.outputs.files }}
    steps:
      - uses: actions/checkout@v2
      - id: file_changes
        uses: trilom/file-changes-action@v1.2.3

  update:
    runs-on: macos-latest
    needs: precheck
    if: contains(fromJson(needs.precheck.outputs.files_changed), 'Podfile.lock') == false
    steps:
      - uses: actions/checkout@v2
      - run: pod install
      - uses: stefanzweifel/git-auto-commit-action@v4.2.0
        with:
          commit_message: Update Podfile.lock
          file_pattern: Podfile.lock

まずは前提条件としてpathsPodfileを指定して、「Podfileが更新されている」ことをワークフローレベルでフィルタリングします。

ここからが本題です。precheckジョブで、trilom/file-changes-actionを使ってファイル差分を取得します。そしてそのステップのoutputジョブのoutputに保存して、後続のジョブからアクセスできるようにします。ここでジョブを分割しているのは

  • 後続の処理が複数ステップに渡る場合、それぞれのステップにifを書くのが面倒・メンテナンスしにくい
  • 今回の例では後続の処理にmacOSが必要だが、macOSは課金が高額(Ubuntuの10倍!)なので、ファイル差分のチェックはUbuntuで行う

ためです。

updateジョブはneedsを使ってprecheckジョブの終了後に直列で実行されるようにします(デフォルトでは複数のジョブは並列で実行されます)。次にジョブレベルのifで、Podfile.lockが変更されていない、という条件を書きます。needs contextを使うと、前段のジョブの実行結果やoutputsにアクセスできます。ここではprecheckジョブでoutputsに保存したtrilom/file-changes-actionの出力結果を使用し、contains関数で変更されたファイル名の配列にPodfile.lockが含まれるかを確認します。

後は実処理として pod installしてPodfile.lockを更新してから、stefanzweifel/git-auto-commit-actionを使ってプルリクエストを作成しています。

こうして「Podfileが更新されているがPodfile.lockが更新されていない時」という条件を実現できました。めでたしめでたし。色んなアクションを組み合わせて柔軟なジョブ制御を実現していきましょう。

`MenuItem.onNavDestinationSelected`と`android:menuCategory="secondary"`の関係

https://developer.android.com/reference/kotlin/androidx/navigation/ui/package-summary#(android.view.MenuItem).onNavDestinationSelected(androidx.navigation.NavController)

By default, the back stack will be popped back to the navigation graph's start destination. Menu items that have android:menuCategory="secondary" will not pop the back stack.

https://developer.android.com/jetpack/androidx/releases/navigation#1.0.0-alpha09 で経緯が分かる。

MenuItems with menuCategory="secondary" will no longer pop the back stack when used with NavigationUI methods. b/120104424

難しい!!!

GitHub ActionsのXcode 10.3ではSwiftPMのビルドがエラーになる

GitHub ActionsではmacOSも実行環境としてサポートされており、現在のOS指定はmacos-latest/macos-10.15の1つのみです。以前はmacos-10.14もサポートされていたのですが少し前に非推奨となり削除されてしまいました。

その際に使用できるXcodeのバージョンも整理されてしまい、GitHub ActionsではXcode 11以降しか使えなくなっていたのですが、ユーザーからの要望によりmacos-10.15に再度Xcode 10.3が追加されました。

さて、この復活したXcode 10.3なのですが、Swiftで書かれたOSSをテストしようとすると実は問題がありました。xcodebuildコマンドでのXcodeプロジェクト・ターゲットとしてのビルドは問題ありませんが、SwiftPMでのビルド swift build をすると次のようなエラーになってしまいます。

This copy of libswiftCore.dylib requires an OS version prior to 10.14.4.
Exited with signal code 6

ということで、GitHub Actionsで複数のXcodeバージョンを使ったmatrixビルドをする場合、Xcode 10.3のSwiftPMでの swift build/swift testだけは除外して、それだけTravis CIでテストするなどの回避策が必要となっています。おしまい。

Swift 5.2では関数・メソッドの最後の引数がデフォルト引数の場合、その1つ前のクロージャの引数をtrailing closureとして呼べるようになった

タイトルがほぼ全てです。

func foo(_ closure: () -> Void, defaultArg: Int = 0) {
  closure()
}

foo { print("foo") }

このコードはSwift 5.2では動作しますが、Swift 5.1以前ではコンパイルエラーになります。

Nimbleに挙がったissueでそのことに気付きました。

Discordのswift-developers-japanで話してみたところ、apple/swiftこのコミットが該当の変更であることを分かりました。

さらに芋づるで分かったことがあって、一時期のSwiftのDevelopment SnapshotでNimbleのビルドが通らなくなったり、そのリグレッションがきっかけでapple/swift-source-compat-suiteにNimbleが追加されたのもこの辺りに関連した変更の影響でした。

色々繋がっていて面白いですね、めでたしめでたし。

GitHub ActionsでのJestのテスト実行時に失敗箇所をPRへのアノテーションとして表示するレポーター

このような便利なパッケージがありました。

GitHub Actionsにはworkflow commandsと呼ばれる、echoコマンドと特定の形式の文字列を使うことでActionsの処理に一部介入できる機能があります。その中にはファイルの特定の箇所(行・カラム)にdebug/warning/errorメッセージをPRのアノテーションとして追加できるコマンドがあります。jest-github-actions-reporterではJestのレポーターの実装としてそのSetting an error messageコマンドを使い、Jestのテストの失敗結果をerrorアノテーションとしてPRの差分表示上で簡単に結果が閲覧できるようになっています。

こういうやり方があるのはRenovateのこのPRで気付きました。

きっとそのためのJestのレポーターをパッケージとして作成・公開している人がいるだろうと探してみたら、案の定存在した次第です。

GitHub Actionsで日々の暮らしを楽にしていきましょう。

AndroidのFirebase Installations version 16.2.0で追加されたlintチェックがAndroid Gradle plugin 3.6と互換性がなくてビルドできない

Firebase OSSのこちらのIssueで報告されているように、Android Gradle plugin 3.6(Android Studio 3.6)以上のプロジェクトでFirebase Installations version 16.2.0が依存性に入るとlintでビルドが失敗するようになります。

追加されたlintというのはこちら:

https://firebase.google.com/support/release-notes/android?hl=ja#installations_v16-2-0

Added a lint check to the compile process that prevents parallel usage of Firebase installations and incompatible versions of the Firebase Instance ID SDK that are older than firebase-iid:20.1.0. Firebase installations creates FIDs as Firebase client identifiers. Versions of the Firebase Instance ID SDK before v20.1.0 created different Firebase client identifiers: Instance IDs. This check prevents problems for Firebase targeting that might be caused by conflicting Firebase client identifiers.

数時間前にはこの問題を修正するPRがマージされたので、近々修正されたバージョンがリリースされるはずです。しばらく待ちましょう。

待てずにすぐFirebaseの各種バージョンを上げたい場合は、Issueにあるように該当のlintを無効にすることでひとまず回避することができます。

android {
    lintOptions {
        disable "IncompatibleIidVersion"
    }
}

Swift 5.2

iOS 13.4とXcode 11.4と共にSwift 5.2がリリースされましたね。

Swift.org - Swift 5.2 Released!

  • SE-0249 Key Path Expressions as Functions
  • SE-0253 Callable values of user-defined nominal types
    • SE-0216@dynamicCallableに対してstatic callableとも呼ばれた機能。callAsFunctionというメソッドを定義することで、型や値を直接関数のように実行することができる。
  • Improved Compiler Diagnostics
  • Code Completion Improvements
    • コード補完の改善
  • Improved Build Algorithms
    • 主にインクリメンタルビルドの速度の改善
  • Debugger Improvements
  • Swift Package Manager
    • 依存パッケージがSwift 5.2のパッケージ定義を使っている場合、その依存パッケージのテストターゲットでしか使われていない孫依存パッケージは利用元のプロジェクトでは解決されなくなる(不要なtransitive dependencies:推移的依存性がなくなる)
  • SwiftSyntax Updates
    • ノード階層がprotocolベースからstructベースになったことによる速度改善
  • Language Server Protocol Updates
    • sourcekit-lspというLSPのランゲージサーバーがXcodeとCommand Line Toolsに同梱されるようになった
    • FixItsとLocal Refactoringのサポート追加

というラインナップになっています。今日から早速どんどん活用していきましょう! ⚡️