リリースサイクルランブック
ローカルゲートから、署名済みの GitHub Release を経て、npm 公開に至るまでの完全なリリースワークフロー。
このランブックは、apothem の vX.Y.Z リリースを、クリーンな作業ツリーから検証済みの配布面まで進めます。
手順は gh、git、そしてリリース階層のシェルを扱うメンテナー向けに書かれています。
手順の終わりには、検証済みの Release ページ、記入済みの CHANGELOG、そして各ユーザー向けの面が正規のインストールコマンドに応答することを確認するインストールパスのスモークテストが揃います。
リリースモデルは追加型です。
各リリースは main に 1 つのコミットと、署名付きの注釈付き vX.Y.Z タグを 1 つ追加します。何も強制プッシュされず、以前のタグ、GitHub Release、npm バージョンが削除されることもありません。
各リリースはそれぞれのタグ、GitHub Release、npm バージョンを保持し、すべて公開されたままです。npm のバージョンは不変であり(公開済みの name@version は決して置き換えられません)、ピン留めされたインストールはタグに依存しています。
タグのプッシュは 3 つのワークフローを開始します。
.github/workflows/release.yml は、GitHub Release を完全な成果物セット(sdist、wheel、CycloneDX SBOM、Sigstore cosign バンドル、SLSA-3 来歴、プラットフォームランタイムアーカイブ)とともにビルド、署名、構成証明、公開します。
publish-npm.yml は、npm Trusted Publishing を通じて @ahmed-g-gad/apothem を npmjs.com へ公開し、publish-vscode.yml は VS Code 拡張機能をパッケージ化して Visual Studio Marketplace へ公開します。
バージョン付きの CHANGELOG セクションはリリースコミットに含まれます。オペレーターは、両方のワークフローが完了した後にインストールパスのスモークテストを実行します。
1. 前提条件
メンテナーはタグ付けの前に以下を確認します。
-
作業ツリー。 クリーンであること(
git statusに保留中のものが何も表示されない)。 リリースのすべての機能作業がmain上にあること。 -
CI グリーン。 最新の
mainでgh run list --branch=main --limit=1 --json conclusion --jq '.[0].conclusion'がsuccessを返すこと。 -
ツール。
gh(GitHub CLI)バージョン 2.40 以降がahmed-g-gadとして認証済みであること。git2.40 以降に GPG 署名サブキーがロードされていること。@ahmed-g-gad/apothemの npm 信頼済みパブリッシャーバインディングが有効であること (パブリッシャーアカウントセットアップランブックに従って検証済み)。 -
バージョンアンカーの整合。
pyproject.tomlで宣言されたバージョン文字列が、v接頭辞を除いて計画したタグと一致すること(§2.1 で、他のすべてのアンカーとともに設定します)。検証:grep '^version' pyproject.toml期待される出力(
vX.Y.Zリリースの場合。プレースホルダーは進行中のリリースタグを表します):version = "X.Y.Z" -
CHANGELOG エントリのステージング。 リリースの箇条書きが、Keep-a-Changelog の見出しで
## [Unreleased]の下にあること。§2.1 で、タグを着地させるコミットにおいて、それらが日付付きのバージョンセクションに変わります。
2. タグ付けとトリガー
2.1 リリースコミットを作成する
バージョンは 12 を超えるファイルに記載されているため、手作業で編集しないでください。 1 つのコマンドですべてを更新します。
git checkout main
git pull --ff-only origin main
python scripts/release/bump_version.py X.Y.Zbump_version.py は、すべてのバージョンアンカーをまとめて更新します。
-
すべてのパッケージング、拡張機能、プラグイン、マーケットプレイスのマニフェストと、 引用ファイル(バージョンとリリース日)。完全なリスト:
pyproject.toml package.json site/package.json site/package-lock.json (the project entries only) vscode-extension/package.json gemini-extension.json qwen-extension.json .claude-plugin/marketplace.json (top level and metadata) plugins/apothem/plugin.json plugins/apothem/.codex-plugin/plugin.json CITATION.cff -
CHANGELOG.md:[Unreleased]のエントリが日付付きの## [X.Y.Z]セクションになり、[Unreleased]はvX.Y.Zからの比較になり、[X.Y.Z]リンクが追加されます。 -
SECURITY.md: 新しいマイナーには、サポート対象のX.Y.x行が追加されます。 古いマイナーを掲載し続けるかどうかはあなたが決めます。スクリプトはリマインダーを出力します。
その後、派生ツリー(Claude Code プラグインパッケージ、振る舞い差分ゴールデン、ドキュメントのリファレンスページと変更履歴ページ)を再生成します。
変更を先に一覧表示するには --dry-run を、リリース日を設定するには --date YYYY-MM-DD(デフォルト: UTC での今日)を、再生成をスキップするには --no-regen を渡します。
スクリプトは不正な形式のバージョンやダウングレードを拒否します。現在のバージョンで再実行した場合は、ずれたアンカーを揃え直すだけです。
差分をレビューしてから、コミットします。
git add -A
git commit -S -m "chore(release): cut vX.Y.Z"
git push origin main-S フラグは GPG キーでコミットに署名します。
プッシュは標準の CI マトリクス(lint、test、build)をトリガーします。タグ付けの前に、グリーンになるのを待ってください。
§2.4 の準備状態チェックには、リリースコミットで CodeQL とコンフォーミティがグリーンであることも必要です。どちらも、自身のパスが変更されたときにだけ実行されます。リリースコミットは通常どちらのパスも変更しないため、リリースコミットが main の先頭になったら両方を開始し、その後、各実行がそのコミットを対象にしていることを確認してください:
gh workflow run codeql.yml --ref main
gh workflow run conformity.yml --ref main
gh run list --workflow codeql.yml --commit "$(git rev-parse HEAD)" --limit 1
gh run list --workflow conformity.yml --commit "$(git rev-parse HEAD)" --limit 1両方が成功するまで待ってからタグ付けしてください。また、リリースが公開されるまで main には他に何もプッシュしないでください。後からのプッシュは main をリリースコミットから離してしまい、CI は同じブランチで進行中の実行をキャンセルします。
2.2 タグに署名してプッシュする
git tag -a -s vX.Y.Z -m "vX.Y.Z"
git push origin vX.Y.Z-a -s の組み合わせは、注釈付きで GPG 署名されたタグを生成します。
プッシュは .github/workflows/release.yml をトリガーし、このワークフローがビルド、署名、構成証明、公開を行います。
2.3 リリースワークフローの完了を確認する
gh run watch $(gh run list --workflow=release.yml --limit=1 --json databaseId --jq '.[0].databaseId')ワークフローは、ビルド(sdist + wheel、続いてそれらのディストリビューションの CycloneDX SBOM をその隣に書き出す)、キーレス cosign 署名、SLSA-3 来歴の生成と検証、プラットフォームアーカイブのビルド(darwin / linux / windows)、集約された SHA256SUMS マニフェストによるアーカイブ署名、そして最終的な GitHub Release の公開を実行します。
メンテナーは publish GitHub Release ジョブのログを確認し、アセットアップロードの確認メッセージを探します。
publish GitHub Release ジョブは release 環境で実行されます。この環境はメンテナーの承認を必要とするため、前のジョブが成功すると、実行はそこで待機します。実行のページの Review deployments(デプロイのレビュー)から承認するか、シェルから承認してください:
run_id=$(gh run list --workflow=release.yml --limit=1 --json databaseId --jq '.[0].databaseId')
env_id=$(gh api repos/ahmed-g-gad/apothem/environments/release --jq .id)
gh api -X POST "repos/ahmed-g-gad/apothem/actions/runs/${run_id}/pending_deployments" \
-F "environment_ids[]=${env_id}" -f state=approved -f comment="vX.Y.Z"タグのプッシュは、npm と VS Code 拡張機能のワークフローも開始します。それらの公開ジョブも、§2.4 までは同じ承認を待機します。
2.4 npm 公開を確認する
タグのプッシュでは、release.yml と並んで publish-npm.yml も実行されます。npm のワークフローはリリースワークフローの完了を待たず、ゲートとなるのは release 環境の承認です。§2.3 のリリースワークフローが完了したら、準備状態を確認します。このチェックは、リリース、ワークフローの実行、公開済みの SBOM を読み取るため、まず 2 つの入力を用意します:
GH_TOKEN。ghにすでにログインしている場合でも、このトークンがなければスクリプトは実行を拒否します。ahmed-g-gad/apothemに限定した、きめ細かいスコープの個人用アクセストークンを使ってください。権限は Actions: Read(ワークフローの実行)と Contents: Read(リリース)です。チェックは何も書き込まないため、書き込み権限は不要です。gh auth tokenから得たトークンはログインのすべてのスコープを持つため、きめ細かいトークンを優先してください。- 公開済みの SBOM。 チェックは
dist/release-assets/sbom.cdx.jsonを読み取ります。これはリリースが添付する CycloneDX ファイルです。ローカルのビルドではなく、リリースが公開したコピーをダウンロードしてください。
read -rs GH_TOKEN && export GH_TOKEN
mkdir -p dist/release-assets
gh release download vX.Y.Z --repo ahmed-g-gad/apothem \
--pattern sbom.cdx.json --dir dist/release-assets --clobber
bash scripts/release/check-release-ready.sh vX.Y.Z次の場合、チェックは失敗します。リリースがドラフトまたはプレリリースである場合、タグのコミットに対する必須のワークフローがグリーンでない場合、SBOM が存在しない場合、SBOM が別のバージョンを記述している場合、または SBOM にベンダリングされたパッケージが含まれていない場合です。失敗メッセージには、原因が示されます。
準備状態チェックに合格したら、§2.3 と同じ方法で、待機中の Publish npm の実行を承認します(その実行 ID は gh run list --workflow=publish-npm.yml から取得します)。このワークフローは、npm Trusted Publishing(OIDC)を通じて @ahmed-g-gad/[email protected] を npmjs.com へ公開します。リポジトリにレジストリトークンは保存されません。待機中の Publish VS Code Extension の実行も承認してください。この実行は apothem.vsix をパッケージ化し、それを ahmed-g-gad.apothem-vscode として Visual Studio Marketplace へ公開します。公開ステップは、リポジトリ変数 VSCODE_MARKETPLACE_READY が true であり、かつ認証情報が 1 つ構成されている間だけ実行されます。認証情報は、変数 VSCE_AUTH=oidc(Marketplace Trusted Publishing。保存されるシークレットなし)、変数 VSCE_AUTH=entra、AZURE_CLIENT_ID、AZURE_TENANT_ID(有効期間の短い Microsoft Entra ID トークン。保存されるシークレットなし)、または VSCE_PAT シークレットのいずれかです。どれもない場合、この実行は拡張機能をパッケージ化するだけで公開はスキップします。認証情報は切り替えであって再試行ではありません。あるルートでの公開が失敗しても、自動的に別のルートへフォールバックすることはありません。各ルートのセットアップは、以下のTrusted Publishing による Marketplace への公開(推奨)とMicrosoft Entra ID による Marketplace への公開にあります。
実行が失敗した後に再度公開するには、同じタグに対してワークフローをディスパッチします
(gh workflow run publish-npm.yml --field tag=vX.Y.Z)。
npm のバージョンは不変であるため、バージョンがすでにレジストリにある場合、ワークフローは公開をスキップします。
Trusted Publishing による Marketplace への公開
Trusted Publishing により、Marketplace はこのリポジトリの GitHub OIDC トークンを直接受け入れます。vsce publish --oidc は、公開ジョブのトークンを有効期間の短い Marketplace 認証情報と交換します。保存されるシークレットも Azure リソースもないため、これが推奨ルートです。以下の Entra ルートと VSCE_PAT シークレットは、オペレーターが選択する代替手段として残ります。
-
これをサポートする vsce リリースを使う。 このルートでは、公開ジョブは公開の前に
tools/vsceでロックされた vsce リリースを確認し、ロックがそれより古い場合は、最低限必要なリリースを示すエラーで停止します。Dependabot はそのロックファイルに対して vsce の更新を提案します。切り替える前に、最低限のリリースに達する更新をマージしてください。 -
ポリシーを作成する。 パブリッシャーの Owner としてサインインし、
https://marketplace.visualstudio.com/manage/publishers/ahmed-g-gadを開いて、Trusted Publishing の下にポリシーを追加します:- ポリシー名:
apothem-releaseなど、任意の名前 - リポジトリのオーナー:
Ahmed-G-Gad - リポジトリ:
apothem - ワークフロー:
publish-vscode.yml - 環境:
release
フィールド名は、VS Code の公開ガイドが GitHub Actions と Trusted Publishing による公開のセクションで挙げているものです(
https://code.visualstudio.com/api/working-with-extensions/publishing-extension)。未確認: すべてのパブリッシャーにすでに Trusted Publishing タブが表示されるかどうか。表示されない場合は、Entra ルートを使ってください。 - ポリシー名:
-
ルートを切り替える。
VSCODE_MARKETPLACE_READYをtrueのままにして、セレクターを設定します。次のタグのプッシュはこのルートを通じて公開されるため、待機中のタグがないときに設定してください。gh variable set VSCE_AUTH --body oidc -
公開する。 次のタグのプッシュ、または既存のタグに対するディスパッチが、Trusted Publishing を通じて公開します。このルートにはドライランがありません。最初の公開がチェックとなり、
dry_runを指定したディスパッチは、何も検証されなかったという警告を出すだけです。 -
失敗したらフォールバックする。 セレクターを削除し、同じタグに対して再度ディスパッチします。
VSCE_PATシークレットが設定されていれば、トークンルートが公開します。失敗した公開は何も公開していないため、同じタグを再度ディスパッチできます。gh variable delete VSCE_AUTH
Microsoft Entra ID による Marketplace への公開
Entra ルートは、保存された個人用アクセストークンを有効期間の短いトークンに置き換えます。publish-vscode.yml が GitHub に OIDC トークンを要求し、Azure/login アクションがフェデレーション資格情報を通じてそれを Entra のサインインと交換し、vsce publish --azure-credential が得られたトークンで公開します。クライアントシークレットは存在しません。VSCE_PAT シークレットは、オペレーターが選択するフォールバックとして残ります。ワークフローが自らそれに切り替えることは決してありません。
tools/vsce にピン留めされた vsce リリースは、このルートをサポートしています。このルートには Entra テナント、アプリケーション登録、パブリッシャーのメンバーシップが必要ですが、上記の Trusted Publishing には必要ありません。パブリッシャーが Trusted Publishing を利用できない場合に使ってください。
-
前提条件を確認する。 パブリッシャー
ahmed-g-gadを所有するアカウント(https://marketplace.visualstudio.com/manage/publishers/ahmed-g-gadの Members タブ)と、アプリケーションを登録できる Entra テナントを特定します。未確認: パブリッシャーのオーナーのテナントがアプリケーションのテナントと一致しなければならないかどうか、および Azure DevOps 組織Ahmed-G-Gadを Entra に接続する必要があるかどうか(dev.azure.com/Ahmed-G-Gad、Organization settings、Microsoft Entra)。どちらについても記載している情報源はありません。手順 5 または 6 が失敗した場合は、まずこれらを確認してください。 -
アプリケーションを登録する。
https://entra.microsoft.comで App registrations を開き、New registration を選びます。名前をapothem-vscode-publishとし、シングルテナントを選び、リダイレクト URI は空のままにします。Overview から、Application (client) ID と Directory (tenant) ID をコピーします。クライアントシークレットは作成せず、API のアクセス許可も付与しないでください。この手順には、アプリケーションのオーナー権限か、Application Administrator などの Entra ロールが必要です。 -
フェデレーション資格情報を追加する。 そのアプリケーションで Certificates & secrets、Federated credentials、Add credential を開き、シナリオ「GitHub Actions deploying Azure resources」を選びます。組織
Ahmed-G-Gad、リポジトリapothem、エンティティの種類Environment、環境名release、資格情報名apothem-releaseを入力します。生成されたフィールドは次のとおりでなければなりません:issuer: https://token.actions.githubusercontent.com subject: repo:Ahmed-G-Gad/apothem:environment:release audience: api://AzureADTokenExchange照合は完全一致で、大文字と小文字を区別します。後のサインインが AADSTS700213 または AADSTS7002138 で失敗する場合は、資格情報を、
Azure/loginがジョブログに書き出すsubject claim行と比較してください。作成直後の AADSTS70021 は、資格情報がまだ伝播していないことを意味します。数分待ってから再試行してください。 -
リポジトリ変数を設定する。
VSCODE_MARKETPLACE_READYがtrueの間は、3 つすべてが設定された時点で Entra ルートが有効になるため、承認待ちのリリースタグがないときに設定してください。VSCODE_MARKETPLACE_READY=trueがなければ、何もサインインせず、実行は公開をスキップします。gh variable set AZURE_CLIENT_ID --body "<application-client-id>" gh variable set AZURE_TENANT_ID --body "<directory-tenant-id>" gh variable set VSCE_AUTH --body entraVSCODE_MARKETPLACE_READYとVSCE_PATはそのままにしてください。VSCE_AUTHがentraでもAZURE_CLIENT_IDまたはAZURE_TENANT_IDが空の場合、ワークフローはVSCE_PATが設定されているかどうかにかかわらず警告をログに出し、Entra ルートを使いません。その場合、VSCE_PATシークレットが設定されていればそれを使います。シークレットがなければ何も公開せず、それでも実行はグリーンで終わるため、警告を探してください。 -
ドライランを実行する。 既存のリリースタグに対して、
dry_runを設定してワークフローをディスパッチします。Entra ルートでは、サインインし、Azure DevOps のプロフィールを出力し、公開せずにパブリッシャーへのアクセスを検証します。トークンルートにはドライランがありません。ログにMarketplace credential mode: patと表示された場合、実行は警告付きのグリーンで終わり、何も検証していません。待機中のrelease環境の実行を承認してください。gh workflow run publish-vscode.yml --ref main -f tag=vX.Y.Z -f dry_run=true期待される結果:
Marketplace credential mode: entra、手順 3 の subject と等しいsubject claim行、そして最初のドライランステップが出力するプロフィールのidとdisplayName。検証ステップは、手順 6 までは 403 で失敗するのが想定どおりです。未確認: Azure サブスクリプションなしのサインインで、Azure CLI を通じて Marketplace 用のトークンが得られるかどうか。この実行がその最初のテストです。ここで失敗した場合は、代わりにサブスクリプション内にユーザー割り当てマネージド ID を登録してください。これは Microsoft が文書化しているルートです。 -
アプリケーションをパブリッシャーに追加する。 手順 1 の Members タブで、パブリッシャーの Owner としてサインインし、手順 5 のプロフィールの
idを使って、ロール Contributor のメンバーを追加します。未確認: ダイアログのフィールドラベル、およびアプリケーションが Azure DevOps 組織のメンバーになる前にダイアログがその id を受け付けるかどうか。Azure DevOps は、原則としてアプリケーション ID を組織ごとに追加します。ダイアログが id を拒否した場合は、サービスプリンシパルを組織Ahmed-G-Gadに追加し(Organization settings、Users で、Enterprise application の Object ID を使用)、再試行してください。同じく未確認: その ID が最初に Azure DevOps を呼び出す前にプロフィールが存在するかどうか。 -
ドライランを繰り返す。 検証ステップは今度は「verification succeeded for the publisher」で成功します。Entra トークンは同じ経路を通るため、そのメッセージには引き続き Personal Access Token と表示されます。このチェックが証明するのはパブリッシャーのメンバーシップ(Creator、Owner、Contributor、Reader)であり、公開権限ではありません。未確認: 更新を公開するのに Contributor で十分かどうか。Microsoft のロールの説明では十分とされていますが、それで公開した例を示す情報源はないため、最初の実際の公開が証明となります。
-
リリースを公開する。 §2.2 のとおりにタグを付け、実行を承認します。ステップ
Publish to Visual Studio Marketplace (Entra ID)が実行され、その環境ヘッダーにはAZURE_TENANT_IDだけが表示され、トークンのフォールバックステップはスキップされ、vsce がDONE Published ahmed-g-gad.apothem-vscodeを出力します。Marketplace のギャラリーには、約 4 分後に新しいバージョンが掲載されます。 -
トークンについて決める。 最初の Entra での公開が成功するまでは
VSCE_PATを残し、その後、フォールバックが不要であればシークレットを削除します。削除した後は、Entra の変数が削除されているか空である場合、実行は公開なしでグリーンのままになります。VSCE_AUTHがまだentraであれば警告が出ますが、そうでなければスキップの通知だけが出ます。タグを付けるたびに、実行のアノテーションを読んでください。グローバル個人用アクセストークンの廃止後もフォールバックを残すには、Ahmed-G-Gad向けに、カスタムスコープ Marketplace Manage と許容できる最短の有効期限を指定した組織スコープのトークンを作成し、VSCE_PATとして保存します。未確認: この手順のポータルのラベルは一次情報源ではなく記憶に基づくものであること、Microsoft は組織スコープのトークンを一時的な回避策と呼んでおり、それを受け付けなくなる可能性があること、そして Microsoft のページ間でグローバルトークンの廃止日が食い違っていること。 -
トークンにフォールバックする。 セレクターを削除して再度ディスパッチし、実行を承認します。失敗した Entra での公開は何も公開していないため、同じタグを再度ディスパッチできます。ただし、着地したバージョンを 2 回公開することはできないため、先に Marketplace のページを確認してください。
gh variable delete VSCE_AUTH gh workflow run publish-vscode.yml --ref main -f tag=vX.Y.Z
Entra での公開が失敗した場合は、ステップのログを読んでください:
- 「Can not acquire a Microsoft Entra ID access token」で始まるメッセージは、サインインまたは資格情報のチェーンが失敗したことを意味します。まず
Sign in to Microsoft Entra IDステップとフェデレーション資格情報を確認してください。サインインがグリーンの場合は、ワークフロー内の vsce ステップのenvからAZURE_TENANT_IDを削除してください。GitHub 自身の拡張機能リリースワークフローは、これをエクスポートしていません。 - 「InvalidAccessException」または「not allowed」は、トークンの ID がパブリッシャーのメンバーではないことを意味します。ドライランのプロフィールの
idを Members タブと比較してください。 - ドライランの検証ステップからの 403 は、アプリケーションにまだロールがないことを意味します。
このルートには 3 つの制限があります:
id-token: writeは公開ジョブ全体に付与されるため、トークンモードであっても、その中のすべてのステップが OIDC トークンを要求できます。トークンの subject はrelease環境に結び付けられており、その環境にはレビュアーの承認が必要です。release環境にはデプロイのブランチポリシーもタグポリシーもないため、メンテナーが承認したどの ref でも、環境 subject のトークンを取得できます。これをv*.*.*タグに制限するには、まずrelease.ymlとpublish-npm.ymlが何をディスパッチするかを確認する必要があります。- リポジトリの名前変更や移管は OIDC の subject の形式を変え、フェデレーション資格情報を気付かないうちに壊します。名前を変更した後は、
Azure/loginのログから subject を再度資格情報にコピーしてください。
2.5 テンプレートダイジェストのピンを更新する
タグが存在するようになったら、tests/unit/test_template_digests.py の _LATEST_RELEASE と _LATEST_RELEASE_DIGESTS を、新しいリリースと、そのリリースが出荷した各プレーンテキストテンプレートの SHA-256 ダイジェスト(git show vX.Y.Z:<template path> | sha256sum)に設定します。これは main への次の変更で行い、テンプレートが変更された場合は、以前のダイジェストをマニフェストエントリの earlier_digests に追加してください。release-preflight CI ジョブはすべてのタグをチェックアウトするため、ピンが更新されるまで、タグ名を示して失敗します。
3. 配布面
各面には、「リリースはここに着地したか?」に答える検証コマンドがあります。
| # | 面 | 成果物 | 検証 |
|---|---|---|---|
| 1 | GitHub Release(Python ディストリビューション) | apothem-X.Y.Z.tar.gz(sdist)+ apothem-X.Y.Z-py3-none-any.whl | gh release view vX.Y.Z --json assets --jq '.assets[].name' に両方のファイル名が含まれる |
| 2 | GitHub Release(SBOM) | sbom.cdx.json + sbom.cdx.json.cosign.bundle | アセットリストに両方が含まれる。SBOM の metadata.component.purl が pkg:pypi/[email protected] であり、そのコンポーネントに src/apothem/_vendor/vendor.txt のすべてのパッケージが含まれる |
| 3 | GitHub Release(署名) | sdist、wheel、SBOM、VS Code 拡張機能、プラットフォームアーカイブ、SHA256SUMS のそれぞれにつき 1 つの <asset>.cosign.bundle(以前のリリースでは、アーカイブと SHA256SUMS のバンドルの名前は <asset>.sig) | §5.5 の正確なアイデンティティを指定した cosign verify-blob が 0 で終了する |
| 4 | GitHub Release(来歴) | provenance.intoto.jsonl | bash scripts/release/verify-provenance.sh <download-dir> が 0 で終了する(§5.5) |
| 5 | GitHub Release(プラットフォームアーカイブ) | apothem-vX.Y.Z-darwin.tar.gz、apothem-vX.Y.Z-linux.tar.gz、apothem-vX.Y.Z-windows.zip | アセットリストにすべてのアーカイブと SHA256SUMS が含まれる。darwin と linux のアーカイブは 2 つの名前を持つ同一のバイト列である(ランタイムはプラットフォーム非依存で、--platform は tar.gz か zip かを選ぶだけ)ため、それらの SHA256SUMS 行には 1 つのダイジェストが 2 回現れる |
| 6 | GitHub Release(VS Code 拡張機能) | apothem.vsix + apothem.vsix.cosign.bundle | アセットリストに両方が含まれる。code --install-extension apothem.vsix でインストールできる。リリースワークフローが拡張機能をパッケージ化するようになる前のリリースには、どちらも含まれない |
| 7 | npmjs.com | @ahmed-g-gad/[email protected] | npm view @ahmed-g-gad/apothem version が X.Y.Z を返す。npx @ahmed-g-gad/[email protected] --version が Apothem, version X.Y.Z を出力する |
| 8 | Pages(スクリプトインストーラー) | ドキュメントサイト上の install.sh / install.ps1 | curl -fsSL https://apothem.ahmedgad.com/install.sh | head -n 1 がスクリプトヘッダーを返す |
| 9 | Visual Studio Marketplace | ahmed-g-gad.apothem-vscode バージョン X.Y.Z | 拡張機能の Marketplace ページに X.Y.Z が表示される。code --install-extension ahmed-g-gad.apothem-vscode でインストールできる |
GitHub Release は正規の成果物面であり、npm パッケージとスクリプトインストーラーは、その上に重ねられたインストールパスです。 npm の公開は、同じタグのプッシュでリリースワークフローと並行して実行されます。
4. CHANGELOG の規律
CHANGELOG.md は、Keep-a-Changelog の規約に従い、リリースごとに 1 つのセクションを持ちます。
リリースコミットにおける CHANGELOG の編集では、次のことを行います。
- バージョンセクションが
## [X.Y.Z] - YYYY-MM-DDの見出しを使用していることを確認します (ハイフンです。bump_version.pyがこれを書き込み、extract_release_notes.pyは## [X.Y.Z]接頭辞に一致させます)。 - 標準の見出し(Added、Changed、Deprecated、Removed、Fixed、Security)が、該当する箇所で使用されていることを確認します。 空の見出しは、レンダリングされたファイルから除かれます。
- 実装ではなく能力を記述します。ドメインの言葉のみを使い、 プラン内部の参照、コミットハッシュ、プランやフェーズの識別子は含めません。
メンテナーのレビューを通過した CHANGELOG セクションは、アナウンスの文章のためのリリースノートのアンカーとして読めます。
5. インストールパスのスモークテスト
両方の段階が完了した後、メンテナーはスモークテストを実行します。 スモークテストは、ユーザー向けのインストールコマンドが応答することを確かめる正規の検証です。
5.1 Claude Code プラグイン
/plugin marketplace add ahmed-g-gad/apothem
/plugin install apothem@apothem期待される結果: プラグインがインストールされ、Claude Code 内で apothem コマンドが利用可能になります。
5.2 Node.js(npx)
npx @ahmed-g-gad/[email protected] --version期待される出力: Apothem, version X.Y.Z。
5.3 ワンショットスクリプトインストーラー(POSIX)
インストーラーは apothem ランチャーを ~/.local/bin に、または APOTHEM_BIN_DIR が設定されている場合はその変数で指定されたディレクトリに書き込みます。以下の確認を実行するには、そのディレクトリが PATH に含まれている必要があります。含まれていない場合、インストーラーは追加すべき export PATH の行を表示します。そのディレクトリが PATH に含まれるまで、シェルは apothem を見つけられず、確認は失敗します。インストーラーがランチャーを配置できない場合は、警告を表示し、export PATH の行は表示しません。メンテナーの署名鍵をまだ持っていないホストでは、最初の行がその鍵をインポートします。鍵がなければ、インストーラーは停止します。
curl -fsSL https://github.com/ahmed-g-gad.gpg | gpg --import
curl -fsSL https://apothem.ahmedgad.com/install.sh | sh
apothem --version期待される出力: Apothem, version X.Y.Z。
5.4 ワンショットスクリプトインストーラー(Windows)
最初の行は、Git 自身の bash を通してメンテナーの署名鍵をインポートします。このとき使われる gpg のキーリングは、git verify-tag が読み取るものです。
& "$env:ProgramFiles\Git\bin\bash.exe" -c 'curl -fsSL https://github.com/ahmed-g-gad.gpg | gpg --import'
irm https://apothem.ahmedgad.com/install.ps1 | iex
apothem --version期待される出力: Apothem, version X.Y.Z。
5.5 成果物の検証(サプライチェーンの証拠)
すべてのアセットを空のディレクトリにダウンロードしてから、検証します。
証明書のアイデンティティは、まさにこのタグにおけるリリースワークフローです。
アイデンティティのチェックは大文字と小文字を区別し、証明書には GitHub が報告するとおりのオーナー Ahmed-G-Gad が記載されているため、小文字のオーナーでは失敗します。
mkdir release-vX.Y.Z && cd release-vX.Y.Z
gh release download vX.Y.Z --repo ahmed-g-gad/apothem
cosign verify-blob \
--bundle apothem-X.Y.Z-py3-none-any.whl.cosign.bundle \
--certificate-identity https://github.com/Ahmed-G-Gad/apothem/.github/workflows/release.yml@refs/tags/vX.Y.Z \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
apothem-X.Y.Z-py3-none-any.whl
slsa-verifier verify-artifact \
--provenance-path provenance.intoto.jsonl \
--source-uri github.com/Ahmed-G-Gad/apothem \
--source-tag vX.Y.Z \
apothem-X.Y.Z-py3-none-any.whl apothem-X.Y.Z.tar.gz
bash ../scripts/release/verify-provenance.sh .期待される結果: Verified OK、PASSED: SLSA verification passed、そして
verify-provenance: chain OK (3 of 3 layers verified)。
スクリプトは SHA256SUMS、すべての署名バンドル、来歴を 1 回の実行でチェックします。タグは wheel の名前から導出します(--tag vX.Y.Z で上書きできます)。
スモークテストは面ごとに 1 行の PASS / FAIL を生成します。それらの行をメンテナーのリリースログに記録してください。
6. 障害からの復旧
リリースワークフローには、リリースエンジンと npm パブリッシャーについて文書化された障害モードがあります。
| 障害 | 診断 | 復旧 |
|---|---|---|
| タグのプッシュが拒否される(署名の失敗) | git push origin vX.Y.Z が GPG 関連のメッセージとともに error: failed to push some refs を返す | GPG サブキーがロードされていることを検証する(gpg --list-secret-keys --keyid-format=long)。キーリングを修正した後、ローカルで -s を付けて再度タグを付け、再プッシュする |
リリースビルドが Check the plugin version changed with the plugin で停止する | ビルドジョブのログにプラグインと前のタグが示される。アセットはビルドも公開もされていない | 前回のリリース以降にプラグインパッケージが変更されたが、そのバージョンは変更されていない。タグを削除し(git push --delete origin vX.Y.Z、git tag -d vX.Y.Z)、python scripts/release/bump_version.py X.Y.Z を実行してコミットし、その後タグに署名して再度プッシュする(§2.2)。同じチェックがすべてのプルリクエストで警告アノテーションとして実行されるため、通常はタグ付けの前に表面化する |
release.yml のジョブが単一の段階で失敗する | gh run view <run-id> --log が失敗したジョブ(SBOM も書き出す build / sign / provenance / archive / publish)を示す | gh run rerun <run-id> --failed で失敗したジョブだけを再実行する。障害が繰り返される場合は、再度タグを付ける前に、ジョブの入力をその発生源で修正する |
| SLSA 来歴の検証が失敗する | verify SLSA provenance artifact ジョブが非ゼロで終了する | 来歴成果物にサブジェクトダイジェストの不一致がないか調べる。同じタグから再ビルドする。来歴は正確な成果物ダイジェストに結び付けられているため、成果物を再生成するにはワークフロー全体の再実行が必要 |
| npmjs.com への公開が拒否される | npm ジョブが npm publish 中に非ゼロで終了する。PUT 中のレジストリ 404 は認可 / 信頼済みパブリッシャーの不一致であり、パッケージコードが欠落している証拠ではない | @ahmed-g-gad/apothem の npm Trusted Publishing が、オーナー ahmed-g-gad、リポジトリ apothem、ワークフロー publish-npm.yml、許可されたアクション npm publish を指定していることを検証する。ジョブが、ワークフローでピン留めされた Node バージョンと npm CLI の OIDC 下限で実行されることを確認する |
| タグは見えるがアセットが欠落している | gh release view vX.Y.Z がスタブのリリースを返す | リリースワークフローの publish ジョブを再実行する。このジョブは既存のリリースを編集し、すべてのアセットを再アップロードする。タグから何もユーザーに届いていない場合(アセットなし、npm バージョンなし)に限り、削除して再度タグを付ける。それ以外の場合は、次のパッチリリースで前方修正する(リリース復旧ランブック §2) |
復旧サイクルが 1 回の診断パスで面を着地させられない場合、その面はオープンなイシューへのリンクとともに、既知の障害としてリリースノートに記録されます。 壊れた面がパッチリリースで修正されるまでの間、下流のユーザーは動作している面へ案内されます。
7. 相互参照
- パブリッシャーのセットアップ。 パブリッシャーアカウントセットアップランブックは、 npm の信頼済みパブリッシャーバインディングと、このランブックが前提とする GitHub 側の前提条件を確立します。
- 復旧フロー。 リリース復旧ランブックは、 同じ追加型モデルに従います。失敗したタグやパブリッシャーをステージごとに復旧し、 修正を新しいパッチバージョンとしてリリースすることでロールバックします。 公開済みのタグ、リリース、npm バージョンを削除したり付け替えたりすることでロールバックすることは決してありません。
- Pages の有効化。
publish-static-site.ymlワークフローは、 プロジェクトのウェブサイトを検証してカスタムドメインへデプロイします。 Pages 有効化ランブック(site/content/docs/runbooks/pages-enablement.mdx)は、 そもそもカスタムドメインを確立した上流の手順です。 - バージョニングポリシー。
site/content/docs/governance/release-engineering-policy.mdxは、 このランブックが従う SemVer + 署名 + 非推奨化のポリシーを定めています。