🕌

swift-formatを実行するGitHub Actionを作った

2021/01/11に公開

GitHub ActionsでSwiftもlintしよう

みなさん、Swiftを書くときにどんなlinterを使っているでしょうか。
Swift対応のlinterというとApple謹製のapple/swift-formatとかrealm/SwiftLintが有名ですかね。私は前者のswift-formatの方を使っています。

GitHubリポジトリのmain/masterブランチへPUSHしたときや、Pull Requestが作られたときに自動でswift-formatを実行してくれるGitHub Actionを作ったので良かったら使ってみてください。

https://github.com/mtgto/swift-format-action

GitHub Actionでswift-format使うとどんな感じ?

例えばPull Requestにmtgto/swift-format-actionを利用した場合、swift-formatのlint結果がPull RequestのFiles changedに結果が反映されます。

github.com/mtgto/swift-format-actionのPR1 が結果のサンプルになってます。

swift-format-actionのPR1

使い方

使い方はGitHubのリポジトリに .github/actions/swift-format.yml のようなファイルを作ればOKです。

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint:
    name: Lint
    runs-on: ubuntu-latest
    steps:
      # ソースコードを取得
      - name: Checkout Code
        uses: actions/checkout@v2
        with:
          # Pull Requestの差分ファイル取得のためにgit履歴も取得してください
          fetch-depth: 2
      - name: Lint
        uses: mtgto/swift-format-action@main
        with:
          # configurationファイルがあればgitリポジトリ内でのパスを記述する
          configuration_file: .swift-format
          # falseにするとpushの場合はそのコミット、pull requestの場合はそのpull requestの変更ファイルだけをlint対象とする
	  # trueにするとすべてのファイルをlint対象とする
          all_files: false
          # いくつまでwarningを許容するか。-1なら制限なし。0ならwarningが一個でもあればlintエラーにする
          max_warnings: -1

まだ自分しか使ってないと思うので要望とか質問とかあればコメント欄やTwitterで聞いて下さい。

GitHub ActionsでDockerを使うか使わないか

swift-formatはSwiftで書かれているCLIのプログラムです。これをGitHub Actionsで動かすにはmacOS環境でNode.jsから動かすかDockerコンテナをLinux環境で動かすかどっちかを選ぶ必要があります。

https://docs.github.com/ja/free-pro-team@latest/actions/creating-actions/about-actions#アクションの種類

今回はDockerアクション形式を選択しました。Super-Linterというたくさんのプログラミング言語に対応したGitHub Actionがあるんですが、このActionはAlpine LinuxにたくさんのLinterツールをインストールしたDockerイメージを作ってそれを使ったDockerイメージ形式のGitHub Actionになっており、それに対応することを考えてDocker形式を選びました。

なんでswift-formatをSuper-Linterに対応させなかったかというと、Alpine Linux上でswift-formatを動かすのが2021年1月現在非常に難しいというのが理由です。

https://twitter.com/mtgto/status/1343498955737337862

Appleがswift-formatが使っているlib_InternalSwiftSyntaxParserの静的リンク用ライブラリのLinuxバイナリを提供してくれたらもしかしたらSuper-Linterへの対応ができるかもしれないと思ってチケットだけは切ってあります。 https://bugs.swift.org/browse/SR-14001

他にDocker形式のアクションを選んだ理由としてはAppleがswift-formatをバイナリで配ってないのでどっかの知らない誰かが作ったバイナリを動かすよりはDocker HubのAutomated Buildのほうが信用できるかなと思ったからなのですが、Dockerアクションは作るのにかなり癖があるのでmacOSで動かしたほうが良かったんだろうなと作ったあとでは思っています。そのうちmacOSネイティブに切り替えるかもです。
(swift-formatはApache License 2.0なのでライセンスファイルを同梱すれば再配布できる)

感想:シェルスクリプトってめんどくさい

Dockerベースイメージとして利用した swift:5.3-slim にはPythonもRubyもnodeも入ってないので(Perlは入ってたけど私が書けない)、久しぶりにシェルスクリプトを持ち出してGitHub Actionのメインを書いたんですが、めちゃくちゃめんどくさかったです。

ファイルの差分を git diff --name-only で取り出して、それを swift-format lint のあとにくっつけて、みたいな作業をするわけですがシェルの配列の扱いとかもう全く覚えてないしなんかうまくいかなくなって結局xargsを使ったりしました。

シェルスクリプトを書くときもユニットテストもあったほうがいいんだろうなあと思いつつ結局めんどくさくて用意できなかったので、Dockerコンテナ形式を使うときにはSwift/Goのように別環境で単体バイナリにコンパイルしてそれを使うほうがよかったのかなあというのがGitHub Actionを初めて書いてみた感想です。

Discussion