Перейти к основному содержимому

Выполнение архитектурных проверок GoCPG и управление результатами

Проверьте профили выпуска, базовые находки, исключения и инкрементальный анализ GoCPG. Свяжите решение с полными и доверенными доказательствами.

GoCPG

Архитектурная проверка показывает, какие зависимости нарушают принятые границы компонентов, и связывает каждую находку с исходным кодом. Команда может сначала изучить результаты, затем зафиксировать существующий долг и блокировать новые нарушения в CI. Это руководство объясняет, как результат анализа становится решением о выпуске. Оно предназначено для владельцев репозиториев и операторов CI, у которых уже есть проверенная модель и CPG нужной ревизии. Начните с модели и правил, чтобы определить компоненты и контракты. Для изучения выходных данных используйте интерфейсы и результаты.

gocpg architecture validate проверяет только схему правила и применимость языка. Рабочему процессу CI нужны политика проекта, ключ проекта, документ управления выпуском и выходной файл. Также требуется подтверждение, что граф, факты, модель и правила относятся к проверяемому коммиту.

Выберите профиль для этапа внедрения

Начните с discovery, когда ещё определяете компоненты. Используйте advisory, чтобы рассмотреть находки и настроить политику вместе с командой. После фиксации базового долга enforce_new проверяет новые нарушения. Выберите enforce_all, когда выпуск должен учитывать и существующий долг, или strict, когда требуется полная матрица проверок, включая пустые выборки.

Профиль задаёт отношение к находкам, а полнота входных данных определяет, может ли система принять блокирующее решение.

Профили условий выпуска

Проверка оценивает полноту доказательств до подсчёта находок. Требуются актуальный CPG, полный запуск или эквивалентный инкрементальный запуск, результат каждого активного правила, все обязательные возможности, известные знаменатели зависимостей, покрытие классификации и разрешения зависимостей, а также доверенные решения управления.

Профили условий выпуска
Профиль Обработка находок Решение
discovery Помогает построить модель и классифицировать сущности. NOT_APPLICABLE
advisory Показывает находки, пока команда проверяет политику. NOT_APPLICABLE
enforce_new Блокирует новые находки без исключений. PASS или FAIL_VIOLATIONS при полных доказательствах.
enforce_all Блокирует новые и известные находки без исключений. PASS или FAIL_VIOLATIONS при полных доказательствах.
strict Применяет полную матрицу проверок, включая пустые выборки. PASS или FAIL_VIOLATIONS при полных доказательствах.

Любой блокирующий профиль возвращает BLOCKED_INCOMPLETE, если входные данные устарели, неполны, неизвестны или не заслуживают доверия. Только PASS устанавливает release_allowed=true. NOT_APPLICABLE означает, что блокирующее решение не запрашивалось. Для запуска без разрешённых фактов зависимостей нужен известный знаменатель: пустой результат не позволяет заявить покрытие разрешения 100%.

Ниже приведена форма вызова CI для рабочего репозитория. Запускайте её из корня репозитория в PowerShell. Нужны gocpg в PATH, базовая ссылка Git и четыре пути, настроенные для одного проекта. Замените пути и ключ проекта своими. Политика — это манифест политики репозитория, а не отдельное правило kind: architecture, используемое командой architecture validate.

При первом запуске создайте каталог вывода и постройте CPG из того же корня репозитория. Команда ci-update использует сохранённую привязку CPG к исходникам; для отсутствующей базы архитектурный запуск возвращает git_source_scope_unavailable.

New-Item -ItemType Directory -Force .gocpg | Out-Null
gocpg parse --input . --output .gocpg/cpg.duckdb --lang python

Затем обновите граф и получите архитектурный артефакт:

