今年はコーディングをもっと頑張ろうと思い、前から気になっていたGo言語に挑戦してみています。
コーディング自体も癖はありつつも楽しいんですが、test, installやrelease作成など周辺の仕組みが洗練されていて初心者でも簡単にできました。

試しにCLIツールを作ってみたんですが、その際に諸々整えた流れをまとめておこうと思います。

作ったもの

https://github.com/koh-sh/termclock
ターミナルに大きく時刻を表示するCLIです。
特に実用性はないですが学習目的でお遊びツールとして書いています。
今回整えたCI周りも全てリポジトリで公開しています。

GIF1

開発環境

ローカルのMacにHomeBrewでGoをインストールしています。
エディタはVSCodeで公式?のextensionを使っています。

[koh@Kohs-MacBook-Pro-M1-387] ~
% sw_vers
ProductName:		macOS
ProductVersion:		13.0.1
BuildVersion:		22A400
[koh@Kohs-MacBook-Pro-M1-387] ~
% go version
go version go1.19.4 darwin/arm64
[koh@Kohs-MacBook-Pro-M1-387] ~
%

test

Goの場合testサブコマンドがあるので特に別のツールをインストールする必要はないです。

例えばmain.goのテストを書く時はmain_test.goファイルを作成して、その中に関数ごとのテストを書いていくのですがVSCodeのGo extensionだとその辺の準備を全部やってくれます。

テストを作成したい関数にカーソルを合わせて右クリックし、Go: Generate Unit Tests For Functionを選択するとテスト用のファイルとテスト用の関数のテンプレを用意してくれます。

サンプルとして素数判定の関数とそのテストを作成しています。

GIF2

あとは // TODO: Add test cases.となっているところにテストケースを追加します。
testsにテストケース名、与える引数、期待値を入力するだけで簡単なテストを実行できます。

	tests := []struct {
		name string
		args args
		want bool
	}{
		// TODO: Add test cases.
		{name: "3 should be prime",
			args: args{3},
			want: true},
		{name: "4 should not be prime",
			args: args{4},
			want: false},
	}
[koh@Kohs-MacBook-Pro-M1-387] ~/work/hoge
% go test -v
=== RUN   Test_isPrime
=== RUN   Test_isPrime/3_should_be_prime
=== RUN   Test_isPrime/4_should_not_be_prime
--- PASS: Test_isPrime (0.00s)
    --- PASS: Test_isPrime/3_should_be_prime (0.00s)
    --- PASS: Test_isPrime/4_should_not_be_prime (0.00s)
PASS
ok  	example	0.231s
[koh@Kohs-MacBook-Pro-M1-387] ~/work/hoge
%

release

GoReleaserを使うと全てやってくれました。
設定によりできることは色々ありそうですがデフォルトだと

  • クロスコンパイル
  • GitHubへのバイナリアップロード
  • GitHubのrelease作成

をやってくれます。

HomeBrewでインストールした後に

brew install goreleaser

Quick Startの内容をやればリリースがリポジトリに作成されます。

release

goreleaser initを実行すると .goreleaser.yamlを作成してくれます。

% cat .goreleaser.yaml
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com
before:
  hooks:
    # You may remove this if you don't use go modules.
    #- go mod tidy
    # you may remove this if you don't need go generate
    #- go generate ./...
builds:
  - env:
      - CGO_ENABLED=0
    goos:
      - linux
      - windows
      - darwin

archives:
  - format: tar.gz
    # this name template makes the OS and Arch compatible with the results of uname.
    name_template: >-
      {{ .ProjectName }}_
      {{- title .Os }}_
      {{- if eq .Arch "amd64" }}x86_64
      {{- else if eq .Arch "386" }}i386
      {{- else }}{{ .Arch }}{{ end }}
      {{- if .Arm }}v{{ .Arm }}{{ end }}
    # use zip for windows archives
    format_overrides:
    - goos: windows
      format: zip
checksum:
  name_template: 'checksums.txt'
snapshot:
  name_template: "{{ incpatch .Version }}-next"
changelog:
  sort: asc
  filters:
    exclude:
      - '^docs:'
      - '^test:'
      - '^chore:'

# The lines beneath this are called `modelines`. See `:help modeline`
# Feel free to remove those if you don't want/use them.
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj

基本的にデフォルトのままで大丈夫だと思いますが、私の場合hookは不要(なはず)なのでコメントアウトし、changelogのfiltersにchoreも追記しました。

CI

上記のtestとrelease作成両方ともGitHub Actionsで実行できます。

test

Actionsタブで公式のgoのworkflowがそのままtest用として利用できます。
mainにpushかPRが発行されたときに動く形になっているので適宜変更してください。

actions go

release

GoReleaserの公式のGitHub Actionsが用意されているのでそのまま使用します。

workflow

実行をtag pushに変更しています。

name: goreleaser

on:
  push:
    tags:
      - 'v*'

jobs:
  goreleaser:
    runs-on: ubuntu-latest
    steps:
      -
        name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0
      -
        name: Set up Go
        uses: actions/setup-go@v3
      -
        name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v4
        with:
          # either 'goreleaser' (default) or 'goreleaser-pro'
          distribution: goreleaser
          version: latest
          args: release --rm-dist
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          # Your GoReleaser Pro key, if you are using the 'goreleaser-pro' distribution
          # GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}

これでtag pushすると実行されて自動でrelease作成してくれます。

まとめ

初めて色々触ってみましたが基本的に開発に必要なものが、GoやGitHubの機能で完結するのはとても体験がいいなと思います。
ほぼデフォルト設定でいい感じにできたのでコードを書くことに集中しやすそうです。

Share on: このエントリーをはてなブックマークに追加