ActionsでGoのバイナリをバージョニングして自動リリースする


# 概要

Githubでリリース機能を使ったことがなかったので試しにつかってみた。

ソフトウェアのバージョン管理はセマンティックバージョニングでおこなう。

具体的には、v1.0.3みたいな感じにする。

「ドット」を挟んで以下のような意味。

(メジャーバージョン).(マイナーバージョン).(パッチバージョン)

さて、本題の流れは以下のようになる

バージョンアップするコミットSHAが決まったらバージョンをインクリメントし(ex v1.1.3 -> v1.1.4)、タグを付けてコミットする。

それをトリガーにGithub Actionsでlinux,macOS,windows用にコンパイルしてリリースするという流れである。

ここに例を用意しておく。https://github.com/hgkcho/sumcp

Makefileと.github/workflows/release.ymlあたり

# 使うパッケージ

# gobump

主に使うパッケージは以下

go get github.com/x-motemen/gobump/cmd/gobump
1

バージョンを上げることができるツール

main.goにconst version = "2.3.4"などと書くことでバージョンを認識する

gobump show -r cmd/sumcp
1
gobump up
1

でインタラクティブにどのバージョンを上げるか決めれる

# goxz

go get github.com/Songmu/goxz/cmd/goxz
1

リポジトリのルートディレクトリでコマンドを実行する yourapp_0.0.1_darwin_amd64.zip

linux,macOS,windowsにクロスビルドをしてアーカイブしてくれるもの

goxz -n sumcp -pv=v1.0.3 -build-ldflags="-s -w -X main.revision=v1.0.3" ./cmd/sumcp
1

こんな感じにすればいい

# ghr

go get github.com/tcnksm/ghr
1

Github Releaseを作成し、成果物をアップロードしてくれるツール 手元でやる場合はGithub API TOKENをが必要になるので必要に応じて作成すること

goxzで作成したパッケージをこれでリリースする

ghr v1.0.3 goxz
1

これでOK

# 実際に組み立てていく

shell scriptを書いてもよいが今回はMakefileに書いていく。

これらはローカルでもActions側でもたたける

# Makefile

Makefileの基本的な説明は割愛するが

make (target)
1

でターゲット(処理)を実行できる。

Makefileの大体はこんな感じ

BIN := sumcp
VERSION := $$(make -s show-version)
VERSION_PATH := cmd/$(BIN)
CURRENT_REVISION := $(shell git rev-parse --short HEAD)
BUILD_LDFLAGS := "-s -w -X main.revision=$(CURRENT_REVISION)"
GOBIN ?= $(shell go env GOPATH)/bin
export GO111MODULE=on

.PHONY: show-version
show-version: $(GOBIN)/gobump
        @gobump show -r $(VERSION_PATH)

$(GOBIN)/gobump:
        @cd && go get github.com/x-motemen/gobump/cmd/gobump

.PHONY: cross
cross: $(GOBIN)/goxz
        goxz -n $(BIN) -pv=v$(VERSION) -build-ldflags=$(BUILD_LDFLAGS) ./cmd/$(BIN)

$(GOBIN)/goxz:
        cd && go get github.com/Songmu/goxz/cmd/goxz

.PHONY: bump
bump: $(GOBIN)/gobump
ifneq ($(shell git status --porcelain),)
        $(error git workspace is dirty)
endif
ifneq ($(shell git rev-parse --abbrev-ref HEAD),master)
        $(error current branch is not master)
endif
        @gobump up -w "$(VERSION_PATH)"
        git commit -am "bump up version to $(VERSION)"
        git tag "v$(VERSION)"
        git push origin master
        git push origin "refs/tags/v$(VERSION)"

.PHONY: upload
upload: $(GOBIN)/ghr
        ghr "v$(VERSION)" goxz

$(GOBIN)/ghr:
        cd && go get github.com/tcnksm/ghr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

make show-versionで現在のバージョンを確認

make crossでクロスビルド

make uploadでgithub release に成果物をアップロードする

make bumpでバージョンをアップする

ローカルで使うのはmake bumpのみで、これによってバージョンアップを自動的に行う。

# Actions

ワークフローの全体は以下の用な感じになる。

name: Release

on:
  push:
    tags:
    - 'v*'

jobs:
  release:
    name: Release
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@master
    - name: Setup Go
      uses: actions/setup-go@v1
      with:
        go-version: 1.14.x
    - name: Add $GOPATH/bin to $PATH
      run: echo "::add-path::$(go env GOPATH)/bin"
    - name: Cross build
      run: make cross
    - name: Create Release
      id: create_release
      uses: actions/create-release@master
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      with:
        tag_name: ${{ github.ref }}
        release_name: Release ${{ github.ref }}
    - name: Upload
      run: make upload
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

タグを付けてリモートにプッシュするとreleaseジョブが流れる仕様。

流れはセットアップ -> クロスビルド -> github release 作成 -> アップロードとなっている。

ワークフローの中で先程のMakefileで定義したターゲットを逐次実行している

これによってmake bumpでバージョニングして自動リリースできるようになった。

# 最後に

コマンド1つでバージョンアップできるのは気持ちいい。

本題とはあまり関係ないないが、Makefileでコマンドを管理すると、シェルスクリプトをbin/フォルダで管理するのに比べて、1ファイルで何をするかまとまるのでシンプルでよかった。