Skip to content

feat(source-set): добавить dependsOn и dependency-aware build для CFE → CFE #32

Description

@zeegin

Контекст

Связано с IngvarConsulting/unica#170: тестовое расширение TESTS использует API расширения YaXUnit и должно собираться/загружаться вместе с ним и основной конфигурацией.

Проверено на:

  • v0.5.1;
  • v0.5.2-pre.1 / current master (be558db1c456f2d3a828c0f4de121b980ba6ccdc).

Сейчас source-set содержит только name, type и path: SourceSetSchema.

Validator проверяет только глобальное условие «если существует EXTENSION, должна существовать хотя бы одна CONFIGURATION», но не связывает конкретное расширение с базовой конфигурацией или другим расширением: validate_source_sets.

Проблема

В реальном проекте расширения могут зависеть от API других расширений:

main CONFIGURATION
└── yaxunit EXTENSION
    └── TESTS EXTENSION

Текущий canonical order группирует все конфигурации, затем все расширения, сохраняя YAML-порядок внутри группы: ordered_source_sets.

Это позволяет вручную поставить YaXUnit перед TESTS, но не фиксирует причинную связь. Порядок декларации становится скрытым operational contract.

Дополнительно build --source-set TESTS выбирает только TESTS, без основной конфигурации и YaXUnit: selected_ordered_source_sets.

test yaxunit частично маскирует проблему, поскольку перед тестом запускает build всех source-set с source_set: None: run_tests coordinator.

Это operational co-loading всех расширений, а не dependency contract. Из-за этого полный тестовый запуск может работать, а scoped build на чистой ИБ — зависеть от уже установленного состояния или завершаться ошибкой.

Минимальное воспроизведение

source-set:
  - name: main
    type: CONFIGURATION
    path: src/cf

  - name: yaxunit
    type: EXTENSION
    path: vendor/yaxunit

  - name: TESTS
    type: EXTENSION
    path: src/cfe/TESTS

Условия:

  1. TESTS вызывает экспортный API YaXUnit.
  2. Полный build обрабатывает элементы только по category/YAML order.
  3. build --source-set TESTS не включает main и yaxunit.
  4. В v8project.yaml невозможно выразить, что TESTS требует YaXUnit.

Предлагаемый контракт

Добавить optional source-set[].dependsOn — список stable source-set.name непосредственных зависимостей:

source-set:
  - name: main
    type: CONFIGURATION
    path: src/cf

  - name: yaxunit
    type: EXTENSION
    path: vendor/yaxunit
    dependsOn:
      - main

  - name: TESTS
    type: EXTENSION
    path: src/cfe/TESTS
    dependsOn:
      - yaxunit

Семантика A.dependsOn: [B]:

  • B должен быть успешно построен/загружен раньше A;
  • scoped operation для A включает B;
  • транзитивные зависимости B также включаются;
  • связь направленная и не означает обратной зависимости B → A.

Closure для примера:

main → yaxunit → TESTS

Validation contract

До любого platform call необходимо проверять:

  • каждое имя dependency существует;
  • self-reference и повторяющиеся зависимости запрещены;
  • dependency target имеет тип CONFIGURATION или EXTENSION;
  • граф ацикличен;
  • closure dependency-aware расширения содержит ровно одну CONFIGURATION;
  • несколько ветвей зависимостей не приводят к разным configuration roots;
  • ошибка содержит source-set и путь проблемы, например:
source-set dependency cycle: TESTS -> yaxunit -> TESTS

Base-Project EDT можно проверять на непротиворечивость объявленному configuration root, если он присутствует, но не использовать для неявного вывода CFE → CFE.

Ordering contract

Для полного build использовать stable topological order:

  1. dependency всегда раньше dependent;
  2. для несвязанных узлов сохраняется существующий canonical category order;
  3. внутри равноправной группы сохраняется порядок из YAML.

Добавление графа не должно случайно переставлять независимые source-set.

Scoped closure

v8-runner build --source-set TESTS

должен построить:

main
yaxunit
TESTS

Каждый source-set обрабатывается не более одного раза. Change detection применяется к каждому элементу closure отдельно: неизменённая зависимость может получить Skipped, но остаётся частью вычисленного плана. Ошибка dependency не должна позволять начать dependent.

Желательно отражать в structured result как исходный selector, так и раскрытый план, например:

{
  "requestedSourceSets": ["TESTS"],
  "expandedSourceSets": ["main", "yaxunit", "TESTS"]
}

Один resolver closure следует использовать во всех scoped runtime-командах, которые собирают или загружают source-set.

Backward compatibility

dependsOn остаётся optional.

Для существующего проекта с одной CONFIGURATION и расширениями без dependsOn сохраняется текущее поведение full build. Для scoped extension build единственная конфигурация может считаться implicit base.

Если конфигураций несколько, dependency-aware extension должен явно приводить closure к одной из них; неоднозначность не следует разрешать порядком YAML.

Критерии готовности

  • JSON Schema, loader и domain model принимают dependsOn: [<source-set-name>...].
  • Unknown dependency, self-reference и duplicate dependency отклоняются до platform calls.
  • Прямой и транзитивный cycle отклоняются с полным cycle path.
  • Dependency на external processor/report отклоняется.
  • Closure расширения разрешает ровно одну configuration root.
  • Полный build использует stable topological order.
  • Независимые source-set сохраняют текущий canonical/YAML order.
  • build --source-set TESTS выполняет main → yaxunit → TESTS.
  • Diamond graph не выполняет общий dependency дважды.
  • Change detection и --full-rebuild работают отдельно для каждого узла closure.
  • Failure dependency блокирует dependent.
  • test yaxunit сохраняет текущее поведение.
  • Старый проект без dependsOn продолжает загружаться.
  • Есть unit tests validation/toposort и integration test scoped transitive build.

Не входит в задачу

  • автоматический вывод зависимостей из вызовов BSL;
  • трактовка YAML-порядка как декларации зависимости;
  • смешивание runtime build/load graph со static-analysis visibility graph;
  • неявный вывод CFE → CFE из EDT layout или имени каталога.

Runtime graph нужен как источник истины, который затем смогут использовать Unica и статические анализаторы, но собственно semantic visibility анализатора должна решаться отдельно.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions