概要
以下を目標に、Go言語で簡単なCLIツールを作りながらCI/CDを実践してみました!- CIで
testやbuildを実行して、READMEにバッジを貼る - テストカバレッジ計測し、
READMEにバッジを貼る - gitで
tagがついたら、バイナリを作ってgithubのリリースページにアップする
実践内容をハンズオンっぽくまとめると共に、ポイントやお世話になった記事をあわせて紹介したいと思いますʕ◔ϖ◔ʔ
A repository to play around with using CircleCI.
github.com/kemokemo/try-circle-ci
CIでtestやbuildを実行して、READMEにバッジを貼る
今回は、CircleCIを使ってCI/CDを実践することにしました。特にCircleCIに対するこだわりがある訳ではなく、「使用経験ないから学習してみっか!」ぐらいの軽い感覚で選定しました。dockerイメージを使ってビルド
CIは繰り返し実行するものです。CIの設定が同じなら何度実行しても同じ結果が得られるように(=冪等性があるように)dockerコンテナを使います。幸い、CircleCI公式でGo言語用のコンテナを用意してくれているのでこれを使います。言語ガイドを見ながら最初の
config.ymlができました。testとbuildのjobを並行に実行します。version: 2
jobs:
test:
docker:
- image: circleci/golang:1.13.5-node
working_directory: /go/src/github.com/kemokemo/try-circle-ci
steps:
- checkout
- run: go version
- run: go get -v -t -d ./...
- run: go test -v -cover ./...
build:
docker:
- image: circleci/golang:1.13.5-node
working_directory: /go/src/github.com/kemokemo/try-circle-ci
steps:
- checkout
- run: go get -v -t -d ./...
- run: go build
workflows:
version: 2
test and build:
jobs:
- test
- build
executorを定義して複数のjobで使う
さて、お気づきの方もいらっしゃると思いますが、上記のconfig.ymlでは複数のjobで下記の「stepを実行する環境」の記述が重複して記述されてます。docker:
- image: circleci/golang:1.13.5-node
working_directory: /go/src/github.com/kemokemo/try-circle-ci
ちょっとモヤモヤします(´・ω・`) 同じ設定で良いならば、1箇所で定義して使いまわしたいです。そこでexecutorという仕組みの出番です!まず、
executorを使うためにはconfig.ymlのバージョンを2.1以降に変更する必要があります。上述の内容にgo-113-5という名称をつけてexecutorとして定義するとこんな感じになります。version: 2.1
# add a docker executor for golang
executors:
go-113-5:
docker:
- image: circleci/golang:1.13.5-node
working_directory: /go/src/github.com/kemokemo/try-circle-ci
(後略)
よしよし。良いですね、名前がつけばそれを呼び出すことができます。実際に使ってみましょうʕ◔ϖ◔ʔversion: 2.1
executors:
go-113-5:
docker:
- image: circleci/golang:1.13.5-node
working_directory: /go/src/github.com/kemokemo/try-circle-ci
jobs:
test:
executor: go-113-5 # using my executor!
steps:
- checkout
- run: go version
- run: go get -v -t -d ./...
- run: go test -v -cover ./...
build:
executor: go-113-5 # using my executor!
steps:
- checkout
- run: go get -v -t -d ./...
- run: go build
workflows:
version: 2
test and build:
jobs:
- test
- build
テストカバレッジ計測し、READMEにバッジを貼る
無事にCircleCIでビルドできるようになったら、READMEにバッジを貼りましょう。CIを使っていて且つビルドが成功しているバッジがあれば、「どんなツールかなぁ」と思ってリポジトリを見に来た時の安心感がグンと増します。(もちろん真っ赤なFailバッジになっていると逆効果ですが・・)- CircleCIのバッジを追加する - CircleCI
- Adding Status Badges - CircleCI (英語の説明の方が画面付きで雰囲気つかみやすいかも)
テストカバレッジ計測し、READMEにバッジを貼る
せっかくCIでtestジョブも実行しているのですから、テストカバレッジも継続的に計測して可視化したいです。まさにやりたいことそのまんまな以下の記事を参考にして、 Codecov というサービスを使うことにしました。
codecovのorbを追加
オーブと聞くと、ドラゴンクエストⅢで6つ集めるアレとか、ドラゴンクエストⅤで砕けたり砕けなかったりするアレとかを思い出すのですが、ここで言うorbとは「CircleCI を手早く使い始めるのに便利なコンフィグパッケージ」(引用元:Orbs を使う - CircleCI)だそうです。codecovのorbを追加してみたのが以下です。version: 2.1
# add codecov's orb
orbs:
codecov: codecov/codecov@1.0.5
executors:
go-113-5:
...
(後略)
この便利なorbという仕組みは、「CircleCI Orb Registry」で検索して探すことができます。上記で追記した内容は、「CircleCI Orb Registry - codecov/codecov」を参考にしました。その他のorbの例としては、静的サイト生成ツールのhugoが使える「CircleCI Orb Registry - circleci/hugo」なんかもあります。便利ですね(*´ω`*)カバレッジの生成と収集
testのジョブでカバレッジ情報をファイルに書き込む処理を追加してcodecovにアップロードしましょう。その際、codecovサービスに対象リポジトリを追加した時に生成されるtokenを、CircleCIのCODECOV_TOKEN環境変数に設定するのを忘れずに。以下のようにtestジョブのステップを書き換えます。jobs:
test:
executor: go-113-5
steps:
- checkout
- run: go version
- run: go test -v -cover
- run: go get -v -t -d ./...
# adding coverprofile
- run: go test -v -cover -coverprofile=coverage.out ./...
# adding upload process to the codecov
- codecov/upload:
file: ./coverage.out
build:
...
(後略)
これで、testジョブを実行する度に最新のカバレッジ情報がcodecovにアップロードされるようになります。カバレッジの可視化と言えばバッジです。上図のように
codecovのSettings - BadgeからREADMEにコピペして使いましょう。
gitでtagがついたら、バイナリを作ってgithubのリリースページにアップする
このパートの内容は、以下の記事を参照してイメージを掴みつつ現在のCircleCI公式のドキュメントで学びながら実践しました。素晴らしい記事です、ありがとうございます。
deployジョブを追加
deployジョブでのおおまかな処理内容は以下です。- mitchellh/gox を使って、マルチプラットフォーム向けのバイナリを生成
- tcnksm/ghr を使って、GitHubのタグページにバイナリをアップロード
goxを使ってマルチプラットフォーム向けのバイナリを生成する処理を追加します。これが実行されると、releaseフォルダにドババっとバイナリが生成されます。(前略)
jobs:
(中略)
deploy:
executor: go-113-5
steps:
- run: echo 'export PATH=${GOPATH}/bin/:${PATH}' >> $BASH_ENV
- checkout
- run: go get -v -t -d ./...
# install gox and add the build process using the gox
- run: go get github.com/mitchellh/gox
- run: mkdir release
- run: gox -output "./release/{{.Dir}}_{{.OS}}_{{.Arch}}" ./ ./...
workflows:
....
(後略)
次に、ghrを使ってGitHubのタグページにファイルをアップする処理を追加します。実際に動かす前に、CircleCIに対してGITHUB_API環境変数の設定が必要です。 「GitHub API Token - tcnksm/ghr」 の内容を参考に、repoスコープ付きのトークンを生成して設定しておきましょう。(前略)
jobs:
(中略)
deploy:
executor: go-113-5
steps:
- run: echo 'export PATH=${GOPATH}/bin/:${PATH}' >> $BASH_ENV
- checkout
- run: go get -v -t -d ./...
- run: go get github.com/mitchellh/gox
- run: mkdir release
- run: gox -output "./release/{{.Dir}}_{{.OS}}_{{.Arch}}" ./ ./...
# install ghr and add the upload process using ghr
- run: go get github.com/tcnksm/ghr
- run: ghr -u $CIRCLE_PROJECT_USERNAME $CIRCLE_TAG release/
...
(後略)
deployワークフローを追加
「v」から始まるタグに対してのみ、上述のdeployジョブを実行するようにワークフローを設定してみましょう。「ジョブの実行を Workflow で制御する - CircleCI」の内容を参考に以下ようにしてみました。(前略)
workflows:
(中略)
- deploy:
jobs:
- build:
filters:
tags:
only: /.*/
- deploy:
requires:
- build
filters:
tags:
only: /^v.*/ # 「v」から始まるタグに対してのみ実行します。
branches:
ignore: /.*/
実際に「v0.0.1」というタグをつけてdeployワークフローを動作させてみた結果が以下です。うむ、素晴らしいです。およそ考えられるほぼ全てのプラットフォーム向けのバイナリが、CI/CDの仕組みによって生成されました。goxもghrも実に良いですね。おまけ
Go言語のリポジトリなら「Go Report Card | Go project code quality report cards」という仕組みを使って、多角的にコードの品質を可視化してくれるサービスも利用可能です。自分のGitHubリポジトリのパスを入力すればレポートを作れますし、バッジも貼れます。良きʕ◔ϖ◔ʔまとめ
CircleCI良いですね。特にorbの仕組みに感動しました。Ver. 2.1から使用可能になったexecutorの仕組みも大変興味深く、自在にCI/CDを構築できる感触を得ました。他にもいくつか同様の仕組みを導入したいツールがあるので、引き続き学習しながら使って行きたいと思います。



