Vim プラグイン開発でも継続的インテグレーションがしたい! (Travis CI 編)


2013年 02月 06日

問題

昨今は継続的インテグレーション(CI)が大ブームです。
そしてオープンソースのプロジェクトならTravis CIを使うことで簡単にCIを始めることができます。
という訳でこのビッグウェーブに乗るしかありません。
それも Vim プラグイン開発で。

しかし、

  • Vim プラグインのテストはどう書けば……
  • 他のプラグインに依存しているプラグインだとどうしよう……

という割と面倒臭い問題があります。
しかしもう2013年です。
Vim プラグイン開発でも CI したいお年頃です。
一体どうすれば良いのでしょうか。

解答

幸いなことにもう2013年です。
なので以下のステップをこなせば
Vim プラグイン開発でも簡単に CI できます:

1. テストの実行に必要なツールをインストールする

Travis CI で CI するにせよローカル環境で CI するにせよ、
テストを実行するためのツールが必要です。
まずは必要なツールをインストールするための Gemfile を作成してコミットしましょう:

source 'https://rubygems.org'

gem 'vim-flavor', '~> 1.1'

Gemfile を作成した後は

bundle install

でツールのインストールは完了です。

2. テストの実行手順をスクリプト化する

人間は細かい手順なんていちいち覚えてられません。
という訳でテストの実行手順をまとめた Rakefile を作成してコミットしましょう:

#!/usr/bin/env rake

task :ci => [:dump, :test]

task :dump do
  sh 'vim --version'
end

task :test do
  sh 'bundle exec vim-flavor test'
end

Rakefile を作成した後は

rake test

でテストの実行ができます。
ci は Travis CI での実行結果に参考情報を出力するものなのでここでは無視してください。

3. Travis CI でのテスト実行のための設定を用意する

Travis CI は様々な言語に対応しており、
割りと何でも CI できるのですが、
その代償として多少の設定を記述する必要があります。
という訳で Travis CI で Vim プラグインのテストを実行する設定を .travis.yml に保存してコミットしましょう:

language: ruby
rvm:
  - 1.9.3
script: rake ci

4. テスト対象の Vim プラグインの依存関係を宣言する

(テスト対象のプラグインが他のプラグインを利用しない場合はこのステップは飛ばしてください)

世の Vim プラグインの大半は独立した存在ですが、
ものによっては他のライブラリ的なプラグインを利用しているプラグインも存在します。

例えば vim-textobj-function は関数単位で編集を行うためのテキストオブジェクトを提供しますが、テキストオブジェクトの定義はぶっちゃけ色んなエッジケースがあって面倒臭いことこの上ないので、 vim-textobj-user を利用することでその面倒臭い部分に蓋をしています。
なので vim-textobj-function のテストをするためには vim-textobj-user が必要です。
しかも

  • Plugin A 1.0.0 は Plugin B 2.2 以降に依存。
  • Plugin A 3.0.0 は Plugin B 4.4 以降に依存。
  • ただし Plugin B の 2.x と 4.x は非互換だから「2.2 以降に依存」するからといって 4.4 を使うと動かない。

のように依存関係の上に互換性も考慮しなければありません。

しかしこのような問題についてはツールが面倒を看てくれるので問題ありません。
という訳で依存するプラグインとそのバージョンの宣言を VimFlavor に保存してコミットしましょう。例えば vim-textobj-function なら vim-textobj-user 0.3 以降(ただし1.x 以降は除く)に依存しているので、以下のように記述します:

flavor 'kana/vim-textobj-user', '~> 0.3'

(Vim プラグインの依存関係の記述方法の詳細 についてはドキュメントを参照してください)

5. Vim プラグインに対するテストを書く

Vim プラグインに対するテストなので Vim に関する細かい操作を記述する必要があります。
という訳でテストは Vim script で記述するのが一番です(かなり特殊なテストなら別ですが、その対応方法は後日書きます)。
ただ Vim script で一からテストを書こうとするとかなり辛い戦いになるので既存のツールを使いましょう。
これまでのステップに従っていれば vim-vspec が自動的に使える状態になっています。
なので、

  • t という名前のディレクトリを作る。
  • テスト用のスクリプトは拡張子を .vim にして t の中に保存する。
  • テストは vim-vspec の書式に従って書く。

というルールを守れば割りと RSpec っぽい感じでテストを書くことができます。
具体例は vim-textobj-function のテストvim-vspec 自身のテスト を参照してください。イメージとしては大体以下のような感じです:

describe ':Expect'
  it 'succeeds if an actual value matches to an expected value'
    let something = 'foo'
    Expect something ==# 'foo'
  end
end

6. GitHub に push する

7. 暫く待つ

8. Travis CI での実行結果を眺めて楽しむ

例: vim-textobj-function の Travis CI での実行結果