インフラ・DevOps
ImpactGate: AIが追加する構造的劣化をスコアリングするマージゲート
ImpactGate: A merge gate that scores the structural decay AI adds (github.com)
要約
ImpactGateは、コード変更が導入する構造的劣化(複雑性の増加)を測定・ゲートするツールです。変更の影響度を計算し、しきい値を超えた場合に警告またはビルドをブロックします。CLI、gitフック、GitHub Actions、GitLab CI、Jenkins CIなどのワークフローに統合でき、絶対的なしきい値またはプロジェクトの履歴に基づいたパーセンタイルによるゲート設定が可能です。
全文翻訳
ImpactGate: AIが追加する構造的劣化をスコアリングするマージゲート
impact-gate 変更が導入する構造的劣化を測定し、ゲートします。スタンドアロンCLI、gitプリコミットフック、またはGitHub、GitLab、Jenkins CIのプラグインとして実行できます。ウェブサイト: https://impactgate.officefloor.net
構造的劣化とは、既存の構造に複雑性が蓄積することです。ゴッドメソッドが別のブランチを成長させます。ゴッドクラスが別のメソッドを獲得します。
ゲートは、変更の影響度測定を使用して、変更をベース(デフォルトではmain)に対してスコアリングします。影響度 = 変更されたファイル数 * Σ max(WMC_other, 1) * CC * Δlines (変更された関数全体)
WMC_otherは、編集中のコンテナに既に存在する複雑性です。これは変更前の状態に基づいて測定されます。そのため、全く新しいファイルやクラスをインポートするのは安価です。以前は何もありませんでした。既に重いクラスに積み重ねるのは高価です。これが劣化のシグナルです。
計算式の根拠については、OfficeFloorブログの「Measuring the Blast Radius of Change」を参照してください。
影響度が高すぎる場合、ゲートは変更の単純化またはコードのリファクタリングを要求します。警告(レポートのみ)またはブロック(ビルド失敗)が可能です。
インストール
pip install impact-gate
# `impact-gate` コマンドをインストールします
または、インストールせずに、公開されているイメージ経由で実行します(gitがバンドルされています。スコアリングするにはリポジトリを/repoにマウントしてください)。
docker run --rm -v "$PWD:/repo" ghcr.io/officefloor/impact-gate \
score --mode range --base origin/main
ローカルでハックするには、チェックアウトからインストールしてください。
python -m venv .venv && . .venv/bin/activate
pip install -e '. [dev]'
# editable install にテスト依存関係を追加
使用方法
# コミットしようとしているコミット(プリコミット): ステージングされた変更 vs HEAD。これはデフォルトです。
impact-gate score
# コミットされていないローカル編集: ワーキングツリー vs HEAD。
impact-gate score --mode worktree
# CIまたはPRレビュー: コミットされたブランチ vs main (merge-base..HEAD)。
impact-gate score --mode range --base origin/main --format json
# しきい値と強制設定。これらは.impact-gate.ymlにも記述できます。
impact-gate score --warn-at 50000 --block-at 200000 --enforcement block
終了コード。
0 は OK または警告(変更は許可されます)を意味します。
2 はブロック(--enforcement block で影響度が高すぎる場合)を意味します。
1 は使用法または環境エラーを意味します。
各レポートには、リファクタリングを検討すべきファイルも、影響度への貢献度順にリストされます。変更レベルの数値がゲートを制御し、ファイルごとのランキングは劣化が集中している場所を示します。これにより、静かにゴッドクラスへと成長しているファイルが、何かをブロックする前に候補として浮上します。
差分がmax_diff_lines(デフォルトで200,000、測定設定内)より大きいソースファイルは、ほぼ常に生成されたダンプまたはベンダー提供のブロブです。ゲートはこれをスキップするため、数値が歪んだり、スコアリングが遅くなったりせず、スキップされたファイルとしてリストされるため、結果がサイレントに間違っていることはありません。
gitプリコミットフックとしての使用
CIの前に、ローカルで各コミットをゲートします。
# .git/hooks/pre-commit をインストールします。各コミット時にステージングされた変更をスコアリングします。
impact-gate install-hook
強制設定付き:
.impact-gate.yml でブロックを設定すると、影響度が高すぎるコミットはブロックされます。警告(またはオフ)の場合は、レポートが表示され、コミットは続行されます。
既存のプリコミットフックを上書きするには --force を付けて再実行してください。
プリコミットフレームワークを好みますか?
このリポジトリはフック定義を提供しています — .pre-commit-config.yaml に追加してください。
repos:
- repo: https://github.com/officefloor/ImpactGate
rev: v0.3.0
hooks:
- id: impact-gate
分布(カーブ)に対する評価
生のしきい値を設定するのは困難です。典型的な変更の影響度は、言語やプロジェクトによって桁違いに異なります。数値を推測する代わりに、分布に対するパーセンタイルで変更を評価し、パーセンタイルでゲートします。
# プロジェクト自身のインパクト分布をマージされた履歴からビルド(またはリフレッシュ)します。
# .impact-gate-baseline.json を書き込みます。ブランチが進むにつれて再実行してください。
impact-gate baseline --base-ref main
# 絶対数ではなく、グレードでゲートします。
impact-gate score --curve --warn-percentile 90 --block-percentile 98
グレードは2つの分布をブレンドします。1つはツールに付属するシードプライアである、20リポジトリのオープンソースコーパスから構築された言語ごとのパーセンタイルテーブルで、テーブルにない言語にはプールされたフォールバックがあります。もう1つはプロジェクトのベースラインで、リポジトリ自身の変更ごとの分布で、マージされたメインラインからウォークされます(コミットされた作業のみ。進行中のブランチは到達しません)。
ブレンドは、nがベースラインの後ろにあるコミット数、K(curve_prior_weight、デフォルト200)がプロジェクトをシードよりも信頼するのに必要な履歴量である場合、w = n / (n + K) でプロジェクトに重みを付けます。
ベースラインファイルがない新しいリポジトリはシードのみで評価されます。深い履歴はそれ自体に依存します。
グレードは、すべてのフォーマットで生の数値の隣に表示されます。
設定は.impact-gate.yml(リポジトリルート)で行います。
warn_at: 50000 # 警告を発する影響度
block_at: 200000 # ブロックする影響度
enforcement: warn # off, warn, or block. warnから開始し、準備ができたらblockに切り替えます。
tolerance: 1.0 # 両方のしきい値に対するCI調整可能な乗数。1より大きいとより寛容になります。
# measure_config: .impact-measure.yml # オプション: グロブと言語のオーバーライドを無視する
# グレーディングカーブ(パーセンタイルゲート)。有効にすると、warn_at/block_atは無視され、
# ゲートは以下のパーセンタイルを使用します。
curve_enabled: false # 絶対数ではなく、パーセンタイルグレードでゲートする
warn_percentile: 90 # 警告を発するグレード(この値以上)
block_percentile: 98 # ブロックするグレード(この値以上)
curve_prior_weight: 200 # w = n/(n+K) における K: プロジェクトをシードより信頼するのに必要な履歴量
baseline_file: .impact-gate-baseline.json # `impact-gate baseline` が分布をキャッシュする場所
CLIフラグはファイルをオーバーライドします。CIジョブは--toleranceまたは--warn-atを渡すことができます。これにより、チームはリポジトリを編集せずに許容度を調整できます。
カーブのノブにもフラグがあります: --curve, --warn-percentile, --block-percentile, --baseline-file。
GitHub Actionsでの使用
リポジトリにワークフローを追加します。アクションはPRブランチをベースと比較してスコアリングし、サマリーを書き込みます。
fetch-depth: 0 は、ベースブランチとマージベースが存在するために必要です。
name: Change impact
on: pull_request
permissions:
contents: read
pull-requests: write # アクションがPRコメントとしてスコアを投稿できるようにするため
jobs:
impact:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: officefloor/ImpactGate@v0
with:
enforcement: warn # 準備ができたらblockに切り替える
# warn-at: 50000
# block-at: 200000
# tolerance: 1.0
スコアはジョブサマリーとPRのスティッキーコメント(1つのコメント、実行ごとに更新)として表示されます。
ブロックモードでは、影響度がブロックしきい値を超えるとジョブは失敗します。
マージをゲートするには、ブランチ保護でチェックを必須にします。
コメントにはpull-requests: writeが必要です。それがない場合、実行はパスしますが、コメントはスキップされます。
GitLab CIでの使用
ci/gitlab-ci.yml にすぐに使えるジョブがあります。それを.gitlab-ci.ymlにコピーするか、リモートからインクルードしてください。
include:
- remote: 'https://raw.githubusercontent.com/officefloor/ImpactGate/v0/ci/gitlab-ci.yml'
これはマージリクエストパイプラインで実行され、公開されているDockerイメージを使用してMRをベース($CI_MERGE_REQUEST_DIFF_BASE_SHA)に対してスコアリングし、CI/CD変数GITLAB_TOKENにapiスコープが設定されている場合は、MRにスティッキーノートを投稿します(1つのノート、実行ごとに更新)。トークンがない場合でも、スコアリングとゲートは行われますが、ノートはスキップされます。
ブロック強制モードでは、影響度が高すぎるとジョブが失敗します。マージをゲートするには、マージリクエスト設定で必須にしてください。
Jenkinsでの使用
ci/Jenkinsfile にパイプラインスニペットがあります。Dockerを備えたエージェントでDockerイメージを実行し、変更をターゲットブランチ(origin/${CHANGE_TARGET:-main})に対してスコアリングし、レポートをアーカイブします。
ブロック強制モードでは、影響度が高すぎるとステージが失敗します。
PR/MRへのスコアの投稿は、SCMインテグレーションに任されています。ツール自体で投稿するには、プロバイダーのトークンと環境を設定してコンテナ内で `impact-gate comment` を実行してください。
ロードマップ
コアCLI。ステージング、ワーキングツリー、またはレンジのスコアリング。警告またはブロック。テキスト、JSON、Markdown。完了。
GitHubアクション。コンポジットアクション、ジョブサマリーレポート、スティッキーPRコメント。完了。
ベースラインとグレーディングカーブ。impact-gate baseline はプロジェクト履歴をプロファイルします。ゲートは、s