Vim script を GitHub Actions でテストする

Vim プラグインを作成するにあたって、Vim script のテストをCIツールで実行したいと思い、FizzBuzz プラグインをサンプルに、GitHub Actions でテストを実行する流れを整理しました。

## 事前準備

GitHub にリポジトリを作成します。

今回は `fizzbuzz.vim` というリポジトリ名で作成しています。

## FizzBuzz プラグインの追加

「引数として任意の数値を渡すと、FizzBuzz のルールに従い文字列を返す」という関数を定義するプラグインを追加します。

* 参考: [Fizz Buzz - Wikipedia](https://ja.wikipedia.org/wiki/Fizz_Buzz)

```vim:plugin/fizzbuzz.vim
function! fizzbuzz#to_fizzbuzz(number) abort
  let s:divisible_by_3 = (a:number % 3 == 0)
  let s:divisible_by_5 = (a:number % 5 == 0)

  if s:divisible_by_3 && !s:divisible_by_5
    return 'Fizz'
  elseif !s:divisible_by_3 && s:divisible_by_5
    return 'Buzz'
  elseif s:divisible_by_3 && s:divisible_by_5
    return 'FizzBuzz'
  endif

  return ''
endfunction
```

## themis.vim を使ったテストの追加

Vim script 用テストフレームワークの [themis.vim](https://github.com/thinca/vim-themis) を利用して、テストを追加します。（テーミスやテミスと発音するようです）

FizzBuzz のルールに従った戻り値が返ってくることをテストしています。

```vim:test/fizzbuzz.vim
let s:suite = themis#suite('fizzbuzz')
let s:assert = themis#helper('assert')

function! s:suite.to_fizzbuzz_1()
  let l:number = 1
  let l:response = fizzbuzz#to_fizzbuzz(l:number)
  call s:assert.equals(l:response, '')
endfunction

function! s:suite.to_fizzbuzz_3()
  let l:number = 3
  let l:response = fizzbuzz#to_fizzbuzz(l:number)
  call s:assert.equals(l:response, 'Fizz')
endfunction

function! s:suite.to_fizzbuzz_5()
  let l:number = 5
  let l:response = fizzbuzz#to_fizzbuzz(l:number)
  call s:assert.equals(l:response, 'Buzz')
endfunction

function! s:suite.to_fizzbuzz_15()
  let l:number = 15
  let l:response = fizzbuzz#to_fizzbuzz(l:number)
  call s:assert.equals(l:response, 'FizzBuzz')
endfunction
```

ターミナルでのテスト結果はこちら。

```sh
$ ~/.ghq/github.com/stackline/fizzbuzz.vim
$ themis
1..4
ok 1 - fizzbuzz to_fizzbuzz_1
ok 2 - fizzbuzz to_fizzbuzz_3
ok 3 - fizzbuzz to_fizzbuzz_5
ok 4 - fizzbuzz to_fizzbuzz_15

# tests 4
# passes 4
```

## GitHub Actions にワークフロー追加

Vim script のテスト環境構築と実行を行うワークフローを追加します。

GitHub Actions が提供する [Simple workflow](https://github.com/actions/starter-workflows/blob/master/ci/blank.yml) をベースに、async.vim の [.travis.yml](https://github.com/prabirshrestha/async.vim/blob/master/.travis.yml) を参考にしながら作成しました。（ローカルで Dockerfile を `docker build` しながら動作確認しつつ、ある程度固まったタイミングで、ワークフローを作成）

```yaml:.github/workflows/ci.yml
name: Test

on: push

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - name: Initialize
      run: |
        sudo apt-get update
        sudo apt-get install -y vim
        sudo apt-get install -y git
    - name: Clone repositories
      run: |
        # Test framework
        git clone --depth 1 --branch v1.5.4 --single-branch https://github.com/thinca/vim-themis /tmp/vim-themis
        # Repository under test
        git clone --depth 1 --branch master --single-branch https://github.com/stackline/fizzbuzz.vim /tmp/fizzbuzz.vim
    - name: Run tests
      run: /tmp/vim-themis/bin/themis
      working-directory: /tmp/fizzbuzz.vim
```

ワークフローをリモートリポジトリに push すると、次回から push イベントをトリガーにワークフローが実行されます。

## GitHub Actions でテスト実行

例えば `README.md` を追加するコミットを `git push` します。

その後 GitHub で `fizzbuzz.vim` リポジトリにアクセスし、Actions タブをクリックすると、実行したワークフローの一覧が表示されます。

ワークフロー名をクリックすると、以下のようなログが閲覧でき、Vim script のテストが実行されていることを確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58153/6af21cdc-87f5-a157-aa20-2bb61c184506.png)

また、ワークフローのステータスを表すバッジも所定の URL で取得できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58153/acd85515-e510-7064-a749-b5592b467c91.png)

* 参考: https://help.github.com/en/actions/automating-your-workflow-with-github-actions/configuring-a-workflow#adding-a-workflow-status-badge-to-your-repository 

GitHub 内で CI/CD まで完結できるのは便利そうですね :)