Repository navigation
import command_ja
Issue #11 で、読み取り専用の import コマンドと --into による refresh を追加します。コマンドは既存リポジトリを schemaVersion: 1 の設定として取り込み、refresh は設定ファイルが宣言済みの管理範囲だけを、ローカルの意図と元の書式を保ったまま更新します。
| 種別 | Issue |
|---|---|
| 親 | Issue #11 |
| 状態取得と逆変換 | Issue #18 |
| 書式保持 refresh | Issue #19 |
| CLI と収束 | Issue #20 |
repository.description の三状態化 |
Issue #22 |
リポジトリ設定を手作業で書き写すのは誤りやすい一方、refresh が利用者の宣言していないセクションまで黙って管理下に置いてはいけません。既存のスキーマはリポジトリ設定、Actions、security、label、milestone、ruleset、agent variable を既に表現できますが、逆変換と安全なファイル更新の経路がありません。
仕様をコードベースと突き合わせたところ、当初の計画が前提としていて現在の実装では提供できないものが3つ見つかりました。存在しないリポジトリ読み取りが8件、現在の parser では保証できない YAML 編集、そしてライブの値を読まずに更新を報告する planner の比較です。本ページは修正後の契約を記録します。
現在の GitHub クライアントのままでは import を書けません。
| 読み取り | 現状 |
|---|---|
| リポジトリの environment 一覧 | 作成・更新のみ。レスポンスは {total_count, environments} のラップ形式 |
| Actions の selected-actions 許可リスト | 書き込み専用。actions.selectedActions に必要 |
| Actions の既定 workflow 権限 | 書き込み専用。defaultWorkflowPermissions と canApprovePullRequestWorkflows に必要 |
| automated security fixes | 書き込み専用。security.dependabotSecurityUpdates に必要 |
| private vulnerability reporting | 書き込み専用 |
| CodeQL default setup | 書き込み専用 |
リポジトリの security_and_analysis
|
現在デコードしていない。security.secretScanning と security.pushProtection に必要 |
| ruleset の詳細 | list のみ。ruleset の list API は識別情報・target・enforcement しか返さず、rules・conditions・bypass actor を返さないため、ruleset 単位の取得が必要。planner が現在 ruleset を name だけで比較しているのも同じ理由 |
ページングのヘルパーは JSON 配列を直接デコードするため、ラップされた list をページングできません。そのため variable、secret、custom repository role は現状ページングされず、GitHub の既定ページサイズで止まります。ラップ形式に対応した変種の追加が作業に含まれ、ページ数の上限も見直します。
importer は小さな読み取り専用インターフェース、全件ページング、既存の設定型への逆変換を使います。サーバー生成の ruleset ID と timestamp は除外します。
bypass actor は actor type で逆変換します。Integration は app、actor ID の 1 は orgAdmin、RepositoryRole は固定 ID の 2・4・5(maintain、write、admin)を記号的な role とし、それ以外の ID は customRole: id:<number> とします。両者が同じ actor type を共有するためです。team、app、custom role は解決済みの id:<number> 形式を使い、role は使いません。bypass actor が空の場合も空リストとして明示的に出力します。省略すると次の apply で actor が消えるためです。rule の parameters はキーを整列し数値を整数として出力し、バイト列を安定させます。
secret の値と source 環境変数名は GitHub から取得できません。secret 名は YAML コメントまたは JSON の診断情報として報告します。ローカルの意図は推測しません。seed source と seed の overwrite、command、agent のファイルパス、agent の secret、repository.create、repository.allowVisibilityChange は、リポジトリの状態からは導けない判断であり、refresh はこれらをすべて保持します。
--into は既に宣言されているパスとトップレベルセクションだけを更新します。宣言済み collection の中では、GitHub 上に存在する項目を更新し、ファイルに無い項目を名前順で追加します。
GitHub 上に存在しない宣言済み項目は保持し、未適用として報告します。削除はしません。設定の項目は「まだ適用されていないかもしれない希望状態」であり、これを削除すると利用者が受け入れを判断しないままドリフトを追認することになるためです。これは、本拡張が authoritative な同期を採用しなかった理由である追加的な規則とも整合します。未宣言セクションは追加せず、空の宣言済み collection も宣言されたまま更新し、残す項目の順序と付属コメントを維持します。
ライブの状態を取得できなかった security の機能は、false と書かずに既存の宣言を保持して報告します。
YAML の refresh は、すべてのトークンがバイトオフセットを持つ AST へ解析し、変更されたスパンだけを置換します。スパン外のコメント、キー順、字下げ、引用符、改行コードはそのまま残ります。
本拡張が現在使っている YAML parser ではこれを実現できません。ノードの開始位置の行と桁しか公開せず、スパンの終端もバイトオフセットも無いうえ、CRLF を LF へ正規化するため、この経路では元の改行コードを保持できないからです。そこで書き換え経路には2つ目の YAML parser を使い、厳格な読み込みと検証は既存の parser のままにします。両者は「有効な文書」の判断で一致していなければならず、読み込みが拒否するものを書き換え経路が受け入れてはいけません。
JSON は JSON として再整形し、入力形式を維持します。差分を表示してから確認し、変更なし、検証エラー、確認拒否、同時編集、保存エラーの場合は元ファイルを変更しません。保存前の検証からは、seed のパスに対する通常のファイルシステム検査を意図的に除外します。実行環境に seed ディレクトリが無いという理由で refresh が失敗しないようにするためです。
「空の plan」とは、create と update の変更が無く、blocked も無い状態を指します。ただし構造上収束しない2種類は除外します。seed、command、agent のファイルパスに対する manual の項目と、GitHub が値を返さない secret の更新です。import 出力に secret は含まれないため、この除外は refresh の検証にのみ影響します。
この状態に到達するには planner 側の作業も必要です。Actions の workflow 権限、selected actions、environment、security の全機能、ruleset の内容、ruleset の bypass actor は、現在ライブの値を読まずに更新として報告しており、対応する apply 側も同じ理由で無条件に書き込みます。repository.description はキーが無い状態と空の値を区別せずに比較するため、description を管理しない文書は変更を報告し続けます。これを homepage と同じ三状態にします。
repository.visibility はスキーマ上必須なので import は常に出力しますが、allowVisibilityChange は import できないローカルの意図です。そのため import 出力を別のリポジトリへ適用すると visibility の変更が blocked になり得ます。ラウンドトリップの判定基準は、その文書を import した元のリポジトリに対して適用されます。
- importer、不足している読み取り、ラップ形式のページング、逆変換、診断、ruleset の正規化を追加します(Issue #18)。
- 管理範囲の判定とローカルの意図の保持を備えた、YAML と JSON のソース保持 refresh エンジンを追加します(Issue #19)。
- CLI の解析と出力を接続し、planner と apply の比較を補完します(Issue #20)。
-
repository.descriptionを三状態にします(Issue #22)。
YAML と JSON の出力を設定ローダーで読み直し、全対応セクション、1ページを超えるページングと上限超過、ラップ形式のレスポンス、open/closed の milestone、すべての bypass actor 種別、secret 診断、API エラーを検証します。refresh は、コメント、非アルファベット順のキー、両方の改行コード、引用符付きと複数行の値、flow 記法、collection の追加と更新、GitHub 上に存在しない宣言済み項目、空の collection で検証し、編集したスパン以外のバイトが変わらないことを確認します。CLI の契約として、位置引数と -R の併用、位置引数の前後のフラグ、yaml|json 以外の形式、非対話入力での --yes なし実行、usage 表示を検証します。import が GitHub への書き込みを行わないこと、上記の定義で plan が空になることを確認します。
本計画は Issue #11 のみを対象とします。plan --ci、apply --force-secrets、および plan --ci に必要な終了コードの配線は別途追跡します。ここに記録した決定は、リポジトリの docs/adr.md と docs/adr_ja.md にも記載しています。