Satyrographos Repo の CI の話

この記事は [SATySFi Advent Calendar 2020](https://adventar.org/calendars/4965)  18 日目の記事である。


17 日目 @monaqa『[【入門記事】 SATySFi のコマンドを定義する方法](https://zenn.dev/monaqa/articles/2020-12-17-satysfi-for-beginner-command-definition)』
19 日目 @gfngfn『[overfullやunderfullの生じた箇所を可視化する](https://github.com/gfngfn/SATySFi/wiki/overfull%E3%82%84underfull%E3%81%AE%E7%94%9F%E3%81%98%E3%81%9F%E7%AE%87%E6%89%80%E3%82%92%E5%8F%AF%E8%A6%96%E5%8C%96%E3%81%99%E3%82%8B)』

[Satyrographos Repo](https://github.com/na4zagin3/satyrographos-repo) は Satyrographos の CI を Travic CI から GitHub Actions に移行したのでその記録。

# Satyrographos Repo とは？

[Satyrographos](https://github.com/na4zagin3/satyrographos) は SATySFi 向けのパッケージマネージャーであり、現在の所 OPAM に大きく依存している。
Satyrographos でインストール可能なライブラリを保管する [Satyrographos Repo](https://github.com/na4zagin3/satyrographos-repo) は Satyrographos ライブラリ用のカスタム OPAM レポジトリである。

Satyrographos の目指す点として、単にライブラリをインストール・アップデートすれば問題無く使えるようにしたいことがある。
SATySFi の静的型体系は互いに競合するライブラリや、ライブラリの非互換なバージョンを検出することができる場合があるが、これがユーザーの下で検出されてもどうしようもない。CI でなるべくこれを検出しようとするものである。

# Travis CI

[Travis CI](https://travis-ci.com/) は GitHub と連携する継続的インテグレーションツール（CI）である。以前は、オープンソースソフトウェアであれば無条件かつ無制限な無料枠（5並列まで）が付与されていた。

## Satyrographos Repo における Travis CI の用法

Satyrographos Repo は Travis CI で [`travis.sh`](https://github.com/na4zagin3/satyrographos-repo/blob/5008dc005562f169a05ce3ca549028375a4e8658/travis.sh) を実行し、以下の検査をしていた。 


1. OPAM のクリーンインストール（https://github.com/ocaml/ocaml-ci-scripts/blob/master/.travis-opam.sh）
1. `opam lint`
2. スナップショットのビルド・インストール
3. スナップショット内のライブラリによりインストールされるファイルに重複が無いか検査
4. スナップショットには無いがプルリクエストで追加されたライブラリについて、スナップショット内の他ライブラリをなるべく保った状態で、追加ライブラリをビルド・インストール・アンインストール

これにより、

1. OPAM ファイルの正当性
2. スナップショット内の各ライブラリの正当性
3. スナップショットに登録されるか否かを問わず、新規ライブラリの正当性

を検証しようとするものである。

Travis CI では linux bionic を用いていた。

## Travis CI、オープンソースソフトウェアに対する方針を転換す

Travis CI は [2020 年 11 月 2 日に方針の転換を発表](https://blog.travis-ci.com/2020-11-02-travis-ci-new-billing)し、オープンソースソフトウェアへの無条件無制限無料枠の代わりに、一律に利用者あたり 1 万点（Linux 環境での約 1000 分間分）を付与し、定期付与枠は申請を基に審査されることとなった。これは大きな波紋を呼び、以下の記事のように GitHub Actions への移行の動きも見られるようになった。

- xuwei-k『今までありがとうTravis CI、さよならTravis CI』https://xuwei-k.hatenablog.com/entry/2020/11/04/161400

# GitHub Actions
[GitHub Actions](https://docs.github.com/ja/free-pro-team@latest/actions) は GitHub により開発されている CI サービス（[2019 年 11 月 13 日正式リリース](https://it.impress.co.jp/articles/-/18498)）であり、モジュラーで再利用しやすいワークフロー定義等々により人気を博している。

## Satyrographos Repo の CI を GitHub Action に移行するの事
皆もすなる GitHub Actions といふものを我もしてみむとてするなりとて、[8 月頃](https://twilog.org/na4zagin3/date-200816)よりコメントボットを GitHub Actions で運用していたのだが、事此処に至り、スター数 9（2020 年 12 月 19 日現在）の弱小レポジトリに対して必要なだけの枠が割り当てられるか心配であり、また、わざわざ申請するのが面倒であるので、GitHub Actions への全面的移行を余儀なくされることと相成った。

SATySFi への PR （[#250](https://github.com/gfngfn/SATySFi/pull/250/files)）と dune への PR （[#3990](https://github.com/ocaml/dune/pull/3990/files#diff-126bf89616b7daa3d14ebc882ad18666aaf1c3dae888c4ba306a66ec80758bc1)）を参考にした。

以下に 2020 年 12 日 19 日現在のワークフロー定義を示す。

```yaml
name: CI

on:
  - pull_request
  - push

jobs:
  build:
    name: Build
    strategy:
      # 現在は ubuntu-latest で
      #   - OCaml 4.11.1 と SATySFi 開発版
      #   - OCaml 4.11.1 と SATySFi 0.0.5
      #   - OCaml 4.06.1 と SATySFi 0.0.4
      # の 3 つの環境で CI している
      matrix:
        os:
          - 'ubuntu-latest'
        ocaml-version:
          - 4.11.1
        snapshot:
          - stable-0-0-5
          - develop
        include:
          - os: 'ubuntu-latest'
            ocaml-version: '4.06.1'
            snapshot: stable-0-0-4
    runs-on: ${{ matrix.os }}
    env:
      
      OPAMSOLVERTIMEOUT: 3600
      SNAPSHOT: "snapshot-${{ matrix.snapshot }}"
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Cache OPAM directory (Non Windows)
        uses: actions/cache@v2
        if: runner.os != 'Windows'
        with:
          path: "~/.opam"
          key: ${{ runner.os }}-opam-${{ matrix.ocaml-version }}-${{ matrix.snapshot }}

      # 今はまだ不要ではあるが、そのうち Windows でもビルドするかもしれない
      - name: Cache OPAM directory (Windows)
        uses: actions/cache@v2
        if: runner.os == 'Windows'
        with:
          path: "C:\\cygwin\\home\\runneradmin\\.opam"
          key: ${{ runner.os }}-opam-${{ matrix.ocaml-version }}-${{ matrix.snapshot }}

      - name: Setup OCaml ${{ matrix.ocaml-version }}
        uses: avsm/setup-ocaml@v1
        with:
          ocaml-version: ${{ matrix.ocaml-version }}

      - name: Check validity of the snapshot OPAM files
        run: |
          opam lint --strict *.opam
      - name: Check validity of the package OPAM files
        run: |
          find packages -iname opam -exec opam lint --strict '{}' '+'

      - name: Setup OPAM repositories
        run: |
          opam repository add satysfi-external https://github.com/gfngfn/satysfi-external-repo.git
          opam repository add satyrographos-local .
          opam update
          # upgrade が無いと、SATySFi と Satyrographos の依存ライブラリが最短 7 日間は古いままに置かれてしまう
          opam upgrade --yes

      - name: Install the snapshot
        run: |
          opam pin add "${SNAPSHOT}.dev" . --no-action
          opam depext "$SNAPSHOT" --yes --with-doc --with-test
          opam install "$SNAPSHOT" --yes --with-doc --with-test

      - name: Detect file collisions in installed SATySFI libraries
        run: |
          opam exec -- satyrographos install test-satysfi-root

      - name: Remove the snapshot
        run: |
          opam uninstall "$SNAPSHOT"

      - name: Check integrity
        run: |
          ./ci.sh

      - name: Clean up logs and temporary files
        run: |
          opam clean --switch-cleanup --logs
```

要点をかいつまんで書く。

- [プルリクエスト生成時・再オープン時・同期時](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#pull_request)並びに[ブランチへのプッシュ](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#push) で実行される。
- https://github.com/avsm/setup-ocaml により OCaml 環境をセットアップする。smorimoto さんによって活発に改良されているため、今後の更なる高速化等も期待できる。
- `~/.opam` ディレクトリをキャッシュすることで、SATySFi 及び Satyrographos 並びに依存ライブラリを使い回している。

実行時間はキャッシュ無効時でも GitHub Actions の方が若干早くなった。

- Travis CI: 各ジョブ 20〜25 分 [例](https://www.travis-ci.com/github/na4zagin3/satyrographos-repo/builds/196989004)
- GitHub Actions: （キャッシュ無効時）各ジョブ 16〜18 分 [例1](https://github.com/na4zagin3/satyrographos-repo/runs/1568460664?check_suite_focus=true) [例2](https://github.com/na4zagin3/satyrographos-repo/runs/1558196637)、（キャッシュ有効時）各ジョブ 5〜9 分 [例](https://github.com/na4zagin3/satyrographos-repo/actions/runs/426091322) 

# 今後の課題
最も使われている SATySFi ライブラリである satysfi-base のテストケースは JavaScript で書かれているために、Satyrographos Repo の CI では実行されていない。SATySFi の開発版を Satyrographos Repo に登録する際に satysfi-base の互換性の検証が行いたいので、JS のテストケースを実行する方法の編み出すなり、satysfi-base のテストケースを OCaml 化するなりしたいところである。