読者です 読者をやめる 読者になる 読者になる

詩と創作・思索のひろば

ドキドキギュンギュンダイアリーです!!!

Go プロジェクトのバージョニングとリリースを CI で自動化する

Go

gobump で Go プロジェクトのバージョニングをおこなう の続き。すっかり書くのが遅くなってしまったけれど、別にもったいぶるような特別なことはないです。

ここでは、Pull Request のマージを契機に、バージョンを進めるコミットをし、push して、GitHub のリリースを進める……ということを CI でおこなうことを目標とします。

これはわりと簡単で、以下のようなスクリプトで実現できます。必要なものは gobumpghrjq と GitHub のパーソナルアクセストークン。通常はクロスコンパイルするのに gox も使うことになるでしょう。

set -e

repo_owner=motemen
repo_name=test-repository
committer_email=motemen+gobump-bot@gmail.com
committer_name=motemen

# 現在の HEAD が Pull Request のマージコミットだったら
pr_number=$(git show --pretty=%s | sed -n 's/^Merge pull request #\([0-9]\{1,\}\) .*/\1/p')

if [ -n "$pr_number" ]; then
  # バージョンを上げる
  new_version=$(gobump patch -w -v | jq -r '.[]')

  # ソースコードに変更があればコミットする
  if ! git diff --exit-code ./*.go; then
    git config --global user.email "$committer_email"
    git config --global user.name  "$committer_name"

    git add ./*.go
    git commit -m "bump version to $new_version"

    # トークンを使って GitHub に push
    git push "https://$GITHUB_TOKEN@github.com/$repo_owner/$repo_name" HEAD:master >/dev/null 2>&1

    # 新しいバージョンを ghr でリリース(dist/ 以下に成果物がある前提)
    ghr --username "$repo_owner" --repository "$repo_name" --token "$GITHUB_TOKEN" --replace --draft "v$new_version" dist/
  fi
fi

gobump-v オプションを与えると JSON で

{
  "VERSION": "0.1.2"
}

のように出力するので、スクリプトから利用しやすい。

ドラフトとしてリリースを作成するので、デフォルトでは公開されません。そろそろ公開するか、という機運になってきたらプロジェクトのリリースページから文言を整えて publish する、というフローでリリースできます。

f:id:motemen:20150812183016p:plain

以下、CI as a Service を利用する場合。

Travis CI での設定方法

上記のスクリプトをリポジトリに置いて、after_success フェーズで実行する。.travis.yml はこんな感じ。

language: go
go:
  - 1.4
before_install:
  - go get github.com/mitchellh/gox
  - gox -build-toolchain
  - go get github.com/motemen/gobump/cmd/gobump
  - go get github.com/tcnksm/ghr
script:
  - go test -v ./...
  - gox -output "dist/{{.OS}}_{{.Arch}}_{{.Dir}}"
after_success:
  - ./scripts/bump-release.sh

Wercker

Wercker には専用のステップを作っていて、motemen/ghqmotemen/gore ではこれを使っています。こちらはもうちょっと高度なことをしていて、Pull Request についたラベルによってマイナーバージョンを上げる、みたいなこともできる(作ったはいいものの、使わなかったけど……)。werckerbot 名義でコミットします。

このステップは GOBUMP_NEW_VERSION 環境変数に新しいバージョンを格納するので、その後のステップから利用できます。

wercker.yml のエッセンスを見るとこんな感じ。

deploy:
  steps:
    ...
    - motemen/gobump-github-pull-request:
        github_token: $GITHUB_TOKEN
    - wercker/gox:
        os: darwin linux windows
        arch: 386 amd64
        output: '{{.Dir}}_{{.OS}}_{{.Arch}}/{{.Dir}}'
        dest: $WERCKER_OUTPUT_DIR/pkg
    - tcnksm/zip:
        input: $WERCKER_OUTPUT_DIR/pkg
        output: $WERCKER_OUTPUT_DIR/dist
    - script:
        name: set release tag
        code: |
          if [ -n "$GOBUMP_NEW_VERSION" ]; then
            export RELEASE_TAG="v$GOBUMP_NEW_VERSION"
          fi
    - tcnksm/ghr:
        token: $GITHUB_TOKEN
        input: $WERCKER_OUTPUT_DIR/dist
        replace: true
        version: $RELEASE_TAG
        opt: --draft

https://github.com/motemen/ghq/compare/pull/61/head...v0.7.1https://github.com/motemen/gore/compare/pull/42/head...v0.2.5 で、PR のマージを契機にバージョンを上げることができているのが確認できます。

ちなみに Wercker は専用のツールを使うとビルド/デプロイプロセスをローカルの Docker を使って実行することができて、ちょっと癖はあるけれどこれがデバッグにとても便利だった。CI as a Service のデバッグは骨が折れるので……。