スタンドアップを自動化しよう
昨日のLinear課題とGitHubコミットを読み取り、スタンドアップ更新を整形してSlackに投稿します。
ステップ1: セットアップ確認
必要な環境変数が設定されていることを確認します:
echo "LINEAR_API_KEY: ${LINEAR_API_KEY:+set}"
echo "SLACK_WEBHOOK_URL: ${SLACK_WEBHOOK_URL:+set}"
echo "GITHUB_REPO: ${GITHUB_REPO:-not set}"
echo "GITHUB_USERNAME: ${GITHUB_USERNAME:-not set}"
LINEAR_API_KEYが不足している場合: 停止します。ユーザーに伝えてください:「LINEAR_API_KEYが必要です。Linear → 設定 → API → 個人用APIキーから取得し、.envファイルに追加してください。」
SLACK_WEBHOOK_URLが不足している場合: 停止します。ユーザーに伝えてください:「SLACK_WEBHOOK_URLが必要です。api.slack.com/apps → あなたのアプリ → Incoming Webhooksで受信Webhookを作成し、.envファイルに追加してください。」
GITHUB_REPOが不足している場合: 続行します。GitHubコミットはスキップされます。その旨をユーザーに通知してください。
ステップ2: Linearアクティビティを取得
昨日の日付をISO 8601形式で計算します(例:2026-04-09T00:00:00.000Z)。
現在のユーザーIDを取得:
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: Bearer $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "query { viewer { id name email } }"}'
レスポンスからidフィールドを抽出します。LINEAR_USER_IDとして保存します。
自分に割り当てられ、昨日以降に更新された課題を取得:
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: Bearer $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "query($since: DateTime!, $userId: ID!) { issues(first: 50, filter: { assignee: { id: { eq: $userId } } updatedAt: { gte: $since } }) { edges { node { identifier title state { name } url completedAt updatedAt createdAt } } } }",
"variables": {"since": "YESTERDAY_ISO", "userId": "LINEAR_USER_ID"}
}'
課題を分類:
completedAtがnullでない → 完了state.nameが「In Progress」「Started」「In Review」のいずれか → 進行中state.nameが「Cancelled」 → スキップstate.nameが「Todo」または「Backlog」 → スキップ(作業されていない)
課題がゼロの場合:「昨日のLinearアクティビティは見つかりませんでした。」と記載します。
ステップ3: GitHubコミットを取得
GITHUB_REPOが設定されていない場合は、このステップを静かにスキップします。
GITHUB_REPOが設定されている場合:
gh api "repos/$GITHUB_REPO/commits?author=${GITHUB_USERNAME:-$(gh api user --jq .login)}&since=YESTERDAY_ISO&per_page=30" \
--jq '[.[] | {message: .commit.message, url: .html_url}]'
コミットを処理:
- 各コミットメッセージの最初の行を抽出(最初の改行より前)
- マージコミットをスキップ:「Merge」で始まるメッセージは除外
- メッセージテキストで重複を排除
GITHUB_REPOが設定されているがコミットがゼロの場合:「昨日のコミットは見つかりませんでした。」と記載します。
ステップ4: スタンドアップを整形
references/standup-format.mdを事前に全文読んでください。
以下の正確な構造でスタンドアップを作成します:
**完了**
- [ENG-123] 完了した課題のタイトル
- fix: コミットメッセージ
**進行中**
- [ENG-124] 進行中の課題のタイトル
**ブロッカー**
ブロッカーはありません。
standup-format.mdからのルール:
- 一人称代名詞(「私は」「私たちは」)は使用しない
- 完了項目は過去形、進行中項目は現在進行形
- 各Linear項目は
[IDENTIFIER] タイトル形式 - 各GitHubコミットはコミットメッセージの最初の行
- 完了項目がない場合:「完了した項目はありません。」と記載
- 進行中項目がない場合:「進行中の項目はありません。」と記載
- ブロッカーがない場合:「ブロッカーはありません。」と記載
- 合計200語未満
ステップ5: Slackに投稿、または出力
整形したスタンドアップをユーザーに提示します。
「これをSlackに投稿しますか、それとも出力だけにしますか?」と尋ねます。
投稿の確認を得た場合:
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*スタンドアップ — DATE_HERE*\n\n*完了*\nITEMS\n\n*進行中*\nITEMS\n\n*ブロッカー*\nITEMS"
}
}
]
}'
コミットメッセージや課題タイトルに特殊文字が含まれる場合のシェル引用問題を避けるため、一時ファイルまたはヒアドキュメントを使用してボディを渡します:
cat > /tmp/standup-payload.json << 'ENDJSON'
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "STANDUP_CONTENT_HERE"
}
}
]
}
ENDJSON
curl -s -X POST "$SLACK_WEBHOOK_URL" -H "Content-Type: application/json" -d @/tmp/standup-payload.json
投稿後:「スタンドアップを投稿しました。」
「出力のみ」の場合: コードブロック内にスタンドアップを表示してコピー可能にします。