gocpg ci-update --input . --output .gocpg/cpg.duckdb `
  --base-ref origin/main --head-ref HEAD --lang python `
  --architecture-policy .gocpg/architecture/policy.yaml `
  --architecture-project-key my-repository `
  --architecture-release-control .gocpg/architecture/release-control.yaml `
  --architecture-artifact .gocpg/architecture/result.json --json

Четыре архитектурных флага передаются вместе. Минимальный документ управления выпуском для рассмотрения находок может выбрать advisory, но всё равно должен соответствовать текущей схеме и требованиям к доказательствам репозитория. Проверьте идентичность запуска, полноту, результаты правил и статус условий выпуска в выходном файле. Успешного кода завершения CLI недостаточно для подтверждения PASS. Руководство по внедрению объясняет общую последовательность перехода.

Учебный запуск с готовыми входами

Используйте PowerShell 7, Git с настроенными именем и адресом автора, gocpg в PATH и исходную рабочую копию CodeGraph. Замените два пути ниже. Создайте новый каталог для примера. Два Python-модуля дают реальную зависимость для проверки покрытия; поставляемый реестр позволяет найти python/module-boundaries@1.0.0.

$CodeGraphSource = "<path-to-codegraph-source>"
$DemoRoot = "<new-empty-directory>"
New-Item -ItemType Directory -Path $DemoRoot | Out-Null
Set-Location $DemoRoot
New-Item -ItemType Directory -Force app, .gocpg/architecture/fixtures, gocpg/configs/architecture/presets | Out-Null
Copy-Item -Recurse "$CodeGraphSource/gocpg/configs/architecture/presets/v1" gocpg/configs/architecture/presets/v1
@'
from app.helpers import format_greeting

def greet(name):
    return format_greeting(name)
'@ | Set-Content -Encoding utf8 app/service.py
@'
def format_greeting(name):
    return "Hello, " + name
'@ | Set-Content -Encoding utf8 app/helpers.py
@'
.gocpg/cpg.duckdb*
.gocpg/architecture/result.json
'@ | Set-Content -Encoding utf8 .gitignore

Создайте политику одного компонента и документ управления с профилем discovery. Пути fixtures задают пары исходников правила; оценка их соответствия — отдельный этап подготовки промышленной политики.

@'
schema_version: architecture_policy.v1
id: teaching-service/python
version: 1.0.0
preset_ref: python/module-boundaries@1.0.0
source_paths:
- app/*.py
- app/**/*.py
vocabularies:
  layer:
  - service
dispositions:
- id: include-production
  action: include
  paths:
  - app/*.py
  - app/**/*.py
  owner: Architecture Team
  reason: Teaching source population.
components:
- uid: service
  id: service
  name: Service
  kind: leaf
  tags:
    layer:
    - service
classifiers:
- id: service-files
  component: service
  priority: 100
  paths:
  - app/**
  entity_kinds:
  - file
  - function
  - method
  - type
rules:
- id: TEAM-CLASSIFICATION-01
  version: 1.0.0
  contract: exhaustive_classification
  mode: discovery
  owner: Architecture Team
  severity: high
  applicability: python
  rationale: Classify every source entity.
  fixtures:
    valid: fixtures/valid.py
    invalid: fixtures/invalid.py
  spec:
    contract: exhaustive_classification
    languages:
    - python
    minimum_coverage: 1
'@ | Set-Content -Encoding utf8 .gocpg/architecture/policy.yaml
@'
schema_version: architecture_release_control.v1
profile: discovery
scope: enforce_new
previous_modes: {}
governance_manifest_path: ''
advisory_cycles_path: ''
rollback_requested: false
rollback_policy_disabled: false
rollback_from_policy_id: ''
rollback_from_policy_version: ''
rollback_from_policy_digest: ''
'@ | Set-Content -Encoding utf8 .gocpg/architecture/release-control.yaml
"def valid(): return 1" | Set-Content -Encoding utf8 .gocpg/architecture/fixtures/valid.py
"def invalid(): return 0" | Set-Content -Encoding utf8 .gocpg/architecture/fixtures/invalid.py

Зафиксируйте входы в Git, постройте CPG и выполните архитектурную проверку. Локальная ссылка origin/main здесь обозначает ту же учебную ревизию.

git init -b main
git add .
git commit -m "Teaching architecture input"
git update-ref refs/remotes/origin/main HEAD
gocpg parse --input . --output .gocpg/cpg.duckdb --lang python
gocpg ci-update --input . --output .gocpg/cpg.duckdb `
  --base-ref origin/main --head-ref HEAD --lang python `
  --architecture-policy .gocpg/architecture/policy.yaml `
  --architecture-project-key teaching-service `
  --architecture-release-control .gocpg/architecture/release-control.yaml `
  --architecture-artifact .gocpg/architecture/result.json --json
