CircleCI2.0でHaskellのテストを実行する
浅井 勇樹
この記事は RECRUIT MARKETING PARTNERS Advent Calendar 2017 の投稿記事です。
はじめに
こんにちは。英語学習GでiOSエンジニアをしている浅井です。
趣味レベルですがHaskellを愛好しています。家庭内SlackのBotや、ちょっとしたツール類はHaskellで書くことが多いです。その中で得た知見をブログにしていきたいと思います。
本記事では、新規プロジェクト作成からCircleCIへの投入までを解説します。また、本記事で作成したプロジェクトをGitHubで公開していますので、参考にしていただければと思います。
開発環境について
下記のリンクを参考に開発環境をインストールしましょう。インストール済みであればスキップしてください。
プロジェクト作成&テスト実行
まずは stack new
でプロジェクトを作成していきます。プロジェクト名を haskell-circleci-example
とします。今回はテストフレームワークとして Hspec を使いたいので、 hspec
というテンプレートを指定します。
作成されたプロジェクトには、あらかじめサンプルの実装とテストが含まれています。
実装
ある文字列の先頭及び末尾の余白文字列を取り除きます。
module Data.String.Strip (strip) where
import Data.Char
strip :: String -> String
strip = dropWhile isSpace . reverse . dropWhile isSpace . reverse
テスト
module Data.String.StripSpec (main, spec) where
import Test.Hspec
import Test.QuickCheck
import Data.String.Strip
-- `main` is here so that this module can be run from GHCi on its own. It is
-- not needed for automatic spec discovery.
main :: IO ()
main = hspec spec
spec :: Spec
spec = do
describe "strip" $ do
it "removes leading and trailing whitespace" $ do
strip "\t foo bar\n" `shouldBe` "foo bar"
it "is idempotent" $ property $
strip str === strip (strip str)
上記の実装とテストに対して stack test
が通ることを確認しておきましょう。
$ stack test
haskell-circleci-example-0.1.0.0: test (suite: haskell-circleci-example-test)
Data.String.Strip
strip
removes leading and trailing whitespace
is idempotent
Finished in 0.0081 seconds
2 examples, 0 failures
テストが通りましたね👍
CircleCIの設定ファイルを記述
CircleCI 2.0では、ビルドに利用するDockerイメージを好きに選択できます。幾つかの言語はCircleCIによって公式にサポートされていますが、Haskellはサポートされていないようです。以下のDockerイメージを利用することで対処します。
続いて、CircleCIの設定ファイルを記述します。
version: 2
jobs:
build:
docker:
- image: fpco/stack-build:lts-9.14
working_directory: /home/stackage
steps:
- checkout
- restore_cache:
key: cache
- run: stack build --test --only-dependencies --no-terminal --system-ghc
- save_cache:
key: cache
paths:
- ~/.stack
- run: stack install --test --no-terminal --system-ghc
CircleCI 2.0では、CLIを用いてローカルでビルドのチェックを行うことも可能です。本番のCircleCIに投入する前に試行錯誤できるので大変ありがたいです。以下のコマンドでビルドを実行します。
初回はDockerイメージのダウンロードやパッケージの依存関係を解決するために数分かかることがあります。気長に待ちましょう。また、ローカルでのビルドではキャッシュ機構がサポートされていないため restore_cache
と save_cache
のステップでエラーが出ます。気にせず先に進みましょう。
====>> Spin up Environment
...
====>> Checkout code
...
====>> Restoring Cache
Error: Skipping cache - error checking storage: not supported
Step failed
====>> stack build --test --only-dependencies --no-terminal --system-ghc
...
====>> Saving Cache
Error: Skipping cache - error checking storage: not supported
Step failed
====>> stack install --test --no-terminal --system-ghc
...
Success!
CircleCIへ投入
ここまでくれば、あとはCircleCIに投入するだけです。今回はGitHubにリポジトリを作ったので、CircleCIからそのリポジトリを選択します。
Langugageの選択で、 Otherを選ぶと Request a language
という項目が表示されます。せっかくなので Haskell
をリクエストしておきましょう。
ビルドを開始します。
無事に成功しました🚀🚀🚀
最後に
特にハマることなく最後まですすめることができました。CIとしての旨味を活かすために、カバレッジの測定やLintなどやりたいことはまだまだたくさんあります。CircleCI 2.0で新たに追加されたWorkflowを用いて、近々チャレンジしてみようと思います💪