詩と創作・思索のひろば

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

Fork me on GitHub

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

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 のデバッグは骨が折れるので……。

Go で SOCKS5 プロキシを利用する

検索すると golang - net/httpでSOCKS proxyを扱う - Qiita という記事が見つかったけれど、今なら net/proxy パッケージを使えばよさそうだ。

雑な例だとこんな感じ。

import (
    "net/http"
    "golang.org/x/net/proxy"
)

func main() {
    p, err := proxy.SOCKS5("tcp", "127.0.0.1:10001", nil, proxy.Direct)

    client := http.DefaultClient
    client.Transport = &http.Transport{
        Dial: p.Dial,
    }

    resp, err := client.Get(...)
}

proxy.SOCKS5() 関数で proxy.Dialer というのが得られるので、これをたとえば http.TransportDial フィールドに渡してやればよい。簡単。

また proxy.FromEnvironment() を使うと環境変数からプロキシの設定を取得できる。この場合以下のように、all_proxy 環境変数をよしなに設定してやる必要がある。

all_proxy=socks5://127.0.0.1:10001 ./main

ghq v0.7 をリリースしました

2015-08-11 追記

@kyanny さんに指摘いただいた、ghq.root 配下にシンボリックリンクが存在すると ghq list などが不完全になる不具合を修正した バージョン 0.7.1 をリリースしています。最新版はこちらをご利用ください。

Release v0.7.1: Fixed symlink issue of v0.7 · motemen/ghq · GitHub

Vagrantfile による再現環境、シビれましたね。ありがとうございました!


Release v0.7 · motemen/ghq · GitHub

0.6 からだいぶ時間が経ってしまっていましたが、勢いをつけるための久しぶりのリリースです。リリースページからバイナリをダウンロードするか、go get で入手してください。

go get -u github.com/motemen/ghq

バイナリの配布は今回からすべて zip になってますので、自動化している人はご注意ください。

ghq とは

GitHub などのリモートリポジトリをローカルに clone し整理するための簡単なツールです。詳しくは ghqを使ったローカルリポジトリの統一的・効率的な管理について - delirious thoughts をご覧ください。

リリースノート

  • [feature] Bluemix DevOps Git service に対応 (#56, @uetchy)
  • [feature] GHQ_ROOT 環境変数で ghq.root 設定を上書きできるように (#59)
  • [feature] Darcs に対応 (#55, @maoe)
  • [feature] look コマンドがリモートリポジトリの URL も受けつけるように (#51, @ryotarai)
  • [feature] look コマンドが GHQ_LOOK 環境変数を設定するように (#47, @superbrothers)
  • [improvement] list の高速化 (#54, @maoe)
  • [fix] Windows でのテストの修正 (#48, @kkka)

特に #54 の高速化は変な見落としがないか心配なところです。パッケージングの仕方も変えているので、何か問題がありましたら GitHub から報告 いただければと思います。

ghq.root の新たなデフォルト値を考え中

ghq.root はデフォルトで ~/.ghq になっていますが、これで嬉しい人はいないんじゃないかな〜と最近思ってます(自分も ~/dev とかにしてる)。もうちょっとイカしたデフォルト設定があればそれを採用しようか(それとも初回起動時に設定させるとか)と考えてるところなので、もしご意見があればイシューにコメントいただけると幸いです。

Default value for `ghq.root` · Issue #60 · motemen/ghq · GitHub

はてなで一緒に働きませんか?