😺

あなたの現場のGoのフォーマット環境整備屋さん 2.CIでフォーマットチェックの巻

に公開

どもーこんちくわ

ルノアールで執筆作業中ですー

ルノアールすごい椅子がフカフカで好きなんですよね😊

落ち着いた雰囲気も好きです!

さて今回は、フォーマット環境整備第二弾!CIの実装です!

今回実装するのはCIはどんな内容か

GitHubにPR作成またはコミットしたときに、CIを動作させます。

そこで、フォーマットチェックをします。

フォーマットが整備されていなかった場合は、CIエラーと判断します。

そんな内容になっています!

CIの内容を定義するファイルを作ろう

まずは下記コマンドでCIに指示を出すymlファイルを作成しましょう!

# フォルダ作成
mkdir -p .github/workflows
# ファイル作成
touch .github/workflows/format.yml

作成したファイルにこのように書いてください!

name: gofmt

on:
  pull_request:
  push:
    branches: [ main ]

jobs:
  gofmt:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-go@v5
        with:
          go-version-file: go.mod
          cache: true

      - name: gofmt -s check
        shell: bash
        run: |
          set -euo pipefail
          # -w はしない(CIでは“差分が出たら落とす”)
          files="$(gofmt -l -s .)"
          if [ -n "$files" ]; then
            echo "These files are not gofmt -s formatted:"
            echo "$files"
            echo
            echo "Run: gofmt -w -s ."
            exit 1
          fi

CIファイルの内容説明

runs-on: ubuntu-latest

GitHubが用意しているUbuntuの仮想環境で実行されます。

- uses: actions/checkout@v4

リポジトリのコードをCI環境にチェックアウトします。
これがないと、CI環境にはソースコードが存在しません。

- uses: actions/setup-go@v5
  with:
    go-version-file: go.mod
    cache: true

go.mod に記載されているGoバージョンを利用
キャッシュを有効にして高速化
これで gofmt コマンドが使用可能になります。

set -euo pipefail

Bashの中断設定
-e : エラーが出たら即終了
-u : 未定義変数をエラー扱い
pipefail : パイプ処理内の失敗も検知
CIではほぼ必須の設定です。

files="$(gofmt -l -s .)"

差分ファイルの取得

  • -l : 整形が必要なファイル名を出力
  • -s : simplify(簡略化オプション)
  • . : リポジトリ全体を対象
    つまり、
    フォーマットされていないファイル一覧を取得
    しています。
if [ -n "$files" ]; then

$files が空でなければ、
= フォーマットが崩れているファイルが存在する
という意味です。

echo "These files are not gofmt -s formatted:"
echo "$files"
echo
echo "Run: gofmt -w -s ."
exit 1

CIを失敗させる
整形が必要なファイルを表示
修正コマンドを表示
exit 1 でジョブを失敗させる
これにより、フォーマットが崩れているコードはマージできない仕組みになります。

動作確認してみよう!

CIフォルダ、ファイル作成

$ mkdir -p .github/workflows
$ touch .github/workflows/format.yml
# でお好みのエディタで適当にCI設定を記載

そういえばPR作成用ブランチを作っていなかったので作成

$ git checkout -b test/gofmt
Switched to a new branch 'test/gofmt'
$ git push -u origin test/gofmt
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a pull request for 'test/gofmt' on GitHub by visiting:
remote:      https://github.com/KM-rira/gofmt-ci/pull/new/test/gofmt
remote:
To github.com:KM-rira/gofmt-ci.git
 * [new branch]      test/gofmt -> test/gofmt
branch 'test/gofmt' set up to track 'origin/test/gofmt'.

go.modも作成する(今の状態だとエラーになるため)

$ go mod init gofmt-ci
go: creating new go.mod: module gofmt-ci
go: to add module requirements and sums:
        go mod tidy
$ go mod tidy

フォーマットができていないファイルを作成する

$ touch main.go

(私の愛しのNeovimエディタは保存時に勝手にフォーマットする設定となっているので、viで編集)

package main

import "fmt"

func main() {
	arr := []int{1, 2, 3}

	// -s(simplify) で簡略化される(0:len(arr) → :)
	s := arr[0:len(arr)]
	fmt.Println(s)

	// -s で簡略化される(int(1) → 1 など)
	x := []int{int(1), int(2), int(3)}
	fmt.Println(x)

	// これは通常の gofmt でも整形される(スペースなど)
	y  :=  1
	fmt.Println(y)
}

このようになればOK

# フォーマットされていないファイルを出力する
$ gofmt -l -s .
main.go

ステージング、コミット、プッシュ!(雑)

$ git add main.go
$ git commit -m "test commit"
[test/gofmt 920de89] test commit
 1 file changed, 19 insertions(+)
 create mode 100644 main.go
$ git push
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 16 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 536 bytes | 536.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To github.com:KM-rira/gofmt-ci.git
   6154612..920de89  test/gofmt -> test/gofmt

お!動いてる!

フォーマットされていないため、期待通りNG!!

ではフォーマットしましょう!

$ gofmt -w -s .

再度コミットプッシュ

$ git add main.go
$ git commit -m "gofmt -w -s"
$ git push

結果は?

OK!!これで安全なGoの明るいフォーマット未来は保証された!!

みんなも導入してみてね✨

ではでは

GitHubで編集を提案

Discussion