GitHub Actions で dotfiles を自動テスト


# はじめに
私は普段 Mac で作業していますが、たまに Linux に dotfiles を持ち込みたくなることがあります。
ですが、いつもエラーが出るので困ってしまいます。
( 新しい Mac を再セットアップするときも同様 )

そこで、dotfiles の品質を維持するために、[GitHub Actions](https://github.co.jp/features/actions) を使った CI に取り組んでみました。

- テスト項目
    - 実行時エラーチェック ( Mac, Linux )
        - セットアップ用のスクリプト (シンボリックリンク作ったり) の実行
        - `.bash_profile` や `.bashrc` の読み込み
        - `brew bundle` の実行 ( Mac のみ )
    - 静的解析
        - Shell Script (セットアップ用スクリプト, .bash_profile, .bashrc)
        - Vim Script ( init.vim )
        - TOML ( dein.vim )

<br>
( 自分のリポジトリに PR する習慣がないので、いつも master に直接 push しています )
git の内容が変更されると自動的にテストが走り 

| Badge       | 意味 |
|---------------------------------------:|:---------------------------------------|
| <img width="200" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18646/b751db03-8c63-ecfe-e8c9-19e39ffa73e2.png"> | :octocat:  \<「Linuxだとまたエラーが出るぞ。残念w」 |
| <img width="100" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18646/8cca07b8-ef21-a9a1-d745-276ad0810e3f.png"> | :octocat:  \<「きれいに書けてて偉いぞ！」  |


と教えてもらえます。

# dotfiles の構成
[rtakasuke/.dotfiles at 記事投稿時点](https://github.com/rtakasuke/.dotfiles/tree/9524a89ef4a42e30a8a0823a82631390c5232d9c)

```bash
$ tree -a -I ".git|.gitignore|archive|gitconfig|iTerm2|tigrc|README.md"
.
├── .github
│   └── workflows
│       ├── lint.yml     # 静的解析用ワークフロー
│       ├── linux.yml    # 実行時エラーチェック用ワークフロー (Linux)
│       └── macos.yml    # 実行時エラーチェック用ワークフロー (Mac)
├── Brewfile
├── bash_profile
├── bashrc
├── bin
│   └── init.sh          # セットアップスクリプト ( $HOME にシンボリックリンクを作成 )
└── nvim                 # Neovim + dein.vim の設定ファイル
    ├── dein.toml
    ├── dein_statusline.toml
    └── init.vim
```

# GitHub Actions ワークフロー
`.github/workflows` に yaml ファイルを置いて設定を記述します。
詳しい構文は以下をご参照ください。

* [GitHub Actionsのワークフロー構文 - GitHub ヘルプ](https://help.github.com/ja/actions/reference/workflow-syntax-for-github-actions)

## 実行時エラーチェック ( Mac, Linux )
- ワークフロー
    - [macos.yml](https://github.com/rtakasuke/.dotfiles/blob/9524a89ef4a42e30a8a0823a82631390c5232d9c/.github/workflows/macos.yml)
    - [linux.yml](https://github.com/rtakasuke/.dotfiles/blob/9524a89ef4a42e30a8a0823a82631390c5232d9c/.github/workflows/linux.yml)

<img width="700" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18646/50ba6aa3-3dc1-f886-471f-7472d3120dec.png">

### Run brew bundle ( Mac )
```yaml
- name: Run brew bundle
  run: brew bundle
```
`Brewfile` に記述したアプリが Mac にインストールできることをテストします。

- 参考 : [Homebrew/homebrew-bundle](https://github.com/Homebrew/homebrew-bundle)


### Run init.sh
```yaml
- name: Run init.sh
  run: ${GITHUB_WORKSPACE}/bin/init.sh
```
セットアップ用スクリプト ( シンボリックリンクを作成したりする ) が正しく動作することをテストします。
エラー発生時に終了コードが0にならないように、スクリプト側で `set -e` コマンドを実行しています

- 参考 : [シェルスクリプト内のエラーが発生した場所で異常終了したい - Qiita](https://qiita.com/rtakasuke/items/fd35ef60370e3d8c225d)

### Load .bash_profile & .bashrc
```yaml
- name: Load .bash_profile
  run: |
    bash ~/.bash_profile 2> error.log; cat error.log
    if [ -s error.log ]; then false; fi

- name: Load .bashrc
  run: |
    bash ~/.bashrc 2> error.log; cat error.log
    if [ -s error.log ]; then false; f
```
.bash_profile や .bashrc を読み込んだときに、標準エラー出力がないことをテストします。
セットアップコマンドのときのように `set -e` コマンドを使うとシェルが落ちてしまうので、苦肉の策です。

## 静的解析

- ワークフロー
    - [lint.yml](https://github.com/rtakasuke/.dotfiles/blob/9524a89ef4a42e30a8a0823a82631390c5232d9c/.github/workflows/lint.yml)

<img width="700" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18646/cd3d61e1-07f1-93e8-aa68-8183ef6daeb3.png">

### Check bin/init.sh
```yaml
- name: Check bin/init.sh
  run: shellcheck ${GITHUB_WORKSPACE}/bin/init.sh
```
[shellcheck](https://github.com/koalaman/shellcheck) を利用して、セットアップ用スクリプトの書き方に問題がないことをテストします。


### Check .bash_profile & .bashrc
```yaml
- name: Check .bash_profile
  run: shellcheck ${GITHUB_WORKSPACE}/bash_profile --exclude=SC2148,SC1090

- name: Check .bashrc
  run: shellcheck ${GITHUB_WORKSPACE}/bashrc --exclude=SC2148,SC1090
```
同上。
ただし、いくつかの警告を無視するように設定しました。

- [SC2148](https://github.com/koalaman/shellcheck/wiki/SC2148) : shebang が書いてないときの警告だが、.bash_profile に書くものではないので無視
- [SC1090](https://github.com/koalaman/shellcheck/wiki/SC1090) : 外部ソースを読み込めないことによる警告だが無視。

### Check nvim/init.vim
```yaml
- name: Check nvim/init.vim
  run: vint ${GITHUB_WORKSPACE}/nvim/*.vim -cstV --enable-neovim
```
[vint](https://github.com/Vimjas/vint) を利用して、Neovim の設定ファイルの書き方に問題がないことテストします。

### Check nvim/*.toml
```yaml
- name: Check nvim/*.toml
  run: |
      curl -sL https://raw.githubusercontent.com/vmchale/tomlcheck/master/sh/check | sh || true
      find ${GITHUB_WORKSPACE}/nvim/*.toml -type f | xargs -I {} ${GITHUB_WORKSPACE}/tomlcheck --file {}
```
[tomlcheck](https://github.com/vmchale/tomlcheck) を利用して、Neovim のプラグインを記述している TOML ファイルの書き方に問題がないことテストします。
ワイルドカードが使えなかったので、苦肉の策です。

# 最後に
まだ改善の余地は多いと思うので、ご意見いただけると嬉しいです。