$result = Get-Content .gocpg/architecture/result.json -Raw | ConvertFrom-Json
$result | Select-Object status, complete, release_allowed, reason_codes
$result.binding | Select-Object project_key, repository_revision, cpg_repository_revision

Ожидаемый результат: код завершения 0, status=NOT_APPLICABLE, complete=true, release_allowed=false, причина non_enforcing_profile. В binding указан teaching-service, а repository_revision совпадает с cpg_repository_revision и выводом git rev-parse HEAD. В active_rule_ids и rule_outcome_ids присутствует TEAM-CLASSIFICATION-01. Профиль discovery готовит результат анализа для рассмотрения командой.

Получите и объясните находку

Продолжите работу в том же учебном репозитории. Теперь отнесите app/service.py к компоненту service, а app/helpers.py — к storage. Правило TEAM-BOUNDARY-01 запрещает прямой импорт из первого компонента во второй. Существующий импорт в первой строке app/service.py даст одну находку.

Замените политику следующим файлом и добавьте два образца для нового правила. Профиль остаётся discovery: он собирает результаты для изучения зависимостей.

@'
schema_version: architecture_policy.v1
id: teaching-service/python
version: 1.0.0
preset_ref: python/module-boundaries@1.0.0
source_paths:
- app/*.py
- app/**/*.py
vocabularies:
  layer:
  - service
  - storage
dispositions:
- id: include-production
  action: include
  paths:
  - app/*.py
  - app/**/*.py
  owner: Architecture Team
  reason: Teaching source population.
components:
- uid: service
  id: service
  name: Service
  kind: leaf
  tags:
    layer:
    - service
- uid: storage
  id: storage
  name: Storage
  kind: leaf
  tags:
    layer:
    - storage
classifiers:
- id: service-files
  component: service
  priority: 100
  paths:
  - app/service.py
  entity_kinds:
  - file
  - function
  - method
  - type
- id: storage-files
  component: storage
  priority: 100
  paths:
  - app/helpers.py
  entity_kinds:
  - file
  - function
  - method
  - type
rules:
- id: TEAM-CLASSIFICATION-01
  version: 1.0.0
  contract: exhaustive_classification
  mode: discovery
  owner: Architecture Team
  severity: high
  applicability: python
  rationale: Classify every source entity.
  fixtures:
    valid: fixtures/valid.py
    invalid: fixtures/invalid.py
  spec:
    contract: exhaustive_classification
    languages:
    - python
    minimum_coverage: 1
- id: TEAM-BOUNDARY-01
  version: 1.0.0
  contract: forbidden_dependency
  mode: discovery
  owner: Architecture Team
  severity: high
  applicability: python
  rationale: Teaching forbidden service-to-storage import.
  fixtures:
    valid: fixtures/boundary-valid.py
    invalid: fixtures/boundary-invalid.py
  spec:
    contract: forbidden_dependency
    from:
      components:
      - service
    to:
      components:
      - storage
    relation:
      edge_types:
      - import
      reachability: direct
'@ | Set-Content -Encoding utf8 .gocpg/architecture/policy.yaml
@'
def greet(name):
    return name
'@ | Set-Content -Encoding utf8 .gocpg/architecture/fixtures/boundary-valid.py
@'
from app.helpers import format_greeting

def greet(name):
    return format_greeting(name)
'@ | Set-Content -Encoding utf8 .gocpg/architecture/fixtures/boundary-invalid.py

Сохраните новую ревизию, перестройте CPG и повторите анализ. Команды получают ID запуска и отпечаток из артефакта, затем показывают объяснение находки:

