概要
- 【参考】親記事
React Native + Expo(EAS)で開発している iOS アプリのリリース作業について、開発を続けていく中でいくつか自動化できる箇所が出てきました。具体的には、①リリースノート作成(GitHub) と ②iOSアプリ提出(App Store) の2つであり、Claude Code のスキルを使って半自動化できたので今回はそれを記事にしました。
具体的なスキルは以下の2つです。
- 【
/myapp-release-draft <version>】develop→mainのリリース PR 作成、バージョン更新、GitHub Release ドラフト生成までの「リリースノート作成フェーズ」。 - 【
/myapp-deploy】mainマージ後に Lint・型チェック →eas build --auto-submitで本番ビルド & App Store 提出、ストア掲載テキスト生成までの「アプリ提出フェーズ」。
設計の軸は 「人間の承認ポイントを残したまま、定型作業だけを潰す」 ことです。各スキルは SKILL.md という Markdown ファイルに手順とメタデータを書くだけで作成しています。また、リリースフロー全体の流れは以下のとおりです。赤色に示す通り、適宜実行前に人間の承認(GO サイン)を挟んでいます。
背景
個人開発でアプリを継続的にアップデートしていると、リリースのたびに同じ作業を繰り返すことになります。
-
app.jsonのバージョン番号を上げる -
developからmainへの PR を、毎回同じフォーマットで作る - コミットログを
feat:/fix:などで分類してリリースノートに整形する - GitHub Release のドラフトを作る
- マージ後に Lint・型チェックを通してから EAS の本番ビルドを叩く
- App Store Connect 用のプロモーション文・最新情報を書く
個々の作業は難しくないのですが、手順を一つ飛ばすと事故るタイプの作業です。バージョンの上げ忘れ、ビルド番号の不整合、リリースノートの体裁崩れ、など地味なミスが起きやすく、しかもリリース直前という一番ミスしたくないタイミングで発生します。
一人開発だと自分以外のレビュー担当もいないため「自分の注意力」だけが品質ゲートになってしまい、なんとか半自動化できないかを模索していました。そこで、手元の Claude Code を使ってリリース手順そのものを「実行可能なドキュメント」としてスキル化することにしました。手順書をただ書くのではなく、Claude が読んでそのまま実行できる形にすれば、手順書のメンテと自動化が同時に達成できる、という狙いです。
どうやって解決したのか
Claude CodeのSKILL.mdを使って解決しています。.claude/skills/<skill-name>/SKILL.mdを作成することでCLIで/<skill-name>を使うことができます。
今回で言うと.claude/skills/myapp-release-draft/SKILL.mdと.claude/skills/myapp-deploy/SKILL.mdを作成することで、/myapp-release-draftと/myapp-deployの2つのスキルを呼び出すことができます。SKILL.md には メタデータと手順をそれぞれ書きます。
スキル①:/myapp-release-draft — リリース PR の下書きを作る(.claude/skills/myapp-release-draft/SKILL.md)
メタデータ
---
name: myapp-release-draft
description: develop→main へのリリース PR を作成する。引数にリリースバージョン(例: 3.0.0)を必ず指定すること。app.json のバージョンを指定バージョンに更新してコミット・プッシュし、PR と CONTRIBUTING.md テンプレートに基づくリリースノートドラフトを生成する。使用例: /myapp-release-draft 3.0.0
hint: 引数にリリースバージョンを必ず指定してください(例: /myapp-release-draft 3.0.0)。develop ブランチ上で実行してください。
tools: Bash, Read, Edit
allowed-tools:
- Bash(git branch *)
- Bash(git status *)
- Bash(git fetch *)
- Bash(git log *)
- Bash(git add *)
- Bash(git commit *)
- Bash(git push *)
- Bash(cd *)
- Bash(eas build:list *)
- Bash(gh pr create *)
- Bash(gh release create *)
- Read(src/MyApp/app.json)
- Edit(src/MyApp/app.json)
---
あなたはリリースエンジニアとして以下の手順を順番に実行します。途中でエラーが発生した場合は処理を停止してユーザーに報告してください。
> **前提**: このスキルはリポジトリルート(`.claude/` や `CLAUDE.md` がある階層)を作業ディレクトリとして実行することを前提とします。本ドキュメント中のパスはすべてリポジトリルートからの相対パスです。
## 引数
`$ARGUMENTS` にリリースバージョン文字列(例: `3.0.0`)が渡されます。
引数が空の場合は「バージョンを引数に指定してください(例: /myapp-releases-draft 3.0.0)」と伝えて処理を停止する。
## 定数
- **新バージョン**: `$ARGUMENTS` <!-- $ARGUMENTS に引数のバージョン情報が格納されます -->
- **アプリリポジトリ**: リポジトリルート(このスキルを実行している作業ディレクトリ)
- **app.json パス**: `src/MyApp/app.json`
- **GitHub リポジトリ**: `...`
---
## 手順
...
description と hint は、スキルをいつ・どう呼び出すかを Claude 自身に伝えるための記述です。そしてallowed-toolsはこのスキルが実行してよいツール/コマンドのホワイトリストです。上記なら以下の4つの操作が許可されています。
- Git操作(
git) - GitHub操作(
gh *) - EAS操作(
eas build:list) -
app.jsonへの読込・編集
上記にない操作、例えば、rm のような破壊的コマンドや無関係なファイルへの書き込みは構造的に弾かれます。自動化と安全性を両立させる土台になります。
上記のメタデータの説明のほか、本文の初めの一文、スキル内で使用する引数や定数などの情報をファイル冒頭に記載することで、スキルで使用するデータをClaudeに認識させます。
手順
develop ブランチ上で /myapp-release-draft 3.0.0 のようにバージョンを引数($ARGUMENTS)で渡して実行します。SKILL.md には冒頭のメタデータ・定数・引数に加え、次の7ステップが手順として記述されています。
1. 事前確認。 まずブランチと作業ツリーの状態をチェックします。
git branch --show-current
git status --porcelain
- 現在のブランチが
developでなければ停止し「developブランチに切り替えてから実行してください」と伝える - uncommitted な変更がある場合は停止し、変更内容をリストアップしてユーザーに確認を求める
「間違ったブランチでリリースを切る」事故を最初に防ぎます。
2. バージョンの確認。 app.json の expo.version を読み取り、次の形でユーザーに承認を求めます。承認を得てから次に進みます。
現在のバージョン: <app.json の expo.version>
新バージョン: $ARGUMENTS
バージョンをこの内容で更新してよいですか?
3. コミット一覧の取得と分類。 main との差分コミットを取得し、プレフィックスで3グループに分類します。
git fetch origin
git log origin/main..develop --oneline
-
機能改修リスト:
feat:で始まるコミット -
不具合修正リスト:
fix:で始まるコミット -
改善リスト:
refactor:/chore:で始まるコミット - 備考リスト: 上記以外で始まるコミット
このとき、コミットメッセージのプレフィックス(feat: 等)は除去し、PR 番号(#NNN)は末尾に残します。後段のリリースノート整形にそのまま流用できます。
4. app.json の更新(バージョン + ビルド番号)。 まず EAS から直近の production ビルドのビルド番号を取得します。
cd src/MyApp && eas build:list --platform ios --profile production --status finished --limit 1 --json --non-interactive
JSON 出力の appBuildVersion フィールドがビルド番号(CFBundleVersion)です。取得できない場合はユーザーに現在のビルド番号を確認します。続いて Edit ツールで app.json の2フィールドを同時に書き換えます。
| フィールド | 更新値 |
|---|---|
expo.version |
$ARGUMENTS |
expo.ios.buildNumber |
取得したビルド番号(文字列) |
ios.buildNumber はウィジェットのバージョンとして使われるため、EAS の実績値と同期させておく必要があります。手入力ではなく EAS の値を正として取り込むことで、審査やビルドで詰まる事故を防ぎます。更新後はコミット & プッシュ。
git add src/MyApp/app.json
git commit -m "chore: バージョンを Ver$ARGUMENTS に更新"
git push origin develop
5. リリース PR の作成。 以下の PR フォーマットに従い、本文テンプレートをステップ3の分類結果で埋めて gh pr create を実行します。
gh pr create \
--repo your-org/your-app \
--base main \
--head develop \
--title "release: Ver$ARGUMENTS" \
--body "$(cat <<'EOF'
## 変更内容
<ステップ3で分類したコミット一覧を箇条書きで記載(feat/fix/refactor等を含む)>
## 変更理由
- Ver$ARGUMENTS のリリース
## 動作確認方法
- develop ブランチでの動作確認済み
## レビュー観点
- リリース内容に漏れ・誤りがないこと
- バージョンが正しく更新されていること(app.json: Ver$ARGUMENTS)
## 懸念点
-
## その他
-
EOF
)"
6. リリースノートの整形 + GitHub Release ドラフト作成。 ステップ3の分類結果をもとに以下のフォーマットに従って整形します。
# 変更一覧
- **リリース日**: YYYY年MM月DD日
- [App Store リンク](<App Store の URL>)
## 👍機能改修
### <機能改修リストの各項目> #<PR番号>
## 🐛不具合修正
### <不具合修正リストの各項目> #<PR番号>
## 🔄改善
### <改善リストの各項目> #<PR番号>
## ⚠️注意
-
## ✍備考
- iOSアプリ
- 該当するコミットがないセクションは省略する
-
## ✍備考には備考リストのコミットを記載し、- iOSアプリは末尾に残す
整形したリリースノートを一度ユーザーに提示して修正の有無を確認してから、--draft で GitHub Release を作成します(公開はしない)。
gh release create "Ver$ARGUMENTS" \
--repo your-org/your-app \
--title "Ver$ARGUMENTS" \
--notes "<確認済みのリリースノート内容>" \
--draft
タグは Ver$ARGUMENTS(例: Ver3.0.0)。作成後は Release の URL を記録します。
7. 完了報告。 最後に次の形でまとめて報告して終了です。
✅ リリース PR と GitHub Release ドラフトを作成しました
バージョン: <旧バージョン> → $ARGUMENTS
PR URL: <作成された PR の URL>
Release URL: <作成された GitHub Release の URL>
--- リリースノートドラフト ---
<ステップ6で確認済みのリリースノート内容>
ここまでが下書きフェーズで、実際の main へのマージはレビューを経て人間が行います。
スキル②:/myapp-deploy — マージ後に本番ビルド & 提出(.claude/skills/myapp-deploy/SKILL.md)
リリース PR を main にマージしたら、main ブランチ上で /myapp-deploy を実行します。フロントマターは次のとおりで、allowed-tools は引数までほぼ固定の形でホワイトリスト化しています。
メタデータ
---
name: myapp-deploy
description: main ブランチへのリリース PR マージ後に実行するデプロイスキル。Lint・型チェックの事前確認を行い、eas build --auto-submit で iOS プロダクションビルド&App Store 提出を一括実行して結果を報告する。使用例: /myapp-deploy
hint: main ブランチ上で実行してください。EAS CLI にログイン済みであることを確認してください(eas whoami)。
tools: Bash, Read
allowed-tools:
- Read(src/MyApp/app.json)
- Bash(git branch *)
- Bash(git status *)
- Bash(git pull *)
- Bash(cd *)
- Bash(eas whoami)
- Bash(npm run lint)
- Bash(npx tsc --noEmit)
- Bash(eas build --platform ios --profile production --auto-submit --non-interactive)
- Bash(gh release view *)
---
あなたはリリースエンジニアとして以下の手順を順番に実行します。途中でエラーが発生した場合は処理を停止してユーザーに報告してください。
> **前提**: このスキルはリポジトリルート(`.claude/` や `CLAUDE.md` がある階層)を作業ディレクトリとして実行することを前提とします。本ドキュメント中のパスはすべてリポジトリルートからの相対パスです。
## 定数
- **アプリリポジトリ**: リポジトリルート(このスキルを実行している作業ディレクトリ)
- **作業ディレクトリ**: `src/MyApp`
- **app.json パス**: `src/MyApp/app.json`
本文は同じく「あなたはリリースエンジニアとして…」で始まり、定数としてアプリリポジトリ・作業ディレクトリ(src/MyApp)・app.json パスを固定したうえで、次の手順を順に実行します。
手順
1. 事前確認。 ブランチと作業ツリーの状態を確認します。
git branch --show-current
git status --porcelain
- 現在のブランチが
mainでなければ停止し「mainブランチに切り替えてから実行してください」と伝える - uncommitted な変更がある場合は停止し、変更内容をリストアップして確認を求める
2. 最新コードへの同期。
git pull origin main
3. EAS ログイン確認。 失敗したら停止し「eas login でログインしてから実行してください」と伝えます。
cd src/MyApp && eas whoami
4. デプロイ対象バージョンの確認。 app.json の expo.version を読み取り、次の形で承認を求めます。
デプロイ対象バージョン: <app.json の expo.version>
以下の内容でデプロイを開始してよいですか?
- platform: iOS
- profile: production
- auto-submit: 有効(ビルド完了後に App Store Connect へ自動提出)
5. Lint チェック & 型チェック。 ビルドを叩く前に必ず通し、エラーが出たらその時点で停止して内容を報告します。CI が軽い個人開発でも、最低限のゲートをリリース直前に必ず通す運用にできます。
cd src/MyApp && npm run lint && npx tsc --noEmit
6. EAS ビルド & 自動提出。 ゲート通過後に本番ビルド。--auto-submit で完了後に App Store Connect へ自動提出、--non-interactive で対話なし実行します。
cd src/MyApp && eas build --platform ios --profile production --auto-submit --non-interactive
ビルドは EAS サーバー上で非同期に走るので、完了を待たずに EAS ダッシュボードの URL を提示して次へ進みます。
7. 完了報告。 次の形でビルド開始を報告します。
✅ EAS ビルド&サブミットを開始しました
バージョン: <app.json の expo.version>
プラットフォーム: iOS
プロファイル: production
auto-submit: 有効
ビルドの進捗は EAS ダッシュボードで確認してください:
<EAS ダッシュボード URL>
ビルド完了後、自動的に App Store Connect へ提出されます。
8. App Store Connect テキスト生成。 最後に最新リリースのリリースノートを取得します。
gh release view --json tagName,body
取得したリリースノート(👍機能改修 / 🐛不具合修正 / 🔄改善 セクション)をもとに、App Store Connect に貼り付ける2テキストを日本語で生成します。SKILL.md には生成方針がそのまま指示として書かれています。
プロモーション用テキスト(Promotional Text)は、App Store のアプリページ上部に表示されるマーケティング文で、170文字以内(超過したら短縮)。今回のリリースで追加・改善された主要機能を、ユーザー目線で「何が嬉しくなったか」を端的に訴求します。最新情報(What's New)は、アップデート画面に表示されるリリースノートで、機能改修・不具合修正・改善を箇条書きにし、専門用語を避け、先頭に「Ver<バージョン番号> アップデート内容」の見出しを付けます。
出力フォーマットは次のとおりです。
---
📣 プロモーション用テキスト(170字以内)
<生成したプロモーション用テキスト>
文字数: <文字数>/170
---
📝 最新情報(What's New)
Ver? のアップデートをお届けします!
■ 内容1
【詳細】
■ 内容2
【詳細】
...
---
工夫したこと
以上がSKILL.mdの内容になります。開発者向けの粒度のリリースノートをそのまま一般ユーザー向けのストア掲載文に翻訳・要約してくれる処理は個人的には一番嬉しいところです。掲載文生成の工夫として、テンプレの用意と文字数制約の設定があります。これによりトーンのブレをなくし、安定した文章生成ができています。
設計時のポイントは3つあります。
- 【1つ目:承認ポイントを意図的に残したこと】全自動にせず「バージョン更新前」「リリースノート確定前」「ビルド開始前」の3カ所で人間の承認(意思決定)を挟んでいます。自動化したいのは「手順」であって「意思決定」ではないので、この切り分けが良かったと思っています。
- 【2つ目:
allowed-toolsを最小権限にしたこと】deploy 側は引数まで含めてほぼ固定の形でホワイトリスト化しています。ワイルドカードを安易に広げず、スキルが想定外の操作をするのを「構造的に」防げます。 - 【3つ目:2フェーズに分けたこと】 間に人間のレビューとマージという非自動の工程が必ず入るので、フェーズの境界を人間の判断境界と一致させたのは結果的に正解でした。
感想
総じて、リリース手順書を「実行可能なドキュメント」に変えられたのが一番の収穫です。手順書はメンテされず腐りがちですが、スキルは実際に毎回実行されるので、常に最新で正しい状態に保たれます。allowed-tools によるホワイトリスト、承認ポイントの設計、フェーズ分割——このあたりを意識すれば、他のプロジェクトにも応用しやすいはずです。
また、実際に運用してみて感じたことは以下のとおりです。
- 手順の抜け漏れ、特にバージョン・ビルド番号まわりの事故が消えた
- PR・リリースノート・ストア掲載文の体裁が毎回そろう
- リリースのたびにあった「えーっと次は何だっけ」という細かい思い出しコストがゼロ
そして、構造設計的な視点から「禁止事項」も大事だと実感しました。「賢いから大丈夫」ではなく「そもそもできないようにする」という発想が、自動化を信頼するうえで重要だと思いました。
以上になります。
最後までお読みいただきありがとうございました。