1ファイルから始めるNim＋CIで自動テスト・リリース

# まえがき

* NimのプロジェクトにGitHub Actionsを導入して自動テストする
* タグを切ったら自動でGitHub Releaseにリリースできるようにする
* **YAML 1ファイルで構築する**

# やることの意義

* 自動テストすることで、既存の挙動の変化に早期に気付ける
    * どの修正でバグったのかすぐに分かる
    * 時間ロスを減らせる
* どのPCからでもリリースできるようになる
    * ローカルでリリース用のコマンドをインストールして、TOKEN発行して、は手間がかかる
    * ビルド方法やリリース方法を忘れたりする
    * タグを切るだけでリリースできるようにすれば環境構築不要
    * PCが変わってもアカウントがあればいつでもリリースできる 

# リポジトリ

以下のリポジトリで検証しました。
[GitHub - jiro4989/nim_ci_sample](https://github.com/jiro4989/nim_ci_sample)


引数に数値を渡してFizzBuzzするだけのコマンドです。

# 1ファイルのYAMLで自動テスト、リリースするための手順

* `nimble init`したリポジトリに、以下のYAMLファイルを`.github/workflows/main.yml`に保存する
* YAMLファイル内の `nim_ci_sample` を自分のリポジトリ名（バイナリ名）に変更する
* ***終わり***

```yml
name: build

on: [push]

jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os:
          - ubuntu-latest
          # - windows-latest
          # - macOS-latest
    env:
      NIM_VERSION: 1.0.4
    steps:
    - uses: actions/checkout@v1
    - name: Cache choosenim
      id: cache-choosenim
      uses: actions/cache@v1
      with:
        path: ~/.choosenim
        key: ${{ runner.os }}-choosenim-${{ env.NIM_VERSION }}
    - name: Cache nimble
      id: cache-nimble
      uses: actions/cache@v1
      with:
        path: ~/.nimble
        key: ${{ runner.os }}-nimble-${{ hashFiles('*.nimble') }}
    - uses: jiro4989/setup-nim-action@v1.0.1
      with:
        nim-version: ${{ env.NIM_VERSION }}
    - run: nimble build -d:release -Y
    - run: nimble test -Y
    - run: nimble install -Y
    - run: nim_ci_sample 10
    - run: nimble doc --project --index:on -o:docs src/nim_ci_sample.nim
    - name: Create artifact
      run: tar czf nim_ci_sample_${{ runner.os }}.tar.gz README.md nim_ci_sample
    - name: Release binary
      uses: softprops/action-gh-release@v1
      if: startsWith(github.ref, 'refs/tags/')
      with:
        files: nim_ci_sample*.tar.gz
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

```

## このYAMLの解説

### 一連のフロー

* git checkoutでリポジトリのソースを取得
* choosenimのソースをキャッシュする宣言
* nimbleのソースをキャッシュする宣言
* Nim 1.0.4のインストール
    * 自作のGitHub Actionで実施
    * [Nim用のGitHub Actionsを作ってみた
](https://qiita.com/jiro4989/items/809f2a520c2e40d65bd3)
* `nimble build`
* `nimble test`
* `nimble install`
* インストールしたコマンドの実行
* ドキュメントの生成
    * ※GitHub Pagesにリリースするのにはちょっと手間が必要なので今回は割愛
* リリースファイルの生成
* GitHub Releaseにリリース

### テストとリリース実行のトリガー

テストはpushの都度実行される。
これはYAML先頭の `on: [push]` の指定から。

タグを切った時だけリリースするのは、最後の`Release binary`の`if: startsWith(github.ref, 'refs/tags/')`の指定。
コレがないとpushの都度リリースされてしまう。

リリース時のジョブのログは以下。
https://github.com/jiro4989/nim_ci_sample/commit/d4a7b526c7e0e597484cbc66235c2eba7fa78e13/checks?check_suite_id=345650672

### リリースに必要なトークン

`GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}`をリリース用に指定しているが、
これは別に自分で用意しなくてよい。
CIが実行される都度発行される揮発性の変数で、60分で無効になる。
> https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/authenticating-with-the-github_token

### バッジ

バッジも発行されるのでREADMEに書いとけば華やかになる。

![Build Status](https://github.com/jiro4989/nim_ci_sample/workflows/build/badge.svg)
> https://github.com/jiro4989/nim_ci_sample/workflows/build/badge.svg

補足
* `nim_ci_sample`の部分がリポジトリ名
* `build`の部分はYAMLの先頭の`name`

### キャッシュ

キャッシュも効くように設定している。
キャッシュしている間はコレくらいの規模なら ***1分*** でCIが終わる。

キャッシュのキーにそれぞれ以下のように指定している。

* `${{ runner.os }}-choosenim-${{ env.NIM_VERSION }}`
* `${{ runner.os }}-nimble-${{ hashFiles('*.nimble') }}`

この指定は、キャシュを特定のタイミングに使わないようにするためのもの。

使用している`actions/cache`は、キャッシュのキーが前ジョブのものと同じ間はキャッシュしていたものを使いまわし続けるみたい。
このキーを固定値にしていると、Nimのバージョンが変わったのにキャッシュが残り続けてバージョンが古いままになったり、
nimbleに依存パッケージを追加したのに毎回依存パッケージをダウンロードするようになったりする。

これを回避するために、`choosenim`のキャッシュのキーにはNimのバージョン番号を含めるようにした。
これでNimのバージョン番号を変更したらキャッシュを使わずに新しくコンパイラをインストールするようになる。

`nimble`のキャッシュのキーには、nimbleファイルのハッシュ値を含めるようにしている。
nimbleファイルが更新されると、nimbleファイルのハッシュも変わる。
すると、前のジョブでキャッシュしていたキャッシュのキーと不一致になるので、キャッシュが使われなくなる。
結果的に、新しくパッケージを取得して、それをキャシュする。

# まとめ

以下の内容について書きました。

* 1ファイルのYAMLで自動テスト、リリースできる
* CI設定の解説

これで快適Nimライフが送れます。
Nimでの開発のお役に立てば幸いです。

以上です。