そのリリースノート、自動化しませんか?
TL;DR
mainブランチマージ時にGitHub ActionsにてNotionに自動でリリースノートを生成し、Slackへ通知を行いましょう。
用意するのは2ファイルだけ。
コピペで簡単、今日から時短!(韻)
作成したリポジトリはこちら
出来上がりのサンプル(お好みで変更可能)
Notionに生成されたリリースノート
ブランチ名のprefix(fix/~~)などに合わせたアイコンを表示します。
開くと、Pull Request作成時のコメントが表示されます。
Slackの通知
リポジトリ名、PR名、GitHubのURL、NotionのURLを表示しています。
使用するライブラリ
適宜npm
やyarn
に置き換えてください。(初めてpnpm使った!)
pnpm add @notionhq/client @tryfabric/martian ts-node
必要なコードについて
Next.jsのApp Routerを使用し ./src/app/api/releaseNote.mjs
に Notion APIを叩くファイルを配置しています。Next.jsでない場合は、ディレクトリを変えたら動くと思います。
"scripts": {
// 以下を追記。pathは必要に応じて書き換えてください。
"release-note": "ts-node ./src/app/api/releaseNote.mjs",
},
実行するactions
name: release note & slack
on:
pull_request:
types: [closed]
branches:
- main
jobs:
create-release-tag:
runs-on: ubuntu-latest
timeout-minutes: 5
if: github.event.pull_request.merged == true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TZ: "Asia/Tokyo"
strategy:
matrix:
node-version: [18.x]
steps:
- uses: actions/checkout@v3
# 前回のリリースタグを取得する
- name: Get previous tag
id: pre_tag
run: |
echo "::set-output name=pre_tag::$(curl -H 'Accept: application/vnd.github.v3+json' -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' https://api.github.com/repos/${{ github.repository }}/releases/latest | jq -r .tag_name)"
# タグを生成する 「{YYYY.MM.DD}-{当日リリース回数}」
- name: Generate release tag
id: release_tag
run: |
today=$(date +'%Y.%m.%d')
pre_release_date=$(echo ${{ steps.pre_tag.outputs.pre_tag }} | awk -F'-' '{print $1}')
pre_release_count=$(echo ${{ steps.pre_tag.outputs.pre_tag }} | awk -F'-' '{print $2}')
if [[ ! $pre_release_date = $today ]]; then
echo "init count"
pre_release_count=0
fi
echo "::set-output name=release_tag::$today-$(($pre_release_count + 1))"
# 環境変数に情報を保存
- name: Register PR detail
id: pr_detail
# https://docs.github.com/ja/github-ae@latest/webhooks-and-events/webhooks/webhook-events-and-payloads#pull_request
run: |
echo "REPOSITORY_NAME=${{ github.event.repository.name }}" >> $GITHUB_ENV
echo "ASSIGNEE=${{ github.event.pull_request.user.login }}" >> $GITHUB_ENV
echo "PR_URL=${{ github.event.pull_request.html_url}}" >> $GITHUB_ENV
# ブランチ名のprefixからラベル名を取得する
- name: Get label name
id: get_label_name
run: |
branch_type=$(echo ${{github.head_ref}} | cut -d "/" -f1)
if [ $branch_type == 'feature' ]; then
label_name=$(echo "enhancement")
elif [ $branch_type == 'fix' ] || [ $branch_type == 'hotfix' ]; then
label_name=$(echo "bug")
else
label_name=""
fi
echo "::set-output name=label_name::$label_name"
echo "PREFIX_LABEL=$label_name" >> $GITHUB_ENV
# リリースノート作成
- name: Create release note
id: release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.release_tag.outputs.release_tag }}
release_name: ${{ github.event.pull_request.title }}
body: ${{ github.event.pull_request.body }}
draft: false
prerelease: false
# リリースノートの内容を格納
- name: Dump release note
id: release_note
run: |
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
echo "RELEASE_NOTE<<$EOF" >> $GITHUB_ENV
curl -X GET -H 'Accept: application/vnd.github.v3+json' -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' -H 'X-GitHub-Api-Version: 2022-11-28' https://api.github.com/repos/${{ github.repository }}/releases/latest >> $GITHUB_ENV
echo "$EOF" >> $GITHUB_ENV
# インストール(cacheを使用):pnpmの場合は下記を使用してください
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- uses: pnpm/action-setup@v2
name: Install pnpm
id: pnpm-install
with:
version: 7
run_install: false
- name: Get pnpm store directory
id: pnpm-cache
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
# インストール(cacheを使用):yarn の場合は下記を使用してください
# - name: Use Node.js ${{ matrix.node-version }}
# uses: actions/setup-node@v3
# with:
# node-version: ${{ matrix.node-version }}
# cache: yarn
# - name: yarn install
# run: yarn install --frozen-lockfile
# releaseNote実行
- name: Generate release note
run: pnpm run release-note
env:
NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
NOTION_DATABASE_ID: ${{ secrets.NOTION_DATABASE_ID }}
# slack通知
- name: Slack notification
uses: slackapi/slack-github-action@v1.24.0
with:
channel-id: ${{ secrets.RELEASE_SLACK_CHANNEL }}
payload: |
{
"text": "リリースしました🎉\n${{ github.event.repository.name }}",
"attachments": [{
"color": "#10AA39",
"fields": [
{
"title": "${{ github.event.pull_request.title }}",
"value": "${{ github.event.pull_request.html_url }}"
},
{
"title": "${{ steps.release_tag.outputs.release_tag }}",
"value": "${{ secrets.NOTION_DB_PAGE_URL }}"
}
]
}]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_FOR_RELEASE_NOTE }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
Notion APIを叩くファイル
import { Client } from "@notionhq/client";
import { markdownToBlocks } from "@tryfabric/martian";
const MemberList = {
"Akihide-Tsue": "津江",
sample_user_name: "適宜追加してください",
};
async function main() {
const RELEASE_NOTE = process.env.RELEASE_NOTE || '{"body": "中身"}';
const ASSIGNEE = process.env.ASSIGNEE;
const PREFIX_LABEL = process.env.PREFIX_LABEL;
const emoji = () => {
switch (PREFIX_LABEL) {
case "enhancement":
return "🚀";
case "bug":
return "💊";
default:
return "🔧";
}
};
try {
const notion = new Client({ auth: process.env.NOTION_TOKEN });
const release_status = JSON.parse(RELEASE_NOTE);
const date = new Date();
date.setTime(date.getTime() + 1000 * 60 * 60 * 9); // JSTに変換
const params = {
parent: {
database_id: process.env.NOTION_DATABASE_ID,
},
icon: {
type: "emoji",
emoji: emoji(),
},
properties: {
// NotionのDBの各項目名と一致する必要があります
Title: {
title: [
{
text: {
content: release_status.name,
},
},
],
},
"Release date": {
date: {
start: date,
time_zone: "Asia/Tokyo",
},
},
Assignee: {
rich_text: [
{
text: {
content: MemberList[ASSIGNEE] || ASSIGNEE,
},
},
],
},
URL: {
url: process.env.PR_URL,
},
},
children: markdownToBlocks(release_status.body),
};
// @ts-ignore
await notion.pages.create(params);
} catch (e) {
console.error("error:", e);
}
}
main();
必要なsecret(環境変数)について
以下のsecretを該当リポジトリの Settings > secrets and variables > New repository secret から登録してください。
- NOTION_TOKEN
→ Notion のAPI token - NOTION_DB_PAGE_URL
→ 更新するNotionのDBのURL - NOTION_DATABASE_ID
→ NOTION_DB_PAGE_URLのid部分: 参考 - RELEASE_SLACK_CHANNEL
→ 通知したいSlackチャンネルのid - SLACK_WEBHOOK_FOR_RELEASE_NOTE
→ インテグレーションのincoming-webhookのid
Notionのコネクトの設定はこちらの記事に詳しく説明があります。
Notion API を使用してデータベースを操作する
必要な設定
こちらの記事を参考にしました。
Notionのコネクトをお忘れなく。
また、Actionsの権限も変更が必要です。
Settings > Actions > General > Workflow permissions は Read and write permissions を選択
VSCodeのおすすめ拡張機能
GitHub Actions
コード補完と作業リポジトリでsecretsが登録されていない場合に教えてくれます。
最後に
Notionに画像が文字列のURLで表示されるので、画像として表示したいです。どなたか対応方法ご存知でしたら教えてください。
GitHub ActionsもApp Routerも今回始めて書いたので、使い方間違っていたらすみません。
参考記事だとtsファイルを実行してNotion API叩いてますが、エラーだったのでmjsファイルにしています。どうしたらいいのか...
なにかありましたらコメントください。
それでは Happy release note!! 🎉
参考記事
Discussion