GitHub Releaseを触ってみた話

## はじめに

最近私の中でGitHubについて理解を深めようキャンペーンが開催されています。
というわけで今回はGitHubのRelease機能について触ってみることにしました。

前回のGitHubの記事はこちら

https://qiita.com/nanana08/items/76a63b5daaa73e0a3348

この記事はTDCソフト株式会社Advent Calendarの8日目です。

https://qiita.com/advent-calendar/2024/tdc-soft


## GitHub Releaseってなんだ？

GitHub上でライブラリやソフトウェアのリリースを管理できる機能のこと。
Gitのタグに紐づいて管理・作成されます。

リポジトリの赤枠部分に載ってるやつですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125818/3f1eadff-e7f3-a8cd-cd15-6476bee09f6f.png)

リリースのリンクを押下すると、リリースノートが表示されるほか、ソースコードやリリースされたソフトウェアといったアセットのダウンロードが出来たりします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125818/c5200880-8b24-3e84-a46a-106cede8cb6c.png)

※画像は[TypeScriptのGitHubリポジトリ](https://github.com/microsoft/TypeScript)

## リリースを作ってみよう

適当なリポジトリを開き、`Create a new release`を押下してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125818/7e26026b-a2a6-a644-5a87-3bebc0f5cbe1.png)

既存のタグor新規タグに紐づけてリリースを作成できます。
リリースノートやソースコード以外に紐づけたいアセットなんかを指定してあげるだけっぽいですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125818/49c5fe65-ee10-5fc1-af27-86c84bbcfacb.png)

`Publish release`を押したらリリースの作成が完了です。
とっても簡単ですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125818/6169f78b-72b7-549d-fccb-f69d6abe4441.png)

### リリースノートのカスタマイズ

さて、リリースを作成するまではできましたがこのままでは味気ないのでリリースノートをカスタマイズしてみましょう。

リポジトリに`.github/release.yml`ファイルを追加することでリリースノートを自動生成することが出来ます。

↓[公式doc](https://docs.github.com/ja/repositories/releasing-projects-on-github/automatically-generated-release-notes#example-configurations)からコピペしてきたrelease.yml

```.github/release.yml
changelog:
  exclude:
    labels:
      - ignore-for-release
    authors:
      - octocat
  categories:
    - title: Breaking Changes 🛠
      labels:
        - Semver-Major
        - breaking-change
    - title: Exciting New Features 🎉
      labels:
        - Semver-Minor
        - enhancement
    - title: Other Changes
      labels:
        - "*"
```

#### exclude
リリースノートから排除したいラベルやユーザを指定します。
今回は`ignore-for-release`というラベルの付いたPRや`octocat`ユーザのPRをリリースノートに載せる情報から除外しています。

#### categories
リリースノートに載せる変更情報のカテゴリを指定します。
今回はメジャーリリース、マイナーリリース、その他のリリースの3つのカテゴリを設定しています。

### どんな感じ？

`release.yml`を追加し、適当にいくつかPRをマージした後にリリースを作成してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125818/789254b1-a683-08a1-378d-f58fcd54253d.png)

PRのラベルに紐づいて変更内容を自動で記載してくれていますね。

## 自動化してみたい
ここで終わってもつまらないのでGitHubActionsを使って自動リリースを試してみましょう。

### ワークフロー

必要最低限の要件として以下2点を満たすようとりあえず動かしたワークフローがこちらです。
* タグが追加されたらリリースを作成する
* アセットにビルドしたアーティファクトを追加する

