詩と創作・思索のひろば

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

Fork me on GitHub

YAPC::Asia Tokyo 2015 に行ってきた #yapcasia

YAPC::Asia Tokyo 2015

今回はキャパも拡大し、あぶれることがあまりなかったのがよかった。それでも立ち見だったり入れなかったりがあるのはさすがの人数。これだけの人間を動かすスタッフのみなさんには困難も多々あったのだろうと思いますがおかげさまで快適でした。

いつにも増して多彩なトーク内容だったなと思う。普段なんとなく名前は聞いて興味はあるけれど、さしせまった個人的な要求がなくてきちんとは知っていなかったトピックについてきっちり一時間かけて知ることができて、楽しかった。今回トークが基本一時間枠になったのがとてもよくて、どんなもんだろうと思っていたけど一時間なんてあっという間だった。これまで20分枠でもひいこら言って話を用意していたけど、これなら自分でもできるかもって思えてよかった。

トークはみんな録画されているから、(質疑を考えなければ)どれを見てもよいのだけど、YAPCあるあるはライブ感的なものが重要そうだと思って席を取りにいった。個人的にはここで 941 さんが nagayama さんの名前をあげていたのがとてもよくて、自分自身、この業界に触れだしたとき、その時は学生だったのだけれど、カンファレンスに参加して、nagayama さんをはじめいろいろな人に出会ったのをおもいだしたのだった。2007 年の YAPC にも行ったっけな、覚えてない。

あと Brad Fitzpatrick による Go のライブコーディングを1時間見続けることができたのは、なんというか、幸せだった。なぜか今は Go 大好きなので嬉しかったし、Perl の名を冠したイベントで普通にこういうのがあるのは YAPC が今や具えている懐の深さであり、Perl が日本の Web 開発コミュニティに果たした役割を感じることができる。まあ過去形じゃなく弊社は Perl バリバリ使ってます。

今回は残念ながら登壇できなかったけれど(というかそもそも応募してないのだが……)、またなんか場があれば話したい。登壇しなかった年はテンションがやや下がる。がんばろう。またどこかでお会いしましょう。

Git config から struct に読みこむ Go パッケージを書いた

Git や GitHub にまつわるツールは gitconfig に値を格納することにしておくのがユーザにも便利で、よく使っているし広く使われているとおもう。いっぽう YAML とか JSON とか設定ファイルによく使われるフォーマットは構造体に値をまとめて読みこむのが普通でもある。そういうわけで表題のようなものを書いた。以下の例を見れば分かるとおり gitconfig ファイルを自力で解析してすべての値を読みこむようなものではないです。

README より GoDoc のほうが詳しいです。

使い方

gitconfig フィールドタグを使います。

import "github.com/motemen/go-gitconfig"

type C struct {
    UserEmail  string `gitconfig:"user.email"`
    PullRebase bool   `gitconfig:"pull.rebase"`
}

var v Config
err := gitconfig.Load(&v)
...

gitconfig.Load メソッドで、タグによって指定されたキーに対応する値が構造体のフィールドに設定されます。対応している型は string[]stringbool、あと int 系。

ソースを指定する

パッケージに定義されている関数を呼び出すと内部ではオプションなしの git config が呼び出されるので、リポジトリローカルの設定もグローバルな設定も参照されることになります。これが都合わるい場合には、以下の変数や関数を使うことでソースを限定できます。

  • gitconfig.Global … グローバル(~/.gitconfig)な設定のみ
  • gitconfig.Local … ローカル(.git/config`)
  • gitconfig.File(file) … 特定のパスのファイル(.gitmodules とか)
url, err := gitconfig.Local.GetString("remote.origin.url")

単一のキーを取得する

上の例にも出ているけれど、GetXXX メソッドで単一のキーを取得することもできる。行きがかり上実装されたメソッドたちです。よく使用するキーを取得したいだけなら tcnksm/go-gitconfig を使うほうがいいと思う(名前一緒になったけど他にやりようがなかったっすサーセン……)。

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

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