goreleaserを使って分かったこと
goreleaserでやったこと
Goのプロジェクト(CLI)のバイナリを
GitHub Releaseにpublishさせる
Windowsだけは.tar.gzではなく.zipにする
Macのbrew (Homebrew) 用のリポジトリに自動コミットさせる
GitHub Actionsでバージョンのタグがついた時に上記のことを自動リリース
導入
Macだと以下で導入できる。(公式がtapの方を使った方が最新版のようなことが書かれている)
code:bash
brew install goreleaser
goreleaser initをすることで.goreleaser.ymlが生成される。
dry run
以下のように--skip-publishいれると、dry runしてくれる。
code:bash
goreleaser --snapshot --skip-publish --rm-dist
(これだと自動でコミットされたり、GitHubの何らかに書き込まれることはなかった)
--rm-distというオプションは./distが存在した時に削除することを表している。
goreleaserはビルド結果をデフォルトだと./distに置くため、ローカルでgoreleaserするとき--rm-distを付けている方が扱いやすい。 .goreleaserのデフォルト値などが埋まったファイル
先ほどのdry runで./dist/config.yamlが自動生成される。このファイルを見ると未指定項目に何があるかと何が設定されているのか一目で分かる。
これがあるとドキュメントに明記されていないさそうな項目を自分好みに変えられる。
--snapshotが罠だったこと
GITHUB_TOKEN=*** goreleaser --snapshot --rm-distのように--snapshotを付けた状態だとリリースしてくれなかった。snapshotをリリースしたいモチベーションは、試しに現在の設定でどのようにリリースされるかを確認するため。いまの知見だと試しにどうリリースされるか検証するためにはgitのtagを付けないといけない。リポジトリを汚したくない場合は検証のリポジトリを使ってどう動くかやる感じになる。
semverに従った形で-...のようにsuffixをつければリリースできるかもしれないので、それができれば手軽に試すことはできそう(あとで試すと思う)。
追記:リリースの試行錯誤する方法
...-snapshot1のようなタグをつけてリリースすることができた。自動でPre-releaseがついたみたい。
https://gyazo.com/da3d2197ad95f66197cfc1c93b0a3684/thumb/500#.png
ただしhomebrewの方もアップデートされた。そのためhomebrewはrevertした方が良さそう。
revertがやや面倒なのと試行錯誤中にbrew install ...した人いる可能性もある...
実際にリリースする方法
.goreleaser.yml
以下のconfigは好みに合わせて作ると思う。これは自分好みに変えた設定。
どういうわけでこの設定にしているのかをコメントしている。
code:.goreleaser.yml
project_name: piping-tunnel
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
# デフォルトでは書かれていないもの
# デフォルトだと.になる
# バイナリのmainになっているため指定している。
main: ./main/main.go
archives:
# GitHub Releaseにリリースされるときのファイルの名前を決めている。
# デフォルトだと"_"が使われていたが、CLIが"-"区切りのため"_"と"-"の共存をさけて"-"にしている。
# 繰り返しにはなるが、未指定のときの設定は"./dist/config.yaml"に書かれているため参考になる。
- name_template: '{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}-{{ .Mips }}{{ end }}'
# Windowsの場合は.tar.gzではなく.zipにする
format_overrides:
- goos: windows
format: zip
# .debと.rpmのファイルもGitHub Releaseさせるために
nfpms:
- license: MIT
maintainer: Ryo Ota <nwtgck@nwtgck.org>
description: "Tunnel over HTTP with Piping Server"
formats:
- rpm
- deb
file_name_template: '{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}-{{ .Mips }}{{ end }}'
checksum:
name_template: 'checksums.txt'
release:
github:
disable: false
prerelease: auto
name_template: "{{.ProjectName}}-v{{.Version}}"
brews:
- tap:
owner: nwtgck
# homebrew用のリポジトリに作成する必要がある。
name: homebrew-piping-tunnel
description: "Tunnel over HTTP with Piping Server"
(あとから気づいたこととして.yamlでもうまくいごくぽい。個人的に.yamlが使えるなら.ymlではなく.yamlを使いたい主義だったが、先ほどのタグつけないと動かせない事情のため気軽に試せず.ymlのままにしている。)
GitHubのトークン
次にPersonal Access Tokenを取得する。
最小の権限を探していて、以下のpublic_repoだけをチェックしたもので動作を確認した。Goのプロジェクトのリポジトリがpublicであることと、homebrewのためのもう1つのリポジトリもpublicであればこの権限だけでいけた。
https://gyazo.com/40f8ca584f15e7936691b49ff799c541/thumb/500#.png
gitのtagをv0.1.1のように付けた状態で以下を実行する。
code:bash
GITHUB_TOKEN=*** goreleaser --rm-dist
(export GITHUB_TOKENのようにしても良いが個人的にこれが好み)
上記を実行するとGitHub Releaseと自分のhomebrewリポジトリにアップロードされた。
goreleaserの実行が終わってもGitHub Releaseに表示されるまで少し時間がかかることに注意。
Changelogを消す方法
GitHub Releaseに行くとデフォルトだとコミットの一覧みたいなのがChangelogになっている。
CHANGELOG.mdなどで管理していたりするとnotable changesだけを記述したいという宗教と異なるし、他のCHANGELOGを自動で書くツールと衝突することがある。
https://gyazo.com/27c74e5a85fd4d24a93970241f8aa0f8
そういう時は以下のように実行することでGitHub Release欄のChangelogの生成を抑制できた。
code:bash
goreleaser --release-notes=<(echo) --dist
helpでオプションを探す
goreleaser --helpではなく、goreleaser release --helpしたほうがリリース関連のヘルプが分かる。
code:flags
Flags:
-f, --config string Load configuration from file
-h, --help help for release
-p, --parallelism int Amount tasks to run concurrently (default 4)
--release-footer string Load custom release notes footer from a markdown file
--release-header string Load custom release notes header from a markdown file
--release-notes string Load custom release notes from a markdown file
--rm-dist Remove the dist folder before building
--skip-publish Skips publishing artifacts
--skip-sign Skips signing the artifacts
--skip-validate Skips several sanity checks
--snapshot Generate an unversioned snapshot release, skipping all validations and without publishing any artifacts
--timeout duration Timeout to the entire release process (default 30m0s)
Global Flags:
--debug Enable debug mode
おそらくgoreleaserとgoreleaser releaseは同じオプションが使えるのだと思う。
GitHub Actionsの設定
code:.github/workflows/release.yml
name: goreleaser
# タグがついた時に動かす
on:
push:
tags:
- '*'
jobs:
goreleaser:
# -latestでなく明示的に指定している
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
with:
# changelogを自動生成させるために
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.15
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
# 明示的にgoreleaserのバージョンを指定している(多くのサンプルはlatestを指定している)
version: v0.149.0
args: release --rm-dist
env:
# homebrewは別リポジトリになるため secrets.GITHUB_TOKEN では権限が足りない
# 先述の方法で取得したPersonal Access Tokenを指定する
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
上記の設定でgitのtagをv0.1.1のようにつけてpushすればGitHub ActionsからGitHub Releaseとhomebrewに自動でリリースされる。 そのほかgoreleaserには自動でGoのプロジェクトのバージョンをあげてファイルを更新してくれる機能があったりするようだが、今回は導入を避けた。