git add .gocpg/architecture
git commit -m "Teaching forbidden dependency"
git update-ref refs/remotes/origin/main HEAD
gocpg parse --input . --output .gocpg/cpg.duckdb --lang python
gocpg ci-update --input . --output .gocpg/cpg.duckdb `
  --base-ref origin/main --head-ref HEAD --lang python `
  --architecture-policy .gocpg/architecture/policy.yaml `
  --architecture-project-key teaching-service `
  --architecture-release-control .gocpg/architecture/release-control.yaml `
  --architecture-artifact .gocpg/architecture/result.json --json
$artifact = Get-Content .gocpg/architecture/result.json -Raw | ConvertFrom-Json
$RunId = $artifact.binding.run_id
$Fingerprint = $artifact.current_advisory_cycle.rule_fingerprints.'TEAM-BOUNDARY-01'[0]
gocpg architecture explain --db .gocpg/cpg.duckdb --run-id $RunId --fingerprint $Fingerprint --json

Ожидайте finding_count: 1, complete: true и статус NOT_APPLICABLE в артефакте. В ответе explain поле rule_id содержит TEAM-BOUNDARY-01, компоненты — service и storage, а поле primary_location указывает на app/service.py, строку 1. Так можно перейти от правила границы к конкретному импорту и связанному файлу.

Для просмотра и экспорта результатов используйте этот $RunId; $Fingerprint выбирает находку для объяснения.

Исправьте исходник и повторите проверку

В том же учебном каталоге перенесите простое форматирование в greet. Функция по-прежнему возвращает Hello, и имя, а прямой импорт из компонента service в storage исчезает. Зафиксируйте изменение и пересоберите граф:

@'
def greet(name):
    return "Hello, " + name
'@ | Set-Content -Encoding utf8 app/service.py
git add app/service.py
git commit -m "Remove forbidden storage dependency"
git update-ref refs/remotes/origin/main HEAD
gocpg parse --input . --output .gocpg/cpg.duckdb --lang python
gocpg ci-update --input . --output .gocpg/cpg.duckdb `
  --base-ref origin/main --head-ref HEAD --lang python `
  --architecture-policy .gocpg/architecture/policy.yaml `
  --architecture-project-key teaching-service `
  --architecture-release-control .gocpg/architecture/release-control.yaml `
  --architecture-artifact .gocpg/architecture/result.json --json
$fixed = Get-Content .gocpg/architecture/result.json -Raw | ConvertFrom-Json
$fixed | Select-Object finding_count, complete, status

В новом артефакте ожидаются finding_count: 0, complete: true и status: BLOCKED_INCOMPLETE. Поле reason_codes содержит canonical_coverage_incomplete: после удаления единственного импорта в этом минимальном проекте нет связей для расчёта покрытия. Правило выполнено, находка устранена, а проверка выпуска отдельно оценивает покрытие графа. Ревизии в binding.repository_revision и binding.cpg_repository_revision должны совпадать с git rev-parse HEAD.

Действие по результату

Действие по результату
Результат Следующее действие
PASS Используйте архитектурный результат в пакете приёмки выпуска.
FAIL_VIOLATIONS Рассмотрите блокирующие находки: исправьте зависимости или получите решение об исключении для текущей области. Затем повторите анализ.
BLOCKED_INCOMPLETE Проверьте ревизию CPG, полноту результатов правил и доверие к документу управления. Обновите недостающие входы и повторите запуск.
NOT_APPLICABLE Рассмотрите результаты discovery/advisory и выберите блокирующий профиль, когда политика готова к применению.

Базовый набор известных находок

Базовый набор фиксирует уже рассмотренный долг для точного правила, версии отпечатка, отпечатка находки и семантического хеша правила. В enforce_new точная известная находка исключается из числа новых нарушений. enforce_all и strict продолжают учитывать известный долг без исключений. Базовый набор подтверждает рассмотрение находки, но не делает зависимость допустимой и не изменяет граф.

Например, UI импортирует хранилище. Если отпечаток рассмотрен как существующий долг, следующий идентичный запуск может считать находку известной. При смене direct на transitive меняется семантический хеш: прежнее решение переходит в needs_review. Если импорт исчезает и затем возвращается, находка считается повторно появившейся, а не автоматически известной.

Для регистрации известного долга выполните полный анализ и рассмотрите каждую находку. Получите подписанный манифест управления от сервиса, который хранит решения по проекту, затем повторите анализ с привязкой к этому манифесту. Локальная выгрузка базового набора помогает сравнить находки между запусками; подписанный манифест определяет, какие решения учитываются при проверке выпуска.

Исключения и доверие

Исключение относится к одной находке и имеет срок действия. Оно содержит владельца правила, заявителя, согласующего, причину, ссылку на решение, отпечаток, семантический хеш, версию отпечатка и область действия. Заявитель и согласующий должны быть разными участниками. Изменение отпечатка, правила, репозитория или ревизии требует нового решения. Псевдоним символа не переносит исключение.

Подписываемые данные Ed25519 связывают проект, репозиторий, коммит, ветку, хеши модели и правил, период действия и монотонную ревизию. Доверенные публичные ключи и состояние отзыва поступают из плоскости управления или конфигурации CI. Проверяются подпись, ID ключа, отзыв, срок действия и точная область. Истёкшие, отозванные, неиспользованные и устаревшие исключения остаются видимыми находками. Ошибка подписи или области блокирует проверку с BLOCKED_INCOMPLETE.

Например, исключение подписано для коммита A, а политика проверяется на B. Не копируйте отпечаток в локальный YAML для подавления находки. После полного запуска получите решение для текущей области.

Инкрементальные проверки

Планировщик использует изменённые пути и UID затронутых компонентов, чтобы решить, можно ли повторно использовать работу. Изменения модели, публичного API, рёбер зависимостей, сильно связных компонент, базового набора и исключений расширяют область пересчёта. Неизвестные компоненты или неполная область пересчёта вызывают ошибку. По умолчанию полный запуск выбирается, если доля затронутых компонентов превышает 0.20. Изменение модели всегда требует полного запуска.

incremental_complete имеет полномочия для выпуска только при совпадении отпечатков, состояний жизненного цикла, базового набора и исключений, покрытия, семантического хеша и решения с полным запуском на тех же данных. Неполный блокирующий запуск получает одну синхронную полную повторную попытку. Если она неполна, завершилась ошибкой, устарела или не совпадает, результат остаётся BLOCKED_INCOMPLETE.

Например, перенос src/ui/ в новый компонент изменяет классификацию и может затронуть рёбра вне списка изменённых файлов. Поэтому изменение модели запускает полный анализ. Проверка только изменённых файлов пропустила бы связи переклассифицированных сущностей.

Переход с прежних проверок

Для прежних проверок выбирается решение: migrate, retain advisory, retire или defer. Режимы discovery и advisory могут показывать явно помеченные прежние доказательства. Но прежний результат не создаёт канонический PASS, состояние находки, базовый набор, исключение или разрешение выпуска.

  1. Перечислите прежние обработчики и наборы правил; назначьте каждому решение.
  2. Выполните прежний и канонический процессы параллельно на одной ревизии. Классифицируйте различия по устойчивому отпечатку и подтверждающим исходникам.
  3. Квалифицируйте эталонные примеры и устраните необъяснённые блокирующие пропуски нарушений.
  4. Наблюдайте два реальных цикла выпуска в advisory с устойчивой семантической идентичностью.
  5. Переведите потребителей на сохранённые канонические результаты и подтвердите отключение прежней блокирующей проверки.

Откат может вернуть блокирующий режим в advisory. Он не даёт прежней проверке полномочий разрешать выпуск. Локальная проверка совпадения подтверждает только свои тестовые данные, а не промышленное внедрение.

Проверки реализации

Из корня модуля gocpg эти тесты проверяют контракты реализации. Они не доказывают, что произвольный репозиторий прошёл условия выпуска.

go test ./pkg/architecture -run '^TestSignedGovernanceRequiresExactScopeAndSeparationOfDuties$' -count=1
go test ./pkg/architecture -run '^TestNormativeGovernanceRequiresCompleteScopeRevisionAndRevocationState$' -count=1
go test ./pkg/architecture -run '^TestNormativeReleaseGateFiveProfilesAndStateMatrix$' -count=1
go test ./pkg/architecture -run '^TestStory1240FullIncrementalEquivalence$' -count=1
go test ./pkg/architecture -run '^TestCodeGraphReleaseGateRejectsLegacyAuthorityInEnforceNew$' -count=1