Bitbucket→GitHub 移行 その3～CIまわり～

Mercurial 使いが Git を使い始め、GitHub にお世話になりはじめた記録です。

* [x] [リポジトリ変換](https://qiita.com/chimatter/items/41f69aa87138538bd524)
* [x] [GitHub](https://qiita.com/chimatter/items/88fc40ecf4b0d3a345dd)
* CIまわり ←今ここ
* (ほかあるかな…？)

もっぱら Go を使ってツールを作っています。

この記事では、CI の仕組みで自動的にリリースしていく方法として、
GitHub Actions 上で [GoReleaser](https://github.com/goreleaser/goreleaser) を使って、タグごとに GitHub Releases にバイナリをアップする設定をしていきます。

# master→main

別にやらなくても、このあとの GitHub Actions の作業や成否には影響しません。

[Git(GitHub)のデフォルトブランチを改名する](https://qiita.com/e_chan1007/items/ad3e849b7e04fcf42fad) にもありますが、デフォルトのブランチ名をmainに変更します。

上記の記事では、ローカルでブランチを切り替えてからそれを push し、GitHub 上でデフォルトブランチを変更する設定をしています。
ローカルでのブランチ切り替えを忘れることがないので、その方法が良いと思います。
__いずれにしても、GitHub のデフォルトブランチは GitHub サイト上でないとできない模様。__

「ひとまず GitHub 上だけの変更で良い」という場合は、GitHub サイト上で完結します。(下記の手順)
ただ、このあと GitHub Actions 絡みでファイルの変更をしますので、サイト上で完結することに拘らなくても良いです。

## GitHub 上でブランチ main を作成する

> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32149/317adfc2-7085-34c2-f91d-b618ec0c9072.png)

↓

"main" って入れる
> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32149/afa21a13-c8a5-ddc6-dc21-3cce40da5bbd.png)

この時点では、まだデフォルトブランチは変わっていません。
(↓ "default" は master についている)
> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32149/0496ea64-3ea9-2f50-6473-868be3ed9136.png)


## デフォルトブランチを変更

ブランチの一覧を表示
> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32149/29606a88-1d4b-a488-87c0-b7bc326f8cf9.png)

↓

"Change default branch" をクリック
> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32149/fdec949e-1cb9-4431-b3e0-da4b9c3fb1cd.png)

↓

main に切り替えて、隣の "Update" ボタンを押す
> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32149/390c2c0a-b577-84ed-7084-7d49e965336f.png)

↓

ブランチ一覧のページに戻り、master のところにあるゴミ箱アイコンをクリック
> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32149/247f56e7-cf69-7eaf-822b-dc3e16f64e7b.png)

↓

こうなる
> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32149/5620c836-cf5c-5b16-ee0d-b0eb6d18733c.png)

## ローカルで switch

```
git pull
git switch main
```

これで、ブランチ変更の手順はおしまいです。

# GitHub Actions

## 2つのファイルを作成・配置する

以下の2つのファイルを作成します。

* .github/workflows/xxx.yml
* goreleaser.yml

作成するファイルの配置場所
> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32149/fb10231d-98d8-d85a-f40b-8fc98aa1614d.png)

ファイルの内容は、下記参照。

## .github/workflows/release.yml

ファイル名は別に release.yml でなくても良いようですが。

```yaml

name: release
on:
  push:
    tags:
    - "v[0-9]+.[0-9]+.[0-9]+"
jobs:
  goreleaser:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Setup Go
        uses: actions/setup-go@v2
      - name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v2
        with:
          version: latest
          args: release --rm-dist
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

もっぱら `uses: xxx` を使って記述していますが、`run: xxx` でシェル上のようにコマンドを使えます。

GoReleaser が git dirty な状態を許さないので、go get でツールをダウンロードして使った場合は GoReleaser の実行前に `run: go mod tidy` をする必要があるかもしれません。

Action は `git push --tags` をしたタイミングで実行するようにしています。
GoReleaser が同じタグに対して複数回リリースできないようなので。
あと、冒頭の記述を `on: push: branches: - main`(改行省略)にしておくと、何故か、そもそも Action が実行されなかった。

## goreleaser.yml を追加

```yaml
project_name: vvin
env:
  - GO111MODULE=on
before:
  hooks:
    - go mod tidy
builds:
  - binary: vvin
    flags:
      - -trimpath
    ldflags:
      - -s -w
      - -X main.Version={{.Version}}
      - -X main.Revision={{.ShortCommit}}
    env:
      - CGO_ENABLED=0
    goos:
      - windows
      - darwin
      - linux
    goarch:
      - amd64
      - 386
    hooks:
      post: upx --lzma '{{ .Path }}'
archives:
  - name_template: '{{ .ProjectName }}_v{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
    replacements:
      darwin: darwin
      linux: linux
      windows: windows
      386: 386
      amd64: amd64
    format_overrides:
      - goos: windows
        format: zip
release:
  prerelease: auto
```

:heart_eyes: リリース系のツールの中でも、`-trimpath` をつけられたり upx を実行できたりするのが有り難いです。

なお、git のタグが `v1.2.3` の場合 `{{ .Version }}` は `1.2.3` になるようです。

また、`goreleaser init` をすれば、`.goreleaser.yml` の雛形を作ってくれます。
上記の内容とは違いますが。

### アーカイブにファイルを追加したい場合

GitHub Releases にリリースするものに色々含めたい場合は、`archives:`に追記します。

```yaml
archives:
  - name_template: '{{ .ProjectName }}_v{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
    replacements:

      :

    files:
      - LICENSE*
      - README*
      - sample.bat
```

`files:` のデフォルトは `LICENSE*`, `README*` のようです。
が、上記のように `files:` を記述した場合はその設定が消えてしまうようですので、デフォルト値も含めて記述する必要があります。

## push

上記の変更をコミットした後 `git push` して、タグを新たに振って、こちらも `git push --tags` します。

タグは `v{Major}.{Minor}.{Patch}` の形式で振ります。
上で設定している release.yml の指定にもある通り、この形式のタグをプッシュしたタイミングでのみ実行されます。

## 結果

> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32149/c3dabc1d-daea-6e3c-2e1c-228d2fb6edab.png)

(ファイルが少ないですが、上記の .goreleaser.yml を Windows 向けバイナリのみに変更しています)

# CircleCI と比較して

BitBucket 上で Mercurial を使っていた頃は CircleCI を使っていました。
GitHub に乗り換えたことをきっかけに、せっかくなので GitHub Actions を体験してみたかったこともあり、乗り換えてみました。

CircleCI はフリープランで使っていますが、そちらで10秒ほどだった処理が、GitHub Actions では30秒ほどかかるようになりました。

あと、これは GoReleaser の仕様にまつわる部分だと思いますが、タグを変えないと上手く Releases にアップできないようです。
機能は変わってないのでタグは変えたくない、という場合に少しストレス…