※プロジェクトは[前回](https://qiita.com/nanana08/items/76a63b5daaa73e0a3348#%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E6%BA%96%E5%82%99)用意したものを流用しています。
```.github/workflows/create_release.yml
name: Release
run-name: release

# タグがプッシュされたら実行する
on: 
  push:
    tags:
      - "v*"

jobs:
  release:
    runs-on: ubuntu-latest

    steps:
      # リポジトリをチェックアウトする
      - name: Checkout repository
        uses: actions/checkout@v4

      # Node.jsを使用する
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20.x'

      # 依存関係をインストール
      - name: Install dependencies
        run: npm install -D

      # ビルドを実行
      - name: Run build
        run: npm run build

      # 1つ前のタグを取得
      - name: Get Previous Tag
        id: get_pre_tag
        run: |
          PRE_TAG=$(git tag --sort=creatordate | tail -n 2 | head -n 1)
          echo "pre_tag=$PRE_TAG" >> $GITHUB_OUTPUT
          echo "previous_tag: $PRE_TAG"
      
      # 前回リリースからの差分をもとに、変更点を取得する
      - name: Generate Release Note
        id: generate_release_note
        run: |
          echo "$(
          curl -X POST \
            -H 'Accept: application/vnd.github.v3+json' \
            -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' \
            https://api.github.com/repos/${{ github.repository }}/releases/generate-notes \
            -d '{
              "tag_name": "${{ github.ref_name }}",
              "previous_tag_name": "${{ steps.get_pre_tag.outputs.pre_tag }}",
              "target_commitish": "main"
            }' | jq .body | sed 's/\\"//g' | sed 's/["“]//g' | sed 's/\\n/\n/g'
          )" >> RELEASE_NOTE

      # リリースを作成
      - name: Create GitHub Release
        id: create_release
        uses: actions/create-release@v1.1.4
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref_name }}
          release_name: Release ${{ github.ref_name }}
          body_path: ./RELEASE_NOTE
          draft: false
          prerelease: false

      # 出力ファイルを圧縮
      - name: Compress bundle
        run: |
          mkdir -p artifacts
          zip -r artifacts/build.zip dist/

      # アセットをアップロード
      - name: Upload release Asset
        uses: actions/upload-release-asset@v1.0.1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: ./artifacts/build.zip
          asset_name: build.zip
          asset_content_type: application/zip
```

#### リリースノート作成
```yml
# 前回リリースからの差分をもとに、変更点を取得する
- name: Generate Release Note
  id: generate_release_note
  run: |
    echo "$(
    curl -X POST \
      -H 'Accept: application/vnd.github.v3+json' \
      -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' \
      https://api.github.com/repos/${{ github.repository }}/releases/generate-notes \
      -d '{
        "tag_name": "${{ github.ref_name }}",
        "previous_tag_name": "${{ steps.get_pre_tag.outputs.pre_tag }}",
        "target_commitish": "main"
      }' | jq .body | sed 's/\\"//g' | sed 's/["“]//g' | sed 's/\\n/\n/g'
    )" >> RELEASE_NOTE
```
[GitHub API](https://docs.github.com/ja/rest/releases/releases?apiVersion=2022-11-28#generate-release-notes-content-for-a-release)を利用して1つ前のタグとの差分リリースノートを生成・出力しています。

#### リリースの作成
```yml
# リリースを作成
- name: Create GitHub Release
  id: create_release
  uses: actions/create-release@v1.1.4
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  with:
    tag_name: ${{ github.ref_name }}
    release_name: Release ${{ github.ref_name }}
    body_path: ./RELEASE_NOTE
    draft: false
    prerelease: false
```
`actions/create-release`というアクションを使用し、リリースの作成を行っています。
タグ名・リリース名はシンプルにpushされたタグ名をそのまま使用しています。

#### アセットの配置
```yml
# 出力ファイルを圧縮
- name: Compress bundle
  run: |
    mkdir -p artifacts
    zip -r artifacts/build.zip dist/

# アセットをアップロード
- name: Upload release Asset
  uses: actions/upload-release-asset@v1.0.1
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  with:
    upload_url: ${{ steps.create_release.outputs.upload_url }}
    asset_path: ./artifacts/build.zip
    asset_name: build.zip
    asset_content_type: application/zip
```
`actions/upload-release-asset`アクションを利用しリリースに紐づくアセットを配置しています。
`upload_url`にはリリースの作成時に出力されたアセットのアップロード用URLを指定しています。

:::note warn
`actions/create-release`・`actions/upload-release-asset`は共に廃止が予定されている`set-output`コマンドを使用しているため、実行時にアラートが出ます。
:::

今回はお試しなので簡易なものを使用しましたが、実際に運用するには別のアクションを利用するなりした方がよさそうです。
↓アラートの様子
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125818/a038964f-5318-7619-8e60-60d6611077d7.png)


https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/

### 動かしてみよう
ワークフローを作ったところで適当にいくつかPRをマージし、タグを追加してみます。

```sh
git tag v2.0.0
git push origin v2.0.0
```

ワークフローが動きだしました。（ワークフローの数に試行回数が現れている）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125818/e4eff05c-3148-bfbd-af85-ee3e8faaf708.png)


リリースが作成され、前バージョンとの差分も記載されているほか、アセットにもbuild.zipが配置されています。
これでタグの追加に応じて自動でリリースを作成するワークフローができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125818/131b2bc8-2bb4-3976-9f73-e2da355c4fdd.png)



## おわりに
今回はGitHub Releaseとは何ぞやというところから実際にどうやって使うんだろう？の入門編という形でやってきましたが、前回学んだGitHubActionsと合わせてそれっぽい学びができたのではないかと思います。

まだまだ私の知らないGitHubの機能はたくさんあるので今後もGitHubについて理解を深めようキャンペーンを継続していきたいですね。


## 参考
https://docs.github.com/ja/repositories/releasing-projects-on-github/about-releases

https://docs.github.com/ja/actions

https://qiita.com/itouoti/items/85f2cf796d1fb3217ca7

https://zenn.dev/rehabforjapan/articles/github-actions-release-note