あくびのあくびしないブログ

エンジニアを目指す学生のブログ兼備忘録

golangのコードにCircleCIを適用してみた話

去年の秋から、ずっとお前を使ってみたかったんだよ。
めっちゃ今更CircleCIをいじってみたので備忘録的なものを書くぞ。

最初に、CircleCIのドキュメントは以下。

circleci.com

CircleCIとは

まずCIってなんだよ、ということにならないために勉強。。。

CIとは、継続的インテグレーション(Continuous Integration)の略。 ソフトウェアを健全な状態に保つことを目的とし、ビルド/テストを常に行うことで問題の発見を迅速に行う開発手法です。

メリットは、というと

チーム開発の生産性、効率、満足度が向上します。 コードにおける問題の迅速な発見と解決につながります。 不具合の少ない高品質なプロダクトの提供を実現します。

コードの品質保証に一役買ってくれる開発手法って感じですね。
メリットに、チーム開発の生産性や満足度の向上も挙げられているところを見るとモチベが上がる!

CircleCIとは、CIを行うためのツールの一つです。他にもGithub ActionsとかJenkinsとかあります。
CircleCIは他のツールと比べ、ビルド/テストの処理速度が早い、らしい。

やりたいこと

ローカルリポジトリからコードをpushしたらテストを実行するって感じにしたい。
継続的デリバリーの方はとりあえず保留。。。デプロイ周りの自動化もやりたいよね。

やったこと

JWTをつかった認証をgoで実装した時のコードを再利用します。
その時の記事が以下。宣伝ですね

GoでJWTを使って認証してみる - Qiita

本流がmasterブランチなので、ブランチ切っときます。developってお名前。無難。

めっちゃちょっとだけテストを書いて、ローカルでテストを通します。よしよし。 f:id:yawn_yawn_yawn:20200309212705p:plain

とりあえず通るテストを用意したので、CircleCIをいじっていきます。

githubアカウントでログインします。
ログインするとこんな感じの画面に。適用したいリポジトリの横のSetUpProjectからセットアップします。 f:id:yawn_yawn_yawn:20200309221509p:plain


セットアップの段階で、configの取得ができます。テンプレがあるのでサクサク。 f:id:yawn_yawn_yawn:20200309221538p:plain

StartBuildingからビルドかけてみます。 configファイルがないので、モーダルにて、どうする?って聞かれます。add configしました...。
けど結局ローカルに手動で設定ファイル作ったので、add manuallyで良かった気がしています。
ビルドはconfigファイル作って、リモートにpushしてからでも良いのではって思います。

次にdevelopブランチにCIのconfigファイルを作成します。
configファイルは、プロジェクトのルートディレクトリに、.circleci/config.ymlとなるように作る必要があります。
config.yamlって名前にするとつらい思いをします。

$ mkdir .circleci
$ touch config.yml


ちなみにconfigの中身はこんな感じ。めっちゃシンプル

# version circleCIのバーション
version: 2

# jobs CIのフローの実行単位を定義
jobs:
  # build workflowsを使わない場合に用意するジョブ
  # プッシュをトリガーとしてCIを実行する時のデフォルトエントリーポイント
  build:
    docker:
      - image: circleci/golang:1.12
    
    working_directory: /go/src/github.com/yawn-yawn-yawn/authJWT-go
    
    # steps 実行内容のリスト
    steps:
      - checkout

      - run: go get -v -t -d ./...
      - run: go test -v ./...

configファイルを書いたらリモートリポジトリにpushします。
するとCIが実行されますー!連携自体はこれで完了!!簡単!

masterにプルリク出して、そこでCIが通るとこんな感じになります。気分が良い。 f:id:yawn_yawn_yawn:20200309221221p:plain


テストなどにエラーがあったりするとこんな感じ。 f:id:yawn_yawn_yawn:20200309221254p:plain

ぐぬぬってなるのでCircleCIの方を確認しにいきます。 テストの結果が吐かれてるのでチェックしたり。 f:id:yawn_yawn_yawn:20200309221317p:plain

導入自体は以上な感じで、サクサクできます!導入コストが低いのめっちゃ助かる。

吐かれたエラーたち

configファイルがない

config.yamlにした場合。こんなエラーを吐かれました。

#!/bin/sh -eo pipefail
# No configuration was found in your project. Please refer to https://circleci.com/docs/2.0/ to get started with your configuration.
# 
# -------
# Warning: This configuration was auto-generated to show you the message above.
# Don't rerun this job. Rerunning will have no effect.
false
Exited with code exit status 1

いやconfigあるが???って気持ちになります。

go getがうまく通ってくれない。

#!/bin/bash -eo pipefail
go get -v -t -d ./...
package auth-jwt/handler: unrecognized import path "auth-jwt/handler" (import path does not begin with hostname)

この開発で最初、go mod init auth-jwtって感じで初期化していたのだけど、どうやらimportのpathはhostnameから書かねばならんらしい。
ということで、module名をgithub.com/yawn-yawn-yawn/authJWT-goに直したところちゃんと通りました。

circleCIのconfigで指定したり、gomodなしで通ったりするんだろうかと思ってみたりした。検証せねば...

go testがつまった

ローカルで通ってたやん!ってなったけどそこじゃなかった。

#!/bin/bash -eo pipefail
go test -v ./...
# github.com/go-sql-driver/mysql
../../go-sql-driver/mysql/driver.go:88:33: undefined: driver.Connector
../../go-sql-driver/mysql/driver.go:99:49: undefined: driver.Connector

このissueみたところ、mysqlのドライバが、go1.9だとサポートできてないっぽい。。。
最初、configをそのままコピーしてたので、1.9だったんですよね...初めから開発環境と揃えろという話。

追加で少しだけ

configファイルにworkflowsを導入

workflowsはジョブを自動化するのに用います。 configファイルはこんな感じになる。

version: 2

jobs:
  test:
    docker:
      - image: circleci/golang:1.12
    working_directory: /go/src/github.com/yawn-yawn-yawn/authJWT-go
    steps:
      - checkout
      - run: go get -v -t -d ./...
      - run: go test -v ./...

workflows:
  version: 2
  testflow:
      jobs:
        - test

先ほどbuildで定義していたジョブを、testって名前に変更して定義します。 testジョブをworkflowsに組み込みます。めっちゃ簡単!
実行するジョブが一個だけだと恩恵がない気がする...複数になった時に管理しやすそうですね。

終わりに

導入手こずったーと思ったけど、思い返すとそこまでじゃないな。。。
CIやるからにはテスト書かなきゃーって気持ちになりますし、品質保証もできるならちゃんと導入しよって思います。
他CIツールとかも使って比べてみたいところです。