From c126e33035a8ea3836968a850b89fa239d191014 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 23 Sep 2026 11:32:34 +0300 Subject: [PATCH 01/26] docs(v1): align reference with pilot behavior --- content/docs/guides/adding-dependency.mdx | 16 +++++++-- content/docs/guides/adding-dependency.ru.mdx | 16 +++++++-- content/docs/guides/buf-migration.mdx | 8 ++--- content/docs/guides/buf-migration.ru.mdx | 11 +++--- content/docs/guides/debugging-replace.mdx | 6 ++-- content/docs/guides/debugging-replace.ru.mdx | 6 ++-- content/docs/reference/easyp-gen-yaml.mdx | 36 +++++++++++++++---- content/docs/reference/easyp-gen-yaml.ru.mdx | 36 +++++++++++++++---- content/docs/reference/easyp-yaml.mdx | 38 ++++++++++---------- content/docs/reference/easyp-yaml.ru.mdx | 38 ++++++++++---------- content/docs/reference/protobuf-lock.mdx | 4 ++- content/docs/reference/protobuf-lock.ru.mdx | 4 ++- content/docs/reference/protobuf-mod.mdx | 2 +- content/docs/reference/protobuf-mod.ru.mdx | 2 +- 14 files changed, 149 insertions(+), 74 deletions(-) diff --git a/content/docs/guides/adding-dependency.mdx b/content/docs/guides/adding-dependency.mdx index 4287081..202578f 100644 --- a/content/docs/guides/adding-dependency.mdx +++ b/content/docs/guides/adding-dependency.mdx @@ -9,7 +9,7 @@ This guide demonstrates how to add a third-party or shared Protobuf module depen ## Workflow Overview -1. **Declare Dependency**: Add the target module repository URL and version tag to `protobuf.mod` or reference it directly via `import` statements in your `.proto` schema files. +1. **Declare Dependency**: Add the target Git repository identity and version tag to `protobuf.mod`. Use `import` statements to reference files from that declared dependency. 2. **Run Resolution**: Execute `easyp mod tidy` to compute the transitive dependency graph. 3. **Commit Lockfile**: Review the updated `protobuf.mod` and `protobuf.lock` files and commit them to version control. @@ -28,7 +28,7 @@ require ( ) ``` -Alternatively, you can write an `import` statement directly in your Protobuf source file: +Then import a file provided by that dependency in your Protobuf source: ```protobuf // proto/user/v1/user.proto @@ -56,6 +56,18 @@ easyp mod tidy - Appends transitive dependencies to `protobuf.mod` marked with `// indirect`. - Generates or updates `protobuf.lock` with Git commit hashes and cryptographic content digests. +### Git repositories using Buf or older EasyP configs + +The consuming project still declares a Git source with `require`. The dependency repository may use another configuration format: + +- EasyP v1 `protobuf.mod`: reads `roots` and `require`. +- Buf v2 `buf.yaml`: reads `modules[].path` as import roots. +- Buf v1 `buf.work.yaml`: reads `directories`; a single-module v1 `buf.yaml` uses `.`. +- Buf v1beta1 `buf.yaml`: reads `build.roots`, defaulting to `.`. +- Older EasyP: reads `direct` dependencies from the old `protobuf.mod` and local `generate.inputs[].directory.root` plus Git inputs from `easyp.yaml`. + +For an old EasyP dependency without a version on one of its Git requirements, `mod tidy` selects its latest stable SemVer tag and pins the selected commit in the v1 lock. Buf Registry `deps` are not Git sources, so declare an appropriate Git module in the consuming `protobuf.mod` when those imports are needed. Buf `includes`/`excludes` filters are not yet supported for Git dependency import roots and produce an explicit error. + Updated `protobuf.mod`: ```protobuf diff --git a/content/docs/guides/adding-dependency.ru.mdx b/content/docs/guides/adding-dependency.ru.mdx index c7f993c..233b3f4 100644 --- a/content/docs/guides/adding-dependency.ru.mdx +++ b/content/docs/guides/adding-dependency.ru.mdx @@ -9,7 +9,7 @@ description: "Пошаговое руководство по добавлени ## Общий процесс -1. **Объявление зависимости**: Добавление URL репозитория и тега версии в `protobuf.mod` или прямое использование `import` в `.proto` файлах. +1. **Объявление зависимости**: Добавление Git-репозитория и тега версии в `protobuf.mod`. Через `import` в `.proto` используются файлы объявленной зависимости. 2. **Запуск резолюции**: Выполнение `easyp mod tidy` для вычисления полного графа транзитивных зависимостей. 3. **Фиксация в Git**: Проверка и коммит обновлённых файлов `protobuf.mod` и `protobuf.lock`. @@ -28,7 +28,7 @@ require ( ) ``` -Также вы можете просто добавить инструкцию `import` прямо в Protobuf-файл: +После этого импортируйте файл зависимости в Protobuf-файле: ```protobuf // proto/user/v1/user.proto @@ -56,6 +56,18 @@ easyp mod tidy - Дописывает транзитивные зависимости в `protobuf.mod` с пометкой `// indirect`. - Генерирует или обновляет `protobuf.lock` с хешами коммитов и контрольными суммами. +### Git-репозитории с конфигурацией Buf или старого EasyP + +Проект-потребитель по-прежнему объявляет Git-источник через `require`. Репозиторий зависимости может использовать другой формат: + +- EasyP v1 `protobuf.mod`: читаются `roots` и `require`. +- Buf v2 `buf.yaml`: `modules[].path` задаёт корни импортов. +- Buf v1 `buf.work.yaml`: читаются `directories`; одиночный модуль с `buf.yaml` v1 использует `.`. +- Buf v1beta1 `buf.yaml`: читаются `build.roots`, по умолчанию `.`. +- Старый EasyP: из прежнего `protobuf.mod` читаются зависимости `direct`, а из `easyp.yaml` — локальные `generate.inputs[].directory.root` и Git-входы. + +Если в старой зависимости EasyP у Git-зависимости не указана версия, `mod tidy` выбирает последний стабильный тег SemVer и фиксирует выбранный commit в v1 lock. `deps` из Buf Registry не являются Git-источниками: когда нужны их импорты, укажите соответствующий Git-модуль в `protobuf.mod` проекта-потребителя. Фильтры Buf `includes`/`excludes` для корней Git-зависимости пока не поддерживаются и вызывают явную ошибку. + Обновлённый `protobuf.mod`: ```protobuf diff --git a/content/docs/guides/buf-migration.mdx b/content/docs/guides/buf-migration.mdx index f14e06e..1426b8f 100644 --- a/content/docs/guides/buf-migration.mdx +++ b/content/docs/guides/buf-migration.mdx @@ -28,12 +28,14 @@ This guide provides a comprehensive migration walkthrough for transitioning exis ### Step 1: Automatic Initial Migration -Run `easyp init` in your project root. EasyP detects existing `buf.yaml` and `buf.gen.yaml` files and automatically generates initial `protobuf.mod`, `easyp.yaml`, and `easyp.gen.yaml` files. +Run `easyp init` in a new project root to create `protobuf.mod`, `easyp.yaml`, and `easyp.gen.yaml`. Pass `--module` when the canonical Git module identity cannot be derived from the repository's `origin` remote. ```bash -easyp init +easyp init --module github.com/acme/my-service ``` +Automatic Buf Registry dependency conversion is deferred. If `buf.yaml` or `buf.yml` exists, `easyp init` stops before writing files because a `buf.build/...` identity cannot be safely treated as a Git module URL. Choose the Git source for each dependency, then create the v1 files explicitly. + ### Step 2: Separate Dependencies into `protobuf.mod` Extract module dependencies from `buf.yaml` into `protobuf.mod`: @@ -60,8 +62,6 @@ linters: breaking: baseline: git:main - categories: - - WIRE ``` ### Step 4: Remove Inputs from Generator Configs diff --git a/content/docs/guides/buf-migration.ru.mdx b/content/docs/guides/buf-migration.ru.mdx index 9495592..90b031d 100644 --- a/content/docs/guides/buf-migration.ru.mdx +++ b/content/docs/guides/buf-migration.ru.mdx @@ -26,14 +26,16 @@ description: "Пошаговое руководство по миграции к ## Пошаговый процесс миграции -### Шаг 1: Автоматическая первичная инициализация +### Шаг 1: Первичная инициализация -Запустите `easyp init` в корне вашего проекта. EasyP обнаружит существующие файлы `buf.yaml` и `buf.gen.yaml` и автоматически создаст первичные `protobuf.mod`, `easyp.yaml` и `easyp.gen.yaml`. +В новом проекте `easyp init` создаёт `protobuf.mod`, `easyp.yaml` и `easyp.gen.yaml`. Укажите `--module`, если идентификатор Git-модуля нельзя получить из удалённого репозитория `origin`. ```bash -easyp init +easyp init --module github.com/acme/my-service ``` +Автоматический перенос зависимостей Buf Registry отложен. При наличии `buf.yaml` или `buf.yml` команда `easyp init` завершится до записи файлов: имя `buf.build/...` нельзя безопасно считать URL Git-модуля. Выберите Git-источник для каждой зависимости и создайте v1-файлы явно. + ### Шаг 2: Вынос зависимостей в `protobuf.mod` Перенесите зависимости модулей из `buf.yaml` в `protobuf.mod`: @@ -60,8 +62,6 @@ linters: breaking: baseline: git:main - categories: - - WIRE ``` ### Шаг 4: Удаление блоков источников из генератора @@ -78,7 +78,6 @@ generate: plugins: - name: go - version: v1.34.2 out: ./gen/go opts: paths: source_relative diff --git a/content/docs/guides/debugging-replace.mdx b/content/docs/guides/debugging-replace.mdx index 90ba8d2..f667628 100644 --- a/content/docs/guides/debugging-replace.mdx +++ b/content/docs/guides/debugging-replace.mdx @@ -38,12 +38,12 @@ When `replace` is active: --- -## CI Build Guardrails +## Reproducible Lock Guardrail -To prevent local file paths from breaking production builds, EasyP enforces a **strict CI check**: +To prevent a local path from entering the reproducible dependency lock, EasyP requires the replacement to be removed before resolving the lock: -EasyP CI commands fail immediately if an active `replace` directive is detected in `protobuf.mod`. +`easyp mod tidy` and `easyp mod update` reject an active local `replace` directive. Run one of these commands in CI to enforce the guard. ### Preparing for PR Submission diff --git a/content/docs/guides/debugging-replace.ru.mdx b/content/docs/guides/debugging-replace.ru.mdx index 002f84f..6f1664b 100644 --- a/content/docs/guides/debugging-replace.ru.mdx +++ b/content/docs/guides/debugging-replace.ru.mdx @@ -38,12 +38,12 @@ replace github.com/acme/weather => ../weather-fork --- -## Защита в CI +## Защита воспроизводимого lock-файла -Чтобы локальные пути к диску не сломали сборку в CI, EasyP включает **строгую проверку**: +Чтобы локальный путь не попал в воспроизводимый граф зависимостей, перед обновлением lock-файла нужно убрать замену: -Команды EasyP в CI завершаются с ошибкой, если в `protobuf.mod` обнаружена активная директива `replace`. +`easyp mod tidy` и `easyp mod update` отклоняют активный локальный `replace`. Запускайте одну из этих команд в CI для проверки. ### Подготовка к отправке PR diff --git a/content/docs/reference/easyp-gen-yaml.mdx b/content/docs/reference/easyp-gen-yaml.mdx index c24cc08..b36a1ce 100644 --- a/content/docs/reference/easyp-gen-yaml.mdx +++ b/content/docs/reference/easyp-gen-yaml.mdx @@ -3,7 +3,7 @@ title: "easyp.gen.yaml Reference" description: "Complete specification for easyp.gen.yaml, configuring consumer-side code generation, plugin outputs, WASM/remote execution, and managed package options." --- -The `easyp.gen.yaml` file specifies **consumer-side code generation rules**. Residing alongside consuming applications or service projects, it defines which modules or packages to compile, which plugins to invoke, where generated artifacts should be written, and language-specific managed options (such as `package_prefix`). +The `easyp.gen.yaml` file specifies **consumer-side code generation rules**. Residing alongside consuming applications or service projects, it defines which modules to compile, which plugins to invoke, where generated artifacts should be written, and managed options. In accordance with EasyP's zero-duplication principles, `easyp.gen.yaml` **never** contains dependency URLs or version numbers for Protobuf schemas—schema sources and versions are resolved strictly through `protobuf.mod` and `protobuf.lock`. @@ -23,11 +23,11 @@ In accordance with EasyP's zero-duplication principles, `easyp.gen.yaml` **never type: "object" }, "generate.modules": { - description: "List of module names or local paths to generate code for.", + description: "List of module identities or repository-relative local module paths to generate. Dependency identities must be present in the consumer module's protobuf.lock. If omitted, the nearest protobuf.mod is selected.", type: "string[]" }, "generate.packages": { - description: "Fine-grained package path filters if full module generation is not required.", + description: "Reserved for future package filtering. v1 currently reports an error when this field is nonempty.", type: "string[]" }, plugins: { @@ -43,7 +43,7 @@ In accordance with EasyP's zero-duplication principles, `easyp.gen.yaml` **never type: "string" }, "plugins[].version": { - description: "Strict version tag of the plugin. ':latest' is prohibited for reproducibility.", + description: "Required SemVer tag for remote plugins. Local and bundled plugins use the selected executable and reject a separate version field.", type: "string" }, "plugins[].out": { @@ -61,6 +61,10 @@ In accordance with EasyP's zero-duplication principles, `easyp.gen.yaml` **never "options.go.package_prefix": { description: "Base Go package prefix automatically prepended to generated go_package imports.", type: "string" + }, + "generate.managed": { + description: "Existing managed descriptor rules: enabled, disable, and override, including module, package, path, and field selectors.", + type: "object" } }} /> @@ -81,12 +85,10 @@ generate: plugins: - name: go - version: v1.34.2 out: ./gen/go opts: paths: source_relative - name: go-grpc - version: v1.4.0 out: ./gen/go opts: paths: source_relative @@ -121,3 +123,25 @@ plugins: Instead of requiring explicit file-level options (like `option go_package = "..."`) inside every individual `.proto` schema file, EasyP's managed `options` block groups settings logically by target language. For example, setting `options.go.package_prefix: github.com/acme/backend/gen/go` automatically computes import paths based on the module directory layout without mutating source `.proto` files. + +The existing managed-mode rules remain available under `generate.managed`. For example, a package-specific override can be written as: + +```yaml +version: v1 +generate: + managed: + enabled: true + override: + - file_option: go_package_prefix + package: user.v1 + value: github.com/acme/backend/gen/user +plugins: + - name: go + out: ./gen/go +``` + +A repository-root `easyp.gen.yaml` may provide `options.go.package_prefix` as a default for nested generator files. Nested `generate.managed` rules take precedence over that inherited default. A prefix declared in the same generator file has the highest priority. Plugin lists stay local to each generator file. + +The current v1 generator selects complete modules. `generate.packages` is reserved for a later release, once its matching syntax is specified. + +Remote plugins require a `version` such as `v2.0.0`. EasyP sends that exact version to the remote generator. For local `protoc-gen-*` executables and bundled WASM plugins, the executable selected at runtime determines the version; the separate `version` field is rejected because EasyP cannot verify it. diff --git a/content/docs/reference/easyp-gen-yaml.ru.mdx b/content/docs/reference/easyp-gen-yaml.ru.mdx index 62bb3ea..f7ab01a 100644 --- a/content/docs/reference/easyp-gen-yaml.ru.mdx +++ b/content/docs/reference/easyp-gen-yaml.ru.mdx @@ -3,7 +3,7 @@ title: "Справочник easyp.gen.yaml" description: "Полная спецификация файла easyp.gen.yaml, управляющего кодогенерацией на стороне потребителя, выводами плагинов, WASM/remote запуском и managed-опциями." --- -Файл `easyp.gen.yaml` задаёт **правила генерации кода на стороне потребителя**. Находясь рядом с приложением или сервисом, он определяет, какие модули и пакеты компилировать, какие плагины вызывать, куда записывать сгенерированный код и какие managed-опции (такие как `package_prefix`) применять. +Файл `easyp.gen.yaml` задаёт **правила генерации кода на стороне потребителя**. Находясь рядом с приложением или сервисом, он определяет, какие модули компилировать, какие плагины вызывать, куда записывать сгенерированный код и какие managed-опции применять. В соответствии с принципом недублирования источников EasyP, `easyp.gen.yaml` **никогда** не содержит URL репозиториев или версий зависимостей — источники и версии протоколов определяются строго через `protobuf.mod` и `protobuf.lock`. @@ -23,11 +23,11 @@ description: "Полная спецификация файла easyp.gen.yaml, type: "object" }, "generate.modules": { - description: "Список имён модулей или локальных путей для генерации кода.", + description: "Список идентификаторов модулей или локальных путей относительно корня репозитория. Идентификаторы зависимостей должны быть в protobuf.lock модуля-потребителя. Если поле отсутствует, выбирается ближайший protobuf.mod.", type: "string[]" }, "generate.packages": { - description: "Фильтр конкретных пакетов, если требуется генерация не всего модуля.", + description: "Резерв для будущей фильтрации пакетов. Сейчас непустое поле вызывает ошибку.", type: "string[]" }, plugins: { @@ -43,7 +43,7 @@ description: "Полная спецификация файла easyp.gen.yaml, type: "string" }, "plugins[].version": { - description: "Строгий тег версии плагина. Использование ':latest' запрещено.", + description: "Обязательный SemVer-тег для удалённых плагинов. Локальные и встроенные плагины используют выбранный исполняемый файл и не принимают отдельное поле version.", type: "string" }, "plugins[].out": { @@ -61,6 +61,10 @@ description: "Полная спецификация файла easyp.gen.yaml, "options.go.package_prefix": { description: "Базовый префикс Go-пакета, автоматически добавляемый к go_package.", type: "string" + }, + "generate.managed": { + description: "Существующие правила managed mode: enabled, disable и override с селекторами module, package, path и field.", + type: "object" } }} /> @@ -81,12 +85,10 @@ generate: plugins: - name: go - version: v1.34.2 out: ./gen/go opts: paths: source_relative - name: go-grpc - version: v1.4.0 out: ./gen/go opts: paths: source_relative @@ -121,3 +123,25 @@ plugins: Вместо явного прописывания опций вроде `option go_package = "..."` внутри каждого `.proto` файла, блок `options` в EasyP группирует настройки по целевым языкам программирования. Например, указание `options.go.package_prefix: github.com/acme/backend/gen/go` автоматически вычисляет пути импортов на основе структуры директорий модуля без модификации исходных `.proto` файлов. + +Существующие правила managed mode доступны в `generate.managed`. Например, переопределение для конкретного Protobuf-пакета: + +```yaml +version: v1 +generate: + managed: + enabled: true + override: + - file_option: go_package_prefix + package: user.v1 + value: github.com/acme/backend/gen/user +plugins: + - name: go + out: ./gen/go +``` + +Корневой `easyp.gen.yaml` может задавать `options.go.package_prefix` по умолчанию для вложенных генераторов. Локальные правила `generate.managed` имеют приоритет над унаследованным префиксом. Префикс, заданный в том же файле генератора, имеет наивысший приоритет. Списки плагинов не наследуются. + +Сейчас v1 генерирует модули целиком. `generate.packages` оставлено для будущей версии после определения синтаксиса выбора пакетов. + +Удалённому плагину нужен `version`, например `v2.0.0`. EasyP передаёт именно эту версию удалённому генератору. Для локального `protoc-gen-*` и встроенного WASM версию определяет выбранный исполняемый файл; отдельное поле `version` отклоняется, поскольку EasyP не может его проверить. diff --git a/content/docs/reference/easyp-yaml.mdx b/content/docs/reference/easyp-yaml.mdx index 456a7de..1346e4b 100644 --- a/content/docs/reference/easyp-yaml.mdx +++ b/content/docs/reference/easyp-yaml.mdx @@ -3,7 +3,7 @@ title: "easyp.yaml Reference" description: "Complete specification for easyp.yaml, configuring producer-side linting rules, breaking change detection, path exclusions, and policy inheritance." --- -The `easyp.yaml` file defines **producer-side policy configuration** for Protocol Buffer schema repositories. It specifies linting standards, breaking change checks against git baselines, path exclusion rules, and policy inheritance via `extends`. +The `easyp.yaml` file defines **producer-side policy configuration** for Protocol Buffer schema repositories. It specifies linting standards, breaking change checks against Git baselines, and issue exclusions. Directory cascading is available; explicit `extends` references are reserved until their resolution rules are specified. `easyp.yaml` files cascade hierarchically down directory structures: for any given `.proto` file, EasyP traverses up the directory tree to find the nearest `easyp.yaml` and applies its configuration. @@ -36,7 +36,7 @@ The `easyp.yaml` file defines **producer-side policy configuration** for Protoco type: "string[]" }, "linters.extends": { - description: "Remote Git module or policy path to inherit base linter rules from.", + description: "Reserved for explicit policy inheritance; currently rejected because ref, path, and merge rules are unspecified.", type: "string" }, "linters-settings": { @@ -48,7 +48,7 @@ The `easyp.yaml` file defines **producer-side policy configuration** for Protoco type: "object" }, "issues.exclude-rules": { - description: "Array of exclusion rules matching file path glob patterns to disabled linters.", + description: "Pathless rules disable the named linters for all files under the selected policy. An empty pathless rule suppresses all issues. Path globs are reserved until their base directory is specified.", type: "object[]" }, breaking: { @@ -56,22 +56,25 @@ The `easyp.yaml` file defines **producer-side policy configuration** for Protoco type: "object" }, "breaking.baseline": { - description: "Git ref or tag target to compare schema changes against (e.g. git:main).", + description: "Git branch to compare schema changes against (e.g. git:main). When omitted, the existing --against flag applies.", type: "string", - default: "git:main" + default: "--against flag" }, "breaking.categories": { - description: "Enforced breaking change categories: FILE, PACKAGE, WIRE_JSON, WIRE.", - type: "string[]", - default: "['WIRE']" + description: "Reserved for future category-specific checks; currently rejected when configured.", + type: "string[]" }, "breaking.ignore_unstable": { - description: "When true, unstable proto packages (v1alpha, v1beta) bypass breaking checks.", + description: "Reserved for future unstable-package filtering; currently rejected when true.", type: "boolean", - default: "true" + default: "false" + }, + "breaking.ignore": { + description: "Directories ignored by the existing breaking checker.", + type: "string[]" }, "breaking.extends": { - description: "Remote Git policy module to inherit breaking change settings from.", + description: "Reserved for explicit policy inheritance; currently rejected because ref, path, and merge rules are unspecified.", type: "string" } }} @@ -100,18 +103,13 @@ linters-settings: issues: exclude-rules: - - path: "gen/**" - - path: "**/legacy/**" - linters: + - linters: - FIELD_LOWER_SNAKE_CASE - - PACKAGE_DIRECTORY_MATCH breaking: baseline: git:main - categories: - - WIRE - - WIRE_JSON - ignore_unstable: true + ignore: + - gen ``` --- @@ -131,3 +129,5 @@ proto/ ``` Sections are inherited as whole units from the nearest declaring file, preventing confusing partial merges. + +The v1 `breaking.baseline` selects the Git branch used by the existing EasyP breaking checker. Its rule set is unchanged. Category selection and unstable-package filtering need separate rule semantics and are not active yet. A path-bearing `issues.exclude-rules` entry currently produces an error; pathless entries work without choosing an implicit glob base. Explicit `linters.extends` and `breaking.extends` currently produce errors: the syntax does not yet define a Git ref, policy path, merge precedence, or lock/integrity behavior. diff --git a/content/docs/reference/easyp-yaml.ru.mdx b/content/docs/reference/easyp-yaml.ru.mdx index 55306e8..7e6fa6c 100644 --- a/content/docs/reference/easyp-yaml.ru.mdx +++ b/content/docs/reference/easyp-yaml.ru.mdx @@ -3,7 +3,7 @@ title: "Справочник easyp.yaml" description: "Полная спецификация файла easyp.yaml, управляющего правилами линтинга продюсера, проверками ломающих изменений, исключениями путей и наследованием политик." --- -Файл `easyp.yaml` определяет **конфигурацию политик на стороне продюсера** для репозиториев Protobuf-схем. Он задаёт стандарты линтинга, проверки ломающих изменений относительно git-baseline, правила исключения путей и наследование политик через `extends`. +Файл `easyp.yaml` определяет **конфигурацию политик на стороне продюсера** для репозиториев Protobuf-схем. Он задаёт стандарты линтинга, проверки ломающих изменений относительно Git-baseline и исключения замечаний. Каскадирование по директориям работает; явные ссылки `extends` оставлены до определения правил разрешения. Файлы `easyp.yaml` каскадируются по иерархии директорий: для каждого файла `.proto` EasyP ищет ближайший `easyp.yaml` вверх по дереву каталогов и применяет его правила. @@ -36,7 +36,7 @@ description: "Полная спецификация файла easyp.yaml, уп type: "string[]" }, "linters.extends": { - description: "Удалённый модуль Git или путь к политике для наследования правил.", + description: "Резерв для явного наследования политик; сейчас выдаёт ошибку, поскольку не определены ref, путь и правила слияния.", type: "string" }, "linters-settings": { @@ -48,7 +48,7 @@ description: "Полная спецификация файла easyp.yaml, уп type: "object" }, "issues.exclude-rules": { - description: "Массив правил исключений, сопоставляющих glob-шаблоны путей с линтерами.", + description: "Правило без path отключает указанные линтеры для всех файлов выбранной политики. Пустое правило без path подавляет все замечания. Glob-пути оставлены до определения базовой директории.", type: "object[]" }, breaking: { @@ -56,22 +56,25 @@ description: "Полная спецификация файла easyp.yaml, уп type: "object" }, "breaking.baseline": { - description: "Ссылка на git-ветку или тег для сравнения изменений (например, git:main).", + description: "Git-ветка для сравнения изменений (например, git:main). Если поле не задано, применяется существующий флаг --against.", type: "string", - default: "git:main" + default: "флаг --against" }, "breaking.categories": { - description: "Категории ломающих изменений: FILE, PACKAGE, WIRE_JSON, WIRE.", - type: "string[]", - default: "['WIRE']" + description: "Резерв для будущих проверок по категориям; при указании сейчас выдаётся ошибка.", + type: "string[]" }, "breaking.ignore_unstable": { - description: "При true нестабильные пакеты (v1alpha, v1beta) игнорируют breaking-проверки.", + description: "Резерв для будущей фильтрации нестабильных пакетов; true сейчас вызывает ошибку.", type: "boolean", - default: "true" + default: "false" + }, + "breaking.ignore": { + description: "Директории, которые пропускает существующий breaking checker.", + type: "string[]" }, "breaking.extends": { - description: "Удалённый модуль политики для наследования настроек breaking-проверок.", + description: "Резерв для явного наследования политик; сейчас выдаёт ошибку, поскольку не определены ref, путь и правила слияния.", type: "string" } }} @@ -100,18 +103,13 @@ linters-settings: issues: exclude-rules: - - path: "gen/**" - - path: "**/legacy/**" - linters: + - linters: - FIELD_LOWER_SNAKE_CASE - - PACKAGE_DIRECTORY_MATCH breaking: baseline: git:main - categories: - - WIRE - - WIRE_JSON - ignore_unstable: true + ignore: + - gen ``` --- @@ -131,3 +129,5 @@ proto/ ``` Секция берётся целиком из ближайшего определяющего файла без частичного слияния. + +В v1 `breaking.baseline` выбирает Git-ветку для существующего checker EasyP. Набор его проверок не меняется. Выбор категорий и фильтрация нестабильных пакетов требуют отдельного определения правил и пока не активны. `issues.exclude-rules` с `path` сейчас выдаёт ошибку; правила без `path` работают без неявного выбора базы для glob. `linters.extends` и `breaking.extends` тоже пока выдают ошибку: ещё не определены Git ref, путь к политике, приоритет слияния и способ фиксации зависимости. diff --git a/content/docs/reference/protobuf-lock.mdx b/content/docs/reference/protobuf-lock.mdx index d6226ba..90f92cf 100644 --- a/content/docs/reference/protobuf-lock.mdx +++ b/content/docs/reference/protobuf-lock.mdx @@ -33,7 +33,7 @@ The `protobuf.lock` file is an auto-generated artifact created by EasyP dependen type: "string" }, "modules[].hash": { - description: "Cryptographic content hash (h1:...) for content integrity validation.", + description: "Go dirhash.Hash1 digest (h1:...) of the Git-tracked regular files at the locked commit.", type: "string" } }} @@ -68,3 +68,5 @@ modules: - `easyp mod tidy`: Resolves required imports, updates indirect dependencies, and regenerates `protobuf.lock`. - `easyp mod update`: Upgrades dependencies to latest semver-compatible versions and updates `protobuf.lock`. - `easyp mod download`: Populates local cache strictly using `protobuf.lock` without reaching out to remote registries or modifying locked versions. + +The `hash` is computed with Go's `dirhash.Hash1` over every regular file tracked by Git at `commit`, using repository-relative paths. EasyP verifies the same digest for a newly downloaded module and for an existing cache entry. A missing cached commit still requires access to its Git repository. diff --git a/content/docs/reference/protobuf-lock.ru.mdx b/content/docs/reference/protobuf-lock.ru.mdx index 1b245a9..c621133 100644 --- a/content/docs/reference/protobuf-lock.ru.mdx +++ b/content/docs/reference/protobuf-lock.ru.mdx @@ -33,7 +33,7 @@ description: "Спецификация файла protobuf.lock, автомат type: "string" }, "modules[].hash": { - description: "Криптографический хеш содержимого (h1:...) для контроля целостности.", + description: "Дайджест Go dirhash.Hash1 (h1:...) для обычных файлов, отслеживаемых Git в зафиксированном коммите.", type: "string" } }} @@ -68,3 +68,5 @@ modules: - `easyp mod tidy`: Сканирует импорты, дописывает транзитивные зависимости и перегенерирует `protobuf.lock`. - `easyp mod update`: Обновляет версии зависимостей до свежих совместимых релизов и обновляет `protobuf.lock`. - `easyp mod download`: Наполняет локальный кэш строго по `protobuf.lock` без обращения к внешним реестрам. + +`hash` вычисляется алгоритмом Go `dirhash.Hash1` по всем обычным файлам, отслеживаемым Git в коммите `commit`, с путями относительно корня репозитория. EasyP проверяет этот дайджест при скачивании и при чтении существующего кэша. Если нужного коммита в кэше нет, доступ к Git-репозиторию всё ещё необходим. diff --git a/content/docs/reference/protobuf-mod.mdx b/content/docs/reference/protobuf-mod.mdx index f428d89..5b1c2b7 100644 --- a/content/docs/reference/protobuf-mod.mdx +++ b/content/docs/reference/protobuf-mod.mdx @@ -63,4 +63,4 @@ replace github.com/acme/weather => ../weather-fork 1. **Git-Native Identity**: The canonical identity of a module is its Git URL (e.g., `github.com/acme/weather`). 2. **Per-Module Bounds**: Every module maintains its own independent `protobuf.mod`. MVS operates per-module rather than forcing global monorepo single-version constraints. -3. **Replace Guardrail**: Active `replace` directives are permitted during local development, but cause CI validation to fail. +3. **Replace Guardrail**: Local `replace` directives work during generation. `easyp mod tidy` and `easyp mod update` reject them until they are removed, so a reproducible Git lock never records a local path. diff --git a/content/docs/reference/protobuf-mod.ru.mdx b/content/docs/reference/protobuf-mod.ru.mdx index 01168cb..d6b4513 100644 --- a/content/docs/reference/protobuf-mod.ru.mdx +++ b/content/docs/reference/protobuf-mod.ru.mdx @@ -63,4 +63,4 @@ replace github.com/acme/weather => ../weather-fork 1. **Git-Native идентичность**: Каноническим идентификатором модуля является его Git URL (`github.com/acme/weather`). 2. **Помодульный скоуп**: Каждый модуль имеет собственный `protobuf.mod`. MVS работает помодульно (per-module), не навязывая глобальных ограничений версий в монорепозитории. -3. **Защита в CI**: Активные директивы `replace` разрешены при локальной разработке, но вызывают ошибку при сборке в CI. +3. **Защита lock-файла**: Локальный `replace` работает при генерации. `easyp mod tidy` и `easyp mod update` отклоняют его до удаления, чтобы в воспроизводимый Git lock не попал локальный путь. From 20e96e554785f66cfcb846e1b0e021c96bd91631 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 23 Sep 2026 12:33:42 +0300 Subject: [PATCH 02/26] docs(v1): describe pilot-only CLI configuration --- content/docs/cli/configuration.mdx | 947 ++------------------------ content/docs/cli/configuration.ru.mdx | 947 ++------------------------ 2 files changed, 90 insertions(+), 1804 deletions(-) diff --git a/content/docs/cli/configuration.mdx b/content/docs/cli/configuration.mdx index fec2196..958bea5 100644 --- a/content/docs/cli/configuration.mdx +++ b/content/docs/cli/configuration.mdx @@ -1,932 +1,75 @@ --- -title: "EasyP Configuration Reference" +title: "EasyP v1 Pilot Configuration" +description: "The files and CLI commands used by the EasyP v1 pilot." --- -EasyP can be configured through CLI flags, environment variables, and configuration files. This guide covers all configuration options available in EasyP. +The v1 pilot separates module dependencies, generation, and lint and breaking policies: -## CLI Flags +| File | Purpose | +|------|---------| +| [`protobuf.mod`](/docs/reference/protobuf-mod) | Module identity, source roots, requirements, and local replacements | +| [`protobuf.lock`](/docs/reference/protobuf-lock) | Resolved Git commits and content hashes; generated by `easyp mod tidy` | +| [`easyp.gen.yaml`](/docs/reference/easyp-gen-yaml) | Modules to generate, plugins, outputs, and managed options | +| [`easyp.yaml`](/docs/reference/easyp-yaml) | Lint and breaking policies | -### Global Flags +The CLI commands use the v1 files directly. They do not fall back to the older EasyP generation, lint, breaking, or module-management configuration. A Git dependency can still use older EasyP or Buf configuration: the dependency reader extracts its requirements and proto roots for import resolution. -Available for all commands: +## Typical workflow -| Flag | Short | Environment | Description | Default | -|------|-------|-------------|-------------|---------| -| `--cfg` | `-c` | `EASYP_CFG` | Configuration file path | `easyp.yaml` | -| `--config` | | `EASYP_CFG` | Alias for `--cfg` | `easyp.yaml` | -| `--debug` | `-d` | `EASYP_DEBUG` | Enable debug mode | `false` | -| `--format` | `-f` | `EASYP_FORMAT` | Output format for commands that support multiple formats (`text`/`json`) | command-specific default | - -**Examples:** -```bash -# Use custom config file -easyp --cfg production.easyp.yaml lint - -# Enable debug logging -easyp --debug lint - -# Short form -easyp -c custom.yaml -d lint -``` - -### Command-Specific Flags - -**Lint command:** -```bash -easyp lint [flags] -``` - -| Flag | Short | Environment | Description | Default | -|------|-------|-------------|-------------|---------| -| `--path` | `-p` | | Directory path to lint | `.` | -| `--root` | `-r` | | Base directory for file search | Current working directory | -| `--format` | `-f` | `EASYP_FORMAT` | Uses global format flag (`text`/`json`) | Inherits global default | - -**Examples:** -```bash -# Lint specific directory -easyp lint --path proto/ - -# Lint from subdirectory with proper import resolution -easyp lint --root src/IPC/Contracts --path . - -# JSON output format -easyp --format json lint # global flag - -# Combined flags -easyp -f json lint -p proto/ -``` - -**Generate command:** -```bash -easyp generate [flags] -``` - -| Flag | Short | Environment | Description | Default | -|------|-------|-------------|-------------|---------| -| `--path` | `-p` | `EASYP_ROOT_GENERATE_PATH` | Directory path with proto files to generate | `.` | -| `--root` | `-r` | | Base directory for file search | Current working directory | - -**Examples:** -```bash -# Generate from specific path -easyp generate --path api/ - -# Generate from subdirectory with proper import resolution -easyp generate --root src/IPC/Contracts --path . - -# Using environment variable -EASYP_ROOT_GENERATE_PATH=proto/ easyp generate -``` - -**Breaking command:** -```bash -easyp breaking [flags] -``` - -| Flag | Short | Environment | Description | Default | -|------|-------|-------------|-------------|---------| -| `--against` | | | Git ref to compare against | `master` | -| `--path` | `-p` | | Directory path to check | `.` | -| `--format` | `-f` | `EASYP_FORMAT` | Uses global format flag (`text`/`json`) | Inherits global default | - -**Examples:** -```bash -# Check against main branch -easyp breaking --against main - -# Check specific directory against develop branch -easyp breaking --against develop --path proto/ - -# JSON output -easyp --format json breaking --against main # global flag -``` - -**Init command:** -```bash -easyp init [flags] -``` - -| Flag | Short | Environment | Description | Default | -|------|-------|-------------|-------------|---------| -| `--dir` | `-d` | `EASYP_INIT_DIR` | Directory to initialize | `.` | - -**Examples:** -```bash -# Initialize current directory -easyp init - -# Initialize specific directory -easyp init --dir proto-project/ -``` - -`easyp init` is interactive: -- If `buf.yml`/`buf.yaml` exists in the target directory root, it asks whether to migrate from Buf. -- If `easyp.yaml` already exists, it asks for overwrite confirmation. - -**Validate-config command:** -```bash -easyp validate-config [flags] -``` - -| Flag | Short | Environment | Description | Default | -|------|-------|-------------|-------------|---------| -| `--config` | `-c` | `EASYP_CFG` | Configuration file path | `easyp.yaml` | -| `--format` (global) | `-f` | `EASYP_FORMAT` | Output format for commands that support multiple formats (`json` or `text`) | command-specific (`json` for `validate-config`) | - -**Examples:** -```bash -# Validate default config with JSON output (exit 0 when no errors) -easyp validate-config - -# Validate a different file with text output (global --format) -easyp --format text validate-config --config example.easyp.yaml -``` - -**Package management commands:** - -#### `easyp mod download` -Downloads dependencies based on lock file priority: - -1. **If `easyp.lock` exists** - downloads exact versions from lock file -2. **If `easyp.lock` is missing** - downloads versions from `easyp.yaml` and creates `easyp.lock` - -```bash -# Download exact versions (recommended for production) -easyp mod download -``` - -#### `easyp mod update` -Always downloads dependencies from `easyp.yaml`, ignoring existing lock file: - -1. **Ignores `easyp.lock`** completely -2. **Downloads versions from `easyp.yaml`** -3. **Creates/updates `easyp.lock`** with new versions - -```bash -# Update dependencies and lock file -easyp mod update -``` - -#### `easyp mod vendor` -Copies proto files from dependencies to local `vendor/` directory (similar to `go mod vendor`). - -```bash -# Create local vendor directory with dependencies -easyp mod vendor -``` - -No additional flags. Uses global `--cfg` flag for configuration. - -## Environment Variables - -EasyP supports environment variables for configuration: - -| Variable | Description | Default | -|----------|-------------|---------| -| `EASYP_CFG` | Path to configuration file | `easyp.yaml` | -| `EASYP_DEBUG` | Enable debug logging | `false` | -| `EASYPPATH` | Cache and modules storage directory | `$HOME/.easyp` | -| `EASYP_FORMAT` | Output format for supported commands (`text`/`json`). If not set, each command uses its own default. | command-specific default | -| `EASYP_ROOT_GENERATE_PATH` | Root path for generate command | `.` | -| `EASYP_INIT_DIR` | Directory for init command | `.` | - -**Examples:** ```bash -# Custom cache directory -export EASYPPATH=/tmp/easyp-cache +easyp init --module github.com/acme/contracts +easyp mod tidy easyp mod download - -# Debug mode via environment -export EASYP_DEBUG=true -easyp lint - -# Custom config file -export EASYP_CFG=config/easyp.yaml easyp generate +easyp lint --path proto +easyp breaking --path proto --against main ``` -## Configuration File - -The `easyp.yaml` file is the main configuration file for EasyP, defining how your proto files are linted, generated, and managed. This file is typically placed at the root of your project alongside your proto files. - -### File Structure Overview - -``` -. -├── easyp.yaml -├── easyp.lock -├── proto/ -│ ├── user/ -│ │ └── user.proto -│ └── order/ -│ └── order.proto -└── vendor/ -``` - -### Configuration Format - -EasyP supports both YAML and JSON configuration formats: - -#### YAML Format (Recommended) -```yaml -lint: - use: - - BASIC - - COMMENT_SERVICE -deps: - - github.com/googleapis/googleapis@v1.0.0 -generate: - inputs: - - directory: "proto" - plugins: - - name: go - out: . - opts: - paths: source_relative -breaking: - ignore: - - proto/experimental/ - against_git_ref: main -``` - -#### JSON Format -```json -{ - "lint": { - "use": ["BASIC", "COMMENT_SERVICE"] - }, - "deps": [ - "github.com/googleapis/googleapis@v1.0.0" - ], - "generate": { - "inputs": [ - {"directory": "proto"} - ], - "plugins": [ - { - "name": "go", - "out": ".", - "opts": { - "paths": "source_relative" - } - } - ] - }, - "breaking": { - "ignore": ["proto/experimental/"], - "against_git_ref": "main" - } -} -``` - -### Environment Variables in Configuration - -EasyP supports environment variable expansion directly in the `easyp.yaml` configuration file. This allows you to use environment variables for dynamic configuration values. - -**Example with all supported features:** -```yaml -deps: - # Basic expansion: ${VAR} - expands to the value of VAR - - ${GOOGLEAPIS_REPO}@${GOOGLEAPIS_VERSION} - - # Default value: ${VAR:-default} - uses default if VAR is unset or empty - - ${GNOSTIC_REPO:-github.com/google/gnostic}@${GNOSTIC_VERSION:-v0.7.0} - -generate: - inputs: - # Default value if INPUT_DIR is not set - - directory: ${INPUT_DIR:-proto} - plugins: - - name: go - # Basic expansion - out: ${OUTPUT_DIR} - opts: - # Default value - module: ${MODULE_NAME:-github.com/example/project} - timeout: ${TIMEOUT:-30} - - # Escaping: $$ becomes literal $, $${VAR} becomes literal ${VAR} - path: "${BASE_DIR}/$${TEMP}/file" # Result: "/tmp/${TEMP}/file" (if BASE_DIR=/tmp) - literal: "$$" # Result: "$" -``` - -**Supported syntax:** -- `${VAR}` - expands to the value of `VAR` -- `${VAR:-default}` - uses `default` if `VAR` is unset or empty -- `${VAR:=default}` - uses `default` if `VAR` is unset or empty -- `${VAR-default}` - uses `default` if `VAR` is unset (empty string is kept) -- `$${VAR}` or `$$VAR` - escapes to literal `${VAR}` or `$VAR` -- `$$` - escapes to literal `$` - -**Note:** Environment variables are expanded before YAML parsing, so any `${STRING}` pattern will be processed. Use `$$` to escape dollar signs when you need literal values. - -## Configuration Fields - -### `version` - -**Optional (legacy compatibility).** This field is accepted for backward compatibility and can be omitted in new configs. - -**Type:** `string` -**Default:** omitted -**Recommendation:** if you keep it, use `v1alpha` - -```yaml -# Optional compatibility field (can be omitted) -version: v1alpha -``` - -The runtime behavior does not depend on this field. - -### `lint` - -**Optional.** Configures proto file linting rules and behavior. - -**Type:** `object` -**Default:** Empty (no linting rules applied) - -```yaml -lint: - use: - - BASIC - - COMMENT_SERVICE - enum_zero_value_suffix: "UNSPECIFIED" - service_suffix: "Service" - ignore: - - vendor/ - - proto/legacy/ - except: - - COMMENT_FIELD - allow_comment_ignores: true - ignore_only: - COMMENT_SERVICE: - - proto/experimental/ -``` - -#### `lint.use` - -**Optional.** Specifies which linter rules or rule categories to apply. - -**Type:** `[]string` -**Default:** `[]` (no rules) - -**Available categories:** -- `MINIMAL` - Essential package consistency checks -- `BASIC` - Naming conventions and common patterns -- `DEFAULT` - Additional recommended rules -- `COMMENTS` - Comment requirements -- `UNARY_RPC` - Streaming RPC restrictions - -**Individual rules:** Any specific rule name (e.g., `ENUM_PASCAL_CASE`, `FIELD_LOWER_SNAKE_CASE`) - -```yaml -lint: - use: - - MINIMAL # Use all minimal rules - - BASIC # Use all basic rules - - COMMENT_SERVICE # Require service comments - - ENUM_PASCAL_CASE # Specific rule -``` - -**Rule Categories:** - -**MINIMAL:** -- `DIRECTORY_SAME_PACKAGE` -- `PACKAGE_DEFINED` -- `PACKAGE_DIRECTORY_MATCH` -- `PACKAGE_SAME_DIRECTORY` - -**BASIC:** -- `ENUM_FIRST_VALUE_ZERO` -- `ENUM_NO_ALLOW_ALIAS` -- `ENUM_PASCAL_CASE` -- `ENUM_VALUE_UPPER_SNAKE_CASE` -- `FIELD_LOWER_SNAKE_CASE` -- `IMPORT_NO_PUBLIC` -- `IMPORT_NO_WEAK` -- `IMPORT_USED` -- `MESSAGE_PASCAL_CASE` -- `ONEOF_LOWER_SNAKE_CASE` -- `PACKAGE_LOWER_SNAKE_CASE` -- `PACKAGE_SAME_CSHARP_NAMESPACE` -- `PACKAGE_SAME_GO_PACKAGE` -- `PACKAGE_SAME_JAVA_MULTIPLE_FILES` -- `PACKAGE_SAME_JAVA_PACKAGE` -- `PACKAGE_SAME_PHP_NAMESPACE` -- `PACKAGE_SAME_RUBY_PACKAGE` -- `PACKAGE_SAME_SWIFT_PREFIX` -- `RPC_PASCAL_CASE` -- `SERVICE_PASCAL_CASE` - -**DEFAULT:** -- `ENUM_VALUE_PREFIX` -- `ENUM_ZERO_VALUE_SUFFIX` -- `FILE_LOWER_SNAKE_CASE` -- `RPC_REQUEST_RESPONSE_UNIQUE` -- `RPC_REQUEST_STANDARD_NAME` -- `RPC_RESPONSE_STANDARD_NAME` -- `PACKAGE_VERSION_SUFFIX` -- `SERVICE_SUFFIX` - -**COMMENTS:** -- `COMMENT_ENUM` -- `COMMENT_ENUM_VALUE` -- `COMMENT_FIELD` -- `COMMENT_MESSAGE` -- `COMMENT_ONEOF` -- `COMMENT_RPC` -- `COMMENT_SERVICE` - -**UNARY_RPC:** -- `RPC_NO_CLIENT_STREAMING` -- `RPC_NO_SERVER_STREAMING` - -#### `lint.enum_zero_value_suffix` - -**Optional.** Specifies the required suffix for enum zero values. - -**Type:** `string` -**Default:** `""` (no suffix required) -**Common values:** `"UNSPECIFIED"`, `"UNKNOWN"`, `"DEFAULT"` - -```yaml -lint: - enum_zero_value_suffix: "UNSPECIFIED" -``` - -This enforces enum zero values like: -```proto -enum Status { - STATUS_UNSPECIFIED = 0; // Required suffix - STATUS_ACTIVE = 1; - STATUS_INACTIVE = 2; -} -``` - -#### `lint.service_suffix` - -**Optional.** Specifies the required suffix for service names. - -**Type:** `string` -**Default:** `""` (no suffix required) -**Common values:** `"Service"`, `"API"`, `"Svc"` - -```yaml -lint: - service_suffix: "Service" -``` - -This enforces service names like: -```proto -service UserService { // Required "Service" suffix - rpc GetUser(...) returns (...); -} -``` - -#### `lint.ignore` - -**Optional.** Directories or files to exclude from all linting rules. - -**Type:** `[]string` -**Default:** `[]` - -```yaml -lint: - ignore: - - vendor/ - - proto/legacy/ - - testdata/ - - "**/*_test.proto" -``` - -Paths are relative to the `easyp.yaml` file location. Supports glob patterns. - -#### `lint.except` - -**Optional.** Disables specific rules globally across the entire project. - -**Type:** `[]string` -**Default:** `[]` - -```yaml -lint: - except: - - COMMENT_FIELD - - COMMENT_MESSAGE - - SERVICE_SUFFIX -``` - -#### `lint.allow_comment_ignores` - -**Optional.** Enables inline comment-based rule ignoring within proto files. - -**Type:** `boolean` -**Default:** `false` - -```yaml -lint: - allow_comment_ignores: true -``` - -When enabled, allows comments like: -```proto -// buf:lint:ignore COMMENT_SERVICE -service LegacyAPI { - // nolint:COMMENT_RPC - rpc GetData(...) returns (...); -} -``` - -#### `lint.ignore_only` - -**Optional.** Disables specific rules only for certain files or directories. - -**Type:** `map[string][]string` -**Default:** `{}` - -```yaml -lint: - ignore_only: - COMMENT_SERVICE: - - proto/legacy/ - - vendor/ - SERVICE_SUFFIX: - - proto/external/ -``` - -**Key:** Rule name or category -**Value:** Array of file paths or directories - -### `deps` - -**Optional.** Lists external proto dependencies to download and manage. - -**Type:** `[]string` -**Default:** `[]` - -#### Dependency Format - -Dependencies follow the format: `$GIT_LINK@$VERSION` - -**Components:** -- `$GIT_LINK` - Git repository URL (GitHub, GitLab, etc.) -- `$VERSION` - Git tag or full commit hash (optional) - -**Format variations:** -- `owner/repo` - Latest commit from default branch -- `owner/repo@v1.0.0` - Specific git tag -- `owner/repo@47b927cbb41c4fdea1292baf` - Full commit hash -- `github.com/owner/repo@version` - Full URL with version -- `gitlab.com/group/repo@tag` - GitLab repository - -```yaml -deps: - # Latest commit from default branch - - googleapis/googleapis - - # Specific tag (recommended for production) - - googleapis/googleapis@v1.0.0 - - # Full commit hash (most precise) - - googleapis/googleapis@47b927cbb41c4fdea1292bafadb8976f - - # Different Git hosting - - gitlab.com/acme/proto@v2.1.0 -``` - -**Note:** If `@$VERSION` is omitted, EasyP downloads the latest commit from the repository's default branch. - -### `generate` - -**Optional.** Configures code generation from proto files. - -**Type:** `object` -**Default:** `{}` - -```yaml -generate: - inputs: - - directory: "proto" - - git_repo: - url: "github.com/acme/common@v1.0.0" - sub_directory: "proto" - plugins: - - name: go - out: . - opts: - paths: source_relative - - name: go-grpc - out: . - opts: - paths: source_relative - require_unimplemented_servers: false -``` - -#### `generate.inputs` - -**Required when `generate` is set.** Specifies sources of proto files for generation. - -**Type:** `[]object` (minimum 1 item) -**Default:** not set - -```yaml -generate: - inputs: - # Local directory - - directory: "proto" - - # Local directory with advanced options - - directory: - path: "api/proto" - root: "." - - # Remote git repository - - git_repo: - url: "github.com/acme/common@v1.0.0" - sub_directory: "proto" - root: "." -``` - -**Directory input fields:** -- `directory` (string or object) - Local directory path -- `directory.path` (string) - Directory path -- `directory.root` (string) - Root path for import resolution (default: ".") - -**Git repository input fields:** -- `git_repo.url` (string) - Repository URL with optional version -- `git_repo.sub_directory` (string) - Subdirectory within the repository -- `git_repo.root` (string) - Root path used for import resolution - -#### `generate.plugins` - -**Required when `generate` is set.** Configures protoc plugins for code generation. - -**Type:** `[]object` (minimum 1 item) -**Default:** not set - -```yaml -generate: - plugins: - # Local plugin - - name: go - out: . - opts: - paths: source_relative - - # Remote plugin - - remote: "buf.build/bufbuild/protovalidate-go:v0.4.0" - out: gen/go - opts: - paths: source_relative - - # Plugin with import dependencies - - name: grpc-gateway - out: . - with_imports: true - opts: - paths: source_relative -``` - -**Plugin fields:** -- `name` (string, optional) - Plugin name (omit `protoc-gen-` prefix) -- `remote` (string, optional) - Remote plugin URL for execution -- `path` (string, optional) - Path to plugin executable file -- `command` ([]string, optional) - Command to execute plugin -- `out` (string, optional) - Output directory for generated files; defaults to the resolved generate root -- `opts` (map[string](string | number | boolean | array<string | number | boolean>), optional) - Plugin-specific options; each key can be a single scalar value or an array of scalar values -- `with_imports` (boolean, optional) - Include imported dependencies - -Plugin source is `one-of`: exactly one of `name`, `remote`, `path`, or `command` must be set. - -**Common plugin options:** -```yaml -# Go plugin options -opts: - paths: source_relative # Generate files relative to input - module: github.com/acme/api # Go module path - -# gRPC Gateway options -opts: - paths: source_relative - grpc_api_configuration: api.yaml # gRPC API configuration - -# OpenAPI v2 options -opts: - simple_operation_ids: true # Use simple operation IDs - generate_unbound_methods: false # Skip unbound methods - -# ts-proto options with repeated key values -opts: - env: node - outputServices: - - grpc-js - - generic-definitions -``` - -When an `opts` value is a list, EasyP serializes it as repeated plugin params, e.g. `outputServices=grpc-js,outputServices=generic-definitions`. - -### `breaking` - -**Optional.** Configures backward compatibility checking. - -**Type:** `object` -**Default:** `{}` - -```yaml -breaking: - ignore: - - proto/experimental/ - - proto/internal/ - against_git_ref: main -``` - -#### `breaking.ignore` +`mod tidy` resolves requirements and writes `protobuf.lock`. `mod download` fetches exactly the locked commits. `mod update` refreshes required versions within their current major versions, then updates the lock. Local `replace` directives work for generation and linting; remove them before `mod tidy` or `mod update` writes a reproducible lock. -**Optional.** Directories or files to exclude from breaking change detection. +## Command flags -**Type:** `[]string` -**Default:** `[]` - -```yaml -breaking: - ignore: - - proto/experimental/ - - proto/alpha/ - - testdata/ -``` - -#### `breaking.against_git_ref` - -**Optional.** Git reference (branch, tag, or commit) to compare against for breaking changes. - -**Type:** `string` -**Default:** `""` (falls back to CLI `--against` default: `master`) - -```yaml -breaking: - against_git_ref: main -``` - -Can be overridden by the `--against` CLI flag. +| Command | Relevant flags | +|---------|----------------| +| `generate` | `--project`, `--descriptor_set_out`, `--include_imports` | +| `lint` | `--path` (`-p`), `--root` (`-r`) | +| `breaking` | `--path` (`-p`), `--root` (`-r`), `--against` | +| `init` | `--dir` (`-d`), `--module` | +| `validate-config` | `--config` (alias of `--cfg`), `--format` | +The global flags are `--cfg` (alias `--config`, default `easyp.yaml`), `--debug` (`-d`), and `--format` (`-f`, `text` or `json`). `EASYP_CFG`, `EASYP_DEBUG`, and `EASYP_FORMAT` set their respective defaults. The module cache uses `EASYPPATH` or `$HOME/.easyp`. +`generate` discovers `easyp.gen.yaml` files beneath the current directory. Use `--project` to choose one consumer project. Modules and their source roots come from `protobuf.mod`; `generate.packages` is reserved and currently returns an error if nonempty. The old `generate --path` and `generate --root` flags are unavailable. -## Configuration Examples +`lint` and `breaking` read the v1 `easyp.yaml`. They use the nearest module's declared roots and locked or local dependency roots for imports. A policy may exist without a `protobuf.mod`; in that case the commands use the scanned files and built-in imports. -### Minimal Configuration +The v1 pilot has no `mod vendor` or `ls-files` command. -```yaml -lint: - use: - - MINIMAL -``` +## Minimal files -### Development Configuration - -```yaml -lint: - use: - - BASIC - - COMMENT_SERVICE - - COMMENT_RPC - allow_comment_ignores: true - ignore: - - vendor/ - - testdata/ -deps: - - github.com/googleapis/googleapis@v1.0.0 -generate: - inputs: - - directory: "proto" - plugins: - - name: go - out: . - opts: - paths: source_relative - - name: go-grpc - out: . - opts: - paths: source_relative +```text +module github.com/acme/contracts +roots proto +require github.com/acme/shared v1.2.0 ``` -### Production Configuration - ```yaml -lint: - use: - - MINIMAL - - BASIC - - DEFAULT - - COMMENTS - enum_zero_value_suffix: "UNSPECIFIED" - service_suffix: "Service" - ignore: - - vendor/ - except: [] - allow_comment_ignores: false -deps: - - github.com/googleapis/googleapis@v1.56.0 - - github.com/grpc-ecosystem/grpc-gateway@v2.18.0 +# easyp.gen.yaml +version: v1 generate: - inputs: - - directory: "proto" - plugins: - - name: go - out: gen/go - opts: - paths: source_relative - module: github.com/acme/api/gen/go - - name: go-grpc - out: gen/go - opts: - paths: source_relative - require_unimplemented_servers: false - - name: grpc-gateway - out: gen/go - opts: - paths: source_relative - - name: openapiv2 - out: gen/openapi - opts: - simple_operation_ids: true -breaking: - ignore: - - proto/experimental/ - against_git_ref: main + modules: [github.com/acme/contracts] +plugins: + - name: go + out: ./gen/go ``` -### Multi-Service Configuration - ```yaml -lint: - use: - - BASIC - - COMMENT_SERVICE - - COMMENT_RPC - service_suffix: "Service" - ignore_only: - COMMENT_FIELD: - - proto/internal/ - SERVICE_SUFFIX: - - proto/legacy/ -deps: - - github.com/googleapis/googleapis@v1.0.0 - - github.com/acme/common-proto@v2.1.0 -generate: - inputs: - - directory: "proto/public" - - directory: "proto/internal" - - git_repo: - url: "github.com/acme/shared-proto@v1.0.0" - sub_directory: "proto" - plugins: - - name: go - out: gen/go - opts: - paths: source_relative - - name: go-grpc - out: gen/go - opts: - paths: source_relative - - name: grpc-gateway - out: gen/go - opts: - paths: source_relative - - remote: "buf.build/bufbuild/protovalidate-go:v0.4.0" - out: gen/go - opts: - paths: source_relative +# easyp.yaml +version: v1 +linters: + default: STANDARD breaking: - ignore: - - proto/internal/ - - proto/experimental/ - against_git_ref: develop -``` - -## Configuration Validation - -EasyP validates configuration files on startup and provides helpful error messages: - -```bash -# Invalid rule name -Error: invalid rule: INVALID_RULE_NAME - -# Missing required field in generate section -Error: required field "plugins" is missing (path: generate.plugins) - -# Invalid dependency format -Error: invalid dependency format: invalid-repo-url + baseline: git:main ``` -Use `easyp --debug` for detailed validation information. - -## Migration from Buf - -EasyP is fully compatible with Buf configurations. To migrate: - -1. Place `buf.yaml` or `buf.yml` in the project root -2. Run `easyp init` and confirm migration when prompted -3. Update `deps` format if using BSR modules -4. Review migrated lint/breaking settings and adjust as needed - -Most Buf configurations work without changes in EasyP. +For the exact fields and current limits, use the linked reference pages above. diff --git a/content/docs/cli/configuration.ru.mdx b/content/docs/cli/configuration.ru.mdx index 12d158c..900cc41 100644 --- a/content/docs/cli/configuration.ru.mdx +++ b/content/docs/cli/configuration.ru.mdx @@ -1,932 +1,75 @@ --- -title: "EasyP Configuration Reference" +title: "Конфигурация EasyP v1 Pilot" +description: "Файлы и команды CLI пилотной версии EasyP v1." --- -EasyP can be configured through CLI flags, environment variables, and configuration files. This guide covers all configuration options available in EasyP. +В пилотной версии v1 зависимости, генерация и правила проверки находятся в разных файлах: -## CLI Flags +| Файл | Назначение | +|------|------------| +| [`protobuf.mod`](/ru/docs/reference/protobuf-mod) | Имя модуля, корни исходников, зависимости и локальные замены | +| [`protobuf.lock`](/ru/docs/reference/protobuf-lock) | Зафиксированные Git-коммиты и хеши содержимого; создаётся командой `easyp mod tidy` | +| [`easyp.gen.yaml`](/ru/docs/reference/easyp-gen-yaml) | Модули для генерации, плагины, выходные каталоги и managed mode | +| [`easyp.yaml`](/ru/docs/reference/easyp-yaml) | Правила линтинга и проверки совместимости | -### Global Flags +Команды CLI читают формат v1 напрямую и не переходят на старую логику генерации, линтинга, проверки совместимости или управления модулями. Зависимость в Git при этом может использовать старый формат EasyP или Buf: адаптер извлекает её требования и корни `.proto` для разрешения импортов. -Available for all commands: +## Обычный порядок работы -| Flag | Short | Environment | Description | Default | -|------|-------|-------------|-------------|---------| -| `--cfg` | `-c` | `EASYP_CFG` | Configuration file path | `easyp.yaml` | -| `--config` | | `EASYP_CFG` | Alias for `--cfg` | `easyp.yaml` | -| `--debug` | `-d` | `EASYP_DEBUG` | Enable debug mode | `false` | -| `--format` | `-f` | `EASYP_FORMAT` | Формат вывода для команд с поддержкой нескольких форматов (`text`/`json`) | значение по умолчанию зависит от команды | - -**Examples:** -```bash -# Use custom config file -easyp --cfg production.easyp.yaml lint - -# Enable debug logging -easyp --debug lint - -# Short form -easyp -c custom.yaml -d lint -``` - -### Command-Specific Flags - -**Lint command:** -```bash -easyp lint [flags] -``` - -| Flag | Short | Environment | Description | Default | -|------|-------|-------------|-------------|---------| -| `--path` | `-p` | | Directory path to lint | `.` | -| `--root` | `-r` | | Базовая директория для поиска файлов | Текущая рабочая директория | -| `--format` | `-f` | `EASYP_FORMAT` | Использует глобальный флаг формата (`text`/`json`) | Использует глобальное значение по умолчанию | - -**Examples:** -```bash -# Lint specific directory -easyp lint --path proto/ - -# Lint из поддиректории с правильным разрешением импортов -easyp lint --root src/IPC/Contracts --path . - -# JSON output format -easyp --format json lint # глобальный флаг - -# Combined flags -easyp -f json lint -p proto/ -``` - -**Generate command:** -```bash -easyp generate [flags] -``` - -| Flag | Short | Environment | Description | Default | -|------|-------|-------------|-------------|---------| -| `--path` | `-p` | `EASYP_ROOT_GENERATE_PATH` | Путь к директории с proto файлами для генерации | `.` | -| `--root` | `-r` | | Базовая директория для поиска файлов | Текущая рабочая директория | - -**Examples:** -```bash -# Generate from specific path -easyp generate --path api/ - -# Generate из поддиректории с правильным разрешением импортов -easyp generate --root src/IPC/Contracts --path . - -# Using environment variable -EASYP_ROOT_GENERATE_PATH=proto/ easyp generate -``` - -**Breaking command:** -```bash -easyp breaking [flags] -``` - -| Flag | Short | Environment | Description | Default | -|------|-------|-------------|-------------|---------| -| `--against` | | | Git ref to compare against | `master` | -| `--path` | `-p` | | Directory path to check | `.` | -| `--format` | `-f` | `EASYP_FORMAT` | Использует глобальный флаг формата (`text`/`json`) | Использует глобальное значение по умолчанию | - -**Examples:** -```bash -# Check against main branch -easyp breaking --against main - -# Check specific directory against develop branch -easyp breaking --against develop --path proto/ - -# JSON output -easyp --format json breaking --against main # глобальный флаг -``` - -**Init command:** -```bash -easyp init [flags] -``` - -| Flag | Short | Environment | Description | Default | -|------|-------|-------------|-------------|---------| -| `--dir` | `-d` | `EASYP_INIT_DIR` | Directory to initialize | `.` | - -**Examples:** -```bash -# Initialize current directory -easyp init - -# Initialize specific directory -easyp init --dir proto-project/ -``` - -`easyp init` работает интерактивно: -- Если в корне целевой директории есть `buf.yml`/`buf.yaml`, команда предложит миграцию из Buf. -- Если `easyp.yaml` уже существует, команда запросит подтверждение на перезапись. - -**Validate-config command:** -```bash -easyp validate-config [flags] -``` - -| Flag | Short | Environment | Description | Default | -|------|-------|-------------|-------------|---------| -| `--config` | `-c` | `EASYP_CFG` | Путь до файла конфигурации | `easyp.yaml` | -| `--format` (global) | `-f` | `EASYP_FORMAT` | Глобальный формат вывода для команд с несколькими форматами (`json` или `text`) | зависит от команды (`json` для `validate-config`) | - -**Examples:** -```bash -# Проверить конфиг по умолчанию с JSON выводом (статус 0 если ошибок нет) -easyp validate-config - -# Проверить другой файл и вывести в текстовом формате (глобальный --format) -easyp --format text validate-config --config example.easyp.yaml -``` - -**Package management commands:** - -#### `easyp mod download` -Downloads dependencies based on lock file priority: - -1. **If `easyp.lock` exists** - downloads exact versions from lock file -2. **If `easyp.lock` is missing** - downloads versions from `easyp.yaml` and creates `easyp.lock` - -```bash -# Download exact versions (recommended for production) -easyp mod download -``` - -#### `easyp mod update` -Always downloads dependencies from `easyp.yaml`, ignoring existing lock file: - -1. **Ignores `easyp.lock`** completely -2. **Downloads versions from `easyp.yaml`** -3. **Creates/updates `easyp.lock`** with new versions - -```bash -# Update dependencies and lock file -easyp mod update -``` - -#### `easyp mod vendor` -Copies proto files from dependencies to local `vendor/` directory (similar to `go mod vendor`). - -```bash -# Create local vendor directory with dependencies -easyp mod vendor -``` - -No additional flags. Uses global `--cfg` flag for configuration. - -## Environment Variables - -EasyP supports environment variables for configuration: - -| Variable | Description | Default | -|----------|-------------|---------| -| `EASYP_CFG` | Path to configuration file | `easyp.yaml` | -| `EASYP_DEBUG` | Enable debug logging | `false` | -| `EASYPPATH` | Cache and modules storage directory | `$HOME/.easyp` | -| `EASYP_FORMAT` | Формат вывода для поддерживаемых команд (`text`/`json`). Если не указан, каждая команда использует своё значение по умолчанию. | значение по умолчанию зависит от команды | -| `EASYP_ROOT_GENERATE_PATH` | Root path for generate command | `.` | -| `EASYP_INIT_DIR` | Directory for init command | `.` | - -**Examples:** ```bash -# Custom cache directory -export EASYPPATH=/tmp/easyp-cache +easyp init --module github.com/acme/contracts +easyp mod tidy easyp mod download - -# Debug mode via environment -export EASYP_DEBUG=true -easyp lint - -# Custom config file -export EASYP_CFG=config/easyp.yaml easyp generate +easyp lint --path proto +easyp breaking --path proto --against main ``` -## Configuration File - -The `easyp.yaml` file is the main configuration file for EasyP, defining how your proto files are linted, generated, and managed. This file is typically placed at the root of your project alongside your proto files. - -### File Structure Overview - -``` -. -├── easyp.yaml -├── easyp.lock -├── proto/ -│ ├── user/ -│ │ └── user.proto -│ └── order/ -│ └── order.proto -└── vendor/ -``` - -### Configuration Format - -EasyP supports both YAML and JSON configuration formats: - -#### YAML Format (Recommended) -```yaml -lint: - use: - - BASIC - - COMMENT_SERVICE -deps: - - github.com/googleapis/googleapis@v1.0.0 -generate: - inputs: - - directory: "proto" - plugins: - - name: go - out: . - opts: - paths: source_relative -breaking: - ignore: - - proto/experimental/ - against_git_ref: main -``` - -#### JSON Format -```json -{ - "lint": { - "use": ["BASIC", "COMMENT_SERVICE"] - }, - "deps": [ - "github.com/googleapis/googleapis@v1.0.0" - ], - "generate": { - "inputs": [ - {"directory": "proto"} - ], - "plugins": [ - { - "name": "go", - "out": ".", - "opts": { - "paths": "source_relative" - } - } - ] - }, - "breaking": { - "ignore": ["proto/experimental/"], - "against_git_ref": "main" - } -} -``` - -### Переменные окружения в конфигурации - -EasyP поддерживает расширение переменных окружения непосредственно в файле конфигурации `easyp.yaml`. Это позволяет использовать переменные окружения для динамических значений конфигурации. - -**Пример со всеми поддерживаемыми возможностями:** -```yaml -deps: - # Базовое расширение: ${VAR} - расширяется в значение переменной VAR - - ${GOOGLEAPIS_REPO}@${GOOGLEAPIS_VERSION} - - # Значение по умолчанию: ${VAR:-default} - использует default, если VAR не установлена или пустая - - ${GNOSTIC_REPO:-github.com/google/gnostic}@${GNOSTIC_VERSION:-v0.7.0} - -generate: - inputs: - # Значение по умолчанию, если INPUT_DIR не установлена - - directory: ${INPUT_DIR:-proto} - plugins: - - name: go - # Базовое расширение - out: ${OUTPUT_DIR} - opts: - # Значение по умолчанию - module: ${MODULE_NAME:-github.com/example/project} - timeout: ${TIMEOUT:-30} - - # Экранирование: $$ становится буквальным $, $${VAR} становится буквальным ${VAR} - path: "${BASE_DIR}/$${TEMP}/file" # Результат: "/tmp/${TEMP}/file" (если BASE_DIR=/tmp) - literal: "$$" # Результат: "$" -``` - -**Поддерживаемый синтаксис:** -- `${VAR}` - расширяется в значение переменной `VAR` -- `${VAR:-default}` - использует `default`, если `VAR` не установлена или пустая -- `${VAR:=default}` - использует `default`, если `VAR` не установлена или пустая -- `${VAR-default}` - использует `default`, если `VAR` не установлена (пустая строка сохраняется) -- `$${VAR}` или `$$VAR` - экранирует в буквальную строку `${VAR}` или `$VAR` -- `$$` - экранирует в буквальный символ `$` - -**Примечание:** Переменные окружения расширяются до парсинга YAML, поэтому любой паттерн `${STRING}` будет обработан. Используйте `$$` для экранирования символов доллара, когда нужны буквальные значения. - -## Configuration Fields - -### `version` - -**Опционально (legacy-совместимость).** Поле поддерживается для обратной совместимости и может быть опущено в новых конфигурациях. - -**Type:** `string` -**Default:** не задано -**Рекомендация:** если сохраняете поле, используйте `v1alpha` - -```yaml -# Опциональное поле для совместимости (можно опустить) -version: v1alpha -``` - -На поведение рантайма это поле не влияет. - -### `lint` - -**Optional.** Configures proto file linting rules and behavior. - -**Type:** `object` -**Default:** Empty (no linting rules applied) - -```yaml -lint: - use: - - BASIC - - COMMENT_SERVICE - enum_zero_value_suffix: "UNSPECIFIED" - service_suffix: "Service" - ignore: - - vendor/ - - proto/legacy/ - except: - - COMMENT_FIELD - allow_comment_ignores: true - ignore_only: - COMMENT_SERVICE: - - proto/experimental/ -``` - -#### `lint.use` - -**Optional.** Specifies which linter rules or rule categories to apply. - -**Type:** `[]string` -**Default:** `[]` (no rules) - -**Available categories:** -- `MINIMAL` - Essential package consistency checks -- `BASIC` - Naming conventions and common patterns -- `DEFAULT` - Additional recommended rules -- `COMMENTS` - Comment requirements -- `UNARY_RPC` - Streaming RPC restrictions - -**Individual rules:** Any specific rule name (e.g., `ENUM_PASCAL_CASE`, `FIELD_LOWER_SNAKE_CASE`) - -```yaml -lint: - use: - - MINIMAL # Use all minimal rules - - BASIC # Use all basic rules - - COMMENT_SERVICE # Require service comments - - ENUM_PASCAL_CASE # Specific rule -``` - -**Rule Categories:** - -**MINIMAL:** -- `DIRECTORY_SAME_PACKAGE` -- `PACKAGE_DEFINED` -- `PACKAGE_DIRECTORY_MATCH` -- `PACKAGE_SAME_DIRECTORY` - -**BASIC:** -- `ENUM_FIRST_VALUE_ZERO` -- `ENUM_NO_ALLOW_ALIAS` -- `ENUM_PASCAL_CASE` -- `ENUM_VALUE_UPPER_SNAKE_CASE` -- `FIELD_LOWER_SNAKE_CASE` -- `IMPORT_NO_PUBLIC` -- `IMPORT_NO_WEAK` -- `IMPORT_USED` -- `MESSAGE_PASCAL_CASE` -- `ONEOF_LOWER_SNAKE_CASE` -- `PACKAGE_LOWER_SNAKE_CASE` -- `PACKAGE_SAME_CSHARP_NAMESPACE` -- `PACKAGE_SAME_GO_PACKAGE` -- `PACKAGE_SAME_JAVA_MULTIPLE_FILES` -- `PACKAGE_SAME_JAVA_PACKAGE` -- `PACKAGE_SAME_PHP_NAMESPACE` -- `PACKAGE_SAME_RUBY_PACKAGE` -- `PACKAGE_SAME_SWIFT_PREFIX` -- `RPC_PASCAL_CASE` -- `SERVICE_PASCAL_CASE` - -**DEFAULT:** -- `ENUM_VALUE_PREFIX` -- `ENUM_ZERO_VALUE_SUFFIX` -- `FILE_LOWER_SNAKE_CASE` -- `RPC_REQUEST_RESPONSE_UNIQUE` -- `RPC_REQUEST_STANDARD_NAME` -- `RPC_RESPONSE_STANDARD_NAME` -- `PACKAGE_VERSION_SUFFIX` -- `SERVICE_SUFFIX` - -**COMMENTS:** -- `COMMENT_ENUM` -- `COMMENT_ENUM_VALUE` -- `COMMENT_FIELD` -- `COMMENT_MESSAGE` -- `COMMENT_ONEOF` -- `COMMENT_RPC` -- `COMMENT_SERVICE` - -**UNARY_RPC:** -- `RPC_NO_CLIENT_STREAMING` -- `RPC_NO_SERVER_STREAMING` - -#### `lint.enum_zero_value_suffix` - -**Optional.** Specifies the required suffix for enum zero values. - -**Type:** `string` -**Default:** `""` (no suffix required) -**Common values:** `"UNSPECIFIED"`, `"UNKNOWN"`, `"DEFAULT"` - -```yaml -lint: - enum_zero_value_suffix: "UNSPECIFIED" -``` - -This enforces enum zero values like: -```proto -enum Status { - STATUS_UNSPECIFIED = 0; // Required suffix - STATUS_ACTIVE = 1; - STATUS_INACTIVE = 2; -} -``` - -#### `lint.service_suffix` - -**Optional.** Specifies the required suffix for service names. - -**Type:** `string` -**Default:** `""` (no suffix required) -**Common values:** `"Service"`, `"API"`, `"Svc"` - -```yaml -lint: - service_suffix: "Service" -``` - -This enforces service names like: -```proto -service UserService { // Required "Service" suffix - rpc GetUser(...) returns (...); -} -``` - -#### `lint.ignore` - -**Optional.** Directories or files to exclude from all linting rules. - -**Type:** `[]string` -**Default:** `[]` - -```yaml -lint: - ignore: - - vendor/ - - proto/legacy/ - - testdata/ - - "**/*_test.proto" -``` - -Paths are relative to the `easyp.yaml` file location. Supports glob patterns. - -#### `lint.except` - -**Optional.** Disables specific rules globally across the entire project. - -**Type:** `[]string` -**Default:** `[]` - -```yaml -lint: - except: - - COMMENT_FIELD - - COMMENT_MESSAGE - - SERVICE_SUFFIX -``` - -#### `lint.allow_comment_ignores` - -**Optional.** Enables inline comment-based rule ignoring within proto files. - -**Type:** `boolean` -**Default:** `false` - -```yaml -lint: - allow_comment_ignores: true -``` - -When enabled, allows comments like: -```proto -// buf:lint:ignore COMMENT_SERVICE -service LegacyAPI { - // nolint:COMMENT_RPC - rpc GetData(...) returns (...); -} -``` - -#### `lint.ignore_only` - -**Optional.** Disables specific rules only for certain files or directories. - -**Type:** `map[string][]string` -**Default:** `{}` - -```yaml -lint: - ignore_only: - COMMENT_SERVICE: - - proto/legacy/ - - vendor/ - SERVICE_SUFFIX: - - proto/external/ -``` - -**Key:** Rule name or category -**Value:** Array of file paths or directories - -### `deps` - -**Optional.** Lists external proto dependencies to download and manage. - -**Type:** `[]string` -**Default:** `[]` - -#### Dependency Format - -Dependencies follow the format: `$GIT_LINK@$VERSION` - -**Components:** -- `$GIT_LINK` - Git repository URL (GitHub, GitLab, etc.) -- `$VERSION` - Git tag or full commit hash (optional) - -**Format variations:** -- `owner/repo` - Latest commit from default branch -- `owner/repo@v1.0.0` - Specific git tag -- `owner/repo@47b927cbb41c4fdea1292baf` - Full commit hash -- `github.com/owner/repo@version` - Full URL with version -- `gitlab.com/group/repo@tag` - GitLab repository - -```yaml -deps: - # Latest commit from default branch - - googleapis/googleapis - - # Specific tag (recommended for production) - - googleapis/googleapis@v1.0.0 - - # Full commit hash (most precise) - - googleapis/googleapis@47b927cbb41c4fdea1292bafadb8976f - - # Different Git hosting - - gitlab.com/acme/proto@v2.1.0 -``` - -**Note:** If `@$VERSION` is omitted, EasyP downloads the latest commit from the repository's default branch. - -### `generate` - -**Optional.** Configures code generation from proto files. - -**Type:** `object` -**Default:** `{}` - -```yaml -generate: - inputs: - - directory: "proto" - - git_repo: - url: "github.com/acme/common@v1.0.0" - sub_directory: "proto" - plugins: - - name: go - out: . - opts: - paths: source_relative - - name: go-grpc - out: . - opts: - paths: source_relative - require_unimplemented_servers: false -``` - -#### `generate.inputs` - -**Required when `generate` is set.** Specifies sources of proto files for generation. - -**Type:** `[]object` (minimum 1 item) -**Default:** not set - -```yaml -generate: - inputs: - # Local directory - - directory: "proto" - - # Local directory with advanced options - - directory: - path: "api/proto" - root: "." - - # Remote git repository - - git_repo: - url: "github.com/acme/common@v1.0.0" - sub_directory: "proto" - root: "." -``` - -**Directory input fields:** -- `directory` (string or object) - Local directory path -- `directory.path` (string) - Directory path -- `directory.root` (string) - Root path for import resolution (default: ".") - -**Git repository input fields:** -- `git_repo.url` (string) - Repository URL with optional version -- `git_repo.sub_directory` (string) - Subdirectory within the repository -- `git_repo.root` (string) - Root path used for import resolution - -#### `generate.plugins` - -**Required when `generate` is set.** Configures protoc plugins for code generation. - -**Type:** `[]object` (minimum 1 item) -**Default:** not set - -```yaml -generate: - plugins: - # Local plugin - - name: go - out: . - opts: - paths: source_relative - - # Remote plugin - - remote: "buf.build/bufbuild/protovalidate-go:v0.4.0" - out: gen/go - opts: - paths: source_relative - - # Plugin with import dependencies - - name: grpc-gateway - out: . - with_imports: true - opts: - paths: source_relative -``` - -**Plugin fields:** -- `name` (string, optional) - Plugin name (omit `protoc-gen-` prefix) -- `remote` (string, optional) - Remote plugin URL for execution -- `path` (string, optional) - Path to plugin executable file -- `command` ([]string, optional) - Command to execute plugin -- `out` (string, optional) - Output directory for generated files; defaults to the resolved generate root -- `opts` (map[string](string | number | boolean | array<string | number | boolean>), optional) - Plugin-specific options; each key can be a single scalar value or an array of scalar values -- `with_imports` (boolean, optional) - Include imported dependencies - -Plugin source is `one-of`: exactly one of `name`, `remote`, `path`, or `command` must be set. - -**Common plugin options:** -```yaml -# Go plugin options -opts: - paths: source_relative # Generate files relative to input - module: github.com/acme/api # Go module path - -# gRPC Gateway options -opts: - paths: source_relative - grpc_api_configuration: api.yaml # gRPC API configuration - -# OpenAPI v2 options -opts: - simple_operation_ids: true # Use simple operation IDs - generate_unbound_methods: false # Skip unbound methods - -# ts-proto options with repeated key values -opts: - env: node - outputServices: - - grpc-js - - generic-definitions -``` - -When an `opts` value is a list, EasyP serializes it as repeated plugin params, e.g. `outputServices=grpc-js,outputServices=generic-definitions`. - -### `breaking` - -**Optional.** Configures backward compatibility checking. - -**Type:** `object` -**Default:** `{}` - -```yaml -breaking: - ignore: - - proto/experimental/ - - proto/internal/ - against_git_ref: main -``` - -#### `breaking.ignore` +`mod tidy` разрешает зависимости и записывает `protobuf.lock`. `mod download` скачивает только зафиксированные коммиты. `mod update` обновляет версии в пределах текущей мажорной версии и пересоздаёт lock. Локальные `replace` работают при генерации и линтинге; перед `mod tidy` или `mod update` их нужно убрать, чтобы получить воспроизводимый lock. -**Optional.** Directories or files to exclude from breaking change detection. +## Флаги команд -**Type:** `[]string` -**Default:** `[]` - -```yaml -breaking: - ignore: - - proto/experimental/ - - proto/alpha/ - - testdata/ -``` - -#### `breaking.against_git_ref` - -**Optional.** Git reference (branch, tag, or commit) to compare against for breaking changes. - -**Type:** `string` -**Default:** `""` (falls back to CLI `--against` default: `master`) - -```yaml -breaking: - against_git_ref: main -``` - -Can be overridden by the `--against` CLI flag. +| Команда | Основные флаги | +|---------|----------------| +| `generate` | `--project`, `--descriptor_set_out`, `--include_imports` | +| `lint` | `--path` (`-p`), `--root` (`-r`) | +| `breaking` | `--path` (`-p`), `--root` (`-r`), `--against` | +| `init` | `--dir` (`-d`), `--module` | +| `validate-config` | `--config` (псевдоним `--cfg`), `--format` | +Общие флаги: `--cfg` (псевдоним `--config`, по умолчанию `easyp.yaml`), `--debug` (`-d`) и `--format` (`-f`, `text` или `json`). Переменные `EASYP_CFG`, `EASYP_DEBUG` и `EASYP_FORMAT` задают значения по умолчанию. Кеш модулей находится в `EASYPPATH` или `$HOME/.easyp`. +`generate` ищет `easyp.gen.yaml` внутри текущего каталога. Флаг `--project` выбирает один проект-потребитель. Список модулей и корни исходников берутся из `protobuf.mod`. Поле `generate.packages` зарезервировано: непустое значение пока вызывает ошибку. Старые флаги `generate --path` и `generate --root` удалены. -## Configuration Examples +`lint` и `breaking` читают `easyp.yaml` версии v1. Для импортов они используют корни ближайшего модуля и его зафиксированных или локальных зависимостей. Политика может существовать без `protobuf.mod`; тогда используются проверяемые файлы и встроенные импорты. -### Minimal Configuration +В пилотной версии v1 нет команд `mod vendor` и `ls-files`. -```yaml -lint: - use: - - MINIMAL -``` +## Минимальный пример -### Development Configuration - -```yaml -lint: - use: - - BASIC - - COMMENT_SERVICE - - COMMENT_RPC - allow_comment_ignores: true - ignore: - - vendor/ - - testdata/ -deps: - - github.com/googleapis/googleapis@v1.0.0 -generate: - inputs: - - directory: "proto" - plugins: - - name: go - out: . - opts: - paths: source_relative - - name: go-grpc - out: . - opts: - paths: source_relative +```text +module github.com/acme/contracts +roots proto +require github.com/acme/shared v1.2.0 ``` -### Production Configuration - ```yaml -lint: - use: - - MINIMAL - - BASIC - - DEFAULT - - COMMENTS - enum_zero_value_suffix: "UNSPECIFIED" - service_suffix: "Service" - ignore: - - vendor/ - except: [] - allow_comment_ignores: false -deps: - - github.com/googleapis/googleapis@v1.56.0 - - github.com/grpc-ecosystem/grpc-gateway@v2.18.0 +# easyp.gen.yaml +version: v1 generate: - inputs: - - directory: "proto" - plugins: - - name: go - out: gen/go - opts: - paths: source_relative - module: github.com/acme/api/gen/go - - name: go-grpc - out: gen/go - opts: - paths: source_relative - require_unimplemented_servers: false - - name: grpc-gateway - out: gen/go - opts: - paths: source_relative - - name: openapiv2 - out: gen/openapi - opts: - simple_operation_ids: true -breaking: - ignore: - - proto/experimental/ - against_git_ref: main + modules: [github.com/acme/contracts] +plugins: + - name: go + out: ./gen/go ``` -### Multi-Service Configuration - ```yaml -lint: - use: - - BASIC - - COMMENT_SERVICE - - COMMENT_RPC - service_suffix: "Service" - ignore_only: - COMMENT_FIELD: - - proto/internal/ - SERVICE_SUFFIX: - - proto/legacy/ -deps: - - github.com/googleapis/googleapis@v1.0.0 - - github.com/acme/common-proto@v2.1.0 -generate: - inputs: - - directory: "proto/public" - - directory: "proto/internal" - - git_repo: - url: "github.com/acme/shared-proto@v1.0.0" - sub_directory: "proto" - plugins: - - name: go - out: gen/go - opts: - paths: source_relative - - name: go-grpc - out: gen/go - opts: - paths: source_relative - - name: grpc-gateway - out: gen/go - opts: - paths: source_relative - - remote: "buf.build/bufbuild/protovalidate-go:v0.4.0" - out: gen/go - opts: - paths: source_relative +# easyp.yaml +version: v1 +linters: + default: STANDARD breaking: - ignore: - - proto/internal/ - - proto/experimental/ - against_git_ref: develop -``` - -## Configuration Validation - -EasyP validates configuration files on startup and provides helpful error messages: - -```bash -# Invalid rule name -Error: invalid rule: INVALID_RULE_NAME - -# Missing required field in generate section -Error: required field "plugins" is missing (path: generate.plugins) - -# Invalid dependency format -Error: invalid dependency format: invalid-repo-url + baseline: git:main ``` -Use `easyp --debug` for detailed validation information. - -## Migration from Buf - -EasyP is fully compatible with Buf configurations. To migrate: - -1. Place `buf.yaml` or `buf.yml` in the project root -2. Run `easyp init` and confirm migration when prompted -3. Update `deps` format if using BSR modules -4. Review migrated lint/breaking settings and adjust as needed - -Most Buf configurations work without changes in EasyP. +Точные поля и текущие ограничения описаны в справочниках по ссылкам выше. From 39f6bfca42e89df58fc0a1624da0e5bc26623016 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 23 Sep 2026 12:41:41 +0300 Subject: [PATCH 03/26] docs(v1): replace legacy CLI guides and quickstart --- content/docs/cli/breaking-changes/index.mdx | 450 +------------- .../docs/cli/breaking-changes/index.ru.mdx | 440 +------------- content/docs/cli/generator/examples/go.mdx | 161 +---- content/docs/cli/generator/examples/go.ru.mdx | 161 +---- .../cli/generator/examples/grpc-gateway.mdx | 165 +----- .../generator/examples/grpc-gateway.ru.mdx | 165 +----- .../docs/cli/generator/examples/validate.mdx | 146 +---- .../cli/generator/examples/validate.ru.mdx | 146 +---- content/docs/cli/generator/index.mdx | 159 ++--- content/docs/cli/generator/index.ru.mdx | 159 ++--- content/docs/cli/linter/index.mdx | 429 +------------- content/docs/cli/linter/index.ru.mdx | 345 +---------- .../docs/cli/package-manager/easyp-vs-buf.mdx | 463 +-------------- .../cli/package-manager/easyp-vs-buf.ru.mdx | 438 +------------- content/docs/cli/package-manager/index.mdx | 554 +----------------- content/docs/cli/package-manager/index.ru.mdx | 460 +-------------- content/docs/guides/breaking-checks-ci.mdx | 139 +---- content/docs/guides/breaking-checks-ci.ru.mdx | 137 +---- content/docs/introduction/quickstart.mdx | 230 ++------ content/docs/introduction/quickstart.ru.mdx | 232 ++------ content/docs/introduction/what-is.mdx | 34 +- content/docs/introduction/what-is.ru.mdx | 34 +- 22 files changed, 541 insertions(+), 5106 deletions(-) diff --git a/content/docs/cli/breaking-changes/index.mdx b/content/docs/cli/breaking-changes/index.mdx index 00d09a3..5ba8927 100644 --- a/content/docs/cli/breaking-changes/index.mdx +++ b/content/docs/cli/breaking-changes/index.mdx @@ -1,453 +1,25 @@ --- title: "Breaking Changes Detection" +description: "Compare protobuf schemas with a Git ref using EasyP v1." --- -[[toc]] - -EasyP's breaking changes detection helps you maintain backward compatibility in your protobuf APIs by automatically identifying changes that could break existing clients. This is crucial for maintaining stable APIs in production environments. - -## Overview - -The breaking changes checker compares your current protobuf files against a previous version (typically from another Git branch) and identifies modifications that could cause compatibility issues for existing clients. - -### Key Features - -- **Git-based Comparison**: Compare against any Git reference (branch, tag, or commit) -- **Comprehensive Analysis**: Checks services, messages, enums, fields, and imports -- **Selective Ignore**: Skip specific directories from breaking change analysis -- **Detailed Reports**: Clear error messages with file locations and line numbers - -## How It Works - -The breaking changes detector follows this process: - -1. **Checkout Comparison Branch**: Retrieves proto files from the specified Git reference -2. **Parse Both Versions**: Analyzes current and previous proto file structures -3. **Compare Entities**: Systematically checks all protobuf elements for breaking changes -4. **Generate Report**: Produces detailed issue reports with locations and descriptions - -## Detection Level - -EasyP implements **WIRE+ level** breaking change detection: -- ✅ **Full wire format compatibility** - ensures old and new versions can exchange data -- ✅ **Element deletion detection** - catches deleted services, messages, fields, etc. -- ✅ **Type safety** - detects incompatible type changes -- ❌ **Field/method renames** - currently not detected (planned for future releases) -- ❌ **File-level changes** - package moves, file options not checked yet - -This provides strong compatibility guarantees while being less strict than some tools that check generated code compatibility. - -## Configuration - -Configure breaking changes detection in your `easyp.yaml`: +`easyp breaking` compares current `.proto` files with a Git reference and reports incompatible changes detected by the existing checker. ```yaml +# easyp.yaml +version: v1 breaking: - # Git reference to compare against (branch, tag, or commit hash) - against_git_ref: "main" - - # Directories to ignore during breaking changes analysis - ignore: - - "experimental" - - "internal/proto" - - "vendor" -``` - -### Configuration Options - -| Option | Description | Default | Required | -|--------|-------------|---------|----------| -| `against_git_ref` | Git reference to compare against | `"master"` | No | -| `ignore` | List of directories to exclude from analysis | `[]` | No | - -## Usage - -### Basic Usage - -Compare current changes against the main branch: - -```bash -easyp breaking --against main + baseline: git:main + ignore: [experimental] ``` -### Using Configuration File - -With a custom configuration file: - ```bash -easyp --cfg my-config.yaml breaking -``` - -### Override Git Reference - -Override the configured branch: - -```bash -easyp breaking --against feature/new-api -``` - -## Detection Level - -EasyP currently implements **WIRE+ level** breaking change detection, which provides comprehensive wire format compatibility plus some generated code protections: - -### Comparison with Buf Categories - -| Check Type | Buf WIRE | Buf WIRE_JSON | Buf FILE | EasyP Current | -|------------|----------|---------------|----------|---------------| -| **Element Deletions** | -| Service deletion | ❌ | ❌ | ✅ | ✅ | -| RPC method deletion | ❌ | ❌ | ✅ | ✅ | -| Message deletion | ❌ | ❌ | ✅ | ✅ | -| Field deletion (by number) | ✅ | ✅ | ✅ | ✅ | -| Enum deletion | ❌ | ❌ | ✅ | ✅ | -| Enum value deletion | ✅ | ✅ | ✅ | ✅ | -| OneOf deletion | ❌ | ❌ | ✅ | ✅ | -| Import deletion | ❌ | ❌ | ✅ | ✅ | -| **Type Changes** | -| Field type change | ✅ | ✅ | ✅ | ✅ | -| RPC request/response type | ✅ | ✅ | ✅ | ✅ | -| Optional/required changes | ✅ | ✅ | ✅ | ✅ | -| **Naming (Generated Code)** | -| Field rename (same number) | ❌ | ✅ | ✅ | ❌ | -| Enum value rename | ❌ | ✅ | ✅ | ✅ | -| **File Structure** | -| Package change | ✅ | ✅ | ✅ | ❌ | -| File options (go_package, etc) | ❌ | ❌ | ✅ | ❌ | -| Moving types between files | ❌ | ❌ | ✅ | ❌ | - -### What This Means - -**✅ EasyP WILL detect:** -- All wire format breaking changes -- Deletion of services, methods, messages, fields -- Type changes that break serialization -- Enum value renames (same number, different name) - -**❌ EasyP will NOT detect:** -- Field renames (same number, different name) -- Package name changes -- File option changes (go_package, java_package, etc.) -- Moving types between files in the same package - -## Breaking Change Rules - -EasyP detects the following types of breaking changes: - -### Comparison with Other Tools - -| Detection Level | Description | EasyP Support | -|----------------|-------------|---------------| -| **WIRE** | Wire format compatibility only | ✅ **Full support** | -| **WIRE+** | Wire + element deletion detection | ✅ **Current level** | -| **FILE** | Generated code compatibility | ❌ Partial (planned) | -## Breaking Change Rules - -EasyP detects the following categories of breaking changes. Each rule has detailed documentation with examples: - -### 🚨 Service and RPC Changes - -| Rule | Description | Status | -|------|-------------|---------| -| [SERVICE_NO_DELETE](./rules/service-no-delete.md) | Services cannot be deleted | ✅ Implemented | -| [RPC_NO_DELETE](./rules/rpc-no-delete.md) | RPC methods cannot be deleted | ✅ Implemented | -| [RPC_SAME_REQUEST_TYPE](./rules/rpc-same-request-type.md) | RPC request types cannot be changed | ✅ Implemented | -| [RPC_SAME_RESPONSE_TYPE](./rules/rpc-same-response-type.md) | RPC response types cannot be changed | ✅ Implemented | - -### 📦 Message and Field Changes - -| Rule | Description | Status | -|------|-------------|---------| -| [MESSAGE_NO_DELETE](./rules/message-no-delete.md) | Messages cannot be deleted | ✅ Implemented | -| [FIELD_NO_DELETE](./rules/field-no-delete.md) | Fields cannot be deleted | ✅ Implemented | -| [FIELD_SAME_TYPE](./rules/field-same-type.md) | Field types cannot be changed | ✅ Implemented | -| [FIELD_SAME_CARDINALITY](./rules/field-same-cardinality.md) | Field optionality (optional/required) cannot be changed | ✅ Implemented | - -### 🔢 Enum Changes - -| Rule | Description | Status | -|------|-------------|---------| -| [ENUM_NO_DELETE](./rules/enum-no-delete.md) | Enums cannot be deleted | ✅ Implemented | -| [ENUM_VALUE_NO_DELETE](./rules/enum-value-no-delete.md) | Enum values cannot be deleted | ✅ Implemented | -| [ENUM_VALUE_SAME_NAME](./rules/enum-value-same-name.md) | Enum value names cannot be changed | ✅ Implemented | - -### 🔗 OneOf Changes - -| Rule | Description | Status | -|------|-------------|---------| -| [ONEOF_NO_DELETE](./rules/oneof-no-delete.md) | OneOf fields cannot be deleted | ✅ Implemented | -| [ONEOF_FIELD_NO_DELETE](./rules/oneof-field-no-delete.md) | Fields within oneofs cannot be deleted | ✅ Implemented | -| [ONEOF_FIELD_SAME_TYPE](./rules/oneof-field-same-type.md) | OneOf field types cannot be changed | ✅ Implemented | - -### 📥 Import Changes - -| Rule | Description | Status | -|------|-------------|---------| -| [IMPORT_NO_DELETE](./rules/import-no-delete.md) | Import statements cannot be removed | ✅ Implemented | - -## Not Currently Detected - -The following changes are **NOT detected** by EasyP (but may break generated code): - -| Change Type | Example | Impact | -|-------------|---------|---------| -| Field renaming | `string name = 1` → `string full_name = 1` | Generated code breaks | -| Package changes | `package v1` → `package v2` | Import paths change | -| File options | `option go_package = "old"` → `option go_package = "new"` | Generated code location | -| Moving between files | Message moved to different .proto file | Import dependencies | - -## Detailed Rules Documentation - -For comprehensive examples and migration strategies, see the individual rule documentation: - -- **Service Changes**: [SERVICE_NO_DELETE](./rules/service-no-delete.md), [RPC_NO_DELETE](./rules/rpc-no-delete.md), [RPC_SAME_REQUEST_TYPE](./rules/rpc-same-request-type.md), [RPC_SAME_RESPONSE_TYPE](./rules/rpc-same-response-type.md) -- **Message Changes**: [MESSAGE_NO_DELETE](./rules/message-no-delete.md), [FIELD_NO_DELETE](./rules/field-no-delete.md), [FIELD_SAME_TYPE](./rules/field-same-type.md), [FIELD_SAME_CARDINALITY](./rules/field-same-cardinality.md) -- **Enum Changes**: [ENUM_NO_DELETE](./rules/enum-no-delete.md), [ENUM_VALUE_NO_DELETE](./rules/enum-value-no-delete.md), [ENUM_VALUE_SAME_NAME](./rules/enum-value-same-name.md) -- **OneOf Changes**: [ONEOF_NO_DELETE](./rules/oneof-no-delete.md), [ONEOF_FIELD_NO_DELETE](./rules/oneof-field-no-delete.md), [ONEOF_FIELD_SAME_TYPE](./rules/oneof-field-same-type.md) -- **Import Changes**: [IMPORT_NO_DELETE](./rules/import-no-delete.md) - -Each rule includes: -- ❌ **Bad examples** with actual breaking changes -- ✅ **Good alternatives** showing safe approaches -- 🔧 **Migration strategies** for handling necessary changes -- 📋 **Real error messages** from EasyP - -## Quick Examples - -### ✅ Safe Changes (Always Allowed) -```proto -// Adding new elements is always safe -message User { - string name = 1; - string email = 2; - string phone = 3; // ✅ New field - safe -} - -service UserService { - rpc GetUser(GetUserRequest) returns (GetUserResponse); - rpc GetUserProfile(GetUserRequest) returns (UserProfile); // ✅ New RPC - safe -} - -enum Status { - STATUS_UNSPECIFIED = 0; - STATUS_ACTIVE = 1; - STATUS_PENDING = 2; // ✅ New enum value - safe -} -``` - -### ❌ Breaking Changes (Always Detected) -```proto -// Deletions and type changes break compatibility -message User { - string name = 1; - // ❌ Deleted field - BREAKING -} - -service UserService { - // ❌ Deleted RPC method - BREAKING - rpc GetUser(GetUserRequestV2) returns (GetUserResponse); // ❌ Changed request type - BREAKING -} +easyp breaking --path proto --against main +easyp --format json breaking --path proto ``` -### Scenario 3: Breaking Changes (Currently Not Detected) - -```proto -// 🟡 Breaks generated code but passes EasyP checks -message User { - string user_name = 1; // Renamed from "name" - string user_email = 2; // Renamed from "email" -} - -service UserService { - rpc GetUserProfile(GetUserRequest) returns (GetUserResponse); // Renamed from GetUser -} -``` +`breaking.baseline` selects the Git ref. If it is absent, `--against` supplies the ref (default `master`). `--path` selects a directory relative to the scan root; `--root` changes that root from the policy file's directory. `breaking.ignore` excludes directories from the check. -## Output Format - -### Text Format (Default) - -``` -services.proto:45:1: Previously present RPC "DeleteUser" on service "UserService" was deleted. (BREAKING_CHECK) -messages.proto:15:3: Previously present field "2" with name "email" on message "User" was deleted. (BREAKING_CHECK) -``` - -### JSON Format - -```bash -easyp --format json breaking --against main -``` - -```json -{ - "path": "services.proto", - "position": { - "line": 45, - "column": 1 - }, - "source_name": "", - "message": "Previously present RPC \"DeleteUser\" on service \"UserService\" was deleted.", - "rule_name": "BREAKING_CHECK" -} -``` - -## Best Practices - -### 1. Regular Checks -Run breaking change detection in your CI/CD pipeline: - -```yaml -# GitHub Actions example -- name: Check for breaking changes - run: easyp breaking --against origin/main -``` - -### 2. Branch Protection -Use breaking change checks to protect important branches: - -```yaml -# Only allow PRs that don't introduce breaking changes -if: github.event_name == 'pull_request' -run: | - easyp breaking --against origin/main - if [ $? -eq 1 ]; then - echo "Breaking changes detected!" - exit 1 - fi -``` - -### 3. Versioning Strategy -When breaking changes are necessary: - -- Create a new package version (e.g., `myservice.v2`) -- Maintain the old version during migration period -- Use deprecation notices in the old version - -### 4. Ignore Patterns -Use ignore patterns wisely: - -```yaml -breaking: - ignore: - - "experimental/**" # Experimental APIs - - "internal/**" # Internal-only APIs - - "**/testing/**" # Test utilities -``` - -## Common Issues and Solutions - -### Issue: "Repository does not exist" -**Solution**: Ensure you're running the command in a Git repository with the specified branch available. - -### Issue: "Cannot find git ref" -**Solution**: Verify the branch/tag name exists and is accessible: -```bash -git branch -a # List all branches -git tag # List all tags -``` - -### Issue: False Positives in Generated Code -**Solution**: Add generated directories to ignore list: -```yaml -breaking: - ignore: - - "generated/**" - - "**/pb/**" -``` - -### Issue: Large Number of Changes -**Solution**: For major refactoring, consider: -1. Creating a new API version -2. Implementing changes incrementally -3. Using feature flags for gradual rollout - -## Integration Examples - -### CI/CD Pipeline Integration - -#### GitHub Actions - -```yaml -name: API Compatibility Check - -on: - pull_request: - branches: [ main ] - -jobs: - breaking-changes: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 # Fetch full history - - - name: Install EasyP - run: | - curl -sSfL https://raw.githubusercontent.com/easyp-tech/easyp/main/install.sh | sh - - - name: Check for breaking changes - run: | - ./bin/easyp breaking --against origin/main -``` - -#### GitLab CI - -```yaml -breaking-changes: - stage: test - image: easyp/lint:latest - script: - - git fetch origin main - - easyp breaking --against origin/main - rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" -``` - -### Pre-commit Hook - -```bash -#!/bin/sh -# .git/hooks/pre-push - -protected_branch='main' -current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,') - -if [ $current_branch = $protected_branch ]; then - echo "Running breaking changes check..." - easyp breaking --against HEAD~1 - if [ $? -eq 1 ]; then - echo "❌ Breaking changes detected. Push rejected." - exit 1 - fi - echo "✅ No breaking changes detected." -fi -``` - -## Troubleshooting - -### Debug Mode -Enable debug logging for detailed information: - -```bash -easyp --debug breaking --against main -``` - -### Manual Comparison -For complex cases, you can manually inspect the comparison: - -```bash -# Compare specific files -git show main:path/to/file.proto > old_version.proto -easyp lint old_version.proto # Validate old version -easyp lint current_file.proto # Validate current version -``` - -### Performance Optimization -For large repositories: - -```bash -# Limit scope to specific paths -easyp breaking --against main --path api/ -``` +The v1 pilot keeps the existing breaking check set. `breaking.categories`, `breaking.ignore_unstable`, and `breaking.extends` are not implemented and return an error instead of silently changing behavior. The old `breaking_check.against_git_ref` key is not accepted by the v1 CLI. -The breaking changes detection in EasyP provides a robust foundation for maintaining API compatibility while allowing your protobuf schemas to evolve safely over time. +See the [`easyp.yaml` reference](/docs/reference/easyp-yaml) for the policy format. For imports, the checker uses the module and dependency roots resolved for the scan root; a policy can also run without a module manifest. diff --git a/content/docs/cli/breaking-changes/index.ru.mdx b/content/docs/cli/breaking-changes/index.ru.mdx index 915e8b7..c42fea4 100644 --- a/content/docs/cli/breaking-changes/index.ru.mdx +++ b/content/docs/cli/breaking-changes/index.ru.mdx @@ -1,441 +1,25 @@ --- -title: "Обнаружение несовместимых изменений (Breaking Changes Detection)" +title: "Проверка несовместимых изменений" +description: "Сравнение protobuf-схем с Git-ссылкой в EasyP v1." --- -[[toc]] +`easyp breaking` сравнивает текущие `.proto` с Git-ссылкой и выводит несовместимые изменения, обнаруженные существующим механизмом проверки. -Механизм EasyP для обнаружения несовместимых (breaking) изменений помогает поддерживать обратную совместимость ваших protobuf API, автоматически выявляя изменения, способные сломать существующих клиентов. Это критично для стабильных API в продакшене. - -## Обзор - -Проверка несовместимых изменений сравнивает текущий набор protobuf‑файлов с предыдущей версией (обычно из другой Git ветки) и фиксирует модификации, которые могут вызвать проблемы совместимости для уже работающих клиентов. - -### Ключевые возможности - -- **Сравнение через Git**: Сопоставление с любой Git‑ссылкой (ветка, тег, commit) -- **Комплексный анализ**: Проверка сервисов, сообщений, enum'ов, полей и import'ов -- **Выборочное игнорирование**: Пропуск указанных директорий из анализа -- **Детализированные отчёты**: Понятные ошибки с именами файлов, строками и позициями - -## Как работает - -Детектор breaking changes выполняет следующие шаги: - -1. **Получение ветки сравнения**: Забирает proto-файлы из указанной Git‑ссылки -2. **Парсинг обеих версий**: Анализирует структуру текущих и предыдущих файлов -3. **Сравнение сущностей**: Последовательно проверяет все элементы protobuf на breaking изменения -4. **Формирование отчёта**: Генерирует подробные записи об ошибках с локациями и описаниями - -## Уровень проверки - -EasyP реализует уровень проверки **WIRE+**: -- ✅ **Полная совместимость по wire‑формату** — старые и новые версии могут обмениваться данными -- ✅ **Обнаружение удалений элементов** — сервисы, сообщения, поля и т.п. -- ✅ **Безопасность типов** — выявляет несовместимые изменения типов -- ❌ **Переименования полей/методов** — пока не детектируются (в планах) -- ❌ **Изменения на уровне файлов** — переносы пакетов, file options ещё не проверяются - -Это даёт сильные гарантии совместимости и меньше ограничений, чем инструменты, требующие совместимости сгенерированного кода. - -## Конфигурация - -Настройка в `easyp.yaml`: - -```yaml -breaking: - # Git reference для сравнения (branch, tag или commit hash) - against_git_ref: "main" - - # Директории, игнорируемые в анализе breaking changes - ignore: - - "experimental" - - "internal/proto" - - "vendor" -``` - -### Параметры конфигурации - -| Option | Description | Default | Required | -|--------|-------------|---------|----------| -| `against_git_ref` | Git‑ссылка для сравнения | `"master"` | No | -| `ignore` | Список директорий для исключения из анализа | `[]` | No | - -## Использование - -### Базовый пример - -Сравнение текущих изменений с веткой main: - -```bash -easyp breaking --against main -``` - -### Использование файла конфигурации - -```bash -easyp --cfg my-config.yaml breaking -``` - -### Переопределение Git‑ссылки - -```bash -easyp breaking --against feature/new-api -``` - -## Уровень проверки - -EasyP сейчас работает на уровне **WIRE+**, обеспечивая совместимость wire‑формата плюс защиту от удалений и изменения критичных типов. - -### Сравнение с категориями Buf - -| Check Type | Buf WIRE | Buf WIRE_JSON | Buf FILE | EasyP Current | -|------------|----------|---------------|----------|---------------| -| **Element Deletions** | -| Service deletion | ❌ | ❌ | ✅ | ✅ | -| RPC method deletion | ❌ | ❌ | ✅ | ✅ | -| Message deletion | ❌ | ❌ | ✅ | ✅ | -| Field deletion (by number) | ✅ | ✅ | ✅ | ✅ | -| Enum deletion | ❌ | ❌ | ✅ | ✅ | -| Enum value deletion | ✅ | ✅ | ✅ | ✅ | -| OneOf deletion | ❌ | ❌ | ✅ | ✅ | -| Import deletion | ❌ | ❌ | ✅ | ✅ | -| **Type Changes** | -| Field type change | ✅ | ✅ | ✅ | ✅ | -| RPC request/response type | ✅ | ✅ | ✅ | ✅ | -| Optional/required changes | ✅ | ✅ | ✅ | ✅ | -| **Naming (Generated Code)** | -| Field rename (same number) | ❌ | ✅ | ✅ | ❌ | -| Enum value rename | ❌ | ✅ | ✅ | ✅ | -| **File Structure** | -| Package change | ✅ | ✅ | ✅ | ❌ | -| File options (go_package, etc) | ❌ | ❌ | ✅ | ❌ | -| Moving types between files | ❌ | ❌ | ✅ | ❌ | - -### Что это означает - -**✅ EasyP обнаружит:** -- Все breaking изменения wire‑формата -- Удаления сервисов, методов, сообщений, полей -- Изменения типов, ломающие сериализацию -- Переименования enum‑значений (при сохранении номера) - -**❌ EasyP НЕ обнаружит:** -- Переименование полей (с тем же номером) -- Изменение package -- File options (go_package, java_package, и т.п.) -- Перемещение типов между файлами в одном package - -## Правила Breaking Changes - -EasyP обнаруживает следующие типы breaking изменений: - -### Сравнение уровней - -| Detection Level | Description | EasyP Support | -|----------------|-------------|---------------| -| **WIRE** | Совместимость только по wire‑формату | ✅ **Full support** | -| **WIRE+** | Wire + обнаружение удалений | ✅ **Current level** | -| **FILE** | Совместимость сгенерированного кода | ❌ Partial (planned) | - -## Категории правил - -Каждая категория имеет свою документацию с примерами: - -### 🚨 Изменения Service и RPC - -| Rule | Description | Status | -|------|-------------|---------| -| [SERVICE_NO_DELETE](./rules/service-no-delete.md) | Services cannot be deleted | ✅ Implemented | -| [RPC_NO_DELETE](./rules/rpc-no-delete.md) | RPC methods cannot be deleted | ✅ Implemented | -| [RPC_SAME_REQUEST_TYPE](./rules/rpc-same-request-type.md) | RPC request types cannot be changed | ✅ Implemented | -| [RPC_SAME_RESPONSE_TYPE](./rules/rpc-same-response-type.md) | RPC response types cannot be changed | ✅ Implemented | - -### 📦 Изменения Message и Field - -| Rule | Description | Status | -|------|-------------|---------| -| [MESSAGE_NO_DELETE](./rules/message-no-delete.md) | Messages cannot be deleted | ✅ Implemented | -| [FIELD_NO_DELETE](./rules/field-no-delete.md) | Fields cannot be deleted | ✅ Implemented | -| [FIELD_SAME_TYPE](./rules/field-same-type.md) | Field types cannot be changed | ✅ Implemented | -| [FIELD_SAME_CARDINALITY](./rules/field-same-cardinality.md) | Field optionality (optional/required) cannot be changed | ✅ Implemented | - -### 🔢 Изменения Enum - -| Rule | Description | Status | -|------|-------------|---------| -| [ENUM_NO_DELETE](./rules/enum-no-delete.md) | Enums cannot be deleted | ✅ Implemented | -| [ENUM_VALUE_NO_DELETE](./rules/enum-value-no-delete.md) | Enum values cannot be deleted | ✅ Implemented | -| [ENUM_VALUE_SAME_NAME](./rules/enum-value-same-name.md) | Enum value names cannot be changed | ✅ Implemented | - -### 🔗 Изменения OneOf - -| Rule | Description | Status | -|------|-------------|---------| -| [ONEOF_NO_DELETE](./rules/oneof-no-delete.md) | OneOf fields cannot be deleted | ✅ Implemented | -| [ONEOF_FIELD_NO_DELETE](./rules/oneof-field-no-delete.md) | Fields within oneofs cannot be deleted | ✅ Implemented | -| [ONEOF_FIELD_SAME_TYPE](./rules/oneof-field-same-type.md) | OneOf field types cannot be changed | ✅ Implemented | - -### 📥 Изменения Import - -| Rule | Description | Status | -|------|-------------|---------| -| [IMPORT_NO_DELETE](./rules/import-no-delete.md) | Import statements cannot be removed | ✅ Implemented | - -## Не обнаруживается сейчас - -Изменения ниже **НЕ детектируются** EasyP (могут ломать сгенерированный код): - -| Change Type | Example | Impact | -|-------------|---------|--------| -| Field renaming | `string name = 1` → `string full_name = 1` | Ломает код | -| Package changes | `package v1` → `package v2` | Меняются пути импорта | -| File options | `option go_package = "old"` → `option go_package = "new"` | Меняется расположение кода | -| Moving between files | Message перемещено в другой .proto | Зависимости import'ов | - -## Документация правил - -См. подробные файлы правил для примеров и стратегий миграции: - -- Service: [SERVICE_NO_DELETE](./rules/service-no-delete.md), [RPC_NO_DELETE](./rules/rpc-no-delete.md), [RPC_SAME_REQUEST_TYPE](./rules/rpc-same-request-type.md), [RPC_SAME_RESPONSE_TYPE](./rules/rpc-same-response-type.md) -- Message: [MESSAGE_NO_DELETE](./rules/message-no-delete.md), [FIELD_NO_DELETE](./rules/field-no-delete.md), [FIELD_SAME_TYPE](./rules/field-same-type.md), [FIELD_SAME_CARDINALITY](./rules/field-same-cardinality.md) -- Enum: [ENUM_NO_DELETE](./rules/enum-no-delete.md), [ENUM_VALUE_NO_DELETE](./rules/enum-value-no-delete.md), [ENUM_VALUE_SAME_NAME](./rules/enum-value-same-name.md) -- OneOf: [ONEOF_NO_DELETE](./rules/oneof-no-delete.md), [ONEOF_FIELD_NO_DELETE](./rules/oneof-field-no-delete.md), [ONEOF_FIELD_SAME_TYPE](./rules/oneof-field-same-type.md) -- Import: [IMPORT_NO_DELETE](./rules/import-no-delete.md) - -Каждое правило содержит: -- ❌ Плохие примеры (breaking) -- ✅ Безопасные альтернативы -- 🔧 Стратегии миграции -- 📋 Реальные сообщения ошибок из EasyP - -## Быстрые примеры - -### ✅ Безопасные изменения (разрешены всегда) -```proto -// Добавление новых элементов — безопасно -message User { - string name = 1; - string email = 2; - string phone = 3; // ✅ Новое поле -} - -service UserService { - rpc GetUser(GetUserRequest) returns (GetUserResponse); - rpc GetUserProfile(GetUserRequest) returns (UserProfile); // ✅ Новый RPC -} - -enum Status { - STATUS_UNSPECIFIED = 0; - STATUS_ACTIVE = 1; - STATUS_PENDING = 2; // ✅ Новое enum значение -} -``` - -### ❌ Несовместимые изменения (обнаруживаются всегда) -```proto -// Удаления и смена типов ломают совместимость -message User { - string name = 1; - // ❌ Удалённое поле -} - -service UserService { - // ❌ Удалённый RPC метод - rpc GetUser(GetUserRequestV2) returns (GetUserResponse); // ❌ Изменён тип запроса -} -``` - -### Сценарий: Изменения пока не детектируются - -```proto -// 🟡 Ломает сгенерированный код, но проходит проверки EasyP -message User { - string user_name = 1; // Переименовано с "name" - string user_email = 2; // Переименовано с "email" -} - -service UserService { - rpc GetUserProfile(GetUserRequest) returns (GetUserResponse); // Переименовано с GetUser -} -``` - -## Формат вывода - -### Текстовый формат (по умолчанию) - -``` -services.proto:45:1: Previously present RPC "DeleteUser" on service "UserService" was deleted. (BREAKING_CHECK) -messages.proto:15:3: Previously present field "2" with name "email" on message "User" was deleted. (BREAKING_CHECK) -``` - -### JSON формат - -```bash -easyp --format json breaking --against main -``` - -```json -{ - "path": "services.proto", - "position": { - "line": 45, - "column": 1 - }, - "source_name": "", - "message": "Previously present RPC \"DeleteUser\" on service \"UserService\" was deleted.", - "rule_name": "BREAKING_CHECK" -} -``` - -## Best Practices - -### 1. Регулярный запуск -Добавьте проверку несовместимых изменений в CI/CD: - -```yaml -- name: Check for breaking changes - run: easyp breaking --against origin/main -``` - -### 2. Защита веток -Блокируйте слияния с breaking изменениями: - -```yaml -if: github.event_name == 'pull_request' -run: | - easyp breaking --against origin/main - if [ $? -eq 1 ]; then - echo "Breaking changes detected!" - exit 1 - fi -``` - -### 3. Стратегия версионирования -При необходимости breaking изменений: -- Создайте новую версию пакета (`myservice.v2`) -- Поддерживайте старую версию в период миграции -- Добавляйте уведомления о деприкации - -### 4. Игнорирование путей -Используйте ignore осознанно: - -```yaml -breaking: - ignore: - - "experimental/**" - - "internal/**" - - "**/testing/**" -``` - -## Частые проблемы - -### Проблема: "Repository does not exist" -Решение: Выполняйте команду внутри Git репозитория с нужной веткой. - -### Проблема: "Cannot find git ref" -Решение: Проверьте наличие ссылки: -```bash -git branch -a -git tag -``` - -### Проблема: Ложные срабатывания на сгенерированный код -Решение: Исключите директории генерации: ```yaml +# easyp.yaml +version: v1 breaking: - ignore: - - "generated/**" - - "**/pb/**" + baseline: git:main + ignore: [experimental] ``` -### Проблема: Очень много изменений -Решение: -1. Создайте новую версию API -2. Вносите изменения постепенно -3. Используйте feature flags - -## Примеры интеграции - -### GitHub Actions - -```yaml -name: API Compatibility Check - -on: - pull_request: - branches: [ main ] - -jobs: - breaking-changes: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Install EasyP - run: | - curl -sSfL https://raw.githubusercontent.com/easyp-tech/easyp/main/install.sh | sh - - name: Check for breaking changes - run: | - ./bin/easyp breaking --against origin/main -``` - -### GitLab CI - -```yaml -breaking-changes: - stage: test - image: easyp/lint:latest - script: - - git fetch origin main - - easyp breaking --against origin/main - rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" -``` - -### Pre-commit / pre-push hook - -```bash -#!/bin/sh -# .git/hooks/pre-push - -protected_branch='main' -current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,') - -if [ $current_branch = $protected_branch ]; then - echo "Running breaking changes check..." - easyp breaking --against HEAD~1 - if [ $? -eq 1 ]; then - echo "❌ Breaking changes detected. Push rejected." - exit 1 - fi - echo "✅ No breaking changes detected." -fi -``` - -## Troubleshooting - -### Режим отладки -Включите debug‑логирование: - -```bash -easyp --debug breaking --against main -``` - -### Ручное сравнение -Для сложных случаев: - ```bash -git show main:path/to/file.proto > old_version.proto -easyp lint old_version.proto -easyp lint current_file.proto +easyp breaking --path proto --against main +easyp --format json breaking --path proto ``` -### Оптимизация производительности -Ограничьте область: +`breaking.baseline` выбирает Git-ссылку. Если поле не задано, используется `--against` (по умолчанию `master`). `--path` указывает каталог относительно корня проверки; `--root` меняет этот корень с каталога файла политики. `breaking.ignore` исключает каталоги из проверки. -```bash -easyp breaking --against main --path api/ -``` +Пилотная версия v1 сохраняет существующий набор breaking-проверок. `breaking.categories`, `breaking.ignore_unstable` и `breaking.extends` не реализованы и возвращают ошибку, чтобы не менять поведение незаметно. Старый ключ `breaking_check.against_git_ref` CLI v1 не принимает. -Механизм обнаружения несовместимых изменений в EasyP обеспечивает надёжную основу для безопасной эволюции protobuf‑схем при сохранении совместимости API. +Формат политики описан в [справочнике `easyp.yaml`](/ru/docs/reference/easyp-yaml). Для импортов проверка использует корни модуля и зависимостей, найденные для корня проверки. Политика может работать и без манифеста модуля. diff --git a/content/docs/cli/generator/examples/go.mdx b/content/docs/cli/generator/examples/go.mdx index 62bf134..1a57d5f 100644 --- a/content/docs/cli/generator/examples/go.mdx +++ b/content/docs/cli/generator/examples/go.mdx @@ -1,147 +1,32 @@ --- -title: "Go" +title: "Generate Go code" +description: "A minimal EasyP v1 generator using local Go plugins." --- -## Installing Plugins +Declare the source root in `protobuf.mod`: -First, install the necessary plugins for working with gRPC: - -```shell -go install google.golang.org/protobuf/cmd/protoc-gen-go@latest -go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest +```text +module github.com/acme/contracts +roots proto ``` -These commands will install the `protoc-gen-go` and `protoc-gen-go-grpc` plugins for use with EasyP. - -## Example Proto Service - -Here is an example proto file for an Echo service: - -```proto -syntax = "proto3"; - -package api.echo.v1; - -option go_package = "github.com/easyp-tech/example/api/echo/v1;pb"; - -service EchoAPI { - rpc Echo(EchoRequest) returns (EchoResponse); - rpc EchoStream(EchoStreamRequest) returns (EchoResponse); -} - -message EchoRequest { - string payload = 1; -} - -message EchoResponse { - string payload = 2; -} - -message EchoStreamRequest { - string payload = 1; -} - -message EchoStreamResponse { - string payload = 2; -} +Select that module and the plugins in `easyp.gen.yaml`: + +```yaml +version: v1 +generate: + modules: [github.com/acme/contracts] +plugins: + - name: go + out: ./gen/go + opts: + paths: source_relative + - name: go-grpc + out: ./gen/go + opts: + paths: source_relative ``` -## Configuration Setup - -Compare generator configurations across formats: - - - - ```yaml - version: v1 - generate: - plugins: - - name: go - out: ./gen/go - opts: - paths: source_relative - - name: go-grpc - out: ./gen/go - opts: - paths: source_relative - require_unimplemented_servers: false - ``` - - - ```yaml - version: v2 - plugins: - - remote: buf.build/protocolbuffers/go - out: gen/go - opt: paths=source_relative - - remote: buf.build/grpc/go - out: gen/go - opt: - - paths=source_relative - - require_unimplemented_servers=false - ``` - - - -## Target Language Comparisons - - - - ```yaml - generate: - plugins: - - name: go - out: ./gen/go - opts: - paths: source_relative - - name: go-grpc - out: ./gen/go - opts: - paths: source_relative - ``` - - - ```yaml - generate: - plugins: - - name: ts - out: ./gen/ts - opts: - target: es2017 - - name: grpc-web - out: ./gen/ts - opts: - import_style: typescript - mode: grpcweb - ``` - - - ```yaml - generate: - plugins: - - name: python - out: ./gen/python - - name: grpc_python - out: ./gen/python - ``` - - - -## Generating Code - -To generate code, execute the EasyP generator command: - - - - ```shell - easyp generate - ``` - - - ```shell - easyp --cfg easyp.yaml generate - ``` - - +Place `protoc-gen-go` and `protoc-gen-go-grpc` on `PATH`, then run `easyp generate`. A `go_package` option in each source file, or a managed `options.go.package_prefix`, supplies the Go import path. See the [managed options reference](/docs/reference/easyp-gen-yaml). -Now you have generated code stubs ready for integration! +The `go` and `go-grpc` names identify plugins; the v1 generator has no `generate.inputs` or `--path` option. Its inputs come from the selected module's roots. diff --git a/content/docs/cli/generator/examples/go.ru.mdx b/content/docs/cli/generator/examples/go.ru.mdx index ab420b1..b9a73bc 100644 --- a/content/docs/cli/generator/examples/go.ru.mdx +++ b/content/docs/cli/generator/examples/go.ru.mdx @@ -1,147 +1,32 @@ --- -title: "Go" +title: "Генерация Go-кода" +description: "Минимальная конфигурация EasyP v1 с локальными Go-плагинами." --- -## Установка плагинов +Объявите корень исходников в `protobuf.mod`: -Сначала установите необходимые плагины для работы с gRPC: - -```shell -go install google.golang.org/protobuf/cmd/protoc-gen-go@latest -go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest +```text +module github.com/acme/contracts +roots proto ``` -Эти команды установят плагины `protoc-gen-go` и `protoc-gen-go-grpc` для использования с EasyP. - -## Пример proto‑сервиса - -Ниже пример proto-файла для сервиса Echo: - -```proto -syntax = "proto3"; - -package api.echo.v1; - -option go_package = "github.com/easyp-tech/example/api/echo/v1;pb"; - -service EchoAPI { - rpc Echo(EchoRequest) returns (EchoResponse); - rpc EchoStream(EchoStreamRequest) returns (EchoResponse); -} - -message EchoRequest { - string payload = 1; -} - -message EchoResponse { - string payload = 2; -} - -message EchoStreamRequest { - string payload = 1; -} - -message EchoStreamResponse { - string payload = 2; -} +Выберите модуль и плагины в `easyp.gen.yaml`: + +```yaml +version: v1 +generate: + modules: [github.com/acme/contracts] +plugins: + - name: go + out: ./gen/go + opts: + paths: source_relative + - name: go-grpc + out: ./gen/go + opts: + paths: source_relative ``` -## Настройка конфигурации - -Сравнение форматов конфигурации генератора: - - - - ```yaml - version: v1 - generate: - plugins: - - name: go - out: ./gen/go - opts: - paths: source_relative - - name: go-grpc - out: ./gen/go - opts: - paths: source_relative - require_unimplemented_servers: false - ``` - - - ```yaml - version: v2 - plugins: - - remote: buf.build/protocolbuffers/go - out: gen/go - opt: paths=source_relative - - remote: buf.build/grpc/go - out: gen/go - opt: - - paths=source_relative - - require_unimplemented_servers=false - ``` - - - -## Сравнение языковых таргетов - - - - ```yaml - generate: - plugins: - - name: go - out: ./gen/go - opts: - paths: source_relative - - name: go-grpc - out: ./gen/go - opts: - paths: source_relative - ``` - - - ```yaml - generate: - plugins: - - name: ts - out: ./gen/ts - opts: - target: es2017 - - name: grpc-web - out: ./gen/ts - opts: - import_style: typescript - mode: grpcweb - ``` - - - ```yaml - generate: - plugins: - - name: python - out: ./gen/python - - name: grpc_python - out: ./gen/python - ``` - - - -## Генерация кода - -Для генерации кода выполните команду EasyP: - - - - ```shell - easyp generate - ``` - - - ```shell - easyp --cfg easyp.yaml generate - ``` - - +Добавьте `protoc-gen-go` и `protoc-gen-go-grpc` в `PATH`, затем выполните `easyp generate`. Go import path задаётся опцией `go_package` в `.proto` или managed-опцией `options.go.package_prefix`. Подробности — в [справочнике managed mode](/ru/docs/reference/easyp-gen-yaml). -Теперь у вас есть сгенерированный Go‑код, готовый к интеграции! +Имена `go` и `go-grpc` обозначают плагины. У генератора v1 нет `generate.inputs` или флага `--path`: исходники берутся из корней выбранного модуля. diff --git a/content/docs/cli/generator/examples/grpc-gateway.mdx b/content/docs/cli/generator/examples/grpc-gateway.mdx index dbc5a3c..2512129 100644 --- a/content/docs/cli/generator/examples/grpc-gateway.mdx +++ b/content/docs/cli/generator/examples/grpc-gateway.mdx @@ -1,148 +1,29 @@ --- -title: "gRPC-Gateway" +title: "Generate gRPC-Gateway code" +description: "Run the gRPC-Gateway plugin from an EasyP v1 generator file." --- -## Installing Plugins - -In addition to the plugins for working with gRPC, install the following plugins for gRPC-Gateway: - -```bash -go install google.golang.org/protobuf/cmd/protoc-gen-go@latest -go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest -go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest -go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest -``` - -## Example Proto Service - -To use gRPC-Gateway, update your proto file to include HTTP annotations: - -```proto -syntax = "proto3"; -import "google/api/annotations.proto"; - -package api.echo.v1; - -option go_package = "github.com/easyp-tech/example/api/echo/v1;pb"; - -service EchoAPI { - rpc Echo(EchoRequest) returns (EchoResponse) { - option (google.api.http) = { - post: "/api/v1/echo" - body: "*" - }; - } -} - -message EchoRequest { - string payload = 1; -} - -message EchoResponse { - string payload = 2; -} +For a module whose source files use gRPC-Gateway annotations, list the module and plugins in `easyp.gen.yaml`: + +```yaml +version: v1 +generate: + modules: [github.com/acme/contracts] +plugins: + - name: go + out: ./gen/go + opts: + paths: source_relative + - name: go-grpc + out: ./gen/go + opts: + paths: source_relative + - name: grpc-gateway + out: ./gen/go + opts: + paths: source_relative ``` -## Configuration Setup - -Compare generator configurations across formats and target languages: - - - - ```yaml - deps: - - github.com/googleapis/googleapis - - generate: - plugins: - - name: go - out: ./gen/go - opts: - paths: source_relative - - name: go-grpc - out: ./gen/go - opts: - paths: source_relative - require_unimplemented_servers: false - - name: grpc-gateway - out: ./gen/go - opts: - paths: source_relative - - name: openapiv2 - out: ./gen/openapi - opts: - simple_operation_ids: false - ``` - - - ```yaml - version: v2 - plugins: - - remote: buf.build/protocolbuffers/go - out: gen/go - opt: paths=source_relative - - remote: buf.build/grpc/go - out: gen/go - opt: paths=source_relative - - remote: buf.build/grpc-ecosystem/gateway - out: gen/go - opt: paths=source_relative - - remote: buf.build/grpc-ecosystem/openapiv2 - out: gen/openapi - ``` - - - - - - ```yaml - generate: - plugins: - - name: grpc-gateway - out: ./gen/go - opts: - paths: source_relative - - name: openapiv2 - out: ./gen/openapi - ``` - - - ```yaml - generate: - plugins: - - name: ts - out: ./gen/ts - opts: - target: es2017 - - name: grpc-web - out: ./gen/ts - opts: - import_style: typescript - ``` - - - ```yaml - generate: - plugins: - - name: python - out: ./gen/python - - name: grpc_python - out: ./gen/python - ``` - - - -## Generating Code +Install the corresponding `protoc-gen-*` executables on `PATH`. Declare the Git module that provides `google/api/annotations.proto` in the consumer's `protobuf.mod`, then run `easyp mod tidy` and `easyp generate`. The generator obtains that import from the locked dependency roots. - - - ```bash - easyp generate - ``` - - - ```bash - easyp --cfg easyp.yaml generate - ``` - - +The plugin name is local to generation; schema dependency versions belong in `protobuf.mod`, never in `easyp.gen.yaml`. See [adding a dependency](/docs/guides/adding-dependency). diff --git a/content/docs/cli/generator/examples/grpc-gateway.ru.mdx b/content/docs/cli/generator/examples/grpc-gateway.ru.mdx index 692ae23..674ab33 100644 --- a/content/docs/cli/generator/examples/grpc-gateway.ru.mdx +++ b/content/docs/cli/generator/examples/grpc-gateway.ru.mdx @@ -1,148 +1,29 @@ --- -title: "gRPC-Gateway" +title: "Генерация gRPC-Gateway" +description: "Запуск плагина gRPC-Gateway через конфиг EasyP v1." --- -## Установка плагинов - -В дополнение к плагинам для работы с gRPC, установите следующие плагины для gRPC-Gateway: - -```bash -go install google.golang.org/protobuf/cmd/protoc-gen-go@latest -go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest -go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest -go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest -``` - -## Пример Proto сервиса - -Чтобы использовать gRPC-Gateway, обновите proto‑файл, добавив HTTP‑опции: - -```protobuf -syntax = "proto3"; -import "google/api/annotations.proto"; - -package api.echo.v1; - -option go_package = "github.com/easyp-tech/example/api/echo/v1;pb"; - -service EchoAPI { - rpc Echo(EchoRequest) returns (EchoResponse) { - option (google.api.http) = { - post: "/api/v1/echo" - body: "*" - }; - } -} - -message EchoRequest { - string payload = 1; -} - -message EchoResponse { - string payload = 2; -} +Если `.proto` модуля используют аннотации gRPC-Gateway, перечислите модуль и плагины в `easyp.gen.yaml`: + +```yaml +version: v1 +generate: + modules: [github.com/acme/contracts] +plugins: + - name: go + out: ./gen/go + opts: + paths: source_relative + - name: go-grpc + out: ./gen/go + opts: + paths: source_relative + - name: grpc-gateway + out: ./gen/go + opts: + paths: source_relative ``` -## Настройка конфигурации - -Сравнение форматов конфигурации генератора для gRPC-Gateway: - - - - ```yaml - deps: - - github.com/googleapis/googleapis - - generate: - plugins: - - name: go - out: ./gen/go - opts: - paths: source_relative - - name: go-grpc - out: ./gen/go - opts: - paths: source_relative - require_unimplemented_servers: false - - name: grpc-gateway - out: ./gen/go - opts: - paths: source_relative - - name: openapiv2 - out: ./gen/openapi - opts: - simple_operation_ids: false - ``` - - - ```yaml - version: v2 - plugins: - - remote: buf.build/protocolbuffers/go - out: gen/go - opt: paths=source_relative - - remote: buf.build/grpc/go - out: gen/go - opt: paths=source_relative - - remote: buf.build/grpc-ecosystem/gateway - out: gen/go - opt: paths=source_relative - - remote: buf.build/grpc-ecosystem/openapiv2 - out: gen/openapi - ``` - - - - - - ```yaml - generate: - plugins: - - name: grpc-gateway - out: ./gen/go - opts: - paths: source_relative - - name: openapiv2 - out: ./gen/openapi - ``` - - - ```yaml - generate: - plugins: - - name: ts - out: ./gen/ts - opts: - target: es2017 - - name: grpc-web - out: ./gen/ts - opts: - import_style: typescript - ``` - - - ```yaml - generate: - plugins: - - name: python - out: ./gen/python - - name: grpc_python - out: ./gen/python - ``` - - - -## Генерация кода +Добавьте соответствующие исполняемые файлы `protoc-gen-*` в `PATH`. В `protobuf.mod` потребителя объявите Git-модуль, содержащий `google/api/annotations.proto`, затем выполните `easyp mod tidy` и `easyp generate`. Импорт будет найден в корнях зафиксированной зависимости. - - - ```bash - easyp generate - ``` - - - ```bash - easyp --cfg easyp.yaml generate - ``` - - +Имя плагина относится только к генерации; версии зависимостей схем указываются в `protobuf.mod`, а не в `easyp.gen.yaml`. См. [добавление зависимости](/ru/docs/guides/adding-dependency). diff --git a/content/docs/cli/generator/examples/validate.mdx b/content/docs/cli/generator/examples/validate.mdx index 6078d8e..a6a8204 100644 --- a/content/docs/cli/generator/examples/validate.mdx +++ b/content/docs/cli/generator/examples/validate.mdx @@ -1,132 +1,30 @@ --- -title: "Validate" +title: "Generate validation code" +description: "Use a local validation plugin with EasyP v1." --- -## Installing Plugins - -First, install the necessary plugins for working with gRPC and validation: - -```shell -go install google.golang.org/protobuf/cmd/protoc-gen-go@latest -go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest -go install github.com/envoyproxy/protoc-gen-validate@latest +If your `.proto` files import validation annotations, add the Git module that provides those imports to `protobuf.mod`. The plugin runs through `easyp.gen.yaml`: + +```yaml +version: v1 +generate: + modules: [github.com/acme/contracts] +plugins: + - name: go + out: ./gen/go + opts: + paths: source_relative + - name: validate + out: ./gen/go + opts: + lang: go ``` -## Example Proto Service - -Here is an example proto file with validation annotations: - -```proto -syntax = "proto3"; - -package api.echo.v1; - -import "validate/validate.proto"; - -option go_package = "github.com/easyp-tech/example/api/echo/v1;pb"; - -service EchoAPI { - rpc Echo(EchoRequest) returns (EchoResponse); -} +Install `protoc-gen-go` and `protoc-gen-validate` on `PATH`, then run: -message EchoRequest { - string payload = 1 [(validate.rules).string = {max_len: 200}]; -} - -message EchoResponse { - string payload = 2; -} +```bash +easyp mod tidy +easyp generate ``` -## Configuration Setup - -Compare generator configurations across formats: - - - - ```yaml - deps: - - github.com/bufbuild/protoc-gen-validate - - generate: - plugins: - - name: go - out: ./gen/go - opts: - paths: source_relative - - name: go-grpc - out: ./gen/go - opts: - paths: source_relative - - name: validate - out: ./gen/go - opts: - paths: source_relative - lang: "go" - ``` - - - ```yaml - version: v2 - plugins: - - remote: buf.build/protocolbuffers/go - out: gen/go - opt: paths=source_relative - - remote: buf.build/grpc/go - out: gen/go - opt: paths=source_relative - - remote: buf.build/bufbuild/validate-go - out: gen/go - opt: paths=source_relative - ``` - - - - - - ```yaml - generate: - plugins: - - name: validate - out: ./gen/go - opts: - paths: source_relative - lang: "go" - ``` - - - ```yaml - generate: - plugins: - - name: validate-ts - out: ./gen/ts - opts: - lang: "ts" - ``` - - - ```yaml - generate: - plugins: - - name: validate-python - out: ./gen/python - opts: - lang: "python" - ``` - - - -## Generating Code - - - - ```shell - easyp generate - ``` - - - ```shell - easyp --cfg easyp.yaml generate - ``` - - +`easyp mod tidy` pins the schema dependency in `protobuf.lock`; the generator resolves its imports from that lock. The version of the local plugin is selected by the executable on `PATH`. diff --git a/content/docs/cli/generator/examples/validate.ru.mdx b/content/docs/cli/generator/examples/validate.ru.mdx index 37412be..1bbb837 100644 --- a/content/docs/cli/generator/examples/validate.ru.mdx +++ b/content/docs/cli/generator/examples/validate.ru.mdx @@ -1,132 +1,30 @@ --- -title: "Validate" +title: "Генерация кода валидации" +description: "Локальный плагин валидации в EasyP v1." --- -## Установка плагинов - -Сначала установите необходимые плагины для работы с gRPC и валидации: - -```shell -go install google.golang.org/protobuf/cmd/protoc-gen-go@latest -go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest -go install github.com/envoyproxy/protoc-gen-validate@latest +Если `.proto` импортируют аннотации валидации, добавьте Git-модуль с этими файлами в `protobuf.mod`. Плагин запускается через `easyp.gen.yaml`: + +```yaml +version: v1 +generate: + modules: [github.com/acme/contracts] +plugins: + - name: go + out: ./gen/go + opts: + paths: source_relative + - name: validate + out: ./gen/go + opts: + lang: go ``` -## Пример Proto сервиса - -Ниже пример proto‑файла с аннотациями валидации: - -```proto -syntax = "proto3"; - -package api.echo.v1; - -import "validate/validate.proto"; - -option go_package = "github.com/easyp-tech/example/api/echo/v1;pb"; - -service EchoAPI { - rpc Echo(EchoRequest) returns (EchoResponse); -} +Добавьте `protoc-gen-go` и `protoc-gen-validate` в `PATH`, затем выполните: -message EchoRequest { - string payload = 1 [(validate.rules).string = {max_len: 200}]; -} - -message EchoResponse { - string payload = 2; -} +```bash +easyp mod tidy +easyp generate ``` -## Настройка конфигурации - -Сравнение конфигураций генератора валидации: - - - - ```yaml - deps: - - github.com/bufbuild/protoc-gen-validate - - generate: - plugins: - - name: go - out: ./gen/go - opts: - paths: source_relative - - name: go-grpc - out: ./gen/go - opts: - paths: source_relative - - name: validate - out: ./gen/go - opts: - paths: source_relative - lang: "go" - ``` - - - ```yaml - version: v2 - plugins: - - remote: buf.build/protocolbuffers/go - out: gen/go - opt: paths=source_relative - - remote: buf.build/grpc/go - out: gen/go - opt: paths=source_relative - - remote: buf.build/bufbuild/validate-go - out: gen/go - opt: paths=source_relative - ``` - - - - - - ```yaml - generate: - plugins: - - name: validate - out: ./gen/go - opts: - paths: source_relative - lang: "go" - ``` - - - ```yaml - generate: - plugins: - - name: validate-ts - out: ./gen/ts - opts: - lang: "ts" - ``` - - - ```yaml - generate: - plugins: - - name: validate-python - out: ./gen/python - opts: - lang: "python" - ``` - - - -## Генерация кода - - - - ```shell - easyp generate - ``` - - - ```shell - easyp --cfg easyp.yaml generate - ``` - - +`easyp mod tidy` фиксирует зависимость схемы в `protobuf.lock`; генератор находит её импорты через lock. Версия локального плагина определяется исполняемым файлом в `PATH`. diff --git a/content/docs/cli/generator/index.mdx b/content/docs/cli/generator/index.mdx index 96ba850..2cecba3 100644 --- a/content/docs/cli/generator/index.mdx +++ b/content/docs/cli/generator/index.mdx @@ -1,136 +1,55 @@ --- title: "Generator" +description: "Generate code from complete protobuf modules with the EasyP v1 pilot." --- -EasyP includes a powerful generator that simplifies the process of generating code from proto files. By using YAML configurations, EasyP makes this process more user-friendly and intuitive compared to using the protoc command directly. +`easyp generate` finds `easyp.gen.yaml` files beneath the current directory, selects complete modules, compiles their `.proto` files, and runs the listed plugins. Module identities, roots, and dependency versions come from `protobuf.mod` and `protobuf.lock`. -## Key Features of the Generator +## Configure a module -1. **Simplified Code Generation**: - - Generate code from proto files using a `YAML` configuration. - - Avoid the need to write long and complex protoc commands. +```text +# protobuf.mod +module github.com/acme/contracts +roots proto +require github.com/acme/shared v1.2.0 +``` -2. **Wrapper around protoc**: - - EasyP functions as a wrapper around protoc, providing a more convenient API through configuration files. - - Supports all options and plugins available in protoc. +```yaml +# easyp.gen.yaml +version: v1 +generate: + modules: [github.com/acme/contracts] +plugins: + - name: go + out: ./gen/go + opts: + paths: source_relative + - name: go-grpc + out: ./gen/go + opts: + paths: source_relative +``` -3. **Flexibility and Customization**: - - Use the same parameters as protoc plugins, directly in the configuration file. - - Support for multiple plugins and their parameters in a single configuration. +```bash +easyp mod tidy +easyp generate +``` -4. **Generate Code from Multiple Sources**: - - Generate code from local directories or remote repositories. - - Easily integrate with existing projects and repositories. +If `generate.modules` is omitted, the generator selects the nearest `protobuf.mod`. A module entry may also be a repository-relative local module path or a locked dependency identity. `generate.packages` is reserved for future package filtering and currently returns an error when nonempty. -5. **Remote Generation**: - - Generate code from remote Git repositories without local checkout. +## Select a project and output descriptors -6. **Package Manager Integration**: - - Seamless integration with EasyP's package manager for dependency management. - - Automatic resolution and inclusion of proto dependencies. +```bash +easyp generate --project backend +easyp generate --descriptor_set_out descriptors.pb --include_imports +``` -## Configuration Reference +`--project` selects one consumer directory containing `easyp.gen.yaml`. `--include_imports` adds transitive imports to the descriptor set. The v1 command has no `--path` or `--root` flag; source roots are declared in `protobuf.mod`. -### Generator Configuration Comparison +## Plugins and managed options - - - ```yaml - # Package manager dependencies - deps: - - github.com/googleapis/googleapis@common-protos-1_3_1 - - github.com/grpc-ecosystem/grpc-gateway@v2.19.1 - - github.com/bufbuild/protoc-gen-validate@v0.10.1 +`plugins[].name` selects a local executable or a bundled WASM plugin. EasyP selects bundled plugins through the existing plugin resolver. A remote plugin uses `remote` with a separate pinned semantic `version`. Plugin outputs are relative to the generator file. - # Code generation configuration - generate: - plugins: - - name: go - out: ./gen/go - opts: - paths: source_relative - module: github.com/mycompany/myproject - with_imports: true +The existing managed rules remain available under `generate.managed`, including module, package, path, and field selectors. `options.go.package_prefix` can provide a Go package prefix; a repository-root generator file can supply a default for nested generator files. See the full [`easyp.gen.yaml` reference](/docs/reference/easyp-gen-yaml). - - name: go-grpc - out: ./gen/go - opts: - paths: source_relative - require_unimplemented_servers: false - ``` - - - ```yaml - version: v2 - plugins: - - remote: buf.build/protocolbuffers/go - out: gen/go - opt: - - paths=source_relative - - module=github.com/mycompany/myproject - - remote: buf.build/grpc/go - out: gen/go - opt: - - paths=source_relative - - require_unimplemented_servers=false - ``` - - - -### Multi-Language Plugin Examples - - - - ```yaml - plugins: - - name: go - out: ./gen/go - opts: - paths: source_relative - - name: go-grpc - out: ./gen/go - opts: - paths: source_relative - require_unimplemented_servers: false - ``` - - - ```yaml - plugins: - - name: ts - out: ./src/gen - opts: - declaration: true - target: es2017 - - name: grpc-web - out: ./src/gen - opts: - import_style: typescript - mode: grpcweb - ``` - - - ```yaml - plugins: - - name: python - out: ./gen/python - - name: grpc_python - out: ./gen/python - ``` - - - -## Execution Commands - - - - ```bash - easyp generate - ``` - - - ```bash - easyp --cfg custom-easyp.yaml generate - ``` - - +Dependency repositories may use v1 EasyP, older EasyP, Buf v1, or Buf v2 metadata for their proto roots. The consumer's generator still uses the v1 files. diff --git a/content/docs/cli/generator/index.ru.mdx b/content/docs/cli/generator/index.ru.mdx index 3007b74..17f435b 100644 --- a/content/docs/cli/generator/index.ru.mdx +++ b/content/docs/cli/generator/index.ru.mdx @@ -1,136 +1,55 @@ --- title: "Генератор" +description: "Генерация кода из целых protobuf-модулей в пилотной версии EasyP v1." --- -EasyP включает мощный генератор, который упрощает процесс получения кода из proto‑файлов. Благодаря YAML‑конфигурациям работа становится гораздо более удобной и интуитивной по сравнению с прямым использованием команды protoc. +`easyp generate` ищет `easyp.gen.yaml` внутри текущего каталога, выбирает целые модули, компилирует их `.proto` и запускает перечисленные плагины. Имена модулей, корни исходников и версии зависимостей берутся из `protobuf.mod` и `protobuf.lock`. -## Ключевые особенности генератора +## Настройка модуля -1. **Упрощённая генерация кода**: - - Генерация кода из proto через декларативную `YAML`‑конфигурацию. - - Избавляет от необходимости писать длинные и сложные команды protoc. +```text +# protobuf.mod +module github.com/acme/contracts +roots proto +require github.com/acme/shared v1.2.0 +``` -2. **Обёртка над protoc**: - - EasyP выступает как удобный слой над protoc, предоставляя декларативный API. - - Поддерживает все опции и плагины, доступные protoc. +```yaml +# easyp.gen.yaml +version: v1 +generate: + modules: [github.com/acme/contracts] +plugins: + - name: go + out: ./gen/go + opts: + paths: source_relative + - name: go-grpc + out: ./gen/go + opts: + paths: source_relative +``` -3. **Гибкость и кастомизация**: - - Используются те же параметры, что и у плагинов protoc, прямо в конфиге. - - Поддерживается множество плагинов и их параметры в одной конфигурации. +```bash +easyp mod tidy +easyp generate +``` -4. **Генерация из нескольких источников**: - - Локальные директории и удалённые Git‑репозитории одновременно. - - Лёгкая интеграция с существующими проектами и репозиториями. +Если `generate.modules` не указан, выбирается ближайший `protobuf.mod`. Элемент списка может быть путём к локальному модулю относительно репозитория или именем зависимости из lock. Поле `generate.packages` оставлено для будущей фильтрации пакетов; непустое значение пока вызывает ошибку. -5. **Удалённая генерация**: - - Генерация из удалённых Git репозиториев без локального checkout. +## Выбор проекта и дескрипторы -6. **Интеграция с менеджером пакетов**: - - Прозрачная работа с зависимостями через пакетный менеджер EasyP. - - Автоматическое разрешение и подключение proto‑зависимостей. +```bash +easyp generate --project backend +easyp generate --descriptor_set_out descriptors.pb --include_imports +``` -## Справочник конфигурации +`--project` выбирает один каталог потребителя с `easyp.gen.yaml`. `--include_imports` добавляет транзитивные импорты в набор дескрипторов. Флагов `--path` и `--root` у команды v1 нет: корни исходников объявляются в `protobuf.mod`. -### Сравнение конфигураций генератора +## Плагины и managed mode - - - ```yaml - # Зависимости пакетного менеджера - deps: - - github.com/googleapis/googleapis@common-protos-1_3_1 - - github.com/grpc-ecosystem/grpc-gateway@v2.19.1 - - github.com/bufbuild/protoc-gen-validate@v0.10.1 +`plugins[].name` выбирает локальный исполняемый файл или встроенный WASM-плагин. Встроенные плагины выбираются существующим resolver. Для удалённого плагина указываются `remote` и отдельный зафиксированный SemVer в `version`. Выходные каталоги задаются относительно файла генерации. - # Конфигурация генератора - generate: - plugins: - - name: go - out: ./gen/go - opts: - paths: source_relative - module: github.com/mycompany/myproject - with_imports: true +Прежние правила managed mode доступны в `generate.managed`, в том числе селекторы по модулю, пакету, пути и полю. `options.go.package_prefix` задаёт префикс Go-пакетов; корневой `easyp.gen.yaml` может предоставить значение по умолчанию вложенным конфигам. Подробности — в [справочнике `easyp.gen.yaml`](/ru/docs/reference/easyp-gen-yaml). - - name: go-grpc - out: ./gen/go - opts: - paths: source_relative - require_unimplemented_servers: false - ``` - - - ```yaml - version: v2 - plugins: - - remote: buf.build/protocolbuffers/go - out: gen/go - opt: - - paths=source_relative - - module=github.com/mycompany/myproject - - remote: buf.build/grpc/go - out: gen/go - opt: - - paths=source_relative - - require_unimplemented_servers=false - ``` - - - -### Примеры плагинов для различных языков - - - - ```yaml - plugins: - - name: go - out: ./gen/go - opts: - paths: source_relative - - name: go-grpc - out: ./gen/go - opts: - paths: source_relative - require_unimplemented_servers: false - ``` - - - ```yaml - plugins: - - name: ts - out: ./src/gen - opts: - declaration: true - target: es2017 - - name: grpc-web - out: ./src/gen - opts: - import_style: typescript - mode: grpcweb - ``` - - - ```yaml - plugins: - - name: python - out: ./gen/python - - name: grpc_python - out: ./gen/python - ``` - - - -## Команды запуска - - - - ```bash - easyp generate - ``` - - - ```bash - easyp --cfg custom-easyp.yaml generate - ``` - - +Репозитории зависимостей могут описывать корни `.proto` в EasyP v1, старом EasyP, Buf v1 или Buf v2. Конфиг потребителя при этом остаётся v1. diff --git a/content/docs/cli/linter/index.mdx b/content/docs/cli/linter/index.mdx index b993cfa..bb09152 100644 --- a/content/docs/cli/linter/index.mdx +++ b/content/docs/cli/linter/index.mdx @@ -1,420 +1,35 @@ --- title: "Linter" +description: "Configure and run the EasyP v1 protobuf linter." --- -[[toc]] +`easyp lint` checks `.proto` files using the v1 policy in `easyp.yaml`. It reports source locations and rule names for findings. -## Why Use a Linter for Proto Files? - -Linters play a crucial role in modern software development, particularly for proto files. By enforcing style and formatting rules, linters help maintain code quality, reduce potential bugs, and ensure that the codebase is clean and readable. This leads to several benefits: - -- **Reduced Development Costs:** Linters catch errors early in the development cycle, saving time and resources that would be spent on debugging and fixing issues later. -- **Improved Team Collaboration:** A standardized codebase makes it easier for team members to understand and work with each other's code, facilitating a smoother collaborative environment. -- **Business Efficiency:** Teams using linters often produce higher quality code, which translates to fewer production issues and maintenance costs. This makes businesses that adopt linting practices more competitive and cost-effective. - -## Configuration Reference - -EasyP linter provides flexible configuration options to adapt to different project requirements. All configuration is done through the `lint` section in your `easyp.yaml` file. - -### Complete Configuration Example - -```yaml -lint: - # Rules and categories to use - use: - - MINIMAL - - BASIC - - COMMENT_SERVICE - - COMMENT_RPC - - # Custom suffixes for naming conventions - enum_zero_value_suffix: "UNSPECIFIED" - service_suffix: "Service" - - # Directory and rule exclusions - ignore: - - "vendor/" - - "third_party/" - - "legacy/old_protos/" - - except: - - COMMENT_FIELD - - COMMENT_MESSAGE - - # Comment-based rule ignoring - allow_comment_ignores: true - - # File-specific rule ignoring - ignore_only: - COMMENT_SERVICE: ["legacy/", "vendor/"] - SERVICE_SUFFIX: ["proto/external/"] -``` - -### Configuration Parameters - -#### `use` ([]string) -Specifies which linter rules or rule categories to apply. You can mix individual rules with predefined categories. - -**Available categories:** -- **MINIMAL**: Basic package consistency checks -- **BASIC**: Naming conventions and usage patterns -- **DEFAULT**: Recommended rules for most projects -- **COMMENTS**: Comment presence and formatting -- **UNARY_RPC**: Restrictions on streaming RPCs - -**Individual rules**: Any specific rule name (e.g., `ENUM_PASCAL_CASE`, `FIELD_LOWER_SNAKE_CASE`) - -**Examples:** -```yaml -# Use predefined categories -use: [MINIMAL, BASIC, DEFAULT] - -# Mix categories with individual rules -use: - - MINIMAL - - COMMENT_SERVICE - - COMMENT_RPC - - ENUM_PASCAL_CASE - -# Use only specific rules -use: - - PACKAGE_DEFINED - - SERVICE_PASCAL_CASE - - FIELD_LOWER_SNAKE_CASE -``` - -#### `enum_zero_value_suffix` (string) -Defines the required suffix for zero-value enum entries. This enforces a consistent naming pattern for the default enum value. - -**Default**: Empty (no suffix required) -**Common values**: `"UNSPECIFIED"`, `"UNKNOWN"`, `"DEFAULT"` - -**Example:** -```yaml -enum_zero_value_suffix: "UNSPECIFIED" -``` - -With this setting, enum definitions must follow this pattern: -```proto -enum Status { - STATUS_UNSPECIFIED = 0; // Required suffix - STATUS_ACTIVE = 1; - STATUS_INACTIVE = 2; -} -``` - -#### `service_suffix` (string) -Specifies the required suffix for service names. This ensures consistent service naming across your project. - -**Default**: Empty (no suffix required) -**Common values**: `"Service"`, `"API"`, `"Svc"` - -**Example:** -```yaml -service_suffix: "Service" -``` - -With this setting, service definitions must follow this pattern: -```proto -service UserService { // Required "Service" suffix - rpc GetUser(...) returns (...); -} -``` - -#### `ignore` ([]string) -Lists directories or file paths to completely exclude from linting. Supports glob patterns and relative paths from the project root. - -**Use cases:** -- Third-party or vendor proto files -- Generated proto files -- Legacy code being phased out -- Test fixtures that intentionally violate rules - -**Examples:** -```yaml -ignore: - - "vendor/" # Exclude vendor directory - - "third_party/" # Exclude third-party protos - - "testdata/" # Exclude test fixtures - - "proto/legacy/" # Exclude legacy protos - - "**/*_test.proto" # Exclude test proto files -``` - -#### `except` ([]string) -Disables specific rules globally across the entire project. Use this when certain rules don't fit your project's conventions. - -**When to use:** -- Legacy projects with established naming conventions -- Projects with specific style requirements -- Gradual adoption of linting rules - -**Examples:** -```yaml -except: - - COMMENT_FIELD # Don't require field comments - - COMMENT_MESSAGE # Don't require message comments - - SERVICE_SUFFIX # Don't enforce service suffix - - ENUM_ZERO_VALUE_SUFFIX # Don't enforce enum zero suffix -``` - -#### `allow_comment_ignores` (bool) -Enables or disables the ability to ignore specific rules using inline comments in proto files. - -**Default**: `false` -**Recommended**: `true` for flexibility during development - -**Example:** -```yaml -allow_comment_ignores: true -``` - -When enabled, you can use comments to ignore rules on specific elements: -```proto -// buf:lint:ignore COMMENT_SERVICE -service LegacyUserAPI { - // nolint:COMMENT_RPC - rpc GetUser(...) returns (...); -} -``` - -#### `ignore_only` (map[string][]string) -Allows you to disable specific rules only for certain files or directories, while keeping them active elsewhere. - -**Use cases:** -- Legacy code that can't be easily updated -- Third-party protos with different conventions -- Generated code that doesn't follow your style -- Gradual migration strategies - -**Format**: `rule_name: [list_of_paths]` - -**Examples:** ```yaml -ignore_only: - # Don't require service comments in legacy directory - COMMENT_SERVICE: - - "proto/legacy/" - - "vendor/" - - # Don't enforce service suffix for external APIs - SERVICE_SUFFIX: - - "proto/external/" - - "third_party/" - - # Allow old naming in specific files - FIELD_LOWER_SNAKE_CASE: - - "proto/legacy/old_messages.proto" - - "vendor/external_api.proto" -``` - -## Comment-Based Rule Ignoring - -When `allow_comment_ignores` is enabled, you can use inline comments to ignore specific linter rules for individual proto elements. This provides fine-grained control over rule enforcement. - -### Supported Comment Formats - -EasyP supports two comment formats for maximum compatibility: - -#### Buf-compatible format -```proto -// buf:lint:ignore RULE_NAME -``` - -#### EasyP native format -```proto -// nolint:RULE_NAME -``` - -### Usage Examples - -#### Ignoring Service Rules -```proto -// buf:lint:ignore COMMENT_SERVICE -// buf:lint:ignore SERVICE_SUFFIX -service UserAPI { - rpc GetUser(GetUserRequest) returns (GetUserResponse); -} -``` - -#### Ignoring RPC Rules -```proto -service UserService { - // nolint:COMMENT_RPC - // nolint:RPC_REQUEST_STANDARD_NAME - rpc GetUserInfo(UserInfoReq) returns (UserInfoResp); -} -``` - -#### Ignoring Message and Field Rules -```proto -// buf:lint:ignore COMMENT_MESSAGE -message UserData { - // nolint:COMMENT_FIELD - // nolint:FIELD_LOWER_SNAKE_CASE - string userName = 1; -} -``` - -#### Ignoring Enum Rules -```proto -// nolint:COMMENT_ENUM -// nolint:ENUM_ZERO_VALUE_SUFFIX -enum UserType { - UNKNOWN = 0; // Would normally require suffix - ADMIN = 1; - USER = 2; -} -``` - -#### Multiple Rules on One Line -```proto -// buf:lint:ignore COMMENT_SERVICE,SERVICE_SUFFIX -service LegacyAPI { - // nolint:COMMENT_RPC,RPC_REQUEST_STANDARD_NAME - rpc getData(DataReq) returns (DataResp); -} -``` - -### Best Practices for Comment Ignores - -#### Use Sparingly -Comment ignores should be the exception, not the rule. Overuse indicates that your linting configuration may need adjustment. - -**Good:** -```proto -// Legacy service - buf:lint:ignore SERVICE_SUFFIX -service UserAPI { - rpc GetUser(...) returns (...); -} +# easyp.yaml +version: v1 +linters: + default: STANDARD + enable: [COMMENT_SERVICE] + disable: [SERVICE_SUFFIX] +linters-settings: + ENUM_ZERO_VALUE_SUFFIX: + suffix: UNSPECIFIED +issues: + exclude-rules: + - linters: [COMMENT_FIELD] ``` -**Bad:** -```proto -// nolint:COMMENT_SERVICE,SERVICE_SUFFIX,COMMENT_RPC -service UserAPI { - // nolint:COMMENT_RPC,RPC_REQUEST_STANDARD_NAME - rpc getUser(...) returns (...); - // nolint:COMMENT_RPC,RPC_RESPONSE_STANDARD_NAME - rpc updateUser(...) returns (...); -} -``` - -#### Add Explanatory Comments -Always explain why you're ignoring a rule to help future maintainers understand the decision. +The available presets are `MINIMAL`, `BASIC`, `STANDARD`, and `COMMENTS`. `enable` and `disable` add or remove individual rules. The pilot supports `ENUM_ZERO_VALUE_SUFFIX.suffix` and `SERVICE_SUFFIX.suffix` settings. Pathless `issues.exclude-rules` apply to every scanned file; path globs and `linters.extends` are not implemented yet and produce an error. -```proto -// Third-party API compatibility requires non-standard naming -// buf:lint:ignore SERVICE_SUFFIX -service ExternalUserAPI { - // Legacy method name for backwards compatibility - // nolint:RPC_REQUEST_STANDARD_NAME - rpc getUserData(UserReq) returns (UserResp); -} +```bash +easyp lint --path proto +easyp --format json lint --path proto +easyp lint --root ./contracts --path proto ``` -#### Prefer Configuration Over Comments -When multiple files need the same rule ignored, use `ignore_only` configuration instead of individual comments. - -**Instead of:** -```proto -// In file1.proto -// buf:lint:ignore COMMENT_SERVICE -service API1 { ... } - -// In file2.proto -// buf:lint:ignore COMMENT_SERVICE -service API2 { ... } -``` - -**Use:** -```yaml -# In easyp.yaml -lint: - ignore_only: - COMMENT_SERVICE: ["legacy/"] -``` - -## Linter Categories - -To accommodate different project needs and preferences, EasyP linter provides predefined rule categories. These categories group together various rules, allowing teams to quickly select the level of strictness or areas they want to focus on during linting. - -**When to use each category:** - -- **MINIMAL:** Essential for any proto project - ensures basic consistency and prevents fundamental issues -- **BASIC:** Recommended for most projects - enforces common naming conventions and best practices -- **DEFAULT:** Additional quality checks - useful for mature projects with established workflows -- **COMMENTS:** Documentation requirements - important for public APIs and team collaboration -- **UNARY_RPC:** Streaming restrictions - use when your architecture requires only unary RPCs - -The available categories are: -- **MINIMAL:** Basic checks to ensure package consistency. -- **BASIC:** Additional checks for naming conventions and usage patterns. -- **DEFAULT:** A set of default rules that most projects should use. -- **COMMENTS:** Ensures that comments are present and properly formatted. -- **UNARY_RPC:** Specific rules for unary RPC services. - -### Rule Groupings - -Below are the rule groupings under each category: - -#### MINIMAL - -- `DIRECTORY_SAME_PACKAGE` -- `PACKAGE_DEFINED` -- `PACKAGE_DIRECTORY_MATCH` -- `PACKAGE_SAME_DIRECTORY` - -#### BASIC - -- `ENUM_FIRST_VALUE_ZERO` -- `ENUM_NO_ALLOW_ALIAS` -- `ENUM_PASCAL_CASE` -- `ENUM_VALUE_UPPER_SNAKE_CASE` -- `FIELD_LOWER_SNAKE_CASE` -- `IMPORT_NO_PUBLIC` -- `IMPORT_NO_WEAK` -- `IMPORT_USED` -- `MESSAGE_PASCAL_CASE` -- `ONEOF_LOWER_SNAKE_CASE` -- `PACKAGE_LOWER_SNAKE_CASE` -- `PACKAGE_SAME_CSHARP_NAMESPACE` -- `PACKAGE_SAME_GO_PACKAGE` -- `PACKAGE_SAME_JAVA_MULTIPLE_FILES` -- `PACKAGE_SAME_JAVA_PACKAGE` -- `PACKAGE_SAME_PHP_NAMESPACE` -- `PACKAGE_SAME_RUBY_PACKAGE` -- `PACKAGE_SAME_SWIFT_PREFIX` -- `RPC_PASCAL_CASE` -- `SERVICE_PASCAL_CASE` - -#### DEFAULT - -- `ENUM_VALUE_PREFIX` -- `ENUM_ZERO_VALUE_SUFFIX` -- `FILE_LOWER_SNAKE_CASE` -- `RPC_REQUEST_RESPONSE_UNIQUE` -- `RPC_REQUEST_STANDARD_NAME` -- `RPC_RESPONSE_STANDARD_NAME` -- `PACKAGE_VERSION_SUFFIX` -- `SERVICE_SUFFIX` - -#### COMMENTS - -- `COMMENT_ENUM` -- `COMMENT_ENUM_VALUE` -- `COMMENT_FIELD` -- `COMMENT_MESSAGE` -- `COMMENT_ONEOF` -- `COMMENT_RPC` -- `COMMENT_SERVICE` - -#### UNARY_RPC - -- `RPC_NO_CLIENT_STREAMING` -- `RPC_NO_SERVER_STREAMING` +`--path` is relative to the scan root. By default the scan root is the directory of the selected policy file; `--root` changes it. The linter uses the nearest module's source roots and local or locked dependency roots to resolve imports. A policy can also be used without `protobuf.mod`. -## Conclusion +Nested `easyp.yaml` files may override policy sections for files beneath their directories. See the [`easyp.yaml` reference](/docs/reference/easyp-yaml) for the supported fields and merging rules. -Adopting the EasyP linter for your proto files can significantly enhance your development workflow, code quality, -and overall project maintainability. With full compatibility with the Buf linter, teams can easily migrate and start benefiting -from our tool's robust features and flexible configuration options. +The older `lint.use`, `lint.except`, and `lint.ignore_only` configuration is not accepted by the v1 CLI. diff --git a/content/docs/cli/linter/index.ru.mdx b/content/docs/cli/linter/index.ru.mdx index 56dcac1..b340703 100644 --- a/content/docs/cli/linter/index.ru.mdx +++ b/content/docs/cli/linter/index.ru.mdx @@ -1,336 +1,35 @@ --- title: "Линтер" +description: "Настройка и запуск protobuf-линтера EasyP v1." --- -[[toc]] +`easyp lint` проверяет `.proto` по политике v1 из `easyp.yaml`. В найденных проблемах указываются положение в исходнике и имя правила. -## Зачем нужен линтер для proto файлов? - -Линтеры играют ключевую роль в современной разработке, особенно когда речь о `.proto` файлах. Они обеспечивают единый стиль и структуру, помогают находить потенциальные ошибки на ранних этапах и поддерживают читаемость кода. Это даёт выгоды: - -- **Снижение затрат на разработку:** Ошибки ловятся раньше, меньше времени на отладку. -- **Улучшение командного взаимодействия:** Единообразный код легче понимать и сопровождать. -- **Бизнес-эффективность:** Более качественный код → меньше инцидентов в проде → ниже стоимость поддержки. - -## Справочник по конфигурации - -Конфигурация линтера настраивается в секции `lint` файла `easyp.yaml`. - -### Полный пример конфигурации - -```yaml -lint: - # Используемые категории и правила - use: - - MINIMAL - - BASIC - - COMMENT_SERVICE - - COMMENT_RPC - - # Кастомные суффиксы - enum_zero_value_suffix: "UNSPECIFIED" - service_suffix: "Service" - - # Исключения директорий и файлов - ignore: - - "vendor/" - - "third_party/" - - "legacy/old_protos/" - - except: - - COMMENT_FIELD - - COMMENT_MESSAGE - - # Разрешить игнорирование правил комментариями - allow_comment_ignores: true - - # Игнор отдельных правил только для указанных путей - ignore_only: - COMMENT_SERVICE: ["legacy/", "vendor/"] - SERVICE_SUFFIX: ["proto/external/"] -``` - -### Параметры конфигурации - -#### `use` ([]string) -Определяет набор правил или категорий для включения. Можно смешивать категории и конкретные правила. - -**Категории:** -- **MINIMAL**: Базовая согласованность пакетов -- **BASIC**: Соглашения по именованию и структуре -- **DEFAULT**: Рекомендованные правила для большинства проектов -- **COMMENTS**: Требования к комментариям -- **UNARY_RPC**: Ограничение на streaming RPC - -**Индивидуальные правила:** Любое имя правила (например `ENUM_PASCAL_CASE`, `FIELD_LOWER_SNAKE_CASE`) - -**Примеры:** -```yaml -# Только категории -use: [MINIMAL, BASIC, DEFAULT] - -# Смешивание -use: - - MINIMAL - - COMMENT_SERVICE - - COMMENT_RPC - - ENUM_PASCAL_CASE - -# Точный набор -use: - - PACKAGE_DEFINED - - SERVICE_PASCAL_CASE - - FIELD_LOWER_SNAKE_CASE -``` - -#### `enum_zero_value_suffix` (string) -Обязывает нулевое значение enum иметь заданный суффикс. - -**Обычно:** `"UNSPECIFIED"`, `"UNKNOWN"`, `"DEFAULT"` ```yaml -enum_zero_value_suffix: "UNSPECIFIED" +# easyp.yaml +version: v1 +linters: + default: STANDARD + enable: [COMMENT_SERVICE] + disable: [SERVICE_SUFFIX] +linters-settings: + ENUM_ZERO_VALUE_SUFFIX: + suffix: UNSPECIFIED +issues: + exclude-rules: + - linters: [COMMENT_FIELD] ``` -```proto -enum Status { - STATUS_UNSPECIFIED = 0; // Требуемый суффикс - STATUS_ACTIVE = 1; - STATUS_INACTIVE = 2; -} -``` - -#### `service_suffix` (string) -Требуемый суффикс для имён сервисов (унификация стиля). - -```yaml -service_suffix: "Service" -``` - -```proto -service UserService { // Обязательный суффикс - rpc GetUser(...) returns (...); -} -``` - -#### `ignore` ([]string) -Полное исключение путей из линтинга. - -**Use cases:** -- vendor / third_party -- сгенерированные файлы -- легаси подпакеты -- тестовые фикстуры - -```yaml -ignore: - - "vendor/" - - "third_party/" - - "testdata/" - - "proto/legacy/" - - "**/*_test.proto" -``` - -#### `except` ([]string) -Глобально отключает правила. - -```yaml -except: - - COMMENT_FIELD - - COMMENT_MESSAGE - - SERVICE_SUFFIX - - ENUM_ZERO_VALUE_SUFFIX -``` - -#### `allow_comment_ignores` (bool) -Разрешает инлайн‑игнор правил комментариями. - -```yaml -allow_comment_ignores: true -``` +Доступные наборы: `MINIMAL`, `BASIC`, `STANDARD`, `COMMENTS`. Поля `enable` и `disable` добавляют или исключают отдельные правила. Пилотная версия поддерживает настройки `ENUM_ZERO_VALUE_SUFFIX.suffix` и `SERVICE_SUFFIX.suffix`. Правила `issues.exclude-rules` без пути действуют на все проверяемые файлы. Глобы путей и `linters.extends` пока не реализованы и вызывают ошибку. -```proto -// buf:lint:ignore COMMENT_SERVICE -service LegacyUserAPI { - // nolint:COMMENT_RPC - rpc GetUser(...) returns (...); -} +```bash +easyp lint --path proto +easyp --format json lint --path proto +easyp lint --root ./contracts --path proto ``` -#### `ignore_only` (map[string][]string) -Таргетированное игнорирование конкретных правил для указанных путей. - -```yaml -ignore_only: - COMMENT_SERVICE: - - "proto/legacy/" - - "vendor/" - SERVICE_SUFFIX: - - "proto/external/" - - "third_party/" - FIELD_LOWER_SNAKE_CASE: - - "proto/legacy/old_messages.proto" - - "vendor/external_api.proto" -``` - -## Игнор правил комментариями - -Если включён `allow_comment_ignores`, можно точечно отключать правила. - -### Форматы комментариев - -#### Совместимый с Buf -```proto -// buf:lint:ignore RULE_NAME -``` - -#### Нативный EasyP -```proto -// nolint:RULE_NAME -``` - -### Примеры - -#### Игнор правил сервиса -```proto -// buf:lint:ignore COMMENT_SERVICE -// buf:lint:ignore SERVICE_SUFFIX -service UserAPI { - rpc GetUser(GetUserRequest) returns (GetUserResponse); -} -``` - -#### Игнор RPC -```proto -service UserService { - // nolint:COMMENT_RPC - // nolint:RPC_REQUEST_STANDARD_NAME - rpc GetUserInfo(UserInfoReq) returns (UserInfoResp); -} -``` - -#### Игнор Message и Field -```proto -// buf:lint:ignore COMMENT_MESSAGE -message UserData { - // nolint:COMMENT_FIELD - // nolint:FIELD_LOWER_SNAKE_CASE - string userName = 1; -} -``` - -#### Игнор Enum -```proto -// nolint:COMMENT_ENUM -// nolint:ENUM_ZERO_VALUE_SUFFIX -enum UserType { - UNKNOWN = 0; // Обычно требовался бы суффикс - ADMIN = 1; - USER = 2; -} -``` - -#### Несколько правил в одной строке -```proto -// buf:lint:ignore COMMENT_SERVICE,SERVICE_SUFFIX -service LegacyAPI { - // nolint:COMMENT_RPC,RPC_REQUEST_STANDARD_NAME - rpc getData(DataReq) returns (DataResp); -} -``` - -### Рекомендации - -#### Используйте редко -Частое игнорирование = сигнал пересмотреть конфигурацию. -```proto -// Легаси сервис - buf:lint:ignore SERVICE_SUFFIX -service UserAPI { ... } -``` - -#### Плохой пример -```proto -// nolint:COMMENT_SERVICE,SERVICE_SUFFIX,COMMENT_RPC -service UserAPI { ... } -``` - -#### Добавляйте пояснения -```proto -// Совместимость с внешним API -// buf:lint:ignore SERVICE_SUFFIX -service ExternalUserAPI { - // Легаси имя метода - // nolint:RPC_REQUEST_STANDARD_NAME - rpc getUserData(UserReq) returns (UserResp); -} -``` - -#### Предпочитайте конфигурацию -Если нужно игнорировать правило в группе файлов — используйте `ignore_only`. - -## Категории линтера - -Категории помогают быстро выбрать уровень строгости. - -**Когда использовать:** -- **MINIMAL**: Минимальная базовая целостность -- **BASIC**: Частые соглашения имен -- **DEFAULT**: Дополнительные проверки качества -- **COMMENTS**: Обязательные комментарии (API, команды) -- **UNARY_RPC**: Ограничить streaming RPC - -### Группировки правил - -#### MINIMAL -- `DIRECTORY_SAME_PACKAGE` -- `PACKAGE_DEFINED` -- `PACKAGE_DIRECTORY_MATCH` -- `PACKAGE_SAME_DIRECTORY` - -#### BASIC -- `ENUM_FIRST_VALUE_ZERO` -- `ENUM_NO_ALLOW_ALIAS` -- `ENUM_PASCAL_CASE` -- `ENUM_VALUE_UPPER_SNAKE_CASE` -- `FIELD_LOWER_SNAKE_CASE` -- `IMPORT_NO_PUBLIC` -- `IMPORT_NO_WEAK` -- `IMPORT_USED` -- `MESSAGE_PASCAL_CASE` -- `ONEOF_LOWER_SNAKE_CASE` -- `PACKAGE_LOWER_SNAKE_CASE` -- `PACKAGE_SAME_CSHARP_NAMESPACE` -- `PACKAGE_SAME_GO_PACKAGE` -- `PACKAGE_SAME_JAVA_MULTIPLE_FILES` -- `PACKAGE_SAME_JAVA_PACKAGE` -- `PACKAGE_SAME_PHP_NAMESPACE` -- `PACKAGE_SAME_RUBY_PACKAGE` -- `PACKAGE_SAME_SWIFT_PREFIX` -- `RPC_PASCAL_CASE` -- `SERVICE_PASCAL_CASE` - -#### DEFAULT -- `ENUM_VALUE_PREFIX` -- `ENUM_ZERO_VALUE_SUFFIX` -- `FILE_LOWER_SNAKE_CASE` -- `RPC_REQUEST_RESPONSE_UNIQUE` -- `RPC_REQUEST_STANDARD_NAME` -- `RPC_RESPONSE_STANDARD_NAME` -- `PACKAGE_VERSION_SUFFIX` -- `SERVICE_SUFFIX` - -#### COMMENTS -- `COMMENT_ENUM` -- `COMMENT_ENUM_VALUE` -- `COMMENT_FIELD` -- `COMMENT_MESSAGE` -- `COMMENT_ONEOF` -- `COMMENT_RPC` -- `COMMENT_SERVICE` - -#### UNARY_RPC -- `RPC_NO_CLIENT_STREAMING` -- `RPC_NO_SERVER_STREAMING` +`--path` задаётся относительно корня проверки. По умолчанию корень — каталог выбранного файла политики; `--root` меняет его. Для импортов линтер использует корни ближайшего модуля и его локальных либо зафиксированных зависимостей. Политика может работать и без `protobuf.mod`. -## Заключение +Вложенные `easyp.yaml` могут переопределять секции политики для файлов в своих каталогах. Поддерживаемые поля и правила объединения описаны в [справочнике `easyp.yaml`](/ru/docs/reference/easyp-yaml). -Внедрение EasyP линдера для ваших proto файлов заметно улучшит workflow, качество и поддерживаемость кода. Полная совместимость с Buf позволяет командам мигрировать без боли, используя гибкую конфигурацию и мощные возможности из коробки. +Старые поля `lint.use`, `lint.except` и `lint.ignore_only` CLI v1 не принимает. diff --git a/content/docs/cli/package-manager/easyp-vs-buf.mdx b/content/docs/cli/package-manager/easyp-vs-buf.mdx index 8d4d7ab..62ddb69 100644 --- a/content/docs/cli/package-manager/easyp-vs-buf.mdx +++ b/content/docs/cli/package-manager/easyp-vs-buf.mdx @@ -1,455 +1,32 @@ --- -title: "EasyP vs Buf Package Management" +title: "Using Buf-configured Git dependencies" +description: "How the EasyP v1 pilot reads proto roots from Git dependencies that use Buf configuration." --- -[[toc]] +An EasyP v1 project lists Git modules in `protobuf.mod`. A dependency repository can use Buf configuration; EasyP reads that configuration to find its `.proto` source roots. The consumer does not need to copy those roots into `easyp.gen.yaml`. -This document provides a comprehensive comparison between EasyP's decentralized package management approach and Buf's centralized Buf Schema Registry (BSR) model, helping you understand the key differences and choose the right solution for your needs. +| Dependency file | Roots used by EasyP | +|-----------------|---------------------| +| `buf.work.yaml` v1 | `directories` | +| `buf.yaml` v2 | `modules[].path` | +| `buf.yaml` v1 | Repository root | +| `buf.yaml` v1beta1 | `build.roots`, or repository root if omitted | -## Architecture Comparison +When a dependency has no EasyP or Buf configuration, EasyP uses its repository root. If it has an older EasyP `protobuf.mod` or `easyp.yaml`, EasyP also reads its transitive requirements and declared roots. -### EasyP: Decentralized Git-Based Approach - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ EasyP Architecture │ -├─────────────────────────────────────────────────────────────────┤ -│ │ -│ Developer Machine Git Repositories │ -│ ┌──────────────┐ ┌─────────────────┐ │ -│ │ │ clone/ │ github.com/ │ │ -│ │ ~/.easyp/ │◄─────────►│ googleapis/ │ │ -│ │ cache/ │ fetch │ googleapis │ │ -│ │ │ │ │ │ -│ │ mod/ │ ├─────────────────┤ │ -│ │ │ │ company.com/ │ │ -│ └──────────────┘ │ internal-protos │ │ -│ │ │ │ -│ ├─────────────────┤ │ -│ │ gitlab.com/ │ │ -│ │ team/shared │ │ -│ └─────────────────┘ │ -│ │ -│ ✅ Direct repository access │ -│ ✅ No single point of failure │ -│ ✅ Works with any Git hosting │ -│ ✅ Complete control over dependencies │ -│ │ -└─────────────────────────────────────────────────────────────────┘ -``` - -### Buf: Centralized Registry Approach - -``` -┌────────────────────────────────────────────────────────────────┐ -│ Buf Architecture │ -├────────────────────────────────────────────────────────────────┤ -│ │ -│ Developer Machine Buf Schema Registry (BSR) │ -│ ┌──────────────┐ ┌─────────────────────────────┐ │ -│ │ │ push/pull │ │ │ -│ │ ~/.cache/ │◄────────────►│ buf.build │ │ -│ │ bufcli/ │ modules │ │ │ -│ │ │ │ ┌─────────────────────────┐ │ │ -│ │ │ │ │ googleapis/googleapis │ │ │ -│ │ │ │ ├─────────────────────────┤ │ │ -│ │ │ │ │ grpc/grpc │ │ │ -│ │ │ │ ├─────────────────────────┤ │ │ -│ │ │ │ │ envoyproxy/protoc-gen- │ │ │ -│ │ │ │ │ validate │ │ │ -│ └──────────────┘ │ └─────────────────────────┘ │ │ -│ │ │ │ -│ └─────────────────────────────┘ │ -│ │ -│ ⚠️ Centralized dependency │ -│ ⚠️ Single point of control │ -│ ⚠️ Requires buf.build access │ -│ ⚠️ Limited to BSR ecosystem │ -│ │ -└────────────────────────────────────────────────────────────────┘ -``` - -## Key Differences Summary - -| Aspect | EasyP | Buf | -|--------|-------|-----| -| **Architecture** | Decentralized (Git-based) | Centralized (BSR registry) | -| **Dependency Source** | Any Git repository | Buf Schema Registry only | -| **Single Point of Failure** | No | Yes (buf.build) | -| **Enterprise Deployment** | Fully air-gapped support | Requires BSR access or private BSR | -| **Authentication** | Git credentials (SSH/HTTPS) | Buf tokens + Git credentials | -| **Vendor Lock-in** | None | Buf ecosystem | -| **Private Repositories** | Native Git support | Must publish to BSR first | -| **Offline Support** | Full (via vendoring) | Limited (cached modules only) | -| **Cost** | Free (uses existing Git) | Free tier + paid plans | -| **Setup Complexity** | Minimal | Moderate (BSR setup) | - -## Detailed Feature Comparison - -### 1. Dependency Management Philosophy - -#### EasyP: "Any Git Repository is a Package" -```yaml -# Direct Git repository references -deps: - - github.com/googleapis/googleapis@v1.2.3 - - gitlab.company.com/protos/internal@v2.0.1 - - git.example.com/team/shared-types@main -``` - -**Advantages:** -- ✅ Use any existing Git repository immediately -- ✅ No need to "publish" to a separate registry -- ✅ Version control is the source of truth -- ✅ Works with private Git servers out-of-the-box - -#### Buf: "Registry-First Approach" -```yaml -# buf.yaml - Must reference BSR modules -version: v1 -deps: - - buf.build/googleapis/googleapis - - buf.build/grpc/grpc - - buf.build/envoyproxy/protoc-gen-validate -``` - -**Advantages:** -- ✅ Curated, high-quality modules -- ✅ Rich metadata and documentation -- ✅ Dependency graph visualization -- ✅ Semantic versioning enforcement - -**Limitations:** -- ❌ Must publish to BSR before use -- ❌ Requires BSR account and authentication -- ❌ Cannot reference arbitrary Git repositories directly - -### 2. Enterprise and Air-Gapped Environments - -#### EasyP: Full Air-Gap Support - -**Scenario**: Large enterprise with strict network policies - -```bash -# 1. Initial setup (with internet) -easyp mod download # Downloads to ~/.easyp/ -easyp mod vendor # Creates easyp_vendor/ - -# 2. Transfer to air-gapped environment -tar -czf easyp-deps.tar.gz ~/.easyp easyp_vendor/ -# ... transfer archive ... - -# 3. Air-gapped environment (no internet) -tar -xzf easyp-deps.tar.gz -export EASYPPATH=$PWD/.easyp -easyp generate # Works offline -``` - -**Benefits:** -- ✅ Complete independence from external services -- ✅ No need for internal registry infrastructure -- ✅ Uses existing Git infrastructure -- ✅ Simple file-based distribution - -#### Buf: Requires BSR Infrastructure - -**Scenario**: Same enterprise setup - -```bash -# Option 1: Use buf.build (requires internet) -buf mod download # Must reach buf.build - -# Option 2: Set up private BSR (complex) -# - Deploy BSR server infrastructure -# - Migrate all modules to private BSR -# - Configure authentication and access -# - Maintain registry server -``` - -**Challenges:** -- ❌ Requires constant internet access OR expensive private BSR -- ❌ Complex infrastructure for private deployments -- ❌ All modules must be re-published to private registry -- ❌ Additional operational overhead - -### 3. Security and Control - -#### EasyP: Direct Control -```yaml -# Full control over dependency sources -deps: - # Public repository - your choice of version - - github.com/googleapis/googleapis@common-protos-1_3_1 - - # Internal repository - complete control - - gitlab.company.com/security/validated-protos@v1.0.0 - - # Specific commit for security fix - - github.com/bufbuild/protoc-gen-validate@abc123def456 -``` - -**Security advantages:** -- ✅ **No intermediary** - direct from source repository -- ✅ **Audit trail** - Git commit history is the source of truth -- ✅ **Cannot be "banned"** - no external party can revoke access -- ✅ **Custom validation** - implement your own security scanning -- ✅ **Fork protection** - easily fork and maintain dependencies - -#### Buf: Registry Dependency - -```yaml -# Dependencies controlled by BSR -deps: - - buf.build/googleapis/googleapis # Controlled by Buf - - buf.build/grpc/grpc # Could be removed/updated -``` - -**Security considerations:** -- ⚠️ **Intermediary risk** - BSR controls what's available -- ⚠️ **Account suspension** - Could lose access to dependencies -- ⚠️ **Module removal** - Modules can be deleted from registry -- ⚠️ **Update policies** - BSR may force updates or deprecations -- ⚠️ **Third-party trust** - Must trust Buf's security practices - -### 4. Real-World Scenarios - -#### Scenario 1: Startup with Public Dependencies - -**EasyP Approach:** -```yaml -# Simple, direct references -deps: - - github.com/googleapis/googleapis - - github.com/grpc-ecosystem/grpc-gateway@v2.19.1 -``` - -**Buf Approach:** -```yaml -# Requires understanding BSR module names -deps: - - buf.build/googleapis/googleapis - - buf.build/grpcecosystem/grpc-gateway -``` - -**Winner**: Tie - both work well for public dependencies - -#### Scenario 2: Enterprise with Mixed Public/Private Dependencies - -**EasyP Approach:** -```yaml -deps: - # Public - - github.com/googleapis/googleapis@v1.2.3 - - # Private (existing Git repos) - - github.com/mycompany/auth-protos@v2.0.0 - - gitlab.enterprise.com/platform/shared-types@v1.5.1 +```text +# Consumer protobuf.mod +module github.com/acme/service +roots proto +require github.com/acme/buf-contracts v1.2.0 ``` -**Buf Approach:** -```yaml -# All must be published to BSR first -deps: - - buf.build/googleapis/googleapis - - buf.build/mycompany/auth-protos # Requires BSR publication - - buf.build/mycompany/shared-types # Requires BSR publication -``` - -**Winner**: **EasyP** - no additional setup for private repos - -#### Scenario 3: Government/Defense Contractor (Air-Gapped) - -**EasyP Approach:** -```bash -# Internet-connected environment -easyp mod vendor - -# Transfer to classified environment -# Works immediately without any external dependencies -``` - -**Buf Approach:** -```bash -# Must deploy and maintain private BSR infrastructure -# All modules must be re-published internally -# Complex operational overhead -``` - -**Winner**: **EasyP** - significantly simpler air-gap deployment - -#### Scenario 4: Compliance and Auditing - -**EasyP Approach:** -- ✅ **Direct audit trail**: Git commits show exact changes -- ✅ **Compliance-friendly**: No external dependencies in production -- ✅ **Reproducible**: Lock files pin exact Git commits -- ✅ **Vulnerability management**: Direct control over security updates - -**Buf Approach:** -- ⚠️ **Registry dependency**: Must audit BSR's security practices -- ⚠️ **Third-party risk**: BSR is part of your compliance scope -- ⚠️ **Limited control**: Cannot control when modules are updated/removed -- ⚠️ **Audit complexity**: Must trace registry → Git → actual code - -**Winner**: **EasyP** - cleaner compliance story - -### 5. Cost and Infrastructure - -#### EasyP: Zero Additional Infrastructure - -**Costs:** -- ✅ **$0** - Uses existing Git infrastructure -- ✅ **No additional servers** to maintain -- ✅ **No licensing fees** for registry software -- ✅ **Scales with Git** - proven enterprise scalability - -**Infrastructure:** -- Uses existing Git repositories (GitHub, GitLab, etc.) -- Leverages existing authentication systems -- No additional backup/disaster recovery needed - -#### Buf: Registry Infrastructure Costs - -**BSR Hosted (buf.build):** -- ✅ Free tier available -- ❌ Paid plans for private modules and teams -- ❌ Subject to external pricing changes -- ❌ Data locality concerns for some enterprises - -**Private BSR Deployment:** -- ❌ Significant infrastructure costs (servers, databases, load balancers) -- ❌ Operational overhead (monitoring, updates, backups) -- ❌ Licensing costs for enterprise features -- ❌ Additional disaster recovery planning - -### 6. Migration and Lock-in - -#### EasyP: No Lock-in - -**Migration FROM EasyP:** -```yaml -# EasyP dependencies are just Git repositories -# Can easily migrate to any other system that supports Git -deps: - - github.com/googleapis/googleapis@v1.2.3 # Standard Git reference -``` - -**Migration TO EasyP:** ```bash -# From any Git-based system -# Just reference the same repositories directly +easyp mod tidy +easyp mod download +easyp generate ``` -#### Buf: Potential Lock-in - -**Migration FROM Buf:** -- ❌ Must identify original Git repositories for each BSR module -- ❌ BSR-specific module names don't translate directly -- ❌ May lose version history and metadata -- ❌ Complex if heavily integrated with BSR ecosystem - -**Migration TO Buf:** -- ❌ Must publish all dependencies to BSR first -- ❌ Cannot reference Git repositories directly -- ❌ Must adopt BSR workflow and tooling - -## When to Choose Each Solution - -### Choose EasyP When: - -✅ **Enterprise/Air-gapped environments** -- Need to work without external dependencies -- Strict compliance requirements -- Air-gapped or classified networks - -✅ **Security-first organizations** -- Want direct control over dependency sources -- Need to audit entire supply chain -- Concerned about third-party service risks - -✅ **Existing Git-heavy workflows** -- Team already comfortable with Git -- Extensive private repository usage -- Want to minimize new tools/infrastructure - -✅ **Cost-sensitive projects** -- Want to avoid additional licensing costs -- Don't want infrastructure overhead -- Need predictable, zero-cost scaling - -✅ **Mixed public/private dependencies** -- Heavy use of internal Git repositories -- Don't want to republish existing repos -- Need flexibility in dependency sources - -### Choose Buf When: - -✅ **Heavy BSR ecosystem usage** -- Already invested in Buf tooling (lint, breaking changes, generation) -- Want curated, high-quality modules -- Benefit from BSR's rich metadata and docs - -✅ **Collaborative development** -- Need dependency graph visualization -- Want centralized module discovery -- Benefit from BSR's collaboration features - -✅ **Simple public-only dependencies** -- Primarily use well-known public modules -- Don't mind BSR dependency -- Value the curated module experience - -✅ **Team new to protobuf** -- Benefit from BSR's documentation and examples -- Want guided module discovery -- Prefer opinionated, structured approach - -## Migration Paths - -### Migrating from Buf to EasyP - -1. **Identify source repositories** for each BSR module -2. **Map BSR modules** to Git repository references -3. **Update configuration** to use Git URLs -4. **Test compatibility** and resolve any issues - -Example migration: -```yaml -# Before (buf.yaml) -deps: - - buf.build/googleapis/googleapis - - buf.build/grpc/grpc - -# After (easyp.yaml) -deps: - - github.com/googleapis/googleapis@common-protos-1_3_1 - - github.com/grpc/grpc@v1.50.0 -``` - -### Migrating from EasyP to Buf - -1. **Publish modules** to BSR (if not already available) -2. **Create BSR account** and configure authentication -3. **Update configuration** to reference BSR modules -4. **Adopt BSR workflow** (push, pull, etc.) - -## Conclusion - -Both EasyP and Buf offer valid approaches to protobuf dependency management, but they serve different needs: - -**EasyP excels in:** -- Enterprise and air-gapped environments -- Security-conscious organizations -- Cost-sensitive projects -- Direct Git repository usage -- Zero-infrastructure deployments - -**Buf excels in:** -- Collaborative, open-source focused teams -- Organizations wanting curated, high-quality modules -- Teams new to protobuf ecosystem -- Projects heavily using BSR features - -The choice between EasyP and Buf often comes down to your organization's priorities around **control vs. convenience**, **security vs. collaboration features**, and **infrastructure costs vs. managed services**. +`mod tidy` resolves the Git dependency and records the selected commit and content hash in `protobuf.lock`. Buf Registry dependency names are not converted into Git URLs automatically; declare a suitable Git source in the consumer manifest. Buf include/exclude filters are not yet supported for Git dependency import roots and produce an error. -For many enterprise environments, EasyP's decentralized, Git-native approach provides the security, control, and cost-effectiveness needed for production protobuf workflows, while Buf's centralized registry excels in collaborative, open-source focused development environments. +The v1 pilot does not provide `mod vendor`. See the [package manager guide](/docs/cli/package-manager) for the supported commands. diff --git a/content/docs/cli/package-manager/easyp-vs-buf.ru.mdx b/content/docs/cli/package-manager/easyp-vs-buf.ru.mdx index 325a85b..46d15b5 100644 --- a/content/docs/cli/package-manager/easyp-vs-buf.ru.mdx +++ b/content/docs/cli/package-manager/easyp-vs-buf.ru.mdx @@ -1,430 +1,32 @@ --- -title: "EasyP против Buf: управление пакетами" +title: "Git-зависимости с конфигом Buf" +description: "Как пилотная версия EasyP v1 извлекает корни proto из Git-зависимостей на Buf." --- -[[toc]] +Проект EasyP v1 перечисляет Git-модули в `protobuf.mod`. Репозиторий зависимости может использовать конфигурацию Buf: EasyP читает её и находит корни исходных `.proto`. Дублировать эти корни в `easyp.gen.yaml` потребителя не нужно. -Этот документ даёт подробное сравнение децентрализованного подхода EasyP к управлению пакетами и централизованной модели Buf через Buf Schema Registry (BSR), чтобы помочь понять ключевые различия и выбрать подходящее решение для ваших задач. +| Файл зависимости | Корни, которые использует EasyP | +|------------------|---------------------------------| +| `buf.work.yaml` v1 | `directories` | +| `buf.yaml` v2 | `modules[].path` | +| `buf.yaml` v1 | Корень репозитория | +| `buf.yaml` v1beta1 | `build.roots` или корень репозитория | -## Сравнение архитектуры +Если у зависимости нет конфигурации EasyP или Buf, её корнем считается каталог репозитория. Если есть старые EasyP `protobuf.mod` или `easyp.yaml`, EasyP также читает транзитивные требования и объявленные корни. -### EasyP: децентрализованный подход на базе Git - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ Архитектура EasyP │ -├─────────────────────────────────────────────────────────────────┤ -│ │ -│ Машина разработчика Git репозитории │ -│ ┌──────────────┐ ┌─────────────────┐ │ -│ │ │ clone/ │ github.com/ │ │ -│ │ ~/.easyp/ │◄─────────►│ googleapis/ │ │ -│ │ cache/ │ fetch │ googleapis │ │ -│ │ │ │ │ │ -│ │ mod/ │ ├─────────────────┤ │ -│ │ │ │ company.com/ │ │ -│ └──────────────┘ │ internal-protos │ │ -│ │ │ │ -│ ├─────────────────┤ │ -│ │ gitlab.com/ │ │ -│ │ team/shared │ │ -│ └─────────────────┘ │ -│ │ -│ ✅ Прямой доступ к репозиториям │ -│ ✅ Нет единой точки отказа │ -│ ✅ Работает с любым Git хостингом │ -│ ✅ Полный контроль над зависимостями │ -│ │ -└─────────────────────────────────────────────────────────────────┘ -``` - -### Buf: централизованный реестр (BSR) - -``` -┌────────────────────────────────────────────────────────────────┐ -│ Архитектура Buf │ -├────────────────────────────────────────────────────────────────┤ -│ │ -│ Машина разработчика Buf Schema Registry (BSR) │ -│ ┌──────────────┐ ┌─────────────────────────────┐ │ -│ │ │ push/pull │ │ │ -│ │ ~/.cache/ │◄────────────►│ buf.build │ │ -│ │ bufcli/ │ modules │ │ │ -│ │ │ │ ┌─────────────────────────┐ │ │ -│ │ │ │ │ googleapis/googleapis │ │ │ -│ │ │ │ ├─────────────────────────┤ │ │ -│ │ │ │ │ grpc/grpc │ │ │ -│ │ │ │ ├─────────────────────────┤ │ │ -│ │ │ │ │ envoyproxy/protoc-gen- │ │ │ -│ │ │ │ │ validate │ │ │ -│ └──────────────┘ │ └─────────────────────────┘ │ │ -│ │ │ │ -│ └─────────────────────────────┘ │ -│ │ -│ ⚠️ Централизованная зависимость │ -│ ⚠️ Единая точка контроля │ -│ ⚠️ Требуется доступ к buf.build │ -│ ⚠️ Ограничение экосистемой BSR │ -│ │ -└────────────────────────────────────────────────────────────────┘ -``` - -## Краткое резюме различий - -| Аспект | EasyP | Buf | -|--------|-------|-----| -| **Архитектура** | Децентрализованная (Git) | Централизованная (реестр BSR) | -| **Источник зависимостей** | Любой Git репозиторий | Только модули BSR | -| **Единая точка отказа** | Нет | Да (buf.build) | -| **Enterprise / air‑gapped** | Полная поддержка | Требует доступа к BSR или приватного BSR | -| **Аутентификация** | Git (SSH / HTTPS) | Токены Buf + Git | -| **Vendor lock‑in** | Отсутствует | Привязка к экосистеме Buf | -| **Частные репозитории** | Нативно через Git | Нужно опубликовать в BSR | -| **Оффлайн поддержка** | Полная (через vendoring) | Ограничена (кэшированные модули) | -| **Стоимость** | Бесплатно (использует существующий Git) | Бесплатный тариф + платные планы | -| **Сложность настройки** | Минимальная | Средняя (настройка BSR) | - -## Подробное сравнение возможностей - -### 1. Философия управления зависимостями - -#### EasyP: «Любой Git репозиторий — это пакет» -```yaml -# Прямые ссылки на Git репозитории -deps: - - github.com/googleapis/googleapis@v1.2.3 - - gitlab.company.com/protos/internal@v2.0.1 - - git.example.com/team/shared-types@main -``` - -**Преимущества:** -- ✅ Использование любого существующего репозитория сразу -- ✅ Не нужно «публиковать» в отдельный реестр -- ✅ Истинный источник версий — Git -- ✅ Работает с приватными серверами без доп. настроек - -#### Buf: «Сначала реестр» -```yaml -# buf.yaml — ссылки только на модули BSR -version: v1 -deps: - - buf.build/googleapis/googleapis - - buf.build/grpc/grpc - - buf.build/envoyproxy/protoc-gen-validate -``` - -**Преимущества:** -- ✅ Курируемые, проверенные модули -- ✅ Богатые метаданные и документация -- ✅ Визуализация графа зависимостей -- ✅ Принуждение семантического версионирования - -**Ограничения:** -- ❌ Нужно опубликовать в BSR перед использованием -- ❌ Требует аккаунт и аутентификацию -- ❌ Нельзя напрямую сослаться на произвольный Git репозиторий - -### 2. Корпоративные и изолированные (air‑gapped) среды - -#### EasyP: Полноценная оффлайн‑поддержка - -**Сценарий**: крупная компания со строгими сетевыми политиками - -```bash -# 1. Среда с доступом в интернет -easyp mod download # Скачивает в ~/.easyp/ -easyp mod vendor # Создает easyp_vendor/ - -# 2. Перенос в изолированный сегмент -tar -czf easyp-deps.tar.gz ~/.easyp easyp_vendor/ -# ... перенос архива ... - -# 3. В изолированной среде -tar -xzf easyp-deps.tar.gz -export EASYPPATH=$PWD/.easyp -easyp generate # Работает оффлайн -``` - -**Плюсы:** -- ✅ Не зависит от внешних сервисов -- ✅ Не нужен внутренний реестр -- ✅ Использует существующую Git инфраструктуру -- ✅ Простая файловая дистрибуция - -#### Buf: Требует инфраструктуру реестра - -```bash -# Вариант 1: использовать buf.build (нужен интернет) -buf mod download - -# Вариант 2: поднимать приватный BSR (сложно) -# - Развернуть сервер реестра -# - Перепубликовать все модули внутрь -# - Настроить доступы, аутентификацию -# - Поддерживать работоспособность -``` - -**Минусы:** -- ❌ Постоянный интернет или дорогой приватный BSR -- ❌ Сложная инфраструктура для частных установок -- ❌ Все модули нужно републиковать -- ❌ Дополнительные операционные затраты - -### 3. Безопасность и контроль - -#### EasyP: Прямой контроль -```yaml -# Полный контроль источников -deps: - # Публичный репозиторий — ваша конкретная версия - - github.com/googleapis/googleapis@common-protos-1_3_1 - - # Внутренний репозиторий - - gitlab.company.com/security/validated-protos@v1.0.0 - - # Точный коммит (горячий фикс) - - github.com/bufbuild/protoc-gen-validate@abc123def456 -``` - -**Преимущества по безопасности:** -- ✅ Нет посредника — берём из исходного репозитория -- ✅ Аудит через историю Git -- ✅ Нельзя «забанить» доступ извне -- ✅ Свои процессы сканирования / валидации -- ✅ Можно форкнуть и удерживать критические версии - -#### Buf: Зависимость от реестра -```yaml -deps: - - buf.build/googleapis/googleapis - - buf.build/grpc/grpc -``` - -**Риски:** -- ⚠️ Посредник контролирует доступность -- ⚠️ Возможны ограничения / санкции на аккаунт -- ⚠️ Модуль могут удалить или депрекейтнуть -- ⚠️ Политики обновлений диктуются стороной -- ⚠️ Нужно доверять внешней безопасности - -### 4. Реальные сценарии - -#### Сценарий 1: Стартап с публичными зависимостями - -**EasyP:** -```yaml -deps: - - github.com/googleapis/googleapis - - github.com/grpc-ecosystem/grpc-gateway@v2.19.1 -``` - -**Buf:** -```yaml -deps: - - buf.build/googleapis/googleapis - - buf.build/grpcecosystem/grpc-gateway -``` - -**Итог:** Паритет — оба хорошо подходят для публичных пакетов. - -#### Сценарий 2: Компания со смешанными публичными/приватными зависимостями - -**EasyP:** -```yaml -deps: - - github.com/googleapis/googleapis@v1.2.3 - - github.com/mycompany/auth-protos@v2.0.0 - - gitlab.enterprise.com/platform/shared-types@v1.5.1 -``` - -**Buf:** -```yaml -deps: - - buf.build/googleapis/googleapis - - buf.build/mycompany/auth-protos - - buf.build/mycompany/shared-types -``` - -**Итог:** **EasyP** — не требует публикации внутрь BSR. - -#### Сценарий 3: Государственный / оборонный подрядчик (полный air‑gap) - -**EasyP:** -```bash -easyp mod vendor -# Архив → перенос → распаковка → generate (без сети) -``` - -**Buf:** -```bash -# Нужен приватный BSR с поддержкой полного оффлайна -# Сложный цикл публикации и обслуживания -``` - -**Итог:** **EasyP** — значительно проще. - -#### Сценарий 4: Комплаенс и аудит - -**EasyP:** -- ✅ Прямой аудит изменений (коммиты) -- ✅ Нет внешних точек зависимости в проде -- ✅ Повторяемость через фиксированные коммиты / vendor -- ✅ Управление уязвимостями — в ваших руках - -**Buf:** -- ⚠️ Нужно учитывать BSR в области аудита -- ⚠️ Дополнительный риск третьей стороны -- ⚠️ Модули — внешние контролируемые артефакты -- ⚠️ Сложнее трассировать от реестра к исходникам - -**Итог:** **EasyP** — проще для комплаенса. - -### 5. Стоимость и инфраструктура - -#### EasyP: Нулевая дополнительная инфраструктура - -**Затраты:** -- ✅ $0 — используете существующий Git -- ✅ Нет дополнительных сервисов/серверов -- ✅ Нет лицензирования -- ✅ Масштабирование в рамках Git - -**Инфраструктура:** -- Использует текущие репозитории (GitHub/GitLab/и т.д.) -- Аутентификация — штатная -- Резервирование/DR — как уже настроено для Git - -#### Buf: Затраты на реестр - -**Hosted BSR (buf.build):** -- ✅ Бесплатный уровень -- ❌ Платные тарифы для приватного и расширенного использования -- ❌ Потенциальные изменения ценовой политики -- ❌ Вопросы локализации данных - -**Приватный BSR:** -- ❌ Серверы, БД, балансировка -- ❌ Мониторинг, обновления, бэкапы -- ❌ Лицензирование enterprise функционала -- ❌ Доп. планирование отказоустойчивости - -### 6. Миграция и lock‑in - -#### EasyP: Нет привязки - -**Миграция ИЗ EasyP:** -```yaml -deps: - - github.com/googleapis/googleapis@v1.2.3 +```text +# protobuf.mod потребителя +module github.com/acme/service +roots proto +require github.com/acme/buf-contracts v1.2.0 ``` -(Обычные Git ссылки — легко перенести в другой инструмент.) -**Миграция В EasyP:** ```bash -# Просто указываете те же Git репозитории -``` - -#### Buf: Потенциальный lock‑in - -**Миграция ИЗ Buf:** -- ❌ Нужно сопоставить BSR модули с исходными Git репо -- ❌ Имена модулей BSR не совпадают с URL -- ❌ Возможна потеря удобных метаданных -- ❌ Сложно при глубокой интеграции с BSR - -**Миграция В Buf:** -- ❌ Нужно опубликовать всё в BSR -- ❌ Нельзя ссылаться напрямую на Git -- ❌ Принять workflow BSR (push/pull модулей) - -## Когда выбирать каждое решение - -### Выберите EasyP, если: - -✅ **Air‑gapped / закрытые среды** -- Нужна работа без внешних сервисов -- Строгий комплаенс / контроль цепочки поставок - -✅ **Фокус на безопасности** -- Контроль источников зависимостей -- Минимизация рисков третьих сторон - -✅ **Git‑центричная культура** -- Частные репозитории — норма -- Не хотите добавлять новый ключевой сервис - -✅ **Ограниченный бюджет** -- Минимизация операционных расходов -- Предсказуемая стоимость = 0 - -✅ **Смешанные публичные/частные зависимости** -- Не хотите перекладывать всё в реестр -- Нужна гибкость форматов и размещения - -### Выберите Buf, если: - -✅ **Глубокая интеграция в экосистему BSR** -- Уже используете линтеры / генерацию Buf -- Нужны курируемые официальные модули -- Важны метаданные и граф зависимостей - -✅ **Сотрудничество и открытая разработка** -- Централизованное обнаружение модулей -- Совместная работа над общими пакетами - -✅ **Команда новичков в protobuf** -- Требуется «направляющая» структура -- Ценность документации внутри реестра - -✅ **Небольшой набор публичных зависимостей** -- В основном используете популярные общие пакеты -- Вас устраивает зависимость от BSR - -## Пути миграции - -### Переход с Buf на EasyP - -1. Найдите исходные Git репозитории для каждого модуля BSR -2. Сопоставьте имена BSR → Git ссылки (с версиями/тегами) -3. Обновите конфигурацию (`easyp.yaml`) -4. Протестируйте генерацию и совместимость - -```yaml -# Было (buf.yaml) -deps: - - buf.build/googleapis/googleapis - - buf.build/grpc/grpc - -# Стало (easyp.yaml) -deps: - - github.com/googleapis/googleapis@common-protos-1_3_1 - - github.com/grpc/grpc@v1.50.0 +easyp mod tidy +easyp mod download +easyp generate ``` -### Переход с EasyP на Buf - -1. Опубликуйте используемые репозитории как модули BSR -2. Настройте аутентификацию / организацию Buf -3. Замените Git ссылки на BSR модули -4. Перейдите к push/pull workflow Buf - -## Заключение - -Оба инструмента решают задачу управления зависимостями protobuf, но подходят под разные приоритеты: - -**Сильные стороны EasyP:** -- Корпоративные / изолированные среды -- Жёсткие требования безопасности и аудита -- Минимальные затраты и отсутствие доп. инфраструктуры -- Прямое использование Git (без промежуточного слоя) -- Простота масштабирования - -**Сильные стороны Buf:** -- Богатая экосистема вокруг реестра -- Курируемые и документированные модули -- Удобство для новых команд в protobuf -- Средства визуализации и централизованного обмена - -Выбор часто сводится к балансу между **контролем vs. удобством**, **безопасностью vs. централизованными функциями**, и **стоимостью vs. managed‑сервисом**. +`mod tidy` разрешает Git-зависимость и записывает выбранный коммит и хеш содержимого в `protobuf.lock`. Имена зависимостей Buf Registry не превращаются в Git URL автоматически: подходящий Git-источник надо объявить в манифесте потребителя. Фильтры Buf include/exclude для корней Git-зависимостей пока не поддерживаются и вызывают ошибку. -Для большинства enterprise‑окружений децентрализованный Git‑подход EasyP обеспечивает нужные гибкость, безопасность и предсказуемость расходов, тогда как Buf отлично подходит командам, которым важна централизованная коллаборация и богатая экосистема вокруг реестра. +В пилотной версии v1 нет `mod vendor`. Поддерживаемые команды перечислены в [руководстве менеджера пакетов](/ru/docs/cli/package-manager). diff --git a/content/docs/cli/package-manager/index.mdx b/content/docs/cli/package-manager/index.mdx index 2b77bc9..b56478f 100644 --- a/content/docs/cli/package-manager/index.mdx +++ b/content/docs/cli/package-manager/index.mdx @@ -1,554 +1,44 @@ --- title: "Package Manager" +description: "Resolve and lock Git-based protobuf dependencies in EasyP v1." --- -[[toc]] +The v1 package manager reads `protobuf.mod` and writes `protobuf.lock`. It records each selected Git commit and an `h1:` content hash, then verifies the hash when downloading or reusing a cached module. -EasyP provides a powerful package manager for protobuf dependencies that simplifies dependency management through a decentralized, Git-based approach. Unlike centralized solutions, EasyP works directly with Git repositories, giving you complete control over your dependencies. +## Declare dependencies -## Overview +```text +module github.com/acme/contracts +roots proto -The EasyP package manager follows the **Go modules philosophy** - any Git repository can serve as a package source. This approach provides several key advantages: - -- **Decentralized**: No single point of failure or control -- **Security**: Direct access to source repositories -- **Flexibility**: Support for public, private, and enterprise repositories -- **Reproducibility**: Lock files ensure consistent builds across environments -- **Performance**: Local caching minimizes network requests - -### Key Features - -| Feature | Description | -|---------|-------------| -| **Git-Native** | Works with any Git repository - no special server required | -| **Multiple Version Formats** | Tags, commits, pseudo-versions, latest | -| **Lock Files** | Reproducible builds with `easyp.lock` | -| **Local Caching** | Go modules-style cache architecture | -| **Vendoring Support** | Copy dependencies locally for offline builds | -| **YAML Configuration** | Simple, readable dependency declarations | - -## Architecture - -EasyP uses a two-tier caching system inspired by Go modules: - -``` -~/.easyp/ -├── cache/ -│ ├── download/ # Downloaded archives + checksums -│ │ └── github.com/ -│ │ └── googleapis/ -│ │ └── googleapis/ -│ │ ├── v1.2.3.zip # Archive -│ │ ├── v1.2.3.ziphash # Checksum -│ │ └── v1.2.3.info # Metadata -│ └── {git-hash}/ # Git bare repositories (internal) -└── mod/ # Extracted, ready-to-use modules - └── github.com/ - └── googleapis/ - └── googleapis/ - ├── v1.2.3/ # Tagged version - │ ├── google/ - │ │ ├── api/ - │ │ └── rpc/ - │ └── ... - └── v0.0.0-20250101123456-abc123def/ # Pseudo-version - ├── google/ - └── ... -``` - -### Cache Location - -| Environment | Location | How to Set | -|-------------|----------|------------| -| **Default** | `$HOME/.easyp` | Automatic | -| **Custom** | Any directory | Set `EASYPPATH` environment variable | -| **CI/CD** | Project-relative | `export EASYPPATH=$CI_PROJECT_DIR/.easyp` | - -## Configuration - -### Basic Configuration - -Configure dependencies in your `easyp.yaml` file: - -```yaml -deps: - - github.com/googleapis/googleapis@common-protos-1_3_1 - - github.com/grpc-ecosystem/grpc-gateway@v2.19.1 - - github.com/bufbuild/protoc-gen-validate -``` - -### Advanced Configuration Examples - -#### Multi-Environment Setup -```yaml -# development.easyp.yaml -deps: - - github.com/googleapis/googleapis # Latest for development - - github.com/mycompany/internal-protos # Latest internal changes - - github.com/bufbuild/protoc-gen-validate # Latest features - -# production.easyp.yaml -deps: - - github.com/googleapis/googleapis@common-protos-1_3_1 # Pinned - - github.com/mycompany/internal-protos@v2.1.0 # Stable release - - github.com/bufbuild/protoc-gen-validate@v0.10.1 # Tested version -``` - -#### Private Repository Setup -```yaml -deps: - # Public dependencies - - github.com/googleapis/googleapis@common-protos-1_3_1 - - # Private company repositories - - github.com/mycompany/auth-protos@v1.5.0 - - github.com/mycompany/common-types@v2.0.1 - - # Internal GitLab - - gitlab.company.com/platform/messaging-protos@v0.3.0 -``` - -## Versioning Strategies - -EasyP supports multiple versioning approaches to fit different development workflows: - -### 1. Semantic Version Tags (Recommended for Production) - -```yaml -deps: - - github.com/grpc-ecosystem/grpc-gateway@v2.19.1 - - github.com/googleapis/googleapis@common-protos-1_3_1 -``` - -**Use when:** -- Production deployments -- Stable API consumption -- Reproducible builds required - -### 2. Latest Tag (Development) - -```yaml -deps: - - github.com/googleapis/googleapis # Uses latest available tag - - github.com/bufbuild/protoc-gen-validate -``` - -**Use when:** -- Active development -- Want latest features -- Compatibility testing - -### 3. Commit Hashes (Bleeding Edge) - -```yaml -deps: - - github.com/bufbuild/protoc-gen-validate@abc123def456789abcdef123456789abcdef1234 +require ( + github.com/acme/shared v1.2.0 + github.com/acme/weather v2.1.0 +) ``` -**Use when:** -- Need unreleased features -- Testing specific fixes -- Contributing to upstream - -### 4. Pseudo-Versions (Automatic) - -When EasyP can't find a suitable tag, it generates pseudo-versions automatically: - -``` -Format: v0.0.0-{timestamp}-{short-commit-hash} -Example: v0.0.0-20250908104020-660ec2d64e07f2fa8947527443af058b3d7169df -``` - -This ensures every commit can be referenced with a version-like identifier. +`roots` defaults to `.` when omitted. Requirements use semantic versions. `replace module => ../local-copy` points generation and linting at a local checkout. Remove local replacements before writing a reproducible lock with `mod tidy` or `mod update`. ## Commands -### `easyp mod download` - -Downloads and installs all dependencies declared in your configuration. - -**What happens:** -1. **Resolves versions**: Converts tags/latest to specific commits -2. **Downloads archives**: Stores `.zip` files in cache/download -3. **Verifies checksums**: Ensures archive integrity -4. **Extracts modules**: Unpacks to cache/mod with proper structure -5. **Updates lock file**: Records exact versions and content hashes - -**Usage:** -```bash -# Use default easyp.yaml -easyp mod download - -# Use custom config file -easyp --cfg production.easyp.yaml mod download - -# With custom cache location -EASYPPATH=/tmp/easyp-cache easyp mod download -``` - -**Example output:** -``` -INFO Download package package=github.com/googleapis/googleapis version=v0.0.0-20250909114430 commit=8727b5ba -INFO Install package package=github.com/googleapis/googleapis version=v0.0.0-20250909114430 commit=8727b5ba -INFO Download package package=github.com/grpc-ecosystem/grpc-gateway version=v2.19.1 commit=a070de73 -INFO Install package package=github.com/grpc-ecosystem/grpc-gateway version=v2.19.1 commit=a070de73 -``` - -### `easyp mod vendor` - -Copies all installed proto files to a local `easyp_vendor/` directory for offline usage. - -**Use cases:** -- **Docker builds**: Avoid network dependencies in containers -- **Air-gapped environments**: No internet access during builds -- **Reproducible builds**: Bundle exact dependency versions -- **Performance**: Eliminate network latency in repeated builds - -**Usage:** -```bash -easyp mod vendor -``` - -**Result structure:** -``` -easyp_vendor/ -├── github.com/ -│ ├── googleapis/ -│ │ └── googleapis/ -│ │ ├── google/ -│ │ │ ├── api/ -│ │ │ │ ├── annotations.proto -│ │ │ │ └── http.proto -│ │ │ └── rpc/ -│ │ │ └── status.proto -│ │ └── ... -│ └── grpc-ecosystem/ -│ └── grpc-gateway/ -│ └── protoc-gen-openapiv2/ -│ └── options/ -│ └── annotations.proto -``` - -### `easyp mod update` - -Updates module versions based on current configuration and writes resolved versions to the lock file. - -**Behavior:** -- Respects version constraints in `easyp.yaml` -- Updates to latest compatible versions -- Regenerates `easyp.lock` with new versions and hashes - -**Usage:** -```bash -easyp mod update -``` - -## Lock Files - -The `easyp.lock` file ensures reproducible builds by recording exact versions and content hashes: - -``` -github.com/bufbuild/protoc-gen-validate v0.0.0-20250908104020-660ec2d64e07f2fa8947527443af058b3d7169df h1:ZZ5JyUkmrj9OBHM+gOCzeL5L/pAKVbsUl051yhhJTjU= -github.com/googleapis/googleapis v0.0.0-20250909114430-8727b5ba7f23fbbfddda58239e8bc6b547e05878 h1:eI+XYpPio3fxl9H5/VjW2PxlxM/7yqPjEq3oQ6jUkj4= -github.com/grpc-ecosystem/grpc-gateway v2.19.1 h1:01NNlCezvwUQ07ZvblXH0kelWq8hNl2qb44bOMcaSTQ= -``` - -### Lock File Format - -Each line contains three components: -- **Module path**: Full repository path -- **Exact version**: Resolved version (tag or pseudo-version) -- **Content hash**: SHA256 of extracted content (`h1:` prefix) - -### Best Practices - -✅ **Always commit `easyp.lock`** - Ensures team consistency -✅ **Run `mod update` deliberately** - Don't auto-update in CI -✅ **Review lock changes** - Understand what's being updated -❌ **Don't edit manually** - Let EasyP manage the format - -## Authentication - -### Public Repositories - -No setup required - works out of the box: - -```yaml -deps: - - github.com/googleapis/googleapis - - github.com/bufbuild/protoc-gen-validate -``` - -### Private Repositories - -#### SSH Keys (Recommended) - -Configure Git to use SSH for GitHub/GitLab: - -```bash -# For GitHub -git config --global url."git@github.com:".insteadOf "https://github.com/" - -# For GitLab -git config --global url."git@gitlab.com:".insteadOf "https://gitlab.com/" - -# For custom domains -git config --global url."git@gitlab.company.com:".insteadOf "https://gitlab.company.com/" -``` - -Then use normal HTTPS URLs in your config: - -```yaml -deps: - - github.com/mycompany/private-protos@v1.0.0 - - gitlab.company.com/platform/shared-types@v2.1.0 -``` - -#### Personal Access Tokens - -For HTTPS authentication: - -```bash -# Method 1: Credential helper -git config --global credential.helper store -echo "https://username:token@github.com" >> ~/.git-credentials - -# Method 2: URL rewriting -git config --global url."https://username:token@github.com/mycompany".insteadOf "https://github.com/mycompany" -``` - -#### Corporate Environments +| Command | Behavior | +|---------|----------| +| `easyp mod tidy` | Resolves direct and transitive requirements and writes `protobuf.lock` | +| `easyp mod download` | Downloads the exact commits in `protobuf.lock` and verifies their hashes | +| `easyp mod update` | Refreshes requirements within their current major versions, then updates the lock | ```bash -# Configure proxy -git config --global http.proxy http://proxy.company.com:8080 -git config --global https.proxy https://proxy.company.com:8080 - -# Configure certificates for internal Git servers -git config --global http.sslCAInfo /path/to/certificate.pem -``` - -## Common Workflows - -### Initial Project Setup - -```bash -# 1. Create configuration -cat > easyp.yaml << EOF -deps: - - github.com/googleapis/googleapis - - github.com/grpc-ecosystem/grpc-gateway@v2.19.1 -EOF - -# 2. Download dependencies +easyp mod tidy easyp mod download - -# 3. Verify installation -ls ~/.easyp/mod/github.com/googleapis/googleapis/ -``` - -### Adding New Dependencies - -```bash -# 1. Edit easyp.yaml -echo " - github.com/bufbuild/protoc-gen-validate@v0.10.1" >> easyp.yaml - -# 2. Download new dependency -easyp mod download - -# 3. Commit lock file changes -git add easyp.lock -git commit -m "Add protoc-gen-validate dependency" -``` - -### Updating Dependencies - -```bash -# Update to latest compatible versions -easyp mod update - -# Review changes -git diff easyp.lock - -# Test with new versions easyp generate -easyp lint - -# Commit if everything works -git add easyp.lock -git commit -m "Update dependencies" ``` -### Offline Development - -```bash -# Vendor all dependencies -easyp mod vendor - -# Now your project works offline -easyp generate -``` - -## Troubleshooting - -### Common Issues - -#### "Repository not found" or "Authentication failed" - -**Problem**: Can't access private repository -**Solution**: Check authentication setup - -```bash -# Test Git access -git ls-remote https://github.com/mycompany/private-repo - -# Check Git configuration -git config --list | grep url -``` - -#### "Version not found" - -**Problem**: Specified tag/version doesn't exist -**Solution**: Check available tags - -```bash -# List available tags -git ls-remote --tags https://github.com/googleapis/googleapis - -# Use existing tag or commit hash -deps: - - github.com/googleapis/googleapis@common-protos-1_3_1 # Valid tag -``` - -#### "Cache corruption" or "Checksum mismatch" - -**Problem**: Corrupted cache files -**Solution**: Clear cache and re-download - -```bash -# Clear everything -rm -rf ~/.easyp - -# Or clear just downloads -rm -rf ~/.easyp/cache/download - -# Re-download -easyp mod download -``` - -#### Network timeouts - -**Problem**: Slow or unreliable network -**Solution**: Configure Git timeouts - -```bash -# Increase timeout -git config --global http.lowSpeedLimit 1000 -git config --global http.lowSpeedTime 300 - -# Use proxy if available -git config --global http.proxy http://proxy.company.com:8080 -``` - -### Performance Optimization - -#### For Large Teams - -```bash -# Use shared cache server (if available) -export EASYPPATH=/shared/easyp-cache - -# Or use team-specific cache -export EASYPPATH=/team-cache/easyp -``` - -#### For CI/CD Systems - -```bash -# Use project-relative cache -export EASYPPATH=$CI_PROJECT_DIR/.easyp - -# Cache between builds (GitLab CI example) -cache: - key: easyp-$CI_COMMIT_REF_SLUG - paths: - - .easyp/ -``` - -#### Cache Size Management - -```bash -# Check cache usage -du -sh ~/.easyp -du -sh ~/.easyp/cache/download # Archives only -du -sh ~/.easyp/mod # Extracted modules - -# Clean old versions (manual) -find ~/.easyp/mod -type d -name "v0.0.0-*" -mtime +30 -exec rm -rf {} \; -``` - -## Integration Examples - -### Docker Multi-stage Build - -```dockerfile -# Stage 1: Download dependencies -FROM ghcr.io/easyp-tech/easyp:latest AS deps -WORKDIR /workspace -COPY easyp.yaml easyp.lock ./ -RUN easyp mod vendor - -# Stage 2: Build application -FROM alpine:latest AS build -WORKDIR /app -COPY --from=deps /workspace/easyp_vendor ./easyp_vendor -COPY . . -# Use vendored dependencies for generation -RUN easyp generate -``` - -### Monorepo Structure - -``` -my-monorepo/ -├── services/ -│ ├── auth-service/ -│ │ └── easyp.yaml # Service-specific deps -│ └── user-service/ -│ └── easyp.yaml # Different deps -├── shared/ -│ └── common-protos/ # Internal protos -└── easyp.yaml # Global/shared deps -``` - -Each `easyp.yaml` can have different dependencies based on service needs. - -## Best Practices - -### Development Workflow -- ✅ Use **latest tags** during active development -- ✅ **Pin versions** for production deployments -- ✅ **Commit lock files** to ensure reproducibility -- ✅ **Review dependency updates** before merging -- ✅ **Test after updates** to catch compatibility issues +Commit `protobuf.mod` and `protobuf.lock` for repeatable builds. The module cache is under `$HOME/.easyp/v1/git` by default; set `EASYPPATH` to change its parent directory. The v1 pilot does not have `mod vendor`. -### Security -- ✅ **Pin to specific versions** in production -- ✅ **Use SSH keys** for private repositories -- ✅ **Review new dependencies** for security implications -- ✅ **Monitor for vulnerabilities** in dependencies -- ❌ **Don't embed credentials** in configuration files +## Dependencies using Buf or older EasyP -### Performance -- ✅ **Cache aggressively** in CI/CD systems -- ✅ **Use vendoring** for frequently rebuilt projects -- ✅ **Clean old cache** periodically to save space -- ✅ **Use shared cache** for team environments +A Git dependency may declare its proto roots in `buf.work.yaml`, Buf v1 or v2 `buf.yaml`, or an older EasyP `easyp.yaml`. Older EasyP `protobuf.mod` requirements are also read transitively. If none of those files exists, its repository root is used. This compatibility applies to dependency metadata; the consuming project uses v1 `protobuf.mod`. -### Team Collaboration -- ✅ **Document authentication setup** for new team members -- ✅ **Use consistent tooling** across environments -- ✅ **Automate dependency updates** with proper testing -- ✅ **Share cache locations** when possible +Buf Registry dependencies have no automatic Git identity. Declare the corresponding Git module in the consuming `protobuf.mod` when those imports are needed. Buf include/exclude filters are not supported as Git import roots and produce an explicit error. -The EasyP package manager provides a robust, decentralized solution for protobuf dependency management that scales from individual projects to enterprise environments while maintaining the simplicity and reliability developers expect. +See [`protobuf.mod`](/docs/reference/protobuf-mod) and [`protobuf.lock`](/docs/reference/protobuf-lock) for their field-level formats. diff --git a/content/docs/cli/package-manager/index.ru.mdx b/content/docs/cli/package-manager/index.ru.mdx index 653b7bc..d2f74a8 100644 --- a/content/docs/cli/package-manager/index.ru.mdx +++ b/content/docs/cli/package-manager/index.ru.mdx @@ -1,460 +1,44 @@ --- title: "Менеджер пакетов" +description: "Разрешение и фиксация Git-зависимостей protobuf в EasyP v1." --- -[[toc]] +Менеджер пакетов v1 читает `protobuf.mod` и записывает `protobuf.lock`. Для каждого выбранного модуля lock содержит точный Git-коммит и хеш содержимого `h1:`. Хеш проверяется при скачивании и повторном использовании кеша. -EasyP предоставляет мощный менеджер пакетов для protobuf‑зависимостей, упрощающий их управление за счёт децентрализованного подхода на базе Git. В отличие от централизованных решений, EasyP работает напрямую с Git‑репозиториями, давая вам полный контроль. +## Объявление зависимостей -## Обзор +```text +module github.com/acme/contracts +roots proto -Менеджер пакетов EasyP следует философии **Go modules** — любой Git‑репозиторий может быть источником. Это даёт преимущества: - -- **Децентрализация** — нет единой точки отказа или контроля -- **Безопасность** — прямой доступ к исходникам -- **Гибкость** — публичные, приватные и корпоративные репозитории -- **Воспроизводимость** — lock‑файлы обеспечивают одинаковые сборки -- **Производительность** — локальный кеш сокращает сетевые запросы - -### Основные возможности - -| Возможность | Описание | -|-------------|----------| -| **Git-Native** | Любой Git репозиторий, не нужен спец‑сервер | -| **Множество форматов версий** | Теги, коммиты, псевдо‑версии, latest | -| **Lock Files** | Воспроизводимые сборки через `easyp.lock` | -| **Локальный кеш** | Архитектура как у Go modules | -| **Vendoring** | Локальное копирование для оффлайн сборок | -| **YAML конфигурация** | Простые и читаемые декларации | - -## Архитектура - -EasyP использует двухуровневый кеш, вдохновлённый Go modules: - -``` -~/.easyp/ -├── cache/ -│ ├── download/ # Архивы + контрольные суммы -│ │ └── github.com/ -│ │ └── googleapis/ -│ │ └── googleapis/ -│ │ ├── v1.2.3.zip # Архив -│ │ ├── v1.2.3.ziphash # Checksum -│ │ └── v1.2.3.info # Метаданные -│ └── {git-hash}/ # Bare репозитории Git (внутренне) -└── mod/ # Распакованные готовые модули - └── github.com/ - └── googleapis/ - └── googleapis/ - ├── v1.2.3/ # Тегированная версия - │ ├── google/ - │ │ ├── api/ - │ │ └── rpc/ - │ └── ... - └── v0.0.0-20250101123456-abc123def/ # Псевдо‑версия - ├── google/ - └── ... -``` - -### Расположение кеша - -| Окружение | Путь | Как задать | -|-----------|------|-----------| -| **По умолчанию** | `$HOME/.easyp` | Автоматически | -| **Свое** | Любая директория | Переменная `EASYPPATH` | -| **CI/CD** | В каталоге проекта | `export EASYPPATH=$CI_PROJECT_DIR/.easyp` | - -## Конфигурация - -### Базовая конфигурация - -Зависимости описываются в `easyp.yaml`: - -```yaml -deps: - - github.com/googleapis/googleapis@common-protos-1_3_1 - - github.com/grpc-ecosystem/grpc-gateway@v2.19.1 - - github.com/bufbuild/protoc-gen-validate -``` - -### Расширенные примеры - -#### Multi-Environment Setup -```yaml -# development.easyp.yaml -deps: - - github.com/googleapis/googleapis # Последнее для разработки - - github.com/mycompany/internal-protos # Внутренние изменения - - github.com/bufbuild/protoc-gen-validate # Новые фичи - -# production.easyp.yaml -deps: - - github.com/googleapis/googleapis@common-protos-1_3_1 # Зафиксировано - - github.com/mycompany/internal-protos@v2.1.0 # Стабильно - - github.com/bufbuild/protoc-gen-validate@v0.10.1 # Проверено -``` - -#### Приватные репозитории -```yaml -deps: - # Публичное - - github.com/googleapis/googleapis@common-protos-1_3_1 - - # Частные - - github.com/mycompany/auth-protos@v1.5.0 - - github.com/mycompany/common-types@v2.0.1 - - # Внутренний GitLab - - gitlab.company.com/platform/messaging-protos@v0.3.0 -``` - -## Стратегии версионирования - -Поддерживаются разные способы фиксации версий: - -### 1. Семантические теги (для продакшена) - -```yaml -deps: - - github.com/grpc-ecosystem/grpc-gateway@v2.19.1 - - github.com/googleapis/googleapis@common-protos-1_3_1 +require ( + github.com/acme/shared v1.2.0 + github.com/acme/weather v2.1.0 +) ``` -**Используйте когда:** -- Продакшен -- Стабильное потребление API -- Нужна воспроизводимость - -### 2. Последний тег (development) - -```yaml -deps: - - github.com/googleapis/googleapis - - github.com/bufbuild/protoc-gen-validate -``` - -**Подходит для:** -- Активной разработки -- Получения свежих возможностей -- Тестирования совместимости - -### 3. Хеш коммита (Bleeding Edge) - -```yaml -deps: - - github.com/bufbuild/protoc-gen-validate@abc123def456789abcdef123456789abcdef1234 -``` - -**Когда нужно:** -- Нерелизные фичи -- Тест конкретного фикса -- Вклад в upstream - -### 4. Псевдо‑версии (автоматически) - -Если нет подходящего тега — создаётся псевдо‑версия: - -``` -Формат: v0.0.0-{timestamp}-{short-commit-hash} -Пример: v0.0.0-20250908104020-660ec2d64e07f2fa8947527443af058b3d7169df -``` +Если `roots` не указан, используется `.`. Требования задаются семантическими версиями. `replace module => ../local-copy` направляет генерацию и линтинг на локальный каталог. Перед записью воспроизводимого lock через `mod tidy` или `mod update` локальные замены нужно убрать. ## Команды -### `easyp mod download` - -Скачивает и устанавливает все объявленные зависимости. +| Команда | Поведение | +|---------|-----------| +| `easyp mod tidy` | Разрешает прямые и транзитивные требования и записывает `protobuf.lock` | +| `easyp mod download` | Скачивает точные коммиты из lock и проверяет хеши | +| `easyp mod update` | Обновляет требования в пределах текущих мажорных версий и пересоздаёт lock | -**Что делает:** -1. Разрешает версии (теги → коммиты) -2. Скачивает архивы в `cache/download` -3. Проверяет контрольные суммы -4. Распаковывает в `cache/mod` -5. Обновляет `easyp.lock` - -**Пример:** ```bash +easyp mod tidy easyp mod download -easyp --cfg production.easyp.yaml mod download -EASYPPATH=/tmp/easyp-cache easyp mod download -``` - -### `easyp mod vendor` - -Копирует все proto зависимости в локальный `easyp_vendor/` для оффлайна. - -**Сценарии:** -- Docker сборки -- Air-gapped окружения -- Воспроизводимость -- Ускорение - -```bash -easyp mod vendor -``` - -Структура: -``` -easyp_vendor/ -├── github.com/ -│ ├── googleapis/ -│ │ └── googleapis/ -│ │ ├── google/ -│ │ │ ├── api/ -│ │ │ │ ├── annotations.proto -│ │ │ │ └── http.proto -│ │ │ └── rpc/ -│ │ │ └── status.proto -│ │ └── ... -│ └── grpc-ecosystem/ -│ └── grpc-gateway/ -│ └── protoc-gen-openapiv2/ -│ └── options/ -│ └── annotations.proto -``` - -### `easyp mod update` - -Обновляет версии согласно `easyp.yaml`, пересоздаёт lock. - -```bash -easyp mod update -``` - -## Lock файл - -`easyp.lock` фиксирует точные версии и хеш содержимого: - -``` -github.com/bufbuild/protoc-gen-validate v0.0.0-20250908104020-660ec2d64e07f2fa8947527443af058b3d7169df h1:ZZ5JyUkmrj9OBHM+gOCzeL5L/pAKVbsUl051yhhJTjU= -github.com/googleapis/googleapis v0.0.0-20250909114430-8727b5ba7f23fbbfddda58239e8bc6b547e05878 h1:eI+XYpPio3fxl9H5/VjW2PxlxM/7yqPjEq3oQ6jUkj4= -github.com/grpc-ecosystem/grpc-gateway v2.19.1 h1:01NNlCezvwUQ07ZvblXH0kelWq8hNl2qb44bOMcaSTQ= -``` - -**Формат строки:** -- Путь модуля -- Версия (тег или псевдо) -- Хеш содержимого (`h1:`) - -**Практики:** -✅ Коммитить `easyp.lock` -✅ Осознанно обновлять `mod update` -✅ Ревью изменений версий -❌ Не редактировать вручную - -## Аутентификация - -### Публичные репозитории - -Работают без настроек: - -```yaml -deps: - - github.com/googleapis/googleapis - - github.com/bufbuild/protoc-gen-validate -``` - -### Приватные репозитории - -#### SSH ключи (рекомендуется) - -```bash -git config --global url."git@github.com:".insteadOf "https://github.com/" -git config --global url."git@gitlab.com:".insteadOf "https://gitlab.com/" -git config --global url."git@gitlab.company.com:".insteadOf "https://gitlab.company.com/" -``` - -Конфиг остаётся с HTTPS URL: - -```yaml -deps: - - github.com/mycompany/private-protos@v1.0.0 - - gitlab.company.com/platform/shared-types@v2.1.0 -``` - -#### Personal Access Tokens - -```bash -git config --global credential.helper store -echo "https://username:token@github.com" >> ~/.git-credentials - -git config --global url."https://username:token@github.com/mycompany".insteadOf "https://github.com/mycompany" -``` - -#### Корпоративная среда - -```bash -git config --global http.proxy http://proxy.company.com:8080 -git config --global https.proxy https://proxy.company.com:8080 -git config --global http.sslCAInfo /path/to/certificate.pem -``` - -## Типовые workflows - -### Инициализация проекта - -```bash -cat > easyp.yaml << EOF -deps: - - github.com/googleapis/googleapis - - github.com/grpc-ecosystem/grpc-gateway@v2.19.1 -EOF - -easyp mod download -ls ~/.easyp/mod/github.com/googleapis/googleapis/ -``` - -### Добавление зависимости - -```bash -echo " - github.com/bufbuild/protoc-gen-validate@v0.10.1" >> easyp.yaml -easyp mod download -git add easyp.lock -git commit -m "Add protoc-gen-validate dependency" -``` - -### Обновление - -```bash -easyp mod update -git diff easyp.lock -easyp generate -easyp lint -git add easyp.lock -git commit -m "Update dependencies" -``` - -### Оффлайн режим - -```bash -easyp mod vendor easyp generate ``` -## Troubleshooting - -### Частые проблемы - -#### "Repository not found" / "Authentication failed" - -```bash -git ls-remote https://github.com/mycompany/private-repo -git config --list | grep url -``` - -#### "Version not found" - -```bash -git ls-remote --tags https://github.com/googleapis/googleapis -# Проверить корректный тег -deps: - - github.com/googleapis/googleapis@common-protos-1_3_1 -``` - -#### "Cache corruption" / "Checksum mismatch" - -```bash -rm -rf ~/.easyp -rm -rf ~/.easyp/cache/download -easyp mod download -``` - -#### Тайм-ауты сети - -```bash -git config --global http.lowSpeedLimit 1000 -git config --global http.lowSpeedTime 300 -git config --global http.proxy http://proxy.company.com:8080 -``` - -### Оптимизация - -#### Для больших команд - -```bash -export EASYPPATH=/shared/easyp-cache -export EASYPPATH=/team-cache/easyp -``` - -#### Для CI/CD - -```bash -export EASYPPATH=$CI_PROJECT_DIR/.easyp -# Пример кеширования (GitLab CI) -cache: - key: easyp-$CI_COMMIT_REF_SLUG - paths: - - .easyp/ -``` - -#### Управление размером кеша - -```bash -du -sh ~/.easyp -du -sh ~/.easyp/cache/download -du -sh ~/.easyp/mod -find ~/.easyp/mod -type d -name "v0.0.0-*" -mtime +30 -exec rm -rf {} \; -``` - -## Примеры интеграции - -### Docker multi-stage - -```dockerfile -FROM ghcr.io/easyp-tech/easyp:latest AS deps -WORKDIR /workspace -COPY easyp.yaml easyp.lock ./ -RUN easyp mod vendor - -FROM alpine:latest AS build -WORKDIR /app -COPY --from=deps /workspace/easyp_vendor ./easyp_vendor -COPY . . -RUN easyp generate -``` - -### Monorepo - -``` -my-monorepo/ -├── services/ -│ ├── auth-service/ -│ │ └── easyp.yaml -│ └── user-service/ -│ └── easyp.yaml -├── shared/ -│ └── common-protos/ -└── easyp.yaml -``` - -Каждый `easyp.yaml` может иметь свой набор зависимостей. - -## Лучшие практики - -### Workflow разработки -- ✅ Latest теги в активной разработке -- ✅ Фиксация версий в продакшене -- ✅ Коммит lock файла -- ✅ Ревью обновлений -- ✅ Тест после обновления +Храните `protobuf.mod` и `protobuf.lock` в репозитории для воспроизводимой сборки. Кеш по умолчанию расположен в `$HOME/.easyp/v1/git`; переменная `EASYPPATH` меняет его родительский каталог. Команды `mod vendor` в пилотной версии v1 нет. -### Безопасность -- ✅ Фиксируйте версии -- ✅ Используйте SSH ключи -- ✅ Оценивайте новые зависимости -- ✅ Следите за уязвимостями -- ❌ Не храните секреты в конфиге +## Зависимости на Buf или старом EasyP -### Производительность -- ✅ Агрессивное кеширование в CI -- ✅ Vendoring для частых сборок -- ✅ Чистка старого кеша -- ✅ Общий кеш для команды +Git-зависимость может объявлять корни `.proto` через `buf.work.yaml`, Buf v1/v2 `buf.yaml` или старый EasyP `easyp.yaml`. Транзитивные требования из старого EasyP `protobuf.mod` также читаются. Если ни одного такого файла нет, корнем считается каталог репозитория. Совместимость относится к метаданным зависимости; проект-потребитель использует v1 `protobuf.mod`. -### Командная работа -- ✅ Документация по аутентификации -- ✅ Единые инструменты -- ✅ Автоматизация обновлений с тестами -- ✅ Общий кеш при возможности +Зависимости Buf Registry не имеют автоматического Git-идентификатора. Если их импорты нужны, объявите соответствующий Git-модуль в `protobuf.mod` потребителя. Фильтры Buf include/exclude для корней Git-зависимостей пока не поддерживаются и вызывают явную ошибку. -Менеджер пакетов EasyP — масштабируемое децентрализованное решение от одиночных проектов до enterprise, сохраняя простоту и надёжность. +Форматы полей описаны в справочниках [`protobuf.mod`](/ru/docs/reference/protobuf-mod) и [`protobuf.lock`](/ru/docs/reference/protobuf-lock). diff --git a/content/docs/guides/breaking-checks-ci.mdx b/content/docs/guides/breaking-checks-ci.mdx index 8e081f7..dd064a6 100644 --- a/content/docs/guides/breaking-checks-ci.mdx +++ b/content/docs/guides/breaking-checks-ci.mdx @@ -1,134 +1,37 @@ --- -title: "Breaking Change Prevention in CI" -description: "How to configure baseline comparison, severity categories, and unstable package exemptions using EasyP breaking checks in CI pipelines." +title: "Breaking checks in CI" +description: "Run the EasyP v1 breaking checker against a Git baseline in CI." --- -Preventing breaking changes in Protocol Buffer schemas is critical for maintaining backward compatibility across microservices and client applications. EasyP provides the `easyp breaking` command to automatically catch breaking schema modifications before they are merged into your repository's primary branch. - - -Unlike general linting, breaking change detection is an automated gate designed for CI/CD pipelines. It compares your current local working tree against a declared baseline state (such as a Git tag or default branch). - - -## Configuration Reference - -Breaking change rules are configured inside `easyp.yaml` under the `breaking` section. This file is placed in your protocol directory and cascades down through child subdirectories. +The v1 breaking checker compares current `.proto` files with a Git ref. Configure the baseline in `easyp.yaml`: ```yaml -# proto/easyp.yaml version: v1 - breaking: - baseline: git:main - categories: [WIRE, WIRE_JSON] - ignore_unstable: true + baseline: git:origin/main + ignore: [experimental] ``` -### Breaking Check Parameters - -- **`baseline`**: Explicit baseline comparison target. Specified using the `git:` prefix, such as `git:main`, `git:master`, or `git:v1.0.0`. -- **`categories`**: Array of compatibility enforcement levels. Categories are ordered by increasing strictness: - - `WIRE`: Enforces binary wire format compatibility (e.g., prevents changing field numbers, deleting fields without reservation, or altering field types). - - `WIRE_JSON`: Enforces binary wire format compatibility as well as JSON field name mapping compatibility. - - `PACKAGE`: Enforces package-level stability in addition to wire format rules. - - `FILE`: Strict layout checks (prevents moving proto files across directory structures or renaming files). -- **`ignore_unstable`**: Boolean flag (default `true`). When enabled, packages containing unstable version identifiers (such as `v1alpha`, `v1beta1`, `v2alpha2`) are exempt from breaking change checks, allowing rapid API experimentation. - -## Severity Categories Comparison - -The following table summarizes what each breaking category enforces: - -| Category | Binary Wire Compatibility | JSON Mapping Compatibility | Package Structure | File Location | -| --- | --- | --- | --- | --- | -| `WIRE` | Required | Allowed to change | Allowed to change | Allowed to move | -| `WIRE_JSON` | Required | Required | Allowed to change | Allowed to move | -| `PACKAGE` | Required | Required | Required | Allowed to move | -| `FILE` | Required | Required | Required | Required | - -## CI Pipeline Integration - -Integrate `easyp breaking` into your continuous integration workflow to validate pull requests automatically. - - -CI pipelines should only run read-only validation commands (`easyp lint` and `easyp breaking`). Commands that alter lockfiles (`easyp mod tidy` or `easyp mod update`) should never run in CI. Furthermore, commits containing active `replace` directives in `protobuf.mod` must be rejected by CI. - +Then run the check from a checkout containing the comparison ref: - - - ```yaml - # .github/workflows/proto-ci.yml - name: Protocol Buffer CI - - on: - pull_request: - branches: [ main ] - - jobs: - breaking-check: - runs-on: ubuntu-latest - steps: - - name: Checkout Source Code - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Fetch all history for baseline git comparison - - - name: Install EasyP - run: | - curl -fsSL https://easyp.tech/install.sh | sh - echo "$HOME/.easyp/bin" >> $GITHUB_PATH - - - name: Run Proto Linting - run: easyp lint - - - name: Run Breaking Change Detection - run: easyp breaking --against git:origin/main - ``` - - - ```yaml - # .gitlab-ci.yml - stages: - - lint - - breaking - - variables: - GIT_DEPTH: 0 # Required for git baseline comparison - - easyp:lint: - stage: lint - script: - - easyp lint - - easyp:breaking: - stage: breaking - script: - - easyp breaking --against git:origin/main - only: - - merge_requests - ``` - - +```bash +easyp mod download +easyp lint --path proto +easyp breaking --path proto +``` -## Handling Breaking Change Failures +`mod download` verifies the commits and content hashes already recorded in `protobuf.lock`. Fetch the baseline ref in CI before the breaking check. If no `breaking.baseline` is set, pass the ref through `--against origin/main`; the command's default is `master`. -When `easyp breaking` detects an incompatible schema modification, it exits with a non-zero status code and prints detailed error diagnostic messages: +For example, a GitHub Actions checkout step can use full history: -```text -user/v1/user.proto:24:5: field "email" changed type from "string" to "bytes" (category: WIRE) -user/v1/user.proto:18:1: field "phone_number" (number 3) was deleted without reservation (category: WIRE) +```yaml +- uses: actions/checkout@v4 + with: + fetch-depth: 0 +- name: Check protobuf compatibility + run: easyp breaking --path proto --against origin/main ``` -### Remediation Strategies - -1. **Reserve Deleted Tags**: Instead of removing a field entirely, mark its tag number and name as `reserved` to prevent reuse: - ```protobuf - message User { - reserved 3; - reserved "phone_number"; - string id = 1; - string email = 2; - } - ``` -2. **Major Version Bump**: If backwards-incompatible changes are unavoidable, introduce a new major package version (e.g., `user.v2`) in a separate directory (`proto/user/v2/`). -3. **Unstable Iteration**: Work inside an alpha or beta package (e.g., `user.v1alpha1`) where `ignore_unstable: true` allows free modification until API stabilization. +Install the v1 pilot binary earlier in the job. Keep `protobuf.mod` and `protobuf.lock` committed, and resolve dependency updates before CI rather than rewriting the lock during a check. -For related configuration details, refer to the [EasyP Configuration Reference](/docs/cli/configuration) and [Adding Dependencies Guide](/docs/guides/adding-dependencies). +The pilot uses the existing breaking rule set. `breaking.categories` and `breaking.ignore_unstable` are not supported yet and cause an error. See [breaking checks](/docs/cli/breaking-changes). diff --git a/content/docs/guides/breaking-checks-ci.ru.mdx b/content/docs/guides/breaking-checks-ci.ru.mdx index 10e29fe..52274ea 100644 --- a/content/docs/guides/breaking-checks-ci.ru.mdx +++ b/content/docs/guides/breaking-checks-ci.ru.mdx @@ -1,134 +1,37 @@ --- title: "Breaking-проверки в CI" -description: "Настройка проверки обратной совместимости, категорий строгости и исключений для нестабильных пакетов с помощью EasyP в CI/CD." +description: "Запуск проверки совместимости EasyP v1 относительно Git-базы в CI." --- -Предотвращение несовместимых изменений (breaking changes) в схемах Protocol Buffer имеет критическое значение для сохранения обратной совместимости между микросервисами и клиентскими приложениями. EasyP предоставляет команду `easyp breaking` для автоматического обнаружения ломающих изменений до их мёрджа в основную ветку репозитория. - - -В отличие от обычного линтинга, проверка breaking changes — это автоматический гейт для CI/CD пайплайнов. Она сравнивает ваше текущее локальное состояние с объявленным базовым состоянием (таким как Git-тег или ветка по умолчанию). - - -## Конфигурация breaking - -Правила проверки breaking-изменений настраиваются в файле `easyp.yaml` в секции `breaking`. Этот файл размещается в директории с протоколами и каскадируется на все вложенные поддиректории. +Проверка v1 сравнивает текущие `.proto` с Git-ссылкой. Укажите базу в `easyp.yaml`: ```yaml -# proto/easyp.yaml version: v1 - breaking: - baseline: git:main - categories: [WIRE, WIRE_JSON] - ignore_unstable: true + baseline: git:origin/main + ignore: [experimental] ``` -### Параметры проверки - -- **`baseline`**: Явная точка сравнения. Задаётся с префиксом `git:`, например `git:main`, `git:master` или `git:v1.0.0`. -- **`categories`**: Массив уровней строгости проверки. Категории упорядочены по возрастанию строгости: - - `WIRE`: Проверяет бинарную совместимость формата передачи (запрещает изменение номеров полей, удаление полей без резервирования, изменение типов полей). - - `WIRE_JSON`: Проверяет как бинарную совместимость, так и совместимость JSON-маппинга имен полей. - - `PACKAGE`: Проверяет стабильность на уровне пакета в дополнение к бинарной совместимости. - - `FILE`: Строгая проверка структуры (запрещает перемещение proto-файлов между директориями и переименование файлов). -- **`ignore_unstable`**: Флаг (по умолчанию `true`). Если включен, пакеты с суффиксами нестабильных версий (такие как `v1alpha`, `v1beta1`, `v2alpha2`) исключаются из проверки, что позволяет свободно экспериментировать с новым API. - -## Сравнение категорий строгости - -В следующей таблице приведено сравнение того, что гарантирует каждая категория: - -| Категория | Бинарная совместимость WIRE | Совместимость JSON | Сохранение пакетов | Расположение файлов | -| --- | --- | --- | --- | --- | -| `WIRE` | Обязательно | Допускает изменения | Допускает изменения | Допускает перемещение | -| `WIRE_JSON` | Обязательно | Обязательно | Допускает изменения | Допускает перемещение | -| `PACKAGE` | Обязательно | Обязательно | Обязательно | Допускает перемещение | -| `FILE` | Обязательно | Обязательно | Обязательно | Обязательно | - -## Интеграция в CI/CD - -Добавьте `easyp breaking` в ваш непрерывный процесс интеграции для автоматической проверки Merge/Pull Request. - - -В CI должны запускаться только команды валидации в режиме чтения (`easyp lint` и `easyp breaking`). Команды, меняющие lock-файлы (`easyp mod tidy` или `easyp mod update`), никогда не должны запускаться в CI. Кроме того, коммиты с активными `replace`-директивами в `protobuf.mod` должны автоматически отклоняться CI. - +Запустите проверку из рабочего каталога, где доступна ссылка для сравнения: - - - ```yaml - # .github/workflows/proto-ci.yml - name: Protocol Buffer CI - - on: - pull_request: - branches: [ main ] - - jobs: - breaking-check: - runs-on: ubuntu-latest - steps: - - name: Checkout Source Code - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Загрузка всей истории для git-сравнения с baseline - - - name: Install EasyP - run: | - curl -fsSL https://easyp.tech/install.sh | sh - echo "$HOME/.easyp/bin" >> $GITHUB_PATH - - - name: Run Proto Linting - run: easyp lint - - - name: Run Breaking Change Detection - run: easyp breaking --against git:origin/main - ``` - - - ```yaml - # .gitlab-ci.yml - stages: - - lint - - breaking - - variables: - GIT_DEPTH: 0 # Требуется для сравнения с baseline по git - - easyp:lint: - stage: lint - script: - - easyp lint - - easyp:breaking: - stage: breaking - script: - - easyp breaking --against git:origin/main - only: - - merge_requests - ``` - - +```bash +easyp mod download +easyp lint --path proto +easyp breaking --path proto +``` -## Работа с ошибками несовместимости +`mod download` проверяет коммиты и хеши содержимого из уже созданного `protobuf.lock`. Перед breaking-проверкой получите базовую Git-ссылку в CI. Если `breaking.baseline` не указан, передайте ссылку как `--against origin/main`; значение команды по умолчанию — `master`. -Когда `easyp breaking` обнаруживает несовместимое изменение, команда завершается с ненулевым кодом ответа и выводит диагностическое сообщение: +Например, в GitHub Actions можно получить полную историю: -```text -user/v1/user.proto:24:5: field "email" changed type from "string" to "bytes" (category: WIRE) -user/v1/user.proto:18:1: field "phone_number" (number 3) was deleted without reservation (category: WIRE) +```yaml +- uses: actions/checkout@v4 + with: + fetch-depth: 0 +- name: Check protobuf compatibility + run: easyp breaking --path proto --against origin/main ``` -### Способы решения - -1. **Резервирование удаленных тегов**: Вместо полного удаления поля отметьте его номер и имя как `reserved`: - ```protobuf - message User { - reserved 3; - reserved "phone_number"; - string id = 1; - string email = 2; - } - ``` -2. **Повышение мажорной версии**: Если ломающие изменения неизбежны, создайте новую мажорную версию пакета (например, `user.v2`) в отдельной директории (`proto/user/v2/`). -3. **Разработка в нестабильном пакете**: Ведите разработку в альфа- или бета-пакете (`user.v1alpha1`), где `ignore_unstable: true` разрешает любые изменения до стабилизации API. +Установите бинарный файл пилотной версии v1 в предыдущем шаге job. Храните `protobuf.mod` и `protobuf.lock` в репозитории, а обновления зависимостей разрешайте до CI, не переписывая lock во время проверки. -Подробности смотрите в [Справочнике конфигурации EasyP](/ru/docs/cli/configuration) и [Руководстве по добавлению зависимостей](/ru/docs/guides/adding-dependencies). +Пилотная версия использует существующий набор breaking-правил. `breaking.categories` и `breaking.ignore_unstable` пока не поддерживаются и вызывают ошибку. См. [breaking-проверки](/ru/docs/cli/breaking-changes). diff --git a/content/docs/introduction/quickstart.mdx b/content/docs/introduction/quickstart.mdx index baf995b..b91b73b 100644 --- a/content/docs/introduction/quickstart.mdx +++ b/content/docs/introduction/quickstart.mdx @@ -1,174 +1,68 @@ --- title: "Quickstart" +description: "Create a protobuf module and generate code with the EasyP v1 pilot." --- -EasyP is a modern toolkit for working with Protobuf files. In this quickstart, you'll learn to: +Install a v1 pilot build of EasyP and make sure Git is available. This example uses a local Go generator, so put `protoc-gen-go` on `PATH` before the generation step. -1. **Initialize** your project with EasyP configuration -2. **Set up linting** to catch errors and ensure best practices -3. **Manage dependencies** from Git repositories -4. **Generate code** from your Protobuf files - -## Prerequisites - -Before you begin, make sure you have: - -- **EasyP CLI installed** - See [Installation guide](/docs/introduction/install) if you haven't already -- **Git** installed and available in your system path -- **Protobuf files** ready to work with - -Verify your installation for your platform: - - - - ```bash - easyp --version - ``` - - - ```powershell - easyp.exe --version - ``` - - +## 1. Initialize a module -## Initialize your project - -Start by creating an `easyp.yaml` configuration file in your project root: - - - - ```bash - easyp init - ``` - - This interactive command checks for existing `buf.yaml` files to offer automatic migration and generates a base `easyp.yaml`. - - - ```yaml - # Initial easyp.yaml template - version: v1 - - lint: - use: - - DEFAULT - ``` - - - -## Configure linting - -Linting helps catch errors and ensures your Protobuf files follow best practices. EasyP provides default rules compatible with Buf standards. - - - - Run the linter across all `.proto` files in your project tree: - - ```bash - easyp lint - ``` - - - Configure linter rules and exclusions inside `easyp.yaml`: - - ```yaml - version: v1 - lint: - use: - - DEFAULT - except: - - PACKAGE_DIRECTORY_MATCH - ``` - - - - -EasyP's linting rules are 100% compatible with Buf, making migration seamless if you're switching tools. - - -## Manage dependencies - -If your project uses third-party Protobuf packages (like Google APIs or gRPC Gateway), EasyP makes it easy to manage them via `protobuf.mod` or `easyp.yaml`. - -### Dependency format - -Dependencies use a simple format: `$GIT_LINK@$VERSION` - -- **`$GIT_LINK`** - URL to any Git repository (GitHub, GitLab, etc.) -- **`$VERSION`** - Git tag or commit hash (optional) - -### Add and download dependencies - - - - ```bash - # Download dependencies defined in configuration - easyp mod download - - # Update dependencies to the latest matching minimums - easyp mod update - ``` - - - ```powershell - # Download dependencies on Windows - easyp.exe mod download - - # Update dependencies on Windows - easyp.exe mod update - ``` - - - - -**Tip:** Use `easyp mod update` to fetch updated dependencies and refresh `protobuf.lock`. - - -## Generate code - -Now let's configure code generation. EasyP supports all standard Protobuf plugins. - - - - Execute code generation across all target configurations: - - ```bash - easyp generate - ``` - - - Add plugin configuration to `easyp.yaml` (or `easyp.gen.yaml`): - - ```yaml - generate: - plugins: - - name: go - out: ./gen/go - opts: - paths: source_relative - - name: go-grpc - out: ./gen/go - opts: - paths: source_relative - require_unimplemented_servers: false - ``` - - - - -EasyP uses a hybrid execution model with WASM for blazing speed and remote/Docker executors for heavy plugins. - - -## Next steps - -Congratulations! 🎉 You've successfully: -- ✅ Initialized an EasyP project -- ✅ Configured linting rules -- ✅ Managed third-party dependencies -- ✅ Generated code from your Protobuf files - -### Learn more - -- **[CLI Reference](/docs/cli/linter)** - Deep dive into all CLI commands -- **[Architecture Deep-Dive](/docs/architecture/mvs-dependency-resolution)** - Learn about MVS dependency resolution -- **[API Service](/docs/api-service/overview)** - Set up remote code generation +```bash +mkdir contracts && cd contracts +git init +easyp init --module github.com/acme/contracts +``` + +`init` creates three files: `protobuf.mod` for the module, `easyp.yaml` for lint and breaking policies, and `easyp.gen.yaml` for generation. If a file already exists, EasyP asks before replacing it. Automatic migration from Buf dependencies is not part of the pilot. + +## 2. Add a proto file + +```bash +mkdir -p proto/acme/v1 +``` + +Create `proto/acme/v1/hello.proto`: + +```proto +syntax = "proto3"; +package acme.v1; +option go_package = "github.com/acme/contracts/gen/go/acme/v1;acmev1"; + +message Hello { + string name = 1; +} +``` + +Set the module's source root in `protobuf.mod`: + +```text +module github.com/acme/contracts +roots proto +``` + +## 3. Configure generation + +Replace the empty plugin list in `easyp.gen.yaml`: + +```yaml +version: v1 +generate: + modules: [github.com/acme/contracts] +plugins: + - name: go + out: ./gen/go + opts: + paths: source_relative +``` + +## 4. Run the commands + +```bash +easyp mod tidy +easyp generate +easyp lint --path proto +``` + +`mod tidy` creates `protobuf.lock`. Add `require module version` lines to `protobuf.mod` before running it when your sources import another Git module. `mod download` later fetches the exact locked commits. Commit `protobuf.mod` and `protobuf.lock` alongside the source files. + +For a full field reference, see [configuration](/docs/cli/configuration), [generation](/docs/cli/generator), and [dependencies](/docs/cli/package-manager). diff --git a/content/docs/introduction/quickstart.ru.mdx b/content/docs/introduction/quickstart.ru.mdx index 6610162..2c4293a 100644 --- a/content/docs/introduction/quickstart.ru.mdx +++ b/content/docs/introduction/quickstart.ru.mdx @@ -1,174 +1,68 @@ --- -title: "Быстрый старт (Quickstart)" +title: "Быстрый старт" +description: "Создание protobuf-модуля и генерация кода в пилотной версии EasyP v1." --- -EasyP — современный toolkit для работы с файлами Protobuf. В этом кратком руководстве вы научитесь: +Установите пилотную сборку EasyP v1 и убедитесь, что доступен Git. В примере используется локальный Go-плагин: перед генерацией добавьте `protoc-gen-go` в `PATH`. -1. **Инициализировать** проект с конфигурацией EasyP -2. **Настраивать линтинг**, чтобы ловить ошибки и соблюдать лучшие практики -3. **Управлять зависимостями** из Git‑репозиториев -4. **Генерировать код** из ваших Protobuf файлов - -## Предварительные требования - -Перед началом убедитесь, что у вас установлены: - -- **EasyP CLI** — см. [руководство по установке](/ru/docs/introduction/install) -- **Git** доступен в вашем `$PATH` -- **Файлы `.proto`** - -Проверить версию EasyP на вашей платформе: - - - - ```bash - easyp --version - ``` - - - ```powershell - easyp.exe --version - ``` - - +## 1. Создайте модуль -## Инициализация проекта - -Создайте базовый файл конфигурации `easyp.yaml` в корне проекта: - - - - ```bash - easyp init - ``` - - Интерактивная команда проверяет наличие `buf.yaml` для миграции и генерирует шаблон `easyp.yaml`. - - - ```yaml - # Начальный шаблон easyp.yaml - version: v1 - - lint: - use: - - DEFAULT - ``` - - - -## Настройка линтинга - -Линтинг помогает находить проблемы и поддерживать единый стиль. EasyP использует правила, совместимые с Buf. - - - - Запуск линтера по всем `.proto` файлам проекта: - - ```bash - easyp lint - ``` - - - Конфигурация правил линтера в `easyp.yaml`: - - ```yaml - version: v1 - lint: - use: - - DEFAULT - except: - - PACKAGE_DIRECTORY_MATCH - ``` - - - - -Правила линтинга EasyP на 100% совместимы с Buf — мигрировать просто. - - -## Управление зависимостями - -Если вы используете сторонние protobuf пакеты (например Google APIs или gRPC Gateway), EasyP упрощает их подключение. - -### Формат зависимости - -Запись: `$GIT_LINK@$VERSION` - -- **`$GIT_LINK`** — URL любого Git‑репозитория (GitHub, GitLab и т.д.) -- **`$VERSION`** — тег или хеш коммита (опционально) - -### Загрузка и обновление зависимостей - - - - ```bash - # Загрузить зависимости из конфигурации - easyp mod download - - # Обновить зависимости и обновить lock-файл - easyp mod update - ``` - - - ```powershell - # Загрузить зависимости в Windows - easyp.exe mod download - - # Обновить зависимости в Windows - easyp.exe mod update - ``` - - - - -Совет: `easyp mod update` обновляет граф зависимостей и перегенерирует `protobuf.lock`. - - -## Генерация кода - -EasyP поддерживает все стандартные protoc‑плагины. - - - - Запустить генерацию кода: - - ```bash - easyp generate - ``` - - - Добавьте конфигурацию плагинов в `easyp.yaml` (или `easyp.gen.yaml`): - - ```yaml - generate: - plugins: - - name: go - out: ./gen/go - opts: - paths: source_relative - - name: go-grpc - out: ./gen/go - opts: - paths: source_relative - require_unimplemented_servers: false - ``` - - - - -Гибридный рантайм: WASM для максимальной скорости, удалённые исполнители — для сложных плагинов. - - -## Следующие шаги - -Поздравляем! 🎉 Вы успешно: -- ✅ Инициализировали проект EasyP -- ✅ Настроили линтинг -- ✅ Управляете внешними зависимостями -- ✅ Сгенерировали код из `.proto` - -### Узнать больше - -- **[CLI Reference](/ru/docs/cli/linter)** — подробности по командам -- **[Архитектура MVS](/ru/docs/architecture/mvs-dependency-resolution)** — подробнее о резолюции MVS -- **[API Service](/ru/docs/api-service/overview)** — удалённая генерация +```bash +mkdir contracts && cd contracts +git init +easyp init --module github.com/acme/contracts +``` + +`init` создаёт три файла: `protobuf.mod` для модуля, `easyp.yaml` для политик линтинга и проверки совместимости, `easyp.gen.yaml` для генерации. Перед заменой существующего файла EasyP спрашивает пользователя. Автоматическая миграция зависимостей Buf в пилотную версию не входит. + +## 2. Добавьте proto-файл + +```bash +mkdir -p proto/acme/v1 +``` + +Создайте `proto/acme/v1/hello.proto`: + +```proto +syntax = "proto3"; +package acme.v1; +option go_package = "github.com/acme/contracts/gen/go/acme/v1;acmev1"; + +message Hello { + string name = 1; +} +``` + +Укажите корень исходников в `protobuf.mod`: + +```text +module github.com/acme/contracts +roots proto +``` + +## 3. Настройте генерацию + +Замените пустой список плагинов в `easyp.gen.yaml`: + +```yaml +version: v1 +generate: + modules: [github.com/acme/contracts] +plugins: + - name: go + out: ./gen/go + opts: + paths: source_relative +``` + +## 4. Запустите команды + +```bash +easyp mod tidy +easyp generate +easyp lint --path proto +``` + +`mod tidy` создаёт `protobuf.lock`. Если исходники импортируют другой Git-модуль, сначала добавьте в `protobuf.mod` строку `require module version`. Позже `mod download` скачает точные коммиты из lock. Храните `protobuf.mod` и `protobuf.lock` вместе с исходниками в репозитории. + +Подробности: [конфигурация](/ru/docs/cli/configuration), [генерация](/ru/docs/cli/generator), [зависимости](/ru/docs/cli/package-manager). diff --git a/content/docs/introduction/what-is.mdx b/content/docs/introduction/what-is.mdx index b7523d6..b935f06 100644 --- a/content/docs/introduction/what-is.mdx +++ b/content/docs/introduction/what-is.mdx @@ -89,35 +89,11 @@ Unlike other tools, EasyP doesn't rely on a centralized server for package distr - **Version Control**: Full Git history and branching for your proto dependencies - **Enterprise-Friendly**: Works with private repositories and corporate Git infrastructure -## Seamless Migration from Buf - -EasyP is designed with buf compatibility in mind: - -- **Compatible rule sets**: Uses the same linting rules as buf -- **Familiar configuration**: Similar YAML structure with enhanced features -- **Drop-in replacement**: Can often replace buf with minimal configuration changes -- **Gradual migration**: Adopt EasyP features incrementally without disrupting existing workflows - -### EasyP vs buf.build Comparison - -| Feature | EasyP | buf.build | -|---------|--------|-----------| -| **Dependency Management** | Git-based repositories | Buf Schema Registry (BSR) | -| **Vendor Lock-in** | None - works with any Git hosting | Tied to BSR for full features | -| **Plugin Execution** | Local + Remote plugins | Local + BSR plugins | -| **Private Dependencies** | Any Git provider (GitHub, GitLab, etc.) | BSR or manual management | -| **Offline Development** | Full support with `mod vendor` | Limited without BSR access | -| **Enterprise Integration** | Works with existing Git infrastructure | Requires BSR setup | -| **Breaking Change Detection** | Against any Git reference | Against any Git reference | -| **Package Distribution** | Any Git repository | BSR required for publishing | -| **License** | Apache 2.0 | Apache 2.0 | -| **Community** | Growing | Established | - -**Migration Benefits:** -- **No infrastructure changes**: Continue using your existing Git repositories -- **Gradual adoption**: Start with EasyP while keeping existing buf configurations -- **Enhanced flexibility**: Access to both local and remote plugin execution -- **Simplified workflows**: Single configuration file for all protobuf operations +## Using Buf-configured dependencies + +An EasyP v1 project declares Git dependencies in `protobuf.mod`. When a Git dependency uses Buf v1 or v2 configuration, EasyP reads its declared proto roots for imports. Older EasyP dependency configuration is supported in the same way. The consuming project still uses separate `protobuf.mod`, `easyp.gen.yaml`, and `easyp.yaml` files. + +See [Buf-configured Git dependencies](/docs/cli/package-manager/easyp-vs-buf) for supported formats and limits. ## Our Goals for Protobuf diff --git a/content/docs/introduction/what-is.ru.mdx b/content/docs/introduction/what-is.ru.mdx index 11daccb..bf5c322 100644 --- a/content/docs/introduction/what-is.ru.mdx +++ b/content/docs/introduction/what-is.ru.mdx @@ -89,35 +89,11 @@ plugins: - **Полная история**: Ветки, теги, ревью - **Enterprise‑совместимость**: Поддержка приватных репозиториев -## Бесшовная миграция с Buf - -EasyP изначально совместим с экосистемой buf: - -- **Совпадающие rule sets** -- **Похожая структура YAML** -- **Минимальные изменения для замены** -- **Постепенное внедрение** без ломки текущего пайплайна - -### EasyP vs buf.build - -| Feature | EasyP | buf.build | -|---------|--------|-----------| -| **Dependency Management** | Git‑репозитории | Buf Schema Registry (BSR) | -| **Vendor Lock-in** | Нет | Привязка к BSR для полного функционала | -| **Plugin Execution** | Local + Remote | Local + BSR plugins | -| **Private Dependencies** | Любой Git провайдер | BSR или ручное управление | -| **Offline Development** | Полная поддержка (`mod vendor`) | Ограниченно без доступа к BSR | -| **Enterprise Integration** | Использует существующий Git | Требует настройку BSR | -| **Breaking Change Detection** | Против любой Git ссылки | Аналогично | -| **Package Distribution** | Любой Git | Публикация через BSR | -| **License** | Apache 2.0 | Apache 2.0 | -| **Community** | Growing | Established | - -**Преимущества миграции:** -- Без изменения инфраструктуры -- Плавное принятие новых возможностей -- Гибрид локальных и удалённых плагинов -- Единая конфигурация вместо набора файлов +## Зависимости с конфигурацией Buf + +Проект EasyP v1 объявляет Git-зависимости в `protobuf.mod`. Если Git-зависимость использует конфигурацию Buf v1 или v2, EasyP читает её корни `.proto` для разрешения импортов. Старые конфиги EasyP в зависимостях поддерживаются таким же образом. Проект-потребитель использует отдельные `protobuf.mod`, `easyp.gen.yaml` и `easyp.yaml`. + +Поддерживаемые форматы и ограничения описаны на странице [Git-зависимостей с конфигом Buf](/ru/docs/cli/package-manager/easyp-vs-buf). ## Наши цели для Protobuf From 7078035b4b041f5714601c4bd11ee1274ca40f05 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 23 Sep 2026 13:02:09 +0300 Subject: [PATCH 04/26] Document v1 command validation and breaking policies --- content/docs/cli/configuration.mdx | 4 ++++ content/docs/cli/configuration.ru.mdx | 4 ++++ content/docs/cli/index.mdx | 2 ++ content/docs/cli/index.ru.mdx | 2 ++ 4 files changed, 12 insertions(+) diff --git a/content/docs/cli/configuration.mdx b/content/docs/cli/configuration.mdx index 958bea5..93cac7e 100644 --- a/content/docs/cli/configuration.mdx +++ b/content/docs/cli/configuration.mdx @@ -43,6 +43,10 @@ The global flags are `--cfg` (alias `--config`, default `easyp.yaml`), `--debug` `lint` and `breaking` read the v1 `easyp.yaml`. They use the nearest module's declared roots and locked or local dependency roots for imports. A policy may exist without a `protobuf.mod`; in that case the commands use the scanned files and built-in imports. +`breaking` applies the nearest `breaking` section to each reported file. When nested policies select different Git baselines, it compares against each baseline and reports an issue only under the policy that selected it. + +`validate-config --cfg --format json` accepts `easyp.yaml`, `easyp.gen.yaml`, `protobuf.mod`, and `protobuf.lock`. Invalid lock versions, incomplete entries, and malformed hashes are reported as validation errors. + The v1 pilot has no `mod vendor` or `ls-files` command. ## Minimal files diff --git a/content/docs/cli/configuration.ru.mdx b/content/docs/cli/configuration.ru.mdx index 900cc41..69479ca 100644 --- a/content/docs/cli/configuration.ru.mdx +++ b/content/docs/cli/configuration.ru.mdx @@ -43,6 +43,10 @@ easyp breaking --path proto --against main `lint` и `breaking` читают `easyp.yaml` версии v1. Для импортов они используют корни ближайшего модуля и его зафиксированных или локальных зависимостей. Политика может существовать без `protobuf.mod`; тогда используются проверяемые файлы и встроенные импорты. +`breaking` применяет ближайшую секцию `breaking` к каждому файлу с ошибкой. Если вложенные политики выбирают разные Git-базы, команда сравнивает файлы с каждой базой и относит ошибку только к выбравшей её политике. + +`validate-config --cfg <файл> --format json` принимает `easyp.yaml`, `easyp.gen.yaml`, `protobuf.mod` и `protobuf.lock`. Некорректная версия lock-файла, неполные записи и неверные хеши выдаются как ошибки проверки. + В пилотной версии v1 нет команд `mod vendor` и `ls-files`. ## Минимальный пример diff --git a/content/docs/cli/index.mdx b/content/docs/cli/index.mdx index 5ce91e9..89d7cf9 100644 --- a/content/docs/cli/index.mdx +++ b/content/docs/cli/index.mdx @@ -12,6 +12,8 @@ The EasyP CLI is the local toolkit for Protocol Buffers workflows. | `easyp generate` | Run local/remote plugins | | `easyp mod` | Git-based dependencies | | `easyp init` | Project bootstrap | +| `easyp validate-config` | Validate a v1 policy, generator, module manifest, or lockfile | +| `easyp completion bash\|zsh` | Print a shell completion script | ## Sections diff --git a/content/docs/cli/index.ru.mdx b/content/docs/cli/index.ru.mdx index d022083..97446f8 100644 --- a/content/docs/cli/index.ru.mdx +++ b/content/docs/cli/index.ru.mdx @@ -12,6 +12,8 @@ CLI EasyP — локальный инструментарий для Protocol Bu | `easyp generate` | Локальные/удалённые плагины | | `easyp mod` | Git-зависимости | | `easyp init` | Инициализация проекта | +| `easyp validate-config` | Проверка v1-политики, конфигурации генератора, манифеста или lock-файла | +| `easyp completion bash\|zsh` | Вывод скрипта автодополнения | ## Разделы From 5a3ba81ed02d492ded774fc82170cd1c2d0f5234 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 23 Sep 2026 13:19:50 +0300 Subject: [PATCH 05/26] Document v1 vendor, ls-files, and schema-gen commands --- content/docs/cli/configuration.mdx | 9 ++++++++- content/docs/cli/configuration.ru.mdx | 9 ++++++++- content/docs/cli/index.mdx | 2 ++ content/docs/cli/index.ru.mdx | 2 ++ content/docs/cli/package-manager/easyp-vs-buf.mdx | 2 +- content/docs/cli/package-manager/easyp-vs-buf.ru.mdx | 2 +- content/docs/cli/package-manager/index.mdx | 4 +++- content/docs/cli/package-manager/index.ru.mdx | 4 +++- 8 files changed, 28 insertions(+), 6 deletions(-) diff --git a/content/docs/cli/configuration.mdx b/content/docs/cli/configuration.mdx index 93cac7e..b3879b3 100644 --- a/content/docs/cli/configuration.mdx +++ b/content/docs/cli/configuration.mdx @@ -36,6 +36,9 @@ easyp breaking --path proto --against main | `breaking` | `--path` (`-p`), `--root` (`-r`), `--against` | | `init` | `--dir` (`-d`), `--module` | | `validate-config` | `--config` (alias of `--cfg`), `--format` | +| `mod vendor` | No command-specific flags | +| `ls-files` | `--include-imports` (default `true`), `--format` (`json` or `text`) | +| `schema-gen` | `--out-dir` (default `schemas`) | The global flags are `--cfg` (alias `--config`, default `easyp.yaml`), `--debug` (`-d`), and `--format` (`-f`, `text` or `json`). `EASYP_CFG`, `EASYP_DEBUG`, and `EASYP_FORMAT` set their respective defaults. The module cache uses `EASYPPATH` or `$HOME/.easyp`. @@ -47,7 +50,11 @@ The global flags are `--cfg` (alias `--config`, default `easyp.yaml`), `--debug` `validate-config --cfg --format json` accepts `easyp.yaml`, `easyp.gen.yaml`, `protobuf.mod`, and `protobuf.lock`. Invalid lock versions, incomplete entries, and malformed hashes are reported as validation errors. -The v1 pilot has no `mod vendor` or `ls-files` command. +`mod vendor` verifies the locked Git dependencies and copies their `.proto` files into `easyp_vendor` using their import paths. It replaces a previous vendor tree only after all files have been copied successfully. Duplicate import paths are errors. Run `mod tidy` first; local `replace` directives cannot be vendored. + +`ls-files` lists local `.proto` files from `protobuf.mod` roots. By default it also includes reachable imports from dependencies and bundled well-known protos, resolving dependencies through the v1 lock or local replacements. Use `--include-imports=false` to list only local files without resolving dependencies. JSON output contains `files`, `roots`, and any import `errors`. + +`schema-gen --out-dir schemas` writes separate JSON Schemas for `easyp.yaml`, `easyp.gen.yaml`, and `protobuf.lock`, each with a `-v1.schema.json` filename and an unversioned alias. `protobuf.mod` is a text manifest, so validate it with `validate-config` instead. CLI validation also checks semantic rules beyond the JSON Schemas. ## Minimal files diff --git a/content/docs/cli/configuration.ru.mdx b/content/docs/cli/configuration.ru.mdx index 69479ca..72fb41a 100644 --- a/content/docs/cli/configuration.ru.mdx +++ b/content/docs/cli/configuration.ru.mdx @@ -36,6 +36,9 @@ easyp breaking --path proto --against main | `breaking` | `--path` (`-p`), `--root` (`-r`), `--against` | | `init` | `--dir` (`-d`), `--module` | | `validate-config` | `--config` (псевдоним `--cfg`), `--format` | +| `mod vendor` | Нет собственных флагов | +| `ls-files` | `--include-imports` (по умолчанию `true`), `--format` (`json` или `text`) | +| `schema-gen` | `--out-dir` (по умолчанию `schemas`) | Общие флаги: `--cfg` (псевдоним `--config`, по умолчанию `easyp.yaml`), `--debug` (`-d`) и `--format` (`-f`, `text` или `json`). Переменные `EASYP_CFG`, `EASYP_DEBUG` и `EASYP_FORMAT` задают значения по умолчанию. Кеш модулей находится в `EASYPPATH` или `$HOME/.easyp`. @@ -47,7 +50,11 @@ easyp breaking --path proto --against main `validate-config --cfg <файл> --format json` принимает `easyp.yaml`, `easyp.gen.yaml`, `protobuf.mod` и `protobuf.lock`. Некорректная версия lock-файла, неполные записи и неверные хеши выдаются как ошибки проверки. -В пилотной версии v1 нет команд `mod vendor` и `ls-files`. +`mod vendor` проверяет зафиксированные Git-зависимости и копирует их `.proto` в `easyp_vendor` по import path. Старый каталог заменяется только после успешного копирования всех файлов. Совпадающие import path вызывают ошибку. Сначала выполните `mod tidy`; локальные `replace` нельзя вендорить. + +`ls-files` показывает локальные `.proto` из корней `protobuf.mod`. По умолчанию команда также включает достижимые импорты из зависимостей и встроенных well-known proto, разрешая зависимости через v1 lock или локальные замены. `--include-imports=false` показывает только локальные файлы без разрешения зависимостей. В JSON есть поля `files`, `roots` и, при проблемах с импортами, `errors`. + +`schema-gen --out-dir schemas` создаёт отдельные JSON Schema для `easyp.yaml`, `easyp.gen.yaml` и `protobuf.lock`: файлы с суффиксом `-v1.schema.json` и псевдонимы без версии. `protobuf.mod` — текстовый манифест; проверяйте его командой `validate-config`. CLI также проверяет семантические правила, не выраженные в JSON Schema. ## Минимальный пример diff --git a/content/docs/cli/index.mdx b/content/docs/cli/index.mdx index 89d7cf9..294ffb4 100644 --- a/content/docs/cli/index.mdx +++ b/content/docs/cli/index.mdx @@ -13,6 +13,8 @@ The EasyP CLI is the local toolkit for Protocol Buffers workflows. | `easyp mod` | Git-based dependencies | | `easyp init` | Project bootstrap | | `easyp validate-config` | Validate a v1 policy, generator, module manifest, or lockfile | +| `easyp ls-files` | List local protos and reachable imports | +| `easyp schema-gen` | Generate v1 JSON Schemas | | `easyp completion bash\|zsh` | Print a shell completion script | ## Sections diff --git a/content/docs/cli/index.ru.mdx b/content/docs/cli/index.ru.mdx index 97446f8..853809a 100644 --- a/content/docs/cli/index.ru.mdx +++ b/content/docs/cli/index.ru.mdx @@ -13,6 +13,8 @@ CLI EasyP — локальный инструментарий для Protocol Bu | `easyp mod` | Git-зависимости | | `easyp init` | Инициализация проекта | | `easyp validate-config` | Проверка v1-политики, конфигурации генератора, манифеста или lock-файла | +| `easyp ls-files` | Список локальных proto и достижимых импортов | +| `easyp schema-gen` | Генерация JSON Schema для v1 | | `easyp completion bash\|zsh` | Вывод скрипта автодополнения | ## Разделы diff --git a/content/docs/cli/package-manager/easyp-vs-buf.mdx b/content/docs/cli/package-manager/easyp-vs-buf.mdx index 62ddb69..3764f4a 100644 --- a/content/docs/cli/package-manager/easyp-vs-buf.mdx +++ b/content/docs/cli/package-manager/easyp-vs-buf.mdx @@ -29,4 +29,4 @@ easyp generate `mod tidy` resolves the Git dependency and records the selected commit and content hash in `protobuf.lock`. Buf Registry dependency names are not converted into Git URLs automatically; declare a suitable Git source in the consumer manifest. Buf include/exclude filters are not yet supported for Git dependency import roots and produce an error. -The v1 pilot does not provide `mod vendor`. See the [package manager guide](/docs/cli/package-manager) for the supported commands. +After `mod tidy`, `mod vendor` can copy the locked Git dependency's `.proto` files into `easyp_vendor` using the roots extracted from its Buf configuration. See the [package manager guide](/docs/cli/package-manager). diff --git a/content/docs/cli/package-manager/easyp-vs-buf.ru.mdx b/content/docs/cli/package-manager/easyp-vs-buf.ru.mdx index 46d15b5..edb8d0b 100644 --- a/content/docs/cli/package-manager/easyp-vs-buf.ru.mdx +++ b/content/docs/cli/package-manager/easyp-vs-buf.ru.mdx @@ -29,4 +29,4 @@ easyp generate `mod tidy` разрешает Git-зависимость и записывает выбранный коммит и хеш содержимого в `protobuf.lock`. Имена зависимостей Buf Registry не превращаются в Git URL автоматически: подходящий Git-источник надо объявить в манифесте потребителя. Фильтры Buf include/exclude для корней Git-зависимостей пока не поддерживаются и вызывают ошибку. -В пилотной версии v1 нет `mod vendor`. Поддерживаемые команды перечислены в [руководстве менеджера пакетов](/ru/docs/cli/package-manager). +После `mod tidy` команда `mod vendor` может скопировать `.proto` зафиксированной Git-зависимости в `easyp_vendor`, используя корни из её конфигурации Buf. Подробнее — в [руководстве менеджера пакетов](/ru/docs/cli/package-manager). diff --git a/content/docs/cli/package-manager/index.mdx b/content/docs/cli/package-manager/index.mdx index b56478f..f5866c6 100644 --- a/content/docs/cli/package-manager/index.mdx +++ b/content/docs/cli/package-manager/index.mdx @@ -26,14 +26,16 @@ require ( | `easyp mod tidy` | Resolves direct and transitive requirements and writes `protobuf.lock` | | `easyp mod download` | Downloads the exact commits in `protobuf.lock` and verifies their hashes | | `easyp mod update` | Refreshes requirements within their current major versions, then updates the lock | +| `easyp mod vendor` | Verifies locked dependencies and copies their `.proto` files into `easyp_vendor` | ```bash easyp mod tidy easyp mod download +easyp mod vendor easyp generate ``` -Commit `protobuf.mod` and `protobuf.lock` for repeatable builds. The module cache is under `$HOME/.easyp/v1/git` by default; set `EASYPPATH` to change its parent directory. The v1 pilot does not have `mod vendor`. +Commit `protobuf.mod` and `protobuf.lock` for repeatable builds. The module cache is under `$HOME/.easyp/v1/git` by default; set `EASYPPATH` to change its parent directory. `mod vendor` requires the lock and rejects local replacements and duplicate import paths. The `easyp_vendor` directory is a copy of dependency sources, not a replacement for the lock. ## Dependencies using Buf or older EasyP diff --git a/content/docs/cli/package-manager/index.ru.mdx b/content/docs/cli/package-manager/index.ru.mdx index d2f74a8..3174fb2 100644 --- a/content/docs/cli/package-manager/index.ru.mdx +++ b/content/docs/cli/package-manager/index.ru.mdx @@ -26,14 +26,16 @@ require ( | `easyp mod tidy` | Разрешает прямые и транзитивные требования и записывает `protobuf.lock` | | `easyp mod download` | Скачивает точные коммиты из lock и проверяет хеши | | `easyp mod update` | Обновляет требования в пределах текущих мажорных версий и пересоздаёт lock | +| `easyp mod vendor` | Проверяет зафиксированные зависимости и копирует их `.proto` в `easyp_vendor` | ```bash easyp mod tidy easyp mod download +easyp mod vendor easyp generate ``` -Храните `protobuf.mod` и `protobuf.lock` в репозитории для воспроизводимой сборки. Кеш по умолчанию расположен в `$HOME/.easyp/v1/git`; переменная `EASYPPATH` меняет его родительский каталог. Команды `mod vendor` в пилотной версии v1 нет. +Храните `protobuf.mod` и `protobuf.lock` в репозитории для воспроизводимой сборки. Кеш по умолчанию расположен в `$HOME/.easyp/v1/git`; переменная `EASYPPATH` меняет его родительский каталог. `mod vendor` требует lock и отклоняет локальные замены и повторяющиеся import path. Каталог `easyp_vendor` — копия исходников зависимостей, а не замена lock-файла. ## Зависимости на Buf или старом EasyP From 32baf9b0fc76bd12d5965068bd31ee5aa526c87d Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 23 Sep 2026 13:38:49 +0300 Subject: [PATCH 06/26] Clarify local and remote multi-module support --- content/docs/reference/protobuf-mod.mdx | 2 ++ content/docs/reference/protobuf-mod.ru.mdx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/content/docs/reference/protobuf-mod.mdx b/content/docs/reference/protobuf-mod.mdx index 5b1c2b7..fd4d21a 100644 --- a/content/docs/reference/protobuf-mod.mdx +++ b/content/docs/reference/protobuf-mod.mdx @@ -64,3 +64,5 @@ replace github.com/acme/weather => ../weather-fork 1. **Git-Native Identity**: The canonical identity of a module is its Git URL (e.g., `github.com/acme/weather`). 2. **Per-Module Bounds**: Every module maintains its own independent `protobuf.mod`. MVS operates per-module rather than forcing global monorepo single-version constraints. 3. **Replace Guardrail**: Local `replace` directives work during generation. `easyp mod tidy` and `easyp mod update` reject them until they are removed, so a reproducible Git lock never records a local path. + +For multiple local modules in one repository, run `easyp mod tidy` from each module directory; each writes its own `protobuf.lock`. `generate.modules` can select local modules by repository-relative path or module identity. A Git dependency is currently checked out and read from its repository root only: nested `protobuf.mod` files are not discovered as separate remote modules. A local `replace` can target a nested module directory. diff --git a/content/docs/reference/protobuf-mod.ru.mdx b/content/docs/reference/protobuf-mod.ru.mdx index d6b4513..b795332 100644 --- a/content/docs/reference/protobuf-mod.ru.mdx +++ b/content/docs/reference/protobuf-mod.ru.mdx @@ -64,3 +64,5 @@ replace github.com/acme/weather => ../weather-fork 1. **Git-Native идентичность**: Каноническим идентификатором модуля является его Git URL (`github.com/acme/weather`). 2. **Помодульный скоуп**: Каждый модуль имеет собственный `protobuf.mod`. MVS работает помодульно (per-module), не навязывая глобальных ограничений версий в монорепозитории. 3. **Защита lock-файла**: Локальный `replace` работает при генерации. `easyp mod tidy` и `easyp mod update` отклоняют его до удаления, чтобы в воспроизводимый Git lock не попал локальный путь. + +Если в одном репозитории несколько локальных модулей, запускайте `easyp mod tidy` из каталога каждого модуля: у каждого будет свой `protobuf.lock`. `generate.modules` выбирает локальные модули по пути относительно репозитория или по имени модуля. Git-зависимость сейчас скачивается и читается только от корня репозитория: вложенные `protobuf.mod` не обнаруживаются как отдельные удалённые модули. Локальный `replace` может указывать на каталог вложенного модуля. From 6c598a85277b1cfc1bffaaca334695524505b80e Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 23 Sep 2026 14:10:34 +0300 Subject: [PATCH 07/26] Document commit-pinned multi-module dependencies --- content/docs/architecture/mvs-dependency-resolution.mdx | 8 +++++--- .../docs/architecture/mvs-dependency-resolution.ru.mdx | 6 ++++-- content/docs/cli/generator/index.mdx | 2 +- content/docs/cli/generator/index.ru.mdx | 2 +- content/docs/cli/package-manager/index.mdx | 4 +++- content/docs/cli/package-manager/index.ru.mdx | 4 +++- content/docs/guides/adding-dependency.mdx | 2 +- content/docs/guides/adding-dependency.ru.mdx | 2 +- content/docs/reference/easyp-gen-yaml.mdx | 2 +- content/docs/reference/easyp-gen-yaml.ru.mdx | 2 +- content/docs/reference/protobuf-lock.mdx | 4 ++-- content/docs/reference/protobuf-lock.ru.mdx | 4 ++-- content/docs/reference/protobuf-mod.mdx | 4 ++-- content/docs/reference/protobuf-mod.ru.mdx | 4 ++-- 14 files changed, 29 insertions(+), 21 deletions(-) diff --git a/content/docs/architecture/mvs-dependency-resolution.mdx b/content/docs/architecture/mvs-dependency-resolution.mdx index 68e45f9..691eec7 100644 --- a/content/docs/architecture/mvs-dependency-resolution.mdx +++ b/content/docs/architecture/mvs-dependency-resolution.mdx @@ -88,6 +88,8 @@ Unlike workspace-wide resolvers, EasyP resolves dependencies on a **per-module b Because each proto module maintains its own `protobuf.mod` and `protobuf.lock`, teams can update shared dependencies at their own pace without breaking neighboring services in a monorepo. +The maximum-version rule applies to SemVer requirements. A full Git commit hash pins an exact revision without a tag. If the same module is required by two different commits, or by both a commit and a SemVer tag, resolution reports a conflict because those requirements have no common version ordering. + --- ## 3. `protobuf.mod` DSL Directives @@ -115,11 +117,11 @@ replace github.com/acme/weather => ../weather-fork ### Directive Reference -- **`module`**: Declares the canonical module identity (URL/path). Optional when the Git URL matches repository layout. +- **`module`**: Declares the required canonical module identity (URL/path). - **`roots`**: Defines the inner directory root containing `.proto` schema files (defaults to `.`). This ensures imports resolve cleanly without requiring prefix manipulation. -- **`require`**: Declares direct and indirect module dependencies with explicit Semantic Version tags. +- **`require`**: Declares direct and indirect module dependencies with explicit Semantic Version tags or full Git commit hashes. - **`// indirect`**: Appended automatically by `easyp mod tidy` for transitive dependencies not directly imported by the root module's `.proto` files. -- **`replace`**: Overrides a module dependency with a local file path (`../weather-fork`) or an alternative Git repository/version. Useful for local development and debugging. +- **`replace`**: Overrides a module dependency with a local file path (`../weather-fork`) for development. Active `replace` directives are strictly intended for local development. EasyP CI workflows will flag and reject any commit containing an active `replace` directive. diff --git a/content/docs/architecture/mvs-dependency-resolution.ru.mdx b/content/docs/architecture/mvs-dependency-resolution.ru.mdx index 6d39556..c926f46 100644 --- a/content/docs/architecture/mvs-dependency-resolution.ru.mdx +++ b/content/docs/architecture/mvs-dependency-resolution.ru.mdx @@ -88,6 +88,8 @@ description: "Подробный разбор алгоритма Minimal Version Каждый proto-модуль имеет собственный `protobuf.mod` и `protobuf.lock`, поэтому команды могут обновлять зависимости независимых сервисов в своём темпе. +Правило выбора максимума применяется к требованиям SemVer. Полный хеш Git-коммита закрепляет конкретную ревизию без тега. Если один модуль требуется по двум разным коммитам либо одновременно по коммиту и SemVer-тегу, резолвер сообщает о конфликте: для этих требований нет общего порядка версий. + --- ## 3. Директивы DSL `protobuf.mod` @@ -117,9 +119,9 @@ replace github.com/acme/weather => ../weather-fork - **`module`**: Объявляет канонический идентификатор (URL/путь) модуля. - **`roots`**: Задаёт корневую поддиректорию с `.proto` файлами внутри репозитория (по умолчанию `.`). Это позволяет корректно резолвить импорты без срезания путей вручную. -- **`require`**: Прямые и транзитивные зависимости с явными фиксациями SemVer версий. +- **`require`**: Прямые и транзитивные зависимости с явными SemVer-тегами или полными хешами Git-коммитов. - **`// indirect`**: Автоматически дописывается командой `easyp mod tidy` для транзитивных зависимостей, не импортируемых напрямую `.proto` файлами модуля. -- **`replace`**: Переопределяет источник зависимости локальным путем (`../weather-fork`) или другим URL/версией. Используется для локальной отладки. +- **`replace`**: Переопределяет зависимость локальным путем (`../weather-fork`) для разработки. Директива `replace` предназначена исключительно для локальной разработки. CI-пайплайны EasyP отклоняют коммиты с активными `replace`. diff --git a/content/docs/cli/generator/index.mdx b/content/docs/cli/generator/index.mdx index 2cecba3..8f482e7 100644 --- a/content/docs/cli/generator/index.mdx +++ b/content/docs/cli/generator/index.mdx @@ -35,7 +35,7 @@ easyp mod tidy easyp generate ``` -If `generate.modules` is omitted, the generator selects the nearest `protobuf.mod`. A module entry may also be a repository-relative local module path or a locked dependency identity. `generate.packages` is reserved for future package filtering and currently returns an error when nonempty. +If `generate.modules` is omitted, the generator uses `protobuf.mod` beside this `easyp.gen.yaml`, or the repository-root `protobuf.mod` when there is no sibling manifest. A locked dependency identity in `generate.modules` is resolved through that same selected manifest and its lock. A module entry may also be a repository-relative local module path. `generate.packages` is reserved for future package filtering and currently returns an error when nonempty. ## Select a project and output descriptors diff --git a/content/docs/cli/generator/index.ru.mdx b/content/docs/cli/generator/index.ru.mdx index 17f435b..aed1991 100644 --- a/content/docs/cli/generator/index.ru.mdx +++ b/content/docs/cli/generator/index.ru.mdx @@ -35,7 +35,7 @@ easyp mod tidy easyp generate ``` -Если `generate.modules` не указан, выбирается ближайший `protobuf.mod`. Элемент списка может быть путём к локальному модулю относительно репозитория или именем зависимости из lock. Поле `generate.packages` оставлено для будущей фильтрации пакетов; непустое значение пока вызывает ошибку. +Если `generate.modules` не указан, используется `protobuf.mod` рядом с этим `easyp.gen.yaml`, а при его отсутствии — корневой `protobuf.mod` репозитория. Идентификатор зависимости в `generate.modules` разрешается через тот же выбранный манифест и его lock. Элемент списка также может быть путём к локальному модулю относительно репозитория. Поле `generate.packages` оставлено для будущей фильтрации пакетов; непустое значение пока вызывает ошибку. ## Выбор проекта и дескрипторы diff --git a/content/docs/cli/package-manager/index.mdx b/content/docs/cli/package-manager/index.mdx index f5866c6..0af752f 100644 --- a/content/docs/cli/package-manager/index.mdx +++ b/content/docs/cli/package-manager/index.mdx @@ -17,7 +17,9 @@ require ( ) ``` -`roots` defaults to `.` when omitted. Requirements use semantic versions. `replace module => ../local-copy` points generation and linting at a local checkout. Remove local replacements before writing a reproducible lock with `mod tidy` or `mod update`. +`roots` defaults to `.` when omitted. Requirements use semantic versions or full 40- or 64-character Git commit hashes. `replace module => ../local-copy` points generation and linting at a local checkout. Remove local replacements before writing a reproducible lock with `mod tidy` or `mod update`. + +For a Git repository with multiple `protobuf.mod` files, require each nested module separately by the identity declared in its manifest. A module in `foo/` can use a tag such as `foo/v1.2.3` or a full Git commit hash when no tag exists. Another module in `bar/` can use a different tag or commit. EasyP locks and resolves their source roots independently. `mod update` preserves commit-pinned requirements. ## Commands diff --git a/content/docs/cli/package-manager/index.ru.mdx b/content/docs/cli/package-manager/index.ru.mdx index 3174fb2..89c1751 100644 --- a/content/docs/cli/package-manager/index.ru.mdx +++ b/content/docs/cli/package-manager/index.ru.mdx @@ -17,7 +17,9 @@ require ( ) ``` -Если `roots` не указан, используется `.`. Требования задаются семантическими версиями. `replace module => ../local-copy` направляет генерацию и линтинг на локальный каталог. Перед записью воспроизводимого lock через `mod tidy` или `mod update` локальные замены нужно убрать. +Если `roots` не указан, используется `.`. Требования задаются семантическими версиями или полными хешами Git-коммитов из 40 или 64 символов. `replace module => ../local-copy` направляет генерацию и линтинг на локальный каталог. Перед записью воспроизводимого lock через `mod tidy` или `mod update` локальные замены нужно убрать. + +Если в Git-репозитории несколько `protobuf.mod`, объявляйте каждый вложенный модуль отдельным `require` по имени из его манифеста. Для модуля в `foo/` можно использовать тег вида `foo/v1.2.3` или полный хеш Git-коммита, если тегов нет. Модуль в `bar/` может иметь другой тег или коммит. EasyP фиксирует и разрешает их корни исходников независимо. `mod update` сохраняет требования, закреплённые по коммиту. ## Команды diff --git a/content/docs/guides/adding-dependency.mdx b/content/docs/guides/adding-dependency.mdx index 202578f..258f3da 100644 --- a/content/docs/guides/adding-dependency.mdx +++ b/content/docs/guides/adding-dependency.mdx @@ -66,7 +66,7 @@ The consuming project still declares a Git source with `require`. The dependency - Buf v1beta1 `buf.yaml`: reads `build.roots`, defaulting to `.`. - Older EasyP: reads `direct` dependencies from the old `protobuf.mod` and local `generate.inputs[].directory.root` plus Git inputs from `easyp.yaml`. -For an old EasyP dependency without a version on one of its Git requirements, `mod tidy` selects its latest stable SemVer tag and pins the selected commit in the v1 lock. Buf Registry `deps` are not Git sources, so declare an appropriate Git module in the consuming `protobuf.mod` when those imports are needed. Buf `includes`/`excludes` filters are not yet supported for Git dependency import roots and produce an explicit error. +For an old EasyP dependency without a version on one of its Git requirements, `mod tidy` selects its latest stable SemVer tag and pins the selected commit in the v1 lock. If that repository has no tags, declare an explicit full Git commit hash in its requirement instead; the old EasyP `source@` form is also read transitively. Buf Registry `deps` are not Git sources, so declare an appropriate Git module in the consuming `protobuf.mod` when those imports are needed. Buf `includes`/`excludes` filters are not yet supported for Git dependency import roots and produce an explicit error. Updated `protobuf.mod`: diff --git a/content/docs/guides/adding-dependency.ru.mdx b/content/docs/guides/adding-dependency.ru.mdx index 233b3f4..9e15e05 100644 --- a/content/docs/guides/adding-dependency.ru.mdx +++ b/content/docs/guides/adding-dependency.ru.mdx @@ -66,7 +66,7 @@ easyp mod tidy - Buf v1beta1 `buf.yaml`: читаются `build.roots`, по умолчанию `.`. - Старый EasyP: из прежнего `protobuf.mod` читаются зависимости `direct`, а из `easyp.yaml` — локальные `generate.inputs[].directory.root` и Git-входы. -Если в старой зависимости EasyP у Git-зависимости не указана версия, `mod tidy` выбирает последний стабильный тег SemVer и фиксирует выбранный commit в v1 lock. `deps` из Buf Registry не являются Git-источниками: когда нужны их импорты, укажите соответствующий Git-модуль в `protobuf.mod` проекта-потребителя. Фильтры Buf `includes`/`excludes` для корней Git-зависимости пока не поддерживаются и вызывают явную ошибку. +Если в старой зависимости EasyP у Git-зависимости не указана версия, `mod tidy` выбирает последний стабильный тег SemVer и фиксирует выбранный коммит в v1 lock. Если у репозитория нет тегов, укажите полный хеш Git-коммита в требовании; старый формат EasyP `source@` также читается транзитивно. `deps` из Buf Registry не являются Git-источниками: когда нужны их импорты, укажите соответствующий Git-модуль в `protobuf.mod` проекта-потребителя. Фильтры Buf `includes`/`excludes` для корней Git-зависимости пока не поддерживаются и вызывают явную ошибку. Обновлённый `protobuf.mod`: diff --git a/content/docs/reference/easyp-gen-yaml.mdx b/content/docs/reference/easyp-gen-yaml.mdx index b36a1ce..a2d3603 100644 --- a/content/docs/reference/easyp-gen-yaml.mdx +++ b/content/docs/reference/easyp-gen-yaml.mdx @@ -23,7 +23,7 @@ In accordance with EasyP's zero-duplication principles, `easyp.gen.yaml` **never type: "object" }, "generate.modules": { - description: "List of module identities or repository-relative local module paths to generate. Dependency identities must be present in the consumer module's protobuf.lock. If omitted, the nearest protobuf.mod is selected.", + description: "Module identities or repository-relative local module paths to generate. Dependency identities use protobuf.mod and its lock beside this config; when no sibling manifest exists, they use the repository-root module and lock. If omitted, that local module is selected.", type: "string[]" }, "generate.packages": { diff --git a/content/docs/reference/easyp-gen-yaml.ru.mdx b/content/docs/reference/easyp-gen-yaml.ru.mdx index f7ab01a..51ca9ee 100644 --- a/content/docs/reference/easyp-gen-yaml.ru.mdx +++ b/content/docs/reference/easyp-gen-yaml.ru.mdx @@ -23,7 +23,7 @@ description: "Полная спецификация файла easyp.gen.yaml, type: "object" }, "generate.modules": { - description: "Список идентификаторов модулей или локальных путей относительно корня репозитория. Идентификаторы зависимостей должны быть в protobuf.lock модуля-потребителя. Если поле отсутствует, выбирается ближайший protobuf.mod.", + description: "Идентификаторы модулей или локальные пути относительно корня репозитория. Зависимости разрешаются через protobuf.mod и его lock рядом с этим конфигом; если соседнего манифеста нет, используются корневые модуль и lock. Если поле отсутствует, выбирается этот локальный модуль.", type: "string[]" }, "generate.packages": { diff --git a/content/docs/reference/protobuf-lock.mdx b/content/docs/reference/protobuf-lock.mdx index 90f92cf..1dd6d6e 100644 --- a/content/docs/reference/protobuf-lock.mdx +++ b/content/docs/reference/protobuf-lock.mdx @@ -25,7 +25,7 @@ The `protobuf.lock` file is an auto-generated artifact created by EasyP dependen type: "string" }, "modules[].version": { - description: "Resolved Semantic Version tag (e.g. v1.2.3).", + description: "Resolved Semantic Version tag (for example v1.2.3) or the full Git commit hash requested without a tag.", type: "string" }, "modules[].commit": { @@ -66,7 +66,7 @@ modules: ## Lifecycle Commands - `easyp mod tidy`: Resolves required imports, updates indirect dependencies, and regenerates `protobuf.lock`. -- `easyp mod update`: Upgrades dependencies to latest semver-compatible versions and updates `protobuf.lock`. +- `easyp mod update`: Upgrades tagged dependencies to latest semver-compatible versions, preserves commit-pinned requirements, and updates `protobuf.lock`. - `easyp mod download`: Populates local cache strictly using `protobuf.lock` without reaching out to remote registries or modifying locked versions. The `hash` is computed with Go's `dirhash.Hash1` over every regular file tracked by Git at `commit`, using repository-relative paths. EasyP verifies the same digest for a newly downloaded module and for an existing cache entry. A missing cached commit still requires access to its Git repository. diff --git a/content/docs/reference/protobuf-lock.ru.mdx b/content/docs/reference/protobuf-lock.ru.mdx index c621133..a28907b 100644 --- a/content/docs/reference/protobuf-lock.ru.mdx +++ b/content/docs/reference/protobuf-lock.ru.mdx @@ -25,7 +25,7 @@ description: "Спецификация файла protobuf.lock, автомат type: "string" }, "modules[].version": { - description: "Разрешённый тег Semantic Version (например, v1.2.3).", + description: "Разрешённый тег Semantic Version (например, v1.2.3) или полный хеш Git-коммита, указанный вместо тега.", type: "string" }, "modules[].commit": { @@ -66,7 +66,7 @@ modules: ## Команды жизненного цикла - `easyp mod tidy`: Сканирует импорты, дописывает транзитивные зависимости и перегенерирует `protobuf.lock`. -- `easyp mod update`: Обновляет версии зависимостей до свежих совместимых релизов и обновляет `protobuf.lock`. +- `easyp mod update`: Обновляет зависимости с тегами до свежих совместимых релизов, сохраняет закреплённые по коммиту требования и обновляет `protobuf.lock`. - `easyp mod download`: Наполняет локальный кэш строго по `protobuf.lock` без обращения к внешним реестрам. `hash` вычисляется алгоритмом Go `dirhash.Hash1` по всем обычным файлам, отслеживаемым Git в коммите `commit`, с путями относительно корня репозитория. EasyP проверяет этот дайджест при скачивании и при чтении существующего кэша. Если нужного коммита в кэше нет, доступ к Git-репозиторию всё ещё необходим. diff --git a/content/docs/reference/protobuf-mod.mdx b/content/docs/reference/protobuf-mod.mdx index fd4d21a..3b970a6 100644 --- a/content/docs/reference/protobuf-mod.mdx +++ b/content/docs/reference/protobuf-mod.mdx @@ -20,7 +20,7 @@ The `protobuf.mod` file resides at the root of a Protocol Buffer module. Designe type: "directive" }, require: { - description: "Block declaring direct and transitive dependency module bounds with explicit SemVer version tags.", + description: "Block declaring dependencies by SemVer tag or full Git commit hash.", type: "directive block" }, "require // indirect": { @@ -65,4 +65,4 @@ replace github.com/acme/weather => ../weather-fork 2. **Per-Module Bounds**: Every module maintains its own independent `protobuf.mod`. MVS operates per-module rather than forcing global monorepo single-version constraints. 3. **Replace Guardrail**: Local `replace` directives work during generation. `easyp mod tidy` and `easyp mod update` reject them until they are removed, so a reproducible Git lock never records a local path. -For multiple local modules in one repository, run `easyp mod tidy` from each module directory; each writes its own `protobuf.lock`. `generate.modules` can select local modules by repository-relative path or module identity. A Git dependency is currently checked out and read from its repository root only: nested `protobuf.mod` files are not discovered as separate remote modules. A local `replace` can target a nested module directory. +For multiple modules in one repository, put a `protobuf.mod` in each module directory. Run `easyp mod tidy` from each local module directory; each writes its own `protobuf.lock`. `generate.modules` can select local modules by repository-relative path or module identity. A consumer can require a nested Git module by its declared identity, for example `require github.com/acme/contracts/proto/user v1.2.3`. A tagged release uses `proto/user/v1.2.3` in the shared Git repository, matching the [Go multi-module tag convention](https://go.dev/ref/mod#mapping-versions-to-commits). Without tags, use a full 40- or 64-character commit hash instead of `v1.2.3`; `mod update` keeps that commit pinned. Each required module has its own lock entry, version or commit, and source roots. A local `replace` can target a nested module directory. diff --git a/content/docs/reference/protobuf-mod.ru.mdx b/content/docs/reference/protobuf-mod.ru.mdx index b795332..8d5de8d 100644 --- a/content/docs/reference/protobuf-mod.ru.mdx +++ b/content/docs/reference/protobuf-mod.ru.mdx @@ -20,7 +20,7 @@ description: "Спецификация файла protobuf.mod, независи type: "директива" }, require: { - description: "Блок объявления прямых и транзитивных зависимостей с явными SemVer-версиями.", + description: "Блок зависимостей с SemVer-тегом или полным хешем Git-коммита.", type: "блок директив" }, "require // indirect": { @@ -65,4 +65,4 @@ replace github.com/acme/weather => ../weather-fork 2. **Помодульный скоуп**: Каждый модуль имеет собственный `protobuf.mod`. MVS работает помодульно (per-module), не навязывая глобальных ограничений версий в монорепозитории. 3. **Защита lock-файла**: Локальный `replace` работает при генерации. `easyp mod tidy` и `easyp mod update` отклоняют его до удаления, чтобы в воспроизводимый Git lock не попал локальный путь. -Если в одном репозитории несколько локальных модулей, запускайте `easyp mod tidy` из каталога каждого модуля: у каждого будет свой `protobuf.lock`. `generate.modules` выбирает локальные модули по пути относительно репозитория или по имени модуля. Git-зависимость сейчас скачивается и читается только от корня репозитория: вложенные `protobuf.mod` не обнаруживаются как отдельные удалённые модули. Локальный `replace` может указывать на каталог вложенного модуля. +Если в одном репозитории несколько модулей, разместите `protobuf.mod` в каталоге каждого. Запускайте `easyp mod tidy` из каталога каждого локального модуля: у каждого будет свой `protobuf.lock`. `generate.modules` выбирает локальные модули по пути относительно репозитория или по имени. Потребитель может объявить вложенный Git-модуль по его имени, например `require github.com/acme/contracts/proto/user v1.2.3`. Для такого релиза нужен тег `proto/user/v1.2.3` в общем Git-репозитории по [правилу Go для репозиториев с несколькими модулями](https://go.dev/ref/mod#mapping-versions-to-commits). Если тегов нет, вместо `v1.2.3` укажите полный хеш коммита из 40 или 64 символов; `mod update` сохранит этот коммит. У каждого требуемого модуля своя запись lock, версия или коммит и корни исходников. Локальный `replace` может указывать на каталог вложенного модуля. From 70f66b83aa956f8921c713e390f15dd05083fe3c Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 23 Sep 2026 15:03:59 +0300 Subject: [PATCH 08/26] Document automatic untagged module resolution --- content/docs/architecture/mvs-dependency-resolution.mdx | 8 ++++---- .../docs/architecture/mvs-dependency-resolution.ru.mdx | 8 ++++---- content/docs/cli/package-manager/index.mdx | 4 ++-- content/docs/cli/package-manager/index.ru.mdx | 4 ++-- content/docs/guides/adding-dependency.mdx | 2 +- content/docs/guides/adding-dependency.ru.mdx | 2 +- content/docs/reference/protobuf-lock.mdx | 2 +- content/docs/reference/protobuf-lock.ru.mdx | 2 +- content/docs/reference/protobuf-mod.mdx | 4 ++-- content/docs/reference/protobuf-mod.ru.mdx | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/content/docs/architecture/mvs-dependency-resolution.mdx b/content/docs/architecture/mvs-dependency-resolution.mdx index 691eec7..09dd68a 100644 --- a/content/docs/architecture/mvs-dependency-resolution.mdx +++ b/content/docs/architecture/mvs-dependency-resolution.mdx @@ -18,12 +18,12 @@ Traditional dependency resolution algorithms (such as Cargo's PubGrub or npm's M | Challenge in Proto Management | Traditional / Buf v2 Approach | EasyP MVS Approach | | --- | --- | --- | | **Diamond Dependency Conflicts** | Global workspace-wide resolution forces a single version across all consumers, causing cross-team coupling. | Per-module independent resolution graph. Each module resolves its own minimal requirements. | -| **Registry Volatility** | `latest` resolution or registry updates can silently alter build output over time. | Deterministic resolution selecting `max(requested_minimums)`. No SAT solver or registry lookups. | +| **Registry Volatility** | `latest` resolution or registry updates can silently alter build output over time. | SemVer requirements select `max(requested_minimums)`; versionless Git requirements are pinned on first tidy. Subsequent runs reuse the lock. | | **Proto Schema Collision** | Multiple major/minor versions compiled in one proto-root break Fully Qualified Names (FQNs). | Exactly one version of each dependency per module graph, strictly locked via `protobuf.lock`. | ### Core Algorithm Behavior -1. **Explicit Version Bounds**: Every requirement in `protobuf.mod` specifies an explicit baseline version (e.g., `github.com/acme/weather v1.2.0`). This version is treated as a *minimum requirement*, not a range constraint. +1. **Version Bounds or Git HEAD**: A SemVer requirement (for example, `github.com/acme/weather v1.2.0`) supplies a minimum version. A requirement without a version resolves Git HEAD and stores the commit in the lock. 2. **Maximum of Minimums**: When multiple modules in a dependency graph request different minimum versions of the same dependency, MVS selects the **maximum** of those requested minimum versions. 3. **High-Water Mark Determinism**: The resulting selected version is guaranteed to satisfy all minimum requirements without requiring complex backtracking or unexpected automatic major upgrades. @@ -88,7 +88,7 @@ Unlike workspace-wide resolvers, EasyP resolves dependencies on a **per-module b Because each proto module maintains its own `protobuf.mod` and `protobuf.lock`, teams can update shared dependencies at their own pace without breaking neighboring services in a monorepo. -The maximum-version rule applies to SemVer requirements. A full Git commit hash pins an exact revision without a tag. If the same module is required by two different commits, or by both a commit and a SemVer tag, resolution reports a conflict because those requirements have no common version ordering. +The maximum-version rule applies to SemVer requirements. A versionless requirement resolves the repository's current HEAD on its first `mod tidy`; later tidy runs reuse the locked commit, and `mod update` refreshes it. A full Git commit hash pins an exact revision without a tag. If the same module is required by two different commits, or by both a commit and a SemVer tag, resolution reports a conflict because those requirements have no common version ordering. --- @@ -119,7 +119,7 @@ replace github.com/acme/weather => ../weather-fork - **`module`**: Declares the required canonical module identity (URL/path). - **`roots`**: Defines the inner directory root containing `.proto` schema files (defaults to `.`). This ensures imports resolve cleanly without requiring prefix manipulation. -- **`require`**: Declares direct and indirect module dependencies with explicit Semantic Version tags or full Git commit hashes. +- **`require`**: Declares direct and indirect module dependencies. The version may be omitted for automatic Git HEAD resolution, or set to a Semantic Version tag or full Git commit hash. - **`// indirect`**: Appended automatically by `easyp mod tidy` for transitive dependencies not directly imported by the root module's `.proto` files. - **`replace`**: Overrides a module dependency with a local file path (`../weather-fork`) for development. diff --git a/content/docs/architecture/mvs-dependency-resolution.ru.mdx b/content/docs/architecture/mvs-dependency-resolution.ru.mdx index c926f46..37df3f3 100644 --- a/content/docs/architecture/mvs-dependency-resolution.ru.mdx +++ b/content/docs/architecture/mvs-dependency-resolution.ru.mdx @@ -18,12 +18,12 @@ description: "Подробный разбор алгоритма Minimal Version | Проблема при работе с Proto | Подход Buf v2 / Традиционный | Подход EasyP MVS | | --- | --- | --- | | **Рассинхрон версий («diamond»)** | Резолюция на весь workspace целиком: единая версия пакета на всех потребителей, конфликты между командами разруливаются вручную. | Per-module (помодульная) резолюция. Каждый модуль резолвит свои зависимости независимо. | -| **Зависимость от состояния реестра** | Стратегия `latest` или изменения в реестре могут неявно изменить результат повторной сборки. | Детерминированный выбор `max(запрошенных минимумов)`. Без SAT-солвера и обращения к реестру при наличии lock. | +| **Зависимость от состояния реестра** | Стратегия `latest` или изменения в реестре могут неявно изменить результат повторной сборки. | Для SemVer выбирается `max(запрошенных минимумов)`; требование без версии закрепляется в lock при первом tidy. Повторные запуски используют lock. | | **Коллизии Proto-схем** | Несколько мажорных/минорных версий в одном proto-root ломают уникальность FQN. | Ровно одна версия каждой зависимости в графе модуля, строго зафиксированная в `protobuf.lock`. | ### Базовые принципы алгоритма -1. **Явные нижние границы версий**: Каждая зависимость в `protobuf.mod` указывает конкретную базовую версию (например, `github.com/acme/weather v1.2.0`). Эта версия рассматривается как *минимально необходимая requirement*, а не диапазоновое ограничение. +1. **Границы версий или Git HEAD**: SemVer-требование (например, `github.com/acme/weather v1.2.0`) задаёт минимальную версию. Требование без версии разрешается в Git HEAD и записывает коммит в lock. 2. **Максимум из минимумов**: Если несколько модулей в графе требуют разные минимальные версии одной и той же зависимости, MVS выбирает **максимальную** из запрошенных минимальных версий. 3. **Детерминизм High-Water Mark**: Выбранная версия гарантированно удовлетворяет всем объявленным минимальным требованиям без возвратов (backtracking) и неожиданных мажорных обновлений. @@ -88,7 +88,7 @@ description: "Подробный разбор алгоритма Minimal Version Каждый proto-модуль имеет собственный `protobuf.mod` и `protobuf.lock`, поэтому команды могут обновлять зависимости независимых сервисов в своём темпе. -Правило выбора максимума применяется к требованиям SemVer. Полный хеш Git-коммита закрепляет конкретную ревизию без тега. Если один модуль требуется по двум разным коммитам либо одновременно по коммиту и SemVer-тегу, резолвер сообщает о конфликте: для этих требований нет общего порядка версий. +Правило выбора максимума применяется к требованиям SemVer. Требование без версии при первом `mod tidy` разрешается в текущий HEAD репозитория; следующие запуски `tidy` используют коммит из lock, а `mod update` обновляет его. Полный хеш Git-коммита закрепляет конкретную ревизию без тега. Если один модуль требуется по двум разным коммитам либо одновременно по коммиту и SemVer-тегу, резолвер сообщает о конфликте: для этих требований нет общего порядка версий. --- @@ -119,7 +119,7 @@ replace github.com/acme/weather => ../weather-fork - **`module`**: Объявляет канонический идентификатор (URL/путь) модуля. - **`roots`**: Задаёт корневую поддиректорию с `.proto` файлами внутри репозитория (по умолчанию `.`). Это позволяет корректно резолвить импорты без срезания путей вручную. -- **`require`**: Прямые и транзитивные зависимости с явными SemVer-тегами или полными хешами Git-коммитов. +- **`require`**: Прямые и транзитивные зависимости. Версию можно опустить для автоматического разрешения Git HEAD либо указать SemVer-тег или полный хеш Git-коммита. - **`// indirect`**: Автоматически дописывается командой `easyp mod tidy` для транзитивных зависимостей, не импортируемых напрямую `.proto` файлами модуля. - **`replace`**: Переопределяет зависимость локальным путем (`../weather-fork`) для разработки. diff --git a/content/docs/cli/package-manager/index.mdx b/content/docs/cli/package-manager/index.mdx index 0af752f..3149b82 100644 --- a/content/docs/cli/package-manager/index.mdx +++ b/content/docs/cli/package-manager/index.mdx @@ -17,9 +17,9 @@ require ( ) ``` -`roots` defaults to `.` when omitted. Requirements use semantic versions or full 40- or 64-character Git commit hashes. `replace module => ../local-copy` points generation and linting at a local checkout. Remove local replacements before writing a reproducible lock with `mod tidy` or `mod update`. +`roots` defaults to `.` when omitted. A requirement may omit its version: `mod tidy` resolves the Git repository's current HEAD and locks its exact commit. Repeating `tidy` keeps that commit; `mod update` refreshes versionless requirements to HEAD. You may instead give a SemVer tag or a full 40- or 64-character Git commit hash. `replace module => ../local-copy` points generation and linting at a local checkout. Remove local replacements before writing a reproducible lock with `mod tidy` or `mod update`. -For a Git repository with multiple `protobuf.mod` files, require each nested module separately by the identity declared in its manifest. A module in `foo/` can use a tag such as `foo/v1.2.3` or a full Git commit hash when no tag exists. Another module in `bar/` can use a different tag or commit. EasyP locks and resolves their source roots independently. `mod update` preserves commit-pinned requirements. +For a Git repository with multiple `protobuf.mod` files, require each nested module separately by the identity declared in its manifest. For untagged modules, write `require repo/foo` and `require repo/bar`; EasyP finds both manifests and locks the resolved commits without module-specific tags. Explicit commit hashes stay pinned during `mod update`. Tagged releases remain optional: a module in `foo/` uses a tag such as `foo/v1.2.3`. EasyP resolves each module's source roots independently. ## Commands diff --git a/content/docs/cli/package-manager/index.ru.mdx b/content/docs/cli/package-manager/index.ru.mdx index 89c1751..f13ab77 100644 --- a/content/docs/cli/package-manager/index.ru.mdx +++ b/content/docs/cli/package-manager/index.ru.mdx @@ -17,9 +17,9 @@ require ( ) ``` -Если `roots` не указан, используется `.`. Требования задаются семантическими версиями или полными хешами Git-коммитов из 40 или 64 символов. `replace module => ../local-copy` направляет генерацию и линтинг на локальный каталог. Перед записью воспроизводимого lock через `mod tidy` или `mod update` локальные замены нужно убрать. +Если `roots` не указан, используется `.`. Версию в требовании можно опустить: `mod tidy` найдёт текущий HEAD Git-репозитория и закрепит точный коммит. Повторный `tidy` сохранит его, а `mod update` обновит требование без версии до HEAD. При необходимости можно указать SemVer-тег или полный хеш Git-коммита из 40 или 64 символов. `replace module => ../local-copy` направляет генерацию и линтинг на локальный каталог. Перед записью воспроизводимого lock через `mod tidy` или `mod update` локальные замены нужно убрать. -Если в Git-репозитории несколько `protobuf.mod`, объявляйте каждый вложенный модуль отдельным `require` по имени из его манифеста. Для модуля в `foo/` можно использовать тег вида `foo/v1.2.3` или полный хеш Git-коммита, если тегов нет. Модуль в `bar/` может иметь другой тег или коммит. EasyP фиксирует и разрешает их корни исходников независимо. `mod update` сохраняет требования, закреплённые по коммиту. +Если в Git-репозитории несколько `protobuf.mod`, объявляйте каждый вложенный модуль отдельным `require` по имени из его манифеста. Для модулей без тегов достаточно `require repo/foo` и `require repo/bar`: EasyP найдёт оба манифеста и закрепит найденные коммиты без отдельных тегов. Явно указанные хеши останутся закреплёнными при `mod update`. Теги для релизов необязательны; для модуля в `foo/` версия `v1.2.3` использует тег `foo/v1.2.3`. Корни исходников каждого модуля разрешаются независимо. ## Команды diff --git a/content/docs/guides/adding-dependency.mdx b/content/docs/guides/adding-dependency.mdx index 258f3da..4537fc0 100644 --- a/content/docs/guides/adding-dependency.mdx +++ b/content/docs/guides/adding-dependency.mdx @@ -66,7 +66,7 @@ The consuming project still declares a Git source with `require`. The dependency - Buf v1beta1 `buf.yaml`: reads `build.roots`, defaulting to `.`. - Older EasyP: reads `direct` dependencies from the old `protobuf.mod` and local `generate.inputs[].directory.root` plus Git inputs from `easyp.yaml`. -For an old EasyP dependency without a version on one of its Git requirements, `mod tidy` selects its latest stable SemVer tag and pins the selected commit in the v1 lock. If that repository has no tags, declare an explicit full Git commit hash in its requirement instead; the old EasyP `source@` form is also read transitively. Buf Registry `deps` are not Git sources, so declare an appropriate Git module in the consuming `protobuf.mod` when those imports are needed. Buf `includes`/`excludes` filters are not yet supported for Git dependency import roots and produce an explicit error. +For an old EasyP dependency without a version on one of its Git requirements, `mod tidy` resolves the Git repository's HEAD and pins its commit in the v1 lock. No tag is required. The old EasyP `source@` form is also read transitively. Buf Registry `deps` are not Git sources, so declare an appropriate Git module in the consuming `protobuf.mod` when those imports are needed. Buf `includes`/`excludes` filters are not yet supported for Git dependency import roots and produce an explicit error. Updated `protobuf.mod`: diff --git a/content/docs/guides/adding-dependency.ru.mdx b/content/docs/guides/adding-dependency.ru.mdx index 9e15e05..f28a584 100644 --- a/content/docs/guides/adding-dependency.ru.mdx +++ b/content/docs/guides/adding-dependency.ru.mdx @@ -66,7 +66,7 @@ easyp mod tidy - Buf v1beta1 `buf.yaml`: читаются `build.roots`, по умолчанию `.`. - Старый EasyP: из прежнего `protobuf.mod` читаются зависимости `direct`, а из `easyp.yaml` — локальные `generate.inputs[].directory.root` и Git-входы. -Если в старой зависимости EasyP у Git-зависимости не указана версия, `mod tidy` выбирает последний стабильный тег SemVer и фиксирует выбранный коммит в v1 lock. Если у репозитория нет тегов, укажите полный хеш Git-коммита в требовании; старый формат EasyP `source@` также читается транзитивно. `deps` из Buf Registry не являются Git-источниками: когда нужны их импорты, укажите соответствующий Git-модуль в `protobuf.mod` проекта-потребителя. Фильтры Buf `includes`/`excludes` для корней Git-зависимости пока не поддерживаются и вызывают явную ошибку. +Если в старой зависимости EasyP у Git-зависимости не указана версия, `mod tidy` разрешает HEAD Git-репозитория и фиксирует его коммит в v1 lock. Тег не нужен. Старый формат EasyP `source@` также читается транзитивно. `deps` из Buf Registry не являются Git-источниками: когда нужны их импорты, укажите соответствующий Git-модуль в `protobuf.mod` проекта-потребителя. Фильтры Buf `includes`/`excludes` для корней Git-зависимости пока не поддерживаются и вызывают явную ошибку. Обновлённый `protobuf.mod`: diff --git a/content/docs/reference/protobuf-lock.mdx b/content/docs/reference/protobuf-lock.mdx index 1dd6d6e..4464769 100644 --- a/content/docs/reference/protobuf-lock.mdx +++ b/content/docs/reference/protobuf-lock.mdx @@ -66,7 +66,7 @@ modules: ## Lifecycle Commands - `easyp mod tidy`: Resolves required imports, updates indirect dependencies, and regenerates `protobuf.lock`. -- `easyp mod update`: Upgrades tagged dependencies to latest semver-compatible versions, preserves commit-pinned requirements, and updates `protobuf.lock`. +- `easyp mod update`: Upgrades tagged dependencies to latest semver-compatible versions, refreshes versionless requirements to Git HEAD, preserves explicit commit pins, and updates `protobuf.lock`. - `easyp mod download`: Populates local cache strictly using `protobuf.lock` without reaching out to remote registries or modifying locked versions. The `hash` is computed with Go's `dirhash.Hash1` over every regular file tracked by Git at `commit`, using repository-relative paths. EasyP verifies the same digest for a newly downloaded module and for an existing cache entry. A missing cached commit still requires access to its Git repository. diff --git a/content/docs/reference/protobuf-lock.ru.mdx b/content/docs/reference/protobuf-lock.ru.mdx index a28907b..bf6de9a 100644 --- a/content/docs/reference/protobuf-lock.ru.mdx +++ b/content/docs/reference/protobuf-lock.ru.mdx @@ -66,7 +66,7 @@ modules: ## Команды жизненного цикла - `easyp mod tidy`: Сканирует импорты, дописывает транзитивные зависимости и перегенерирует `protobuf.lock`. -- `easyp mod update`: Обновляет зависимости с тегами до свежих совместимых релизов, сохраняет закреплённые по коммиту требования и обновляет `protobuf.lock`. +- `easyp mod update`: Обновляет зависимости с тегами до свежих совместимых релизов, требования без версии — до Git HEAD, сохраняет явно закреплённые хеши и обновляет `protobuf.lock`. - `easyp mod download`: Наполняет локальный кэш строго по `protobuf.lock` без обращения к внешним реестрам. `hash` вычисляется алгоритмом Go `dirhash.Hash1` по всем обычным файлам, отслеживаемым Git в коммите `commit`, с путями относительно корня репозитория. EasyP проверяет этот дайджест при скачивании и при чтении существующего кэша. Если нужного коммита в кэше нет, доступ к Git-репозиторию всё ещё необходим. diff --git a/content/docs/reference/protobuf-mod.mdx b/content/docs/reference/protobuf-mod.mdx index 3b970a6..c894ea3 100644 --- a/content/docs/reference/protobuf-mod.mdx +++ b/content/docs/reference/protobuf-mod.mdx @@ -20,7 +20,7 @@ The `protobuf.mod` file resides at the root of a Protocol Buffer module. Designe type: "directive" }, require: { - description: "Block declaring dependencies by SemVer tag or full Git commit hash.", + description: "Block declaring dependencies by module identity, optionally with a SemVer tag or full Git commit hash.", type: "directive block" }, "require // indirect": { @@ -65,4 +65,4 @@ replace github.com/acme/weather => ../weather-fork 2. **Per-Module Bounds**: Every module maintains its own independent `protobuf.mod`. MVS operates per-module rather than forcing global monorepo single-version constraints. 3. **Replace Guardrail**: Local `replace` directives work during generation. `easyp mod tidy` and `easyp mod update` reject them until they are removed, so a reproducible Git lock never records a local path. -For multiple modules in one repository, put a `protobuf.mod` in each module directory. Run `easyp mod tidy` from each local module directory; each writes its own `protobuf.lock`. `generate.modules` can select local modules by repository-relative path or module identity. A consumer can require a nested Git module by its declared identity, for example `require github.com/acme/contracts/proto/user v1.2.3`. A tagged release uses `proto/user/v1.2.3` in the shared Git repository, matching the [Go multi-module tag convention](https://go.dev/ref/mod#mapping-versions-to-commits). Without tags, use a full 40- or 64-character commit hash instead of `v1.2.3`; `mod update` keeps that commit pinned. Each required module has its own lock entry, version or commit, and source roots. A local `replace` can target a nested module directory. +For multiple modules in one repository, put a `protobuf.mod` in each module directory. Run `easyp mod tidy` from each local module directory; each writes its own `protobuf.lock`. `generate.modules` can select local modules by repository-relative path or module identity. A consumer declares each nested Git module separately by its declared identity. For example, `require github.com/acme/contracts/proto/user` needs no tag or manually supplied commit: `mod tidy` finds the repository's current HEAD and records its exact commit in `protobuf.lock`. Repeating `tidy` preserves that commit; `mod update` refreshes a versionless requirement to the current HEAD. An explicitly supplied full 40- or 64-character commit stays pinned during update. SemVer requirements remain supported for tagged releases; a nested module tagged `v1.2.3` uses `proto/user/v1.2.3`, matching the [Go multi-module tag convention](https://go.dev/ref/mod#mapping-versions-to-commits). Each required module has its own lock entry and source roots. A local `replace` can target a nested module directory. diff --git a/content/docs/reference/protobuf-mod.ru.mdx b/content/docs/reference/protobuf-mod.ru.mdx index 8d5de8d..d47dd51 100644 --- a/content/docs/reference/protobuf-mod.ru.mdx +++ b/content/docs/reference/protobuf-mod.ru.mdx @@ -20,7 +20,7 @@ description: "Спецификация файла protobuf.mod, независи type: "директива" }, require: { - description: "Блок зависимостей с SemVer-тегом или полным хешем Git-коммита.", + description: "Блок зависимостей по имени модуля; SemVer-тег или полный хеш Git-коммита указываются при необходимости.", type: "блок директив" }, "require // indirect": { @@ -65,4 +65,4 @@ replace github.com/acme/weather => ../weather-fork 2. **Помодульный скоуп**: Каждый модуль имеет собственный `protobuf.mod`. MVS работает помодульно (per-module), не навязывая глобальных ограничений версий в монорепозитории. 3. **Защита lock-файла**: Локальный `replace` работает при генерации. `easyp mod tidy` и `easyp mod update` отклоняют его до удаления, чтобы в воспроизводимый Git lock не попал локальный путь. -Если в одном репозитории несколько модулей, разместите `protobuf.mod` в каталоге каждого. Запускайте `easyp mod tidy` из каталога каждого локального модуля: у каждого будет свой `protobuf.lock`. `generate.modules` выбирает локальные модули по пути относительно репозитория или по имени. Потребитель может объявить вложенный Git-модуль по его имени, например `require github.com/acme/contracts/proto/user v1.2.3`. Для такого релиза нужен тег `proto/user/v1.2.3` в общем Git-репозитории по [правилу Go для репозиториев с несколькими модулями](https://go.dev/ref/mod#mapping-versions-to-commits). Если тегов нет, вместо `v1.2.3` укажите полный хеш коммита из 40 или 64 символов; `mod update` сохранит этот коммит. У каждого требуемого модуля своя запись lock, версия или коммит и корни исходников. Локальный `replace` может указывать на каталог вложенного модуля. +Если в одном репозитории несколько модулей, разместите `protobuf.mod` в каталоге каждого. Запускайте `easyp mod tidy` из каталога каждого локального модуля: у каждого будет свой `protobuf.lock`. `generate.modules` выбирает локальные модули по пути относительно репозитория или по имени. Потребитель объявляет каждый вложенный Git-модуль отдельным требованием по имени из его манифеста. Например, для `require github.com/acme/contracts/proto/user` не нужны ни тег, ни вручную указанный коммит: `mod tidy` найдёт текущий HEAD репозитория и запишет точный коммит в `protobuf.lock`. Повторный `tidy` сохранит его; `mod update` обновит требование без версии до текущего HEAD. Явно указанный полный хеш коммита из 40 или 64 символов останется закреплённым при обновлении. SemVer-теги также поддерживаются: для вложенного модуля с версией `v1.2.3` тег называется `proto/user/v1.2.3` по [правилу Go для репозиториев с несколькими модулями](https://go.dev/ref/mod#mapping-versions-to-commits). У каждого требуемого модуля своя запись lock и корни исходников. Локальный `replace` может указывать на каталог вложенного модуля. From 78bc7fcbfd966a944958bd59d6c5cd681c567e2f Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 23 Sep 2026 15:13:30 +0300 Subject: [PATCH 09/26] Clarify roots of nested protobuf modules --- content/docs/reference/protobuf-mod.mdx | 4 +++- content/docs/reference/protobuf-mod.ru.mdx | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/content/docs/reference/protobuf-mod.mdx b/content/docs/reference/protobuf-mod.mdx index c894ea3..d5876a9 100644 --- a/content/docs/reference/protobuf-mod.mdx +++ b/content/docs/reference/protobuf-mod.mdx @@ -16,7 +16,7 @@ The `protobuf.mod` file resides at the root of a Protocol Buffer module. Designe type: "directive" }, roots: { - description: "List of internal repository subdirectories containing .proto schema files. Defaults to '.'.", + description: "Directories containing .proto files, relative to the directory of this protobuf.mod. Defaults to '.'.", type: "directive" }, require: { @@ -66,3 +66,5 @@ replace github.com/acme/weather => ../weather-fork 3. **Replace Guardrail**: Local `replace` directives work during generation. `easyp mod tidy` and `easyp mod update` reject them until they are removed, so a reproducible Git lock never records a local path. For multiple modules in one repository, put a `protobuf.mod` in each module directory. Run `easyp mod tidy` from each local module directory; each writes its own `protobuf.lock`. `generate.modules` can select local modules by repository-relative path or module identity. A consumer declares each nested Git module separately by its declared identity. For example, `require github.com/acme/contracts/proto/user` needs no tag or manually supplied commit: `mod tidy` finds the repository's current HEAD and records its exact commit in `protobuf.lock`. Repeating `tidy` preserves that commit; `mod update` refreshes a versionless requirement to the current HEAD. An explicitly supplied full 40- or 64-character commit stays pinned during update. SemVer requirements remain supported for tagged releases; a nested module tagged `v1.2.3` uses `proto/user/v1.2.3`, matching the [Go multi-module tag convention](https://go.dev/ref/mod#mapping-versions-to-commits). Each required module has its own lock entry and source roots. A local `replace` can target a nested module directory. + +For example, with `repo/foo/protobuf.mod` containing `roots proto`, EasyP reads files under the physical repository path `repo/foo/proto`. A file at `repo/foo/proto/user/v1/user.proto` has the protobuf import path `user/v1/user.proto`: import paths are relative to the resolved root, so the module directory and the root directory are not repeated in imports. With `roots .`, the physical root is `repo/foo`. diff --git a/content/docs/reference/protobuf-mod.ru.mdx b/content/docs/reference/protobuf-mod.ru.mdx index d47dd51..7102bcb 100644 --- a/content/docs/reference/protobuf-mod.ru.mdx +++ b/content/docs/reference/protobuf-mod.ru.mdx @@ -16,7 +16,7 @@ description: "Спецификация файла protobuf.mod, независи type: "директива" }, roots: { - description: "Список внутренних поддиректорий репозитория с файлами .proto. По умолчанию '.'.", + description: "Каталоги с файлами .proto относительно папки этого protobuf.mod. По умолчанию '.'.", type: "директива" }, require: { @@ -66,3 +66,5 @@ replace github.com/acme/weather => ../weather-fork 3. **Защита lock-файла**: Локальный `replace` работает при генерации. `easyp mod tidy` и `easyp mod update` отклоняют его до удаления, чтобы в воспроизводимый Git lock не попал локальный путь. Если в одном репозитории несколько модулей, разместите `protobuf.mod` в каталоге каждого. Запускайте `easyp mod tidy` из каталога каждого локального модуля: у каждого будет свой `protobuf.lock`. `generate.modules` выбирает локальные модули по пути относительно репозитория или по имени. Потребитель объявляет каждый вложенный Git-модуль отдельным требованием по имени из его манифеста. Например, для `require github.com/acme/contracts/proto/user` не нужны ни тег, ни вручную указанный коммит: `mod tidy` найдёт текущий HEAD репозитория и запишет точный коммит в `protobuf.lock`. Повторный `tidy` сохранит его; `mod update` обновит требование без версии до текущего HEAD. Явно указанный полный хеш коммита из 40 или 64 символов останется закреплённым при обновлении. SemVer-теги также поддерживаются: для вложенного модуля с версией `v1.2.3` тег называется `proto/user/v1.2.3` по [правилу Go для репозиториев с несколькими модулями](https://go.dev/ref/mod#mapping-versions-to-commits). У каждого требуемого модуля своя запись lock и корни исходников. Локальный `replace` может указывать на каталог вложенного модуля. + +Например, если в `repo/foo/protobuf.mod` указано `roots proto`, EasyP читает файлы из физического пути `repo/foo/proto` внутри репозитория. У файла `repo/foo/proto/user/v1/user.proto` protobuf import path будет `user/v1/user.proto`: путь импорта считается относительно вычисленного root, поэтому каталог модуля и сам root в импорте не повторяются. При `roots .` физический root — `repo/foo`. From f120236d88fb848091fb43cbc04e9b00e1fc82e6 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 23 Sep 2026 15:43:34 +0300 Subject: [PATCH 10/26] docs(v1): describe easyp get dependency workflow --- content/docs/cli/package-manager/index.mdx | 6 +++-- content/docs/cli/package-manager/index.ru.mdx | 6 +++-- content/docs/guides/adding-dependency.mdx | 26 ++++++++++++++++--- content/docs/guides/adding-dependency.ru.mdx | 26 ++++++++++++++++--- content/docs/reference/protobuf-lock.mdx | 3 ++- content/docs/reference/protobuf-lock.ru.mdx | 3 ++- content/docs/reference/protobuf-mod.mdx | 4 +-- content/docs/reference/protobuf-mod.ru.mdx | 4 +-- 8 files changed, 60 insertions(+), 18 deletions(-) diff --git a/content/docs/cli/package-manager/index.mdx b/content/docs/cli/package-manager/index.mdx index 3149b82..fe7038c 100644 --- a/content/docs/cli/package-manager/index.mdx +++ b/content/docs/cli/package-manager/index.mdx @@ -21,18 +21,20 @@ require ( For a Git repository with multiple `protobuf.mod` files, require each nested module separately by the identity declared in its manifest. For untagged modules, write `require repo/foo` and `require repo/bar`; EasyP finds both manifests and locks the resolved commits without module-specific tags. Explicit commit hashes stay pinned during `mod update`. Tagged releases remain optional: a module in `foo/` uses a tag such as `foo/v1.2.3`. EasyP resolves each module's source roots independently. +Run `easyp get ` from the directory containing your `protobuf.mod` to add a requirement without editing the file. Use `@v1.2.3` or `@` to select a specific version. A newly added requirement without a suffix resolves the current Git HEAD; repeating the command keeps its existing lock pin. The chosen module is a direct requirement; dependencies discovered through it are added to `protobuf.mod` with `// indirect`. Repeating the command does not duplicate requirements. If resolution fails, the manifest and lock are not changed. + ## Commands | Command | Behavior | |---------|----------| +| `easyp get [@version\|@commit]` | Adds or promotes a direct requirement, resolves transitive requirements, and writes `protobuf.lock` | | `easyp mod tidy` | Resolves direct and transitive requirements and writes `protobuf.lock` | | `easyp mod download` | Downloads the exact commits in `protobuf.lock` and verifies their hashes | | `easyp mod update` | Refreshes requirements within their current major versions, then updates the lock | | `easyp mod vendor` | Verifies locked dependencies and copies their `.proto` files into `easyp_vendor` | ```bash -easyp mod tidy -easyp mod download +easyp get github.com/acme/contracts/proto/user easyp mod vendor easyp generate ``` diff --git a/content/docs/cli/package-manager/index.ru.mdx b/content/docs/cli/package-manager/index.ru.mdx index f13ab77..a88ab99 100644 --- a/content/docs/cli/package-manager/index.ru.mdx +++ b/content/docs/cli/package-manager/index.ru.mdx @@ -21,18 +21,20 @@ require ( Если в Git-репозитории несколько `protobuf.mod`, объявляйте каждый вложенный модуль отдельным `require` по имени из его манифеста. Для модулей без тегов достаточно `require repo/foo` и `require repo/bar`: EasyP найдёт оба манифеста и закрепит найденные коммиты без отдельных тегов. Явно указанные хеши останутся закреплёнными при `mod update`. Теги для релизов необязательны; для модуля в `foo/` версия `v1.2.3` использует тег `foo/v1.2.3`. Корни исходников каждого модуля разрешаются независимо. +Выполните `easyp get <модуль>` из каталога с вашим `protobuf.mod`, чтобы добавить зависимость без ручного редактирования файла. Суффикс `@v1.2.3` или `@<полный-коммит>` задаёт конкретную версию. Новое требование без суффикса фиксирует текущий HEAD Git; повторный вызов сохраняет уже выбранный коммит. Выбранный модуль становится прямой зависимостью, а найденные через него зависимости дописываются в `protobuf.mod` с пометкой `// indirect`. Повторный вызов не создаёт дубликатов. При ошибке разрешения манифест и lock не меняются. + ## Команды | Команда | Поведение | |---------|-----------| +| `easyp get <модуль>[@версия\|@коммит]` | Добавляет или делает прямой зависимостью модуль, разрешает транзитивные зависимости и записывает `protobuf.lock` | | `easyp mod tidy` | Разрешает прямые и транзитивные требования и записывает `protobuf.lock` | | `easyp mod download` | Скачивает точные коммиты из lock и проверяет хеши | | `easyp mod update` | Обновляет требования в пределах текущих мажорных версий и пересоздаёт lock | | `easyp mod vendor` | Проверяет зафиксированные зависимости и копирует их `.proto` в `easyp_vendor` | ```bash -easyp mod tidy -easyp mod download +easyp get github.com/acme/contracts/proto/user easyp mod vendor easyp generate ``` diff --git a/content/docs/guides/adding-dependency.mdx b/content/docs/guides/adding-dependency.mdx index 4537fc0..f622d9f 100644 --- a/content/docs/guides/adding-dependency.mdx +++ b/content/docs/guides/adding-dependency.mdx @@ -1,21 +1,39 @@ --- title: "Adding a Dependency" -description: "Step-by-step guide on adding Protobuf module dependencies, resolving transitive dependencies via easyp mod tidy, and committing lockfiles." +description: "Add Protobuf module dependencies with easyp get and commit the resolved lockfile." --- This guide demonstrates how to add a third-party or shared Protobuf module dependency to your EasyP project. --- +## Add a module with `easyp get` + +From the directory containing your `protobuf.mod`, run: + +```bash +easyp get github.com/acme/weather +# Or select a tag or full Git commit: +easyp get github.com/acme/weather@v1.2.3 +``` + +`get` adds the selected module as a direct `require`, writes its transitive dependencies as `// indirect`, and updates `protobuf.lock` with exact commits and content hashes. A module inside a Git repository can be named by its full module path, such as `github.com/acme/contracts/proto/user`. A tag is optional; without one, EasyP locks the repository's current HEAD. Run the command separately in each local module directory that has its own `protobuf.mod`. + +Add the required protobuf `import` to your `.proto` file, then review and commit both `protobuf.mod` and `protobuf.lock`. + +The steps below show the equivalent manual manifest workflow. + +--- + ## Workflow Overview -1. **Declare Dependency**: Add the target Git repository identity and version tag to `protobuf.mod`. Use `import` statements to reference files from that declared dependency. -2. **Run Resolution**: Execute `easyp mod tidy` to compute the transitive dependency graph. +1. **Declare Dependency**: Add the target Git module identity to `protobuf.mod`. Use `import` statements to reference files from that declared dependency. +2. **Run Resolution**: Execute `easyp mod tidy` to compute the transitive dependency graph after editing the manifest manually. 3. **Commit Lockfile**: Review the updated `protobuf.mod` and `protobuf.lock` files and commit them to version control. --- -## Step 1: Declare the Dependency +## Step 1: Declare the Dependency Manually Open your module's `protobuf.mod` file and add the required module under the `require` block: diff --git a/content/docs/guides/adding-dependency.ru.mdx b/content/docs/guides/adding-dependency.ru.mdx index f28a584..e330b42 100644 --- a/content/docs/guides/adding-dependency.ru.mdx +++ b/content/docs/guides/adding-dependency.ru.mdx @@ -1,21 +1,39 @@ --- title: "Добавление зависимости" -description: "Пошаговое руководство по добавлению зависимостей Protobuf-модулей, резолюции транзитивных зависимостей через easyp mod tidy и фиксации lock-файлов." +description: "Добавление зависимостей Protobuf-модулей через easyp get и фиксация разрешённого lock-файла." --- В данном руководстве рассматривается процесс добавления сторонних или общих Protobuf-модулей в проект EasyP. --- +## Добавление модуля через `easyp get` + +Из каталога, в котором лежит ваш `protobuf.mod`, выполните: + +```bash +easyp get github.com/acme/weather +# Либо укажите тег или полный Git-коммит: +easyp get github.com/acme/weather@v1.2.3 +``` + +Команда добавляет выбранный модуль как прямой `require`, записывает его транзитивные зависимости с пометкой `// indirect` и обновляет `protobuf.lock` с точными коммитами и хешами содержимого. Вложенный модуль указывают по полному пути, например `github.com/acme/contracts/proto/user`. Тег необязателен: без него EasyP закрепляет текущий HEAD репозитория. Для каждого локального модуля с собственным `protobuf.mod` запускайте команду в его каталоге. + +Добавьте нужный protobuf `import` в `.proto`, затем проверьте и закоммитьте `protobuf.mod` и `protobuf.lock`. + +Ниже приведён эквивалентный способ с ручным редактированием манифеста. + +--- + ## Общий процесс -1. **Объявление зависимости**: Добавление Git-репозитория и тега версии в `protobuf.mod`. Через `import` в `.proto` используются файлы объявленной зависимости. -2. **Запуск резолюции**: Выполнение `easyp mod tidy` для вычисления полного графа транзитивных зависимостей. +1. **Объявление зависимости**: Добавление Git-модуля в `protobuf.mod`. Через `import` в `.proto` используются файлы объявленной зависимости. +2. **Запуск резолюции**: Выполнение `easyp mod tidy` после ручного изменения манифеста для вычисления полного графа транзитивных зависимостей. 3. **Фиксация в Git**: Проверка и коммит обновлённых файлов `protobuf.mod` и `protobuf.lock`. --- -## Шаг 1: Объявление зависимости +## Шаг 1: Ручное объявление зависимости Откройте `protobuf.mod` вашего модуля и добавьте требуемый модуль в блок `require`: diff --git a/content/docs/reference/protobuf-lock.mdx b/content/docs/reference/protobuf-lock.mdx index 4464769..f9968a0 100644 --- a/content/docs/reference/protobuf-lock.mdx +++ b/content/docs/reference/protobuf-lock.mdx @@ -3,7 +3,7 @@ title: "protobuf.lock Reference" description: "Specification for protobuf.lock, the generated lockfile securing resolved Git commits, versions, and cryptographic hashes for hermetic builds." --- -The `protobuf.lock` file is an auto-generated artifact created by EasyP dependency commands (`easyp mod tidy`, `easyp mod update`). It locks the exact transitive dependency graph to guarantee **100% hermetic, reproducible builds** across all local developer environments and CI pipelines. +The `protobuf.lock` file is an auto-generated artifact created by EasyP dependency commands (`easyp get`, `easyp mod tidy`, `easyp mod update`). It locks the exact transitive dependency graph to guarantee **100% hermetic, reproducible builds** across all local developer environments and CI pipelines. --- @@ -65,6 +65,7 @@ modules: ## Lifecycle Commands +- `easyp get [@version|@commit]`: Adds a direct requirement, records its transitive requirements as indirect, and updates `protobuf.lock`. - `easyp mod tidy`: Resolves required imports, updates indirect dependencies, and regenerates `protobuf.lock`. - `easyp mod update`: Upgrades tagged dependencies to latest semver-compatible versions, refreshes versionless requirements to Git HEAD, preserves explicit commit pins, and updates `protobuf.lock`. - `easyp mod download`: Populates local cache strictly using `protobuf.lock` without reaching out to remote registries or modifying locked versions. diff --git a/content/docs/reference/protobuf-lock.ru.mdx b/content/docs/reference/protobuf-lock.ru.mdx index bf6de9a..9bbcc49 100644 --- a/content/docs/reference/protobuf-lock.ru.mdx +++ b/content/docs/reference/protobuf-lock.ru.mdx @@ -3,7 +3,7 @@ title: "Справочник protobuf.lock" description: "Спецификация файла protobuf.lock, автоматически генерируемого lock-файла для фиксации коммитов Git, версий и криптографических хешей для воспроизводимых сборок." --- -Файл `protobuf.lock` — это автоматически генерируемый артефакт, создаваемый командами управления зависимостями EasyP (`easyp mod tidy`, `easyp mod update`). Он фиксирует точный транзитивный граф зависимостей для обеспечения **100% герметичных и воспроизводимых сборок** во всех локальных окружениях и в CI. +Файл `protobuf.lock` — это автоматически генерируемый артефакт, создаваемый командами управления зависимостями EasyP (`easyp get`, `easyp mod tidy`, `easyp mod update`). Он фиксирует точный транзитивный граф зависимостей для обеспечения **100% герметичных и воспроизводимых сборок** во всех локальных окружениях и в CI. --- @@ -65,6 +65,7 @@ modules: ## Команды жизненного цикла +- `easyp get <модуль>[@версия|@коммит]`: Добавляет прямое требование, записывает его транзитивные требования как indirect и обновляет `protobuf.lock`. - `easyp mod tidy`: Сканирует импорты, дописывает транзитивные зависимости и перегенерирует `protobuf.lock`. - `easyp mod update`: Обновляет зависимости с тегами до свежих совместимых релизов, требования без версии — до Git HEAD, сохраняет явно закреплённые хеши и обновляет `protobuf.lock`. - `easyp mod download`: Наполняет локальный кэш строго по `protobuf.lock` без обращения к внешним реестрам. diff --git a/content/docs/reference/protobuf-mod.mdx b/content/docs/reference/protobuf-mod.mdx index d5876a9..410e2fb 100644 --- a/content/docs/reference/protobuf-mod.mdx +++ b/content/docs/reference/protobuf-mod.mdx @@ -24,7 +24,7 @@ The `protobuf.mod` file resides at the root of a Protocol Buffer module. Designe type: "directive block" }, "require // indirect": { - description: "Transitive dependency marker automatically managed by 'easyp mod tidy'.", + description: "Transitive dependency marker written by 'easyp get' and 'easyp mod tidy'.", type: "annotation" }, replace: { @@ -63,7 +63,7 @@ replace github.com/acme/weather => ../weather-fork 1. **Git-Native Identity**: The canonical identity of a module is its Git URL (e.g., `github.com/acme/weather`). 2. **Per-Module Bounds**: Every module maintains its own independent `protobuf.mod`. MVS operates per-module rather than forcing global monorepo single-version constraints. -3. **Replace Guardrail**: Local `replace` directives work during generation. `easyp mod tidy` and `easyp mod update` reject them until they are removed, so a reproducible Git lock never records a local path. +3. **Replace Guardrail**: Local `replace` directives work during generation. `easyp get`, `easyp mod tidy`, and `easyp mod update` reject them until they are removed, so a reproducible Git lock never records a local path. For multiple modules in one repository, put a `protobuf.mod` in each module directory. Run `easyp mod tidy` from each local module directory; each writes its own `protobuf.lock`. `generate.modules` can select local modules by repository-relative path or module identity. A consumer declares each nested Git module separately by its declared identity. For example, `require github.com/acme/contracts/proto/user` needs no tag or manually supplied commit: `mod tidy` finds the repository's current HEAD and records its exact commit in `protobuf.lock`. Repeating `tidy` preserves that commit; `mod update` refreshes a versionless requirement to the current HEAD. An explicitly supplied full 40- or 64-character commit stays pinned during update. SemVer requirements remain supported for tagged releases; a nested module tagged `v1.2.3` uses `proto/user/v1.2.3`, matching the [Go multi-module tag convention](https://go.dev/ref/mod#mapping-versions-to-commits). Each required module has its own lock entry and source roots. A local `replace` can target a nested module directory. diff --git a/content/docs/reference/protobuf-mod.ru.mdx b/content/docs/reference/protobuf-mod.ru.mdx index 7102bcb..8ad20b4 100644 --- a/content/docs/reference/protobuf-mod.ru.mdx +++ b/content/docs/reference/protobuf-mod.ru.mdx @@ -24,7 +24,7 @@ description: "Спецификация файла protobuf.mod, независи type: "блок директив" }, "require // indirect": { - description: "Метка транзитивной зависимости, управляемая автоматически командой 'easyp mod tidy'.", + description: "Метка транзитивной зависимости, записываемая командами 'easyp get' и 'easyp mod tidy'.", type: "аннотация" }, replace: { @@ -63,7 +63,7 @@ replace github.com/acme/weather => ../weather-fork 1. **Git-Native идентичность**: Каноническим идентификатором модуля является его Git URL (`github.com/acme/weather`). 2. **Помодульный скоуп**: Каждый модуль имеет собственный `protobuf.mod`. MVS работает помодульно (per-module), не навязывая глобальных ограничений версий в монорепозитории. -3. **Защита lock-файла**: Локальный `replace` работает при генерации. `easyp mod tidy` и `easyp mod update` отклоняют его до удаления, чтобы в воспроизводимый Git lock не попал локальный путь. +3. **Защита lock-файла**: Локальный `replace` работает при генерации. `easyp get`, `easyp mod tidy` и `easyp mod update` отклоняют его до удаления, чтобы в воспроизводимый Git lock не попал локальный путь. Если в одном репозитории несколько модулей, разместите `protobuf.mod` в каталоге каждого. Запускайте `easyp mod tidy` из каталога каждого локального модуля: у каждого будет свой `protobuf.lock`. `generate.modules` выбирает локальные модули по пути относительно репозитория или по имени. Потребитель объявляет каждый вложенный Git-модуль отдельным требованием по имени из его манифеста. Например, для `require github.com/acme/contracts/proto/user` не нужны ни тег, ни вручную указанный коммит: `mod tidy` найдёт текущий HEAD репозитория и запишет точный коммит в `protobuf.lock`. Повторный `tidy` сохранит его; `mod update` обновит требование без версии до текущего HEAD. Явно указанный полный хеш коммита из 40 или 64 символов останется закреплённым при обновлении. SemVer-теги также поддерживаются: для вложенного модуля с версией `v1.2.3` тег называется `proto/user/v1.2.3` по [правилу Go для репозиториев с несколькими модулями](https://go.dev/ref/mod#mapping-versions-to-commits). У каждого требуемого модуля своя запись lock и корни исходников. Локальный `replace` может указывать на каталог вложенного модуля. From 74ff4e79239960127c477bc4f3509fbda61290b7 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 23 Sep 2026 17:15:13 +0300 Subject: [PATCH 11/26] docs(v1): describe recursive config validation --- content/docs/cli/configuration.mdx | 8 +++++++- content/docs/cli/configuration.ru.mdx | 8 +++++++- content/docs/cli/index.mdx | 2 +- content/docs/cli/index.ru.mdx | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/content/docs/cli/configuration.mdx b/content/docs/cli/configuration.mdx index b3879b3..2a232a4 100644 --- a/content/docs/cli/configuration.mdx +++ b/content/docs/cli/configuration.mdx @@ -48,7 +48,13 @@ The global flags are `--cfg` (alias `--config`, default `easyp.yaml`), `--debug` `breaking` applies the nearest `breaking` section to each reported file. When nested policies select different Git baselines, it compares against each baseline and reports an issue only under the policy that selected it. -`validate-config --cfg --format json` accepts `easyp.yaml`, `easyp.gen.yaml`, `protobuf.mod`, and `protobuf.lock`. Invalid lock versions, incomplete entries, and malformed hashes are reported as validation errors. +`validate-config` recursively checks every `easyp.yaml`, `easyp.gen.yaml`, `protobuf.mod`, and `protobuf.lock` below the current directory. Pass `--cfg ` to check one file or `--cfg ` to scan another directory. JSON errors identify the file; YAML structure errors also include line and column. Invalid lock versions, incomplete entries, and malformed hashes are reported as validation errors. + +```bash +easyp validate-config +easyp validate-config --cfg ./services --format json +easyp validate-config --cfg ./services/api/easyp.gen.yaml +``` `mod vendor` verifies the locked Git dependencies and copies their `.proto` files into `easyp_vendor` using their import paths. It replaces a previous vendor tree only after all files have been copied successfully. Duplicate import paths are errors. Run `mod tidy` first; local `replace` directives cannot be vendored. diff --git a/content/docs/cli/configuration.ru.mdx b/content/docs/cli/configuration.ru.mdx index 72fb41a..eb1931b 100644 --- a/content/docs/cli/configuration.ru.mdx +++ b/content/docs/cli/configuration.ru.mdx @@ -48,7 +48,13 @@ easyp breaking --path proto --against main `breaking` применяет ближайшую секцию `breaking` к каждому файлу с ошибкой. Если вложенные политики выбирают разные Git-базы, команда сравнивает файлы с каждой базой и относит ошибку только к выбравшей её политике. -`validate-config --cfg <файл> --format json` принимает `easyp.yaml`, `easyp.gen.yaml`, `protobuf.mod` и `protobuf.lock`. Некорректная версия lock-файла, неполные записи и неверные хеши выдаются как ошибки проверки. +`validate-config` рекурсивно проверяет все `easyp.yaml`, `easyp.gen.yaml`, `protobuf.mod` и `protobuf.lock` внутри текущего каталога. Передайте `--cfg <файл>`, чтобы проверить один файл, или `--cfg <каталог>`, чтобы проверить другой каталог. В JSON-ошибках указан файл, а для ошибок структуры YAML — строка и столбец. Некорректная версия lock-файла, неполные записи и неверные хеши выдаются как ошибки проверки. + +```bash +easyp validate-config +easyp validate-config --cfg ./services --format json +easyp validate-config --cfg ./services/api/easyp.gen.yaml +``` `mod vendor` проверяет зафиксированные Git-зависимости и копирует их `.proto` в `easyp_vendor` по import path. Старый каталог заменяется только после успешного копирования всех файлов. Совпадающие import path вызывают ошибку. Сначала выполните `mod tidy`; локальные `replace` нельзя вендорить. diff --git a/content/docs/cli/index.mdx b/content/docs/cli/index.mdx index 294ffb4..c1f248c 100644 --- a/content/docs/cli/index.mdx +++ b/content/docs/cli/index.mdx @@ -12,7 +12,7 @@ The EasyP CLI is the local toolkit for Protocol Buffers workflows. | `easyp generate` | Run local/remote plugins | | `easyp mod` | Git-based dependencies | | `easyp init` | Project bootstrap | -| `easyp validate-config` | Validate a v1 policy, generator, module manifest, or lockfile | +| `easyp validate-config` | Recursively validate v1 configuration and module files | | `easyp ls-files` | List local protos and reachable imports | | `easyp schema-gen` | Generate v1 JSON Schemas | | `easyp completion bash\|zsh` | Print a shell completion script | diff --git a/content/docs/cli/index.ru.mdx b/content/docs/cli/index.ru.mdx index 853809a..696300a 100644 --- a/content/docs/cli/index.ru.mdx +++ b/content/docs/cli/index.ru.mdx @@ -12,7 +12,7 @@ CLI EasyP — локальный инструментарий для Protocol Bu | `easyp generate` | Локальные/удалённые плагины | | `easyp mod` | Git-зависимости | | `easyp init` | Инициализация проекта | -| `easyp validate-config` | Проверка v1-политики, конфигурации генератора, манифеста или lock-файла | +| `easyp validate-config` | Рекурсивная проверка конфигурации и модульных файлов v1 | | `easyp ls-files` | Список локальных proto и достижимых импортов | | `easyp schema-gen` | Генерация JSON Schema для v1 | | `easyp completion bash\|zsh` | Вывод скрипта автодополнения | From 7b89fed39a6b8c24d3fa08bcc92b27d6f43c90d9 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Thu, 24 Sep 2026 17:06:45 +0300 Subject: [PATCH 12/26] docs(v1): document YAML expansion and MCP tool --- content/docs/cli/configuration.mdx | 6 ++++++ content/docs/cli/configuration.ru.mdx | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/content/docs/cli/configuration.mdx b/content/docs/cli/configuration.mdx index 2a232a4..8e8d167 100644 --- a/content/docs/cli/configuration.mdx +++ b/content/docs/cli/configuration.mdx @@ -46,6 +46,10 @@ The global flags are `--cfg` (alias `--config`, default `easyp.yaml`), `--debug` `lint` and `breaking` read the v1 `easyp.yaml`. They use the nearest module's declared roots and locked or local dependency roots for imports. A policy may exist without a `protobuf.mod`; in that case the commands use the scanned files and built-in imports. +`generate` and `ls-files` also work without `protobuf.mod` when there are no module dependencies: the current project directory is treated as the source root. + +EasyP expands environment variables in `easyp.yaml` and `easyp.gen.yaml` before parsing or validation. `${NAME}` uses the variable value, `${NAME:-default}` supplies a fallback, and `$${NAME}` leaves a literal `${NAME}`. An unset variable without a fallback becomes an empty string. YAML comments are ignored during expansion. `protobuf.mod` and `protobuf.lock` do not use this substitution. + `breaking` applies the nearest `breaking` section to each reported file. When nested policies select different Git baselines, it compares against each baseline and reports an issue only under the policy that selected it. `validate-config` recursively checks every `easyp.yaml`, `easyp.gen.yaml`, `protobuf.mod`, and `protobuf.lock` below the current directory. Pass `--cfg ` to check one file or `--cfg ` to scan another directory. JSON errors identify the file; YAML structure errors also include line and column. Invalid lock versions, incomplete entries, and malformed hashes are reported as validation errors. @@ -62,6 +66,8 @@ easyp validate-config --cfg ./services/api/easyp.gen.yaml `schema-gen --out-dir schemas` writes separate JSON Schemas for `easyp.yaml`, `easyp.gen.yaml`, and `protobuf.lock`, each with a `-v1.schema.json` filename and an unversioned alias. `protobuf.mod` is a text manifest, so validate it with `validate-config` instead. CLI validation also checks semantic rules beyond the JSON Schemas. +The exported `github.com/easyp-tech/easyp/mcp/easypconfig` package registers `easyp_config_describe` with an MCP server through `easypconfig.RegisterTool(server)`. The tool describes the two editable YAML files and reads the same JSON Schemas as `schema-gen`. It does not describe `protobuf.mod` or `protobuf.lock`. + ## Minimal files ```text diff --git a/content/docs/cli/configuration.ru.mdx b/content/docs/cli/configuration.ru.mdx index eb1931b..e2e788b 100644 --- a/content/docs/cli/configuration.ru.mdx +++ b/content/docs/cli/configuration.ru.mdx @@ -46,6 +46,10 @@ easyp breaking --path proto --against main `lint` и `breaking` читают `easyp.yaml` версии v1. Для импортов они используют корни ближайшего модуля и его зафиксированных или локальных зависимостей. Политика может существовать без `protobuf.mod`; тогда используются проверяемые файлы и встроенные импорты. +`generate` и `ls-files` тоже работают без `protobuf.mod`, если у проекта нет модульных зависимостей: текущий каталог проекта считается корнем исходников. + +Перед разбором и проверкой `easyp.yaml` и `easyp.gen.yaml` EasyP подставляет переменные окружения. `${NAME}` берёт значение переменной, `${NAME:-default}` задаёт запасное значение, а `$${NAME}` оставляет буквальную строку `${NAME}`. Отсутствующая переменная без запасного значения превращается в пустую строку. Подстановки в комментариях YAML игнорируются. В `protobuf.mod` и `protobuf.lock` такой подстановки нет. + `breaking` применяет ближайшую секцию `breaking` к каждому файлу с ошибкой. Если вложенные политики выбирают разные Git-базы, команда сравнивает файлы с каждой базой и относит ошибку только к выбравшей её политике. `validate-config` рекурсивно проверяет все `easyp.yaml`, `easyp.gen.yaml`, `protobuf.mod` и `protobuf.lock` внутри текущего каталога. Передайте `--cfg <файл>`, чтобы проверить один файл, или `--cfg <каталог>`, чтобы проверить другой каталог. В JSON-ошибках указан файл, а для ошибок структуры YAML — строка и столбец. Некорректная версия lock-файла, неполные записи и неверные хеши выдаются как ошибки проверки. @@ -62,6 +66,8 @@ easyp validate-config --cfg ./services/api/easyp.gen.yaml `schema-gen --out-dir schemas` создаёт отдельные JSON Schema для `easyp.yaml`, `easyp.gen.yaml` и `protobuf.lock`: файлы с суффиксом `-v1.schema.json` и псевдонимы без версии. `protobuf.mod` — текстовый манифест; проверяйте его командой `validate-config`. CLI также проверяет семантические правила, не выраженные в JSON Schema. +Экспортируемый пакет `github.com/easyp-tech/easyp/mcp/easypconfig` регистрирует инструмент `easyp_config_describe` в MCP-сервере через `easypconfig.RegisterTool(server)`. Инструмент описывает два редактируемых YAML-файла и использует те же JSON Schema, что и `schema-gen`. Он не описывает `protobuf.mod` и `protobuf.lock`. + ## Минимальный пример ```text From 141bd45bc7a4ddb1d7bf1f3b250df148b5e8546c Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Thu, 24 Sep 2026 20:22:08 +0300 Subject: [PATCH 13/26] Document v1 plugin sources and add team overview --- content/docs/cli/generator/index.mdx | 2 +- content/docs/cli/generator/index.ru.mdx | 2 +- content/docs/reference/easyp-gen-yaml.mdx | 21 + content/docs/reference/easyp-gen-yaml.ru.mdx | 21 + public/easyp-v1-overview.html | 523 +++++++++++++++++++ 5 files changed, 567 insertions(+), 2 deletions(-) create mode 100644 public/easyp-v1-overview.html diff --git a/content/docs/cli/generator/index.mdx b/content/docs/cli/generator/index.mdx index 8f482e7..784d47b 100644 --- a/content/docs/cli/generator/index.mdx +++ b/content/docs/cli/generator/index.mdx @@ -48,7 +48,7 @@ easyp generate --descriptor_set_out descriptors.pb --include_imports ## Plugins and managed options -`plugins[].name` selects a local executable or a bundled WASM plugin. EasyP selects bundled plugins through the existing plugin resolver. A remote plugin uses `remote` with a separate pinned semantic `version`. Plugin outputs are relative to the generator file. +`plugins[].name` selects a local executable or a bundled WASM plugin. EasyP selects bundled plugins through the existing plugin resolver. `plugins[].path` runs a binary at an explicit path, while `plugins[].command` runs a command with arguments. Each plugin sets exactly one of `name`, `path`, `command`, or `remote`. A remote plugin uses `remote` with a separate pinned semantic `version`. Relative binary paths and commands run from the directory where EasyP starts; plugin outputs are relative to the generator file. The existing managed rules remain available under `generate.managed`, including module, package, path, and field selectors. `options.go.package_prefix` can provide a Go package prefix; a repository-root generator file can supply a default for nested generator files. See the full [`easyp.gen.yaml` reference](/docs/reference/easyp-gen-yaml). diff --git a/content/docs/cli/generator/index.ru.mdx b/content/docs/cli/generator/index.ru.mdx index aed1991..3628af3 100644 --- a/content/docs/cli/generator/index.ru.mdx +++ b/content/docs/cli/generator/index.ru.mdx @@ -48,7 +48,7 @@ easyp generate --descriptor_set_out descriptors.pb --include_imports ## Плагины и managed mode -`plugins[].name` выбирает локальный исполняемый файл или встроенный WASM-плагин. Встроенные плагины выбираются существующим resolver. Для удалённого плагина указываются `remote` и отдельный зафиксированный SemVer в `version`. Выходные каталоги задаются относительно файла генерации. +`plugins[].name` выбирает локальный исполняемый файл или встроенный WASM-плагин. Встроенные плагины выбираются существующим resolver. `plugins[].path` запускает бинарь по явному пути, а `plugins[].command` — команду со списком аргументов. В каждом плагине задаётся ровно одно из `name`, `path`, `command` и `remote`. Для удалённого плагина указываются `remote` и отдельный зафиксированный SemVer в `version`. Относительный путь к бинарю и команда выполняются из каталога запуска EasyP; выходные каталоги задаются относительно файла генерации. Прежние правила managed mode доступны в `generate.managed`, в том числе селекторы по модулю, пакету, пути и полю. `options.go.package_prefix` задаёт префикс Go-пакетов; корневой `easyp.gen.yaml` может предоставить значение по умолчанию вложенным конфигам. Подробности — в [справочнике `easyp.gen.yaml`](/ru/docs/reference/easyp-gen-yaml). diff --git a/content/docs/reference/easyp-gen-yaml.mdx b/content/docs/reference/easyp-gen-yaml.mdx index a2d3603..02fad14 100644 --- a/content/docs/reference/easyp-gen-yaml.mdx +++ b/content/docs/reference/easyp-gen-yaml.mdx @@ -38,6 +38,14 @@ In accordance with EasyP's zero-duplication principles, `easyp.gen.yaml` **never description: "Local executable binary or WASM plugin identifier.", type: "string" }, + "plugins[].path": { + description: "Explicit plugin binary path. Relative paths are resolved from the directory where easyp generate runs.", + type: "string" + }, + "plugins[].command": { + description: "Custom plugin command as an executable followed by its arguments.", + type: "string[]" + }, "plugins[].remote": { description: "gRPC or HTTP remote code generation service URL.", type: "string" @@ -145,3 +153,16 @@ A repository-root `easyp.gen.yaml` may provide `options.go.package_prefix` as a The current v1 generator selects complete modules. `generate.packages` is reserved for a later release, once its matching syntax is specified. Remote plugins require a `version` such as `v2.0.0`. EasyP sends that exact version to the remote generator. For local `protoc-gen-*` executables and bundled WASM plugins, the executable selected at runtime determines the version; the separate `version` field is rejected because EasyP cannot verify it. + +Each plugin declares exactly one source: `name`, `path`, `command`, or `remote`. Use `path` for a specific binary and `command` for an executable plus arguments. Both run from the directory where `easyp generate` starts and, like any Protobuf plugin, must read a `CodeGeneratorRequest` from stdin and write a `CodeGeneratorResponse` to stdout. + +```yaml +version: v1 +plugins: + - path: ./tools/protoc-gen-custom + out: ./gen/custom + - command: [sh, ./tools/protoc-plugin.sh] + out: ./gen/script +``` + +The separate `version` field is also unavailable for `path` and `command`. diff --git a/content/docs/reference/easyp-gen-yaml.ru.mdx b/content/docs/reference/easyp-gen-yaml.ru.mdx index 51ca9ee..8e7d0bd 100644 --- a/content/docs/reference/easyp-gen-yaml.ru.mdx +++ b/content/docs/reference/easyp-gen-yaml.ru.mdx @@ -38,6 +38,14 @@ description: "Полная спецификация файла easyp.gen.yaml, description: "Имя локального бинарного файла или WASM плагина.", type: "string" }, + "plugins[].path": { + description: "Явный путь к бинарному плагину. Относительный путь считается от каталога запуска easyp generate.", + type: "string" + }, + "plugins[].command": { + description: "Команда запуска собственного плагина: список из исполняемого файла и аргументов.", + type: "string[]" + }, "plugins[].remote": { description: "URL удалённого сервиса генерации кода (gRPC или HTTP).", type: "string" @@ -145,3 +153,16 @@ plugins: Сейчас v1 генерирует модули целиком. `generate.packages` оставлено для будущей версии после определения синтаксиса выбора пакетов. Удалённому плагину нужен `version`, например `v2.0.0`. EasyP передаёт именно эту версию удалённому генератору. Для локального `protoc-gen-*` и встроенного WASM версию определяет выбранный исполняемый файл; отдельное поле `version` отклоняется, поскольку EasyP не может его проверить. + +Для каждого плагина указывают ровно один источник: `name`, `path`, `command` или `remote`. `path` запускает конкретный бинарный файл, а `command` принимает список из программы и её аргументов. Оба варианта работают из каталога запуска `easyp generate` и, как любой плагин Protobuf, должны принимать `CodeGeneratorRequest` из stdin и возвращать `CodeGeneratorResponse` в stdout. + +```yaml +version: v1 +plugins: + - path: ./tools/protoc-gen-custom + out: ./gen/custom + - command: [sh, ./tools/protoc-plugin.sh] + out: ./gen/script +``` + +Для `path` и `command` отдельное поле `version` также не указывается. diff --git a/public/easyp-v1-overview.html b/public/easyp-v1-overview.html new file mode 100644 index 0000000..d8c30c3 --- /dev/null +++ b/public/easyp-v1-overview.html @@ -0,0 +1,523 @@ + + + + + + + + EasyP v1.0 — обзор для команды + + + +
+ + +
+
Protobuf workflow / engineering brieffeature/v1.0-pilot · 24.09.2026
+
+
+ EasyP v1.0 · Pilot +

Контракты в Git.
Один путь до кода.

+

Модульные Protobuf-схемы, фиксированные зависимости, генерация через плагины и проверки API теперь собраны в последовательный workflow. Источник версий — protobuf.mod, воспроизводимость — protobuf.lock.

+ +
+
Git + commit + h1Точная фиксация и проверка содержимого зависимости
+
Много модулейНесколько protobuf.mod в одном репозитории, теги не обязательны
+
Разные роли файловМодуль, генератор и политика живут отдельно
+
+
+ +
+
01 / Модель

От исходника до результата

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

Рабочая цепочка v1.0
+
+
01 — DECLARE

protobuf.mod

Идентичность модуля, roots, прямые и транзитивные Git-зависимости.

+
02 — LOCK

protobuf.lock

Выбранный коммит и h1-хеш для каждого внешнего модуля.

+
03 — SELECT

easyp.gen.yaml

Какие модули генерировать, какими плагинами и куда писать файлы.

+
04 — VERIFY

Код + проверки

Генерация, lint, breaking, validate-config и CI из одних источников.

+
+
easyp.yaml задаёт правила линтинга и breaking checks рядом с proto-схемами; потребитель может иметь свой easyp.gen.yaml рядом с приложением.
+
+ +
+
02 / Конфигурация

Четыре файла — четыре задачи

В v1.0 больше не нужно смешивать зависимости, плагины и проверки в одном YAML.

+
+

protobuf.mod

Текстовый манифест модуля. Roots считаются относительно каталога самого файла. Поддерживает require и локальный replace.

modulerootsrequirereplace
+

protobuf.lock

Создаётся командами EasyP. Сохраняет выбранные версии, точные Git-коммиты и h1-хеши. Редактировать вручную не нужно.

version: 1commithash: h1:…
+

easyp.gen.yaml

Конфиг потребителя: выбор модулей, локальные/встроенные/удалённые плагины, опции и managed mode.

generate.modulespluginsmanaged
+

easyp.yaml

Конфиг продюсера: пресеты и правила lint, исключения и Git-baseline для проверки совместимости.

lintersissuesbreaking
+
+
+ +
+
03 / Показываем на примере

Один инструмент, три масштаба

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

+
+
+ + + +
+
+

Контракты как отдельный Git-модуль

Манифест описывает источник proto, генератор выбирает модуль и плагины, политика остаётся рядом со схемами.

основной путь
+
+
protobuf.mod
module github.com/acme/contracts
+roots proto
+
+require github.com/acme/shared v1.2.3
+
easyp.gen.yaml
version: v1
+generate:
+  modules: [github.com/acme/contracts]
+plugins:
+  - name: go
+    out: gen/go
+    opts:
+      paths: source_relative
+  - name: go-grpc
+    out: gen/go
+    opts:
+      paths: source_relative
+
easyp.yaml
version: v1
+linters:
+  default: STANDARD
+breaking:
+  baseline: git:main
+
Команды
easyp mod tidy
+easyp mod download
+easyp generate
+easyp lint --path proto
+easyp breaking --path proto --against main
+
+
+ + +
+
+ +
+
04 / Git-зависимости

Точно закрепить. Легко обновить.

Версия может быть SemVer-тегом, полным коммитом или отсутствовать. В последнем случае EasyP выбирает HEAD и записывает точный коммит в lock.

+
+
get

Добавить модуль

easyp get module[@version|@commit] добавляет прямой require. Найденные транзитивные зависимости записываются с // indirect.

+
tidy

Собрать граф

mod tidy разрешает требования и обновляет lock. Неразрешённый импорт не превращается в ложный пустой lock.

+
h1

Проверить байты

mod download берёт точные коммиты из lock и проверяет h1-хеш содержимого, включая повторное использование кеша.

+
↻

Обновить управляемо

mod update обновляет совместимые версии по тегам и требования без версии до HEAD; явно закреплённый коммит сохраняет выбор.

+
↧

Положить рядом

mod vendor копирует proto-файлы из lock в easyp_vendor. Повторяющиеся import path вызывают ошибку.

+
↔

Читать чужие форматы

Git-зависимость может описывать roots через Buf v1/v2 или старый EasyP. Потребителю достаточно собственного v1-манифеста.

+
+
+

Как находится модуль

У каждого вложенного protobuf.mod своя identity и roots. EasyP читает метаданные зависимости в её каталоге; если подходящего конфига нет, источником считается корень репозитория.

+

Локальная разработка

replace module => ../local-copy помогает при генерации и lint. Перед записью воспроизводимого lock через get, tidy или update локальную замену нужно убрать.

+
+
+ +
+
05 / Генерация

Один выбор модулей, любые выходы

easyp generate обнаруживает consumer-конфиги, компилирует выбранные модули целиком и запускает плагины. Версии proto-зависимостей не дублируются в YAML генератора.

+
+
01

Локальные и WASM

plugins[].name выбирает локальный protoc-gen-* или встроенный WASM-плагин через существующий resolver. Можно задать несколько плагинов и разные out.

+
02

Бинарь по пути

plugins[].path запускает конкретный исполняемый файл. Относительный путь считается от каталога запуска easyp generate.

+
03

Своя команда

plugins[].command принимает список из программы и аргументов, например [sh, ./tools/plugin.sh]. Это поле называлось command и в старом конфиге.

+
04

Удалённые плагины

plugins[].remote подключает удалённый генератор. Отдельное поле version требует зафиксированный SemVer; эта версия передаётся исполнителю.

+
05

Managed mode

generate.managed сохраняет правила disable/override для file и field options с селекторами module, package, path и field.

+
06

Go package prefix

options.go.package_prefix вычисляет Go-импорты без редактирования proto. Корневой generator может дать вложенным значение по умолчанию.

+
07

Несколько потребителей

У каждого сервиса может быть свой easyp.gen.yaml. --project запускает один выбранный consumer. Plugins не наследуются из корня.

+
08

Descriptor set

--descriptor_set_out пишет набор дескрипторов; --include_imports добавляет транзитивные импорты. Результат можно использовать в других инструментах.

+
+
easyp.gen.yaml · явный бинарь и своя команда
version: v1
+plugins:
+  - path: ./tools/protoc-gen-custom
+    out: ./gen/custom
+  - command: [sh, ./tools/protoc-plugin.sh]
+    out: ./gen/script
+

Для каждого плагина указывается один источник: name, path, command или remote. Собственный плагин читает CodeGeneratorRequest из stdin и пишет CodeGeneratorResponse в stdout.

+
Конфиг генератора сначала использует protobuf.mod рядом с собой; если его нет — корневой манифест проекта. Зависимости выбранного модуля берутся оттуда же.
+
+ +
+
06 / Политики

Схемы под контролем

Одни и те же proto-файлы можно проверять локально и в CI. Политики действуют по дереву каталогов, а breaking сравнивает API с Git baseline.

+
+

Lint

Пресеты MINIMAL, BASIC, STANDARD, COMMENTS; выборочные enable/disable и настройки отдельных правил. Ближайший easyp.yaml задаёт секцию для своего поддерева. Исключение без path может подавить выбранные правила.

+

Breaking

breaking.baseline: git:main выбирает Git-ветку для существующего checker. Вложенная политика может выбрать другой baseline; breaking.ignore исключает указанные пути.

+
+
easyp.yaml · пример политики
version: v1
+linters:
+  default: STANDARD
+  enable: [RPC_REQUEST_RESPONSE_UNIQUE]
+  disable: [PACKAGE_VERSION_SUFFIX]
+issues:
+  exclude-rules:
+    - linters: [FIELD_LOWER_SNAKE_CASE]
+breaking:
+  baseline: git:main
+
+ +
+
07 / Опыт разработчика

Проверить раньше, понять быстрее

+
+
✓

validate-config

Рекурсивно проверяет все четыре типа файлов. Можно указать один файл или каталог; JSON-ошибки содержат путь, ошибки структуры YAML — строку и столбец.

+
{ }

schema-gen

Генерирует отдельные JSON Schema для easyp.yaml, easyp.gen.yaml и protobuf.lock. YAML-валидация CLI использует тот же источник схемы.

+
AI

MCP для конфига

Экспортируемый Go-пакет mcp/easypconfig регистрирует easyp_config_describe в своём MCP-сервере. Инструмент описывает редактируемые YAML-файлы.

+
$

Переменные окружения

В двух YAML-конфигах работают ${NAME}, ${NAME:-default} и экранирование $${NAME}. Комментарии YAML подстановке не мешают.

+
ls

ls-files

Показывает локальные proto и доступные импорты из зависимостей и встроенных схем. --include-imports=false оставляет только локальные файлы.

+
⚙

init и completion

init создаёт стартовые v1-файлы, умеет выводить identity из Git origin и учитывает подтверждение перезаписи. completion помогает работать из shell.

+
+
+ +
+
08 / Быстрая шпаргалка

Команды v1.0

Примеры ниже можно запускать из каталога проекта
+
+
easyp initСоздать стартовый набор конфигов и manifest.
+
easyp get MODULE[@REF]Добавить прямую Git-зависимость и записать транзитивные как indirect.
+
easyp mod tidyРазрешить граф из protobuf.mod и обновить lock.
+
easyp mod downloadПолучить ровно те коммиты, которые указаны в lock, с проверкой хеша.
+
easyp mod updateОбновить совместимые версии и lock.
+
easyp mod vendorСкопировать зафиксированные proto-зависимости в easyp_vendor.
+
easyp generate [--project DIR]Сгенерировать код по обнаруженным consumer-конфигам или одному выбранному проекту.
+
easyp lint --path DIRПроверить стиль и структуру proto по ближайшим политикам.
+
easyp breaking --against mainНайти несовместимые изменения относительно Git baseline.
+
easyp ls-filesПоказать исходники и reachable imports; доступен text/JSON формат.
+
easyp validate-configРекурсивно проверить конфиги, manifest и lock.
+
easyp schema-gen --out-dir schemasСоздать JSON Schema для редактора и CI.
+
easyp completionНастроить shell completion.
+
+
+ +
+
09 / Честный статус пилота

Что пока оставлено на потом

Эти ограничения отмечены явно: конфиг не должен молча создавать впечатление, что неподдерживаемая настройка сработала.

+
+
generate.packagesФильтрация Protobuf-пакетов зарезервирована. Непустое значение сейчас вызывает ошибку; генерация выбирает целые модули.
+
Buf Registry → GitАвтоматического преобразования имени зависимости Buf Registry в Git-источник нет. Git-модуль объявляют явно.
+
Расширенные breaking-политикиcategories, ignore_unstable: true и extends не включены в текущий checker и вызывают ошибку.
+
Явное extends и glob-исключенияlinters.extends и issues.exclude-rules.path пока не реализованы; исключения без path работают.
+
Фильтры корней BufБуферные include/exclude-фильтры для Git-зависимостей не перенесены; при их наличии EasyP сообщает об ошибке.
+
MCP scopeeasyp_config_describe объясняет только редактируемые YAML-файлы. protobuf.mod и protobuf.lock остаются за CLI.
+
+

Что показать в живой демонстрации

Откройте вкладку «Несколько модулей», выполните easyp mod tidy, затем easyp ls-files и easyp generate. Коллеги увидят отдельные записи lock для вложенных модулей и import path без префикса каталога модуля.

+
+
+ +
+
+ + + From ff720fdfd99841e5ae2730f9dfa3d121722d4335 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 30 Sep 2026 12:24:21 +0300 Subject: [PATCH 14/26] docs(v1): align migration, policy and generation guides Synchronize English and Russian v1 references and workflows with implemented code. Document preview-first verified v0 migration, historical lock integrity and explicit limitations. Update policy exclusions, unstable filtering, baseline refs and ignore ownership. Preserve explicit project selection and per-plugin with_imports; remove unsupported shared-policy, package-selection and namespace guarantees. Replace stale migration and CI examples without altering publication workflows. Validated all 48 changed MDX pages through the complete site type check and production build. Documented unimplemented contracts remain explicitly reserved. --- .../mvs-dependency-resolution.mdx | 194 +++----- .../mvs-dependency-resolution.ru.mdx | 196 +++----- content/docs/ci-cd/github-actions.mdx | 116 ++++- content/docs/ci-cd/github-actions.ru.mdx | 436 +++--------------- content/docs/ci-cd/gitlab.mdx | 27 +- content/docs/ci-cd/gitlab.ru.mdx | 63 +-- content/docs/cli/breaking-changes/index.mdx | 43 +- .../docs/cli/breaking-changes/index.ru.mdx | 43 +- content/docs/cli/configuration.mdx | 72 +-- content/docs/cli/configuration.ru.mdx | 74 +-- content/docs/cli/generator/index.mdx | 66 ++- content/docs/cli/generator/index.ru.mdx | 66 ++- content/docs/cli/linter/index.mdx | 54 ++- content/docs/cli/linter/index.ru.mdx | 54 ++- .../docs/cli/package-manager/easyp-vs-buf.mdx | 26 +- .../cli/package-manager/easyp-vs-buf.ru.mdx | 26 +- content/docs/cli/package-manager/index.mdx | 46 +- content/docs/cli/package-manager/index.ru.mdx | 46 +- content/docs/guides/breaking-checks-ci.mdx | 46 +- content/docs/guides/breaking-checks-ci.ru.mdx | 46 +- content/docs/guides/buf-migration.mdx | 73 +-- content/docs/guides/buf-migration.ru.mdx | 70 +-- content/docs/guides/debugging-replace.mdx | 52 +-- content/docs/guides/debugging-replace.ru.mdx | 52 +-- .../docs/guides/microservice-isolation.mdx | 4 +- .../docs/guides/microservice-isolation.ru.mdx | 4 +- .../docs/guides/multi-target-generation.mdx | 211 ++++----- .../guides/multi-target-generation.ru.mdx | 225 ++++----- .../docs/guides/organization-lint-style.mdx | 86 ++-- .../guides/organization-lint-style.ru.mdx | 86 ++-- content/docs/guides/reproducibility.mdx | 54 ++- content/docs/guides/reproducibility.ru.mdx | 52 ++- content/docs/guides/version-diamond.mdx | 32 +- content/docs/guides/version-diamond.ru.mdx | 32 +- content/docs/migration/easyp-v0.mdx | 63 +++ content/docs/migration/easyp-v0.ru.mdx | 63 +++ content/docs/migration/meta.json | 1 + content/docs/migration/protoc.mdx | 63 ++- content/docs/migration/protoc.ru.mdx | 290 +++--------- content/docs/migration/prototool.mdx | 63 ++- content/docs/migration/prototool.ru.mdx | 260 ++--------- content/docs/reference/easyp-gen-yaml.mdx | 97 ++-- content/docs/reference/easyp-gen-yaml.ru.mdx | 97 ++-- content/docs/reference/easyp-yaml.mdx | 120 +++-- content/docs/reference/easyp-yaml.ru.mdx | 118 +++-- content/docs/reference/protobuf-lock.mdx | 44 +- content/docs/reference/protobuf-lock.ru.mdx | 42 +- content/docs/reference/protobuf-mod.mdx | 26 +- content/docs/reference/protobuf-mod.ru.mdx | 26 +- 49 files changed, 1969 insertions(+), 2177 deletions(-) create mode 100644 content/docs/migration/easyp-v0.mdx create mode 100644 content/docs/migration/easyp-v0.ru.mdx diff --git a/content/docs/architecture/mvs-dependency-resolution.mdx b/content/docs/architecture/mvs-dependency-resolution.mdx index 09dd68a..ff8d73e 100644 --- a/content/docs/architecture/mvs-dependency-resolution.mdx +++ b/content/docs/architecture/mvs-dependency-resolution.mdx @@ -1,177 +1,89 @@ --- title: "MVS Dependency Resolution" -description: "Architecture deep-dive into Minimal Version Selection (MVS), diamond dependency graph resolution, protobuf.mod specification, and hermetic lockfiles in EasyP." +description: "SemVer selection, compatible commit constraints, and reproducible Git dependencies in EasyP." --- -EasyP adopts **Minimal Version Selection (MVS)** as its core dependency resolution algorithm for Protocol Buffer modules. Designed by Russ Cox for Go modules, MVS departs from traditional package managers (such as Cargo or npm) by selecting the *oldest* (minimal) explicit version that satisfies all module constraints rather than attempting complex constraint satisfaction or defaulting to the latest version. +EasyP resolves dependencies separately for each protobuf module. Semantic requirements use **Minimal Version Selection (MVS)**: select the maximum of the requested minimum versions. Exact Git commits and versionless requirements follow separate rules; SHA values have no invented SemVer ordering. -This document provides a technical deep-dive into the MVS algorithm, its diamond dependency resolution behavior, the `protobuf.mod` domain-specific language (DSL), the hermetic `protobuf.lock` file format, and a comparison with alternative dependency models. +## Selection rules ---- - -## 1. Minimal Version Selection (MVS) Principles +| Requirements for one module | Result | +| --- | --- | +| Several SemVer minimums | Maximum requested minimum | +| One explicit full SHA | Exact commit | +| Selected SemVer and SHA of the same commit | Compatible; the tag stays in the lock for the semantic constraint | +| Different explicit SHAs, or selected tag at another commit | Conflict error | +| Versionless alongside SemVer or SHA | Versionless requirement adds no constraint | +| Only versionless requirements | Tidy uses the existing lock pin, or HEAD without one; update refreshes HEAD | -Traditional dependency resolution algorithms (such as Cargo's PubGrub or npm's Max Version strategy) treat version selection as a Constraint Satisfaction Problem (CSP) solved via NP-complete SAT solvers or aggressive "latest version" upgrades. In contrast, EasyP's implementation of MVS is built around predictability, determinism, and independence from global registry state. +A commit is not considered “newer” than a minimum version based on its date or ancestry. SemVer/SHA compatibility checks the selected tag's exact commit. If a stronger constraint replaces provisional HEAD, its dependency edges are rebuilt; dependencies and errors from discarded HEAD do not remain in the selected graph. Cyclic unstable versionless constraints are rejected. -### Key Motivations for MVS in EasyP +## Diamond dependency example -| Challenge in Proto Management | Traditional / Buf v2 Approach | EasyP MVS Approach | -| --- | --- | --- | -| **Diamond Dependency Conflicts** | Global workspace-wide resolution forces a single version across all consumers, causing cross-team coupling. | Per-module independent resolution graph. Each module resolves its own minimal requirements. | -| **Registry Volatility** | `latest` resolution or registry updates can silently alter build output over time. | SemVer requirements select `max(requested_minimums)`; versionless Git requirements are pinned on first tidy. Subsequent runs reuse the lock. | -| **Proto Schema Collision** | Multiple major/minor versions compiled in one proto-root break Fully Qualified Names (FQNs). | Exactly one version of each dependency per module graph, strictly locked via `protobuf.lock`. | +~~~text +user +├── common v1.2.0 +└── weather v2.1.0 + └── common v1.3.0 +~~~ -### Core Algorithm Behavior +The user graph selects common v1.3.0 and weather v2.1.0. Numerically, v1.3.0 satisfies both common minimums; dependency resolution does not prove schema compatibility. Run easyp breaking separately for that check. -1. **Version Bounds or Git HEAD**: A SemVer requirement (for example, `github.com/acme/weather v1.2.0`) supplies a minimum version. A requirement without a version resolves Git HEAD and stores the commit in the lock. -2. **Maximum of Minimums**: When multiple modules in a dependency graph request different minimum versions of the same dependency, MVS selects the **maximum** of those requested minimum versions. -3. **High-Water Mark Determinism**: The resulting selected version is guaranteed to satisfy all minimum requirements without requiring complex backtracking or unexpected automatic major upgrades. +If user pins a SHA, the selected common v1.3.0 tag must point to that exact commit. A v1.2.0 tag at that SHA is insufficient when the maximum requirement is v1.3.0. If user's common requirement has no version, weather's semantic minimum determines the selection. ---- +## Module and descriptor boundaries -## 2. Step-by-Step Diamond Dependency Graph Resolution - -A classic challenge in module dependency management is the "Diamond Dependency" pattern. Consider a scenario where a primary module `user` depends directly on both `common` and `weather`, while `weather` itself depends transitively on an updated version of `common`. - -### Graph Structure - -```text - +-------------------+ - | proto/user | (Root Module) - +---------+---------+ - | - +-------------+-------------+ - | | - v v -+---------------------+ +---------------------+ -| github.com/acme/ | | github.com/acme/ | -| common v1.2.0 | | weather v2.1.0 | -+---------------------+ +----------+----------+ - | - v - +---------------------+ - | github.com/acme/ | - | common v1.3.0 | - +---------------------+ -``` - -### Step-by-Step MVS Traversal - - - - EasyP begins by parsing the root module's `protobuf.mod` file (`proto/user/protobuf.mod`) and recursively visiting all transitive requirements: - - Root `user` requires `github.com/acme/common v1.2.0`. - - Root `user` requires `github.com/acme/weather v2.1.0`. - - Traversal inspects `github.com/acme/weather v2.1.0`'s `protobuf.mod`, discovering a requirement for `github.com/acme/common v1.3.0`. - - - The algorithm constructs a list of all requested minimum versions for each canonical module URL: - - Target: `github.com/acme/common` - - Requested minimums: `[ v1.2.0 (from user), v1.3.0 (from weather) ]` - - - MVS compares the requested minimum versions semantically: - `Selected Version = max(v1.2.0, v1.3.0) = v1.3.0` - Since `v1.3.0` is backwards-compatible with `v1.2.0` under Semantic Versioning, selecting `v1.3.0` satisfies both `user` and `weather`. - - - The resolved version set (`common v1.3.0`, `weather v2.1.0`) is written to `protobuf.lock` alongside Git commit hashes and cryptographic content digests. - - - -### Per-Module Isolation Guarantee - -Unlike workspace-wide resolvers, EasyP resolves dependencies on a **per-module basis**. If your repository contains separate service modules under `proto/user` and `proto/order`: - -- `proto/user` can resolve `common v1.3.0`. -- `proto/order` can independently resolve `common v2.0.0`. - -Because each proto module maintains its own `protobuf.mod` and `protobuf.lock`, teams can update shared dependencies at their own pace without breaking neighboring services in a monorepo. - -The maximum-version rule applies to SemVer requirements. A versionless requirement resolves the repository's current HEAD on its first `mod tidy`; later tidy runs reuse the locked commit, and `mod update` refreshes it. A full Git commit hash pins an exact revision without a tag. If the same module is required by two different commits, or by both a commit and a SemVer tag, resolution reports a conflict because those requirements have no common version ordering. +Each module has its own protobuf.mod and protobuf.lock. For example, proto/user can select common v1.3.0 while proto/order selects common v2.0.0 in an independent graph. ---- +Independent graphs do not guarantee that their combined generation output is compatible: -## 3. `protobuf.mod` DSL Directives +| Output | Validation | +| --- | --- | +| --descriptor_set_out | Merges compatible graphs; conflicting definitions by import path or symbol are errors | +| --descriptor_set_out_dir | Independent set per project/module pair; graphs are not merged | +| Plugin output | Identical shared files are deduplicated; different contents at one path or Go packages sharing a directory are errors | -The `protobuf.mod` file resides in the root directory of a Protobuf module. It is a tool-neutral specification focused exclusively on dependency declaration. +Managed options remain part of compatibility checks. Different dependency versions can have compatible descriptors, while different consumer settings can make them incompatible. --include_imports affects exported contents only; the full graph is always validated. Plugin import generation is separately controlled by with_imports, default false. -```protobuf -// proto/user/protobuf.mod +## Manifest and local replacements +~~~text module github.com/acme/user - -roots ( - proto -) - +roots proto require ( - github.com/googleapis/googleapis v1.5.0 - github.com/acme/weather v1.2.3 - github.com/grpc-ecosystem/grpc-gateway v2.19.0 // indirect + github.com/acme/common v1.2.0 + github.com/acme/weather v2.1.0 ) - -// Local debug override replace github.com/acme/weather => ../weather-fork -``` +~~~ -### Directive Reference +roots is relative to the manifest directory and defaults to .. The get and mod commands find the nearest ancestor manifest within the workspace. Transitive requirements are recorded with // indirect. -- **`module`**: Declares the required canonical module identity (URL/path). -- **`roots`**: Defines the inner directory root containing `.proto` schema files (defaults to `.`). This ensures imports resolve cleanly without requiring prefix manipulation. -- **`require`**: Declares direct and indirect module dependencies. The version may be omitted for automatic Git HEAD resolution, or set to a Semantic Version tag or full Git commit hash. - - **`// indirect`**: Appended automatically by `easyp mod tidy` for transitive dependencies not directly imported by the root module's `.proto` files. -- **`replace`**: Overrides a module dependency with a local file path (`../weather-fork`) for development. +A relative replace target is resolved from its owning protobuf.mod; an absolute target is used directly. Generation and linting support local replacements. get, mod tidy, mod update, and mod vendor reject them: remove replacements before these commands create or use a reproducible Git lock. This is command validation, not a CI rule rejecting commits. - -Active `replace` directives are strictly intended for local development. EasyP CI workflows will flag and reject any commit containing an active `replace` directive. - +For nested Git modules, require each identity declared by its manifest. Versionless requirements need no tags. Version v1.2.3 of a module in proto/user uses tag proto/user/v1.2.3. ---- +## Locks and immutable published versions -## 4. Hermetic `protobuf.lock` Mechanism +protobuf.lock records the source, selected tag or SHA, exact commit, and content hash. It is created by get, mod tidy, and mod update. mod download uses exact locked commits. The example below illustrates the format, not actual repository data. -The `protobuf.lock` file is an auto-generated artifact created and maintained by EasyP commands (`easyp mod tidy` and `easyp mod update`). - -```yaml -# protobuf.lock - GENERATED FILE, DO NOT EDIT MANUALLY +~~~yaml version: 1 modules: - - source: github.com/googleapis/googleapis - version: v1.5.0 - commit: 8f3a1c94b2e10a84e - hash: h1:a9F8zK... - - source: github.com/acme/weather - version: v1.2.3 - commit: 51d2e071c89f33b11 - hash: h1:x7B3mL... - - source: github.com/grpc-ecosystem/grpc-gateway - version: v2.19.0 - commit: c4f88aa91024e12c4 - hash: h1:p0Q1wK... -``` - -### Guaranteed Hermetic Builds - -1. **Strict Locking**: CI pipelines execute `easyp mod download` against `protobuf.lock`. Neither network fluctuations nor registry state can change the downloaded schema versions. -2. **Digest Verification**: The `hash` attribute validates content integrity against cache tampering or force-pushed Git tags. -3. **Explicit Lifecycle**: `protobuf.lock` is only updated via explicit developer execution of `easyp mod tidy` or `easyp mod update`. + - source: github.com/acme/common + version: v1.3.0 + commit: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + hash: h1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= +~~~ ---- +During tidy, get, and update, a fetched previously locked SemVer must match its recorded commit and hash. A mismatch raises ErrLockedVersionChanged before installing the new graph or writing the manifest or lock, including for transitive requirements and warm caches. A new version may be selected; unconstrained versionless requirements still refresh to HEAD, while explicit SHAs stay pinned. -## 5. Architectural Comparison +mod download can retrieve the old commit after a tag moves if that commit remains available. The Go dirhash.Hash1 digest covers Git-tracked regular files with repository-relative paths. Both newly downloaded and installed cached files are verified. -| Feature / Model | EasyP MVS | Go Modules (MVS) | Cargo / Rust (PubGrub SAT) | Buf v2 (Workspace SVS) | -| --- | --- | --- | --- | --- | -| **Algorithm** | Minimal Version Selection | Minimal Version Selection | SAT Solver (PubGrub) | Workspace Single Version | -| **Selection Rule** | `max(minimums)` | `max(minimums)` | Complex SemVer Ranges (`^1.2.3`) | Global Single Version | -| **Dependency Scope** | Per-module | Per-module | Per-crate | Entire Workspace | -| **Multiple Versions in Binary** | Forbidden (FQN collision) | Allowed across major versions | Allowed across major versions | Forbidden | -| **Lockfile** | `protobuf.lock` | `go.sum` | `Cargo.lock` | `buf.lock` | -| **Local Override** | `replace` directive | `replace` directive | `[patch]` / `path` | Local workspace module | +## Git object reuse -### Why MVS Fits Protobuf Schemas Best +A shared object store is used per remote. Known exact commits can be reused without remote access. The first attempt fetches the requested commit at depth one. If a server rejects a historical SHA, EasyP fetches advertised reachable history and still requires the original commit; HEAD is never substituted. A cold fetch is therefore not always shallow. Tag lookups are refreshed separately so cache reuse cannot hide republishing. -Protobuf schemas enforce strict package name and message Fully Qualified Name (FQN) uniqueness within a compilation unit. Unlike Rust (where Cargo can rename crates under the hood) or Go (where `v2` uses a distinct import path), compiling two versions of `user.v1.User` into the same protoc descriptor set causes immediate FQN collision errors. +Reproducibility depends on pinned commits remaining available and hashes matching. Breaking checks use each revision's own manifests and locks; the baseline is read from an isolated Git snapshot rather than the current working tree. -EasyP's per-module MVS provides the exact balance required for Protobuf: deterministic single-version resolution within each module graph, paired with complete version independence between separate service modules. +See [protobuf.mod](/docs/reference/protobuf-mod), [protobuf.lock](/docs/reference/protobuf-lock), and [generation](/docs/cli/generator) for details. diff --git a/content/docs/architecture/mvs-dependency-resolution.ru.mdx b/content/docs/architecture/mvs-dependency-resolution.ru.mdx index 37df3f3..9572e4d 100644 --- a/content/docs/architecture/mvs-dependency-resolution.ru.mdx +++ b/content/docs/architecture/mvs-dependency-resolution.ru.mdx @@ -1,177 +1,89 @@ --- -title: "Резолюция зависимостей MVS" -description: "Подробный разбор алгоритма Minimal Version Selection (MVS), разрешения ромбовидных зависимостей (diamond dependency), спецификации protobuf.mod и герметичного lock-файла protobuf.lock в EasyP." +title: "Разрешение зависимостей MVS" +description: "Выбор SemVer, совместимые ограничения по коммитам и воспроизводимые Git-зависимости в EasyP." --- -В качестве основного алгоритма разрешения зависимостей для Protocol Buffer модулей EasyP использует **Minimal Version Selection (MVS)**. Разработанный Рассом Коксом (Russ Cox) для модулей Go, MVS отличается от традиционных пакетных менеджеров (таких как Cargo или npm) тем, что выбирает *минимальную* (самую старую из удовлетворяющих) явно объявленную версию, вместо сложного поиска компромиссов через SAT-солверы или автоматического обновления до `latest`. +EasyP разрешает зависимости отдельно для каждого protobuf-модуля. Для требований SemVer применяется **Minimal Version Selection (MVS)**: выбирается максимальная из запрошенных минимальных версий. Точные Git-коммиты и требования без версии имеют отдельные правила; SHA не получает искусственный порядок SemVer. -В данном документе подробно рассматриваются алгоритм MVS, его поведение при разрешении ромбовидных зависимостей (diamond dependencies), DSL файла `protobuf.mod`, устройство `protobuf.lock` и сравнение с альтернативными моделями. +## Правила выбора ---- - -## 1. Концепция Minimal Version Selection (MVS) +| Требования к одному модулю | Результат | +| --- | --- | +| Несколько SemVer-минимумов | Максимум запрошенных минимумов | +| Один явный полный SHA | Точный коммит | +| Выбранный SemVer и SHA того же коммита | Совместимы; тег сохраняется в lock для SemVer-ограничения | +| Разные явные SHA или выбранный тег на другом коммите | Ошибка конфликта | +| Без версии вместе с SemVer или SHA | Требование без версии не добавляет ограничения | +| Только требования без версии | Tidy использует прежний lock или HEAD без lock; update освежает HEAD | -Традиционные алгоритмы разрешения зависимостей (например, PubGrub в Cargo или стратегия Max Version в npm) рассматривают выбор версий как задачу удовлетворения ограничений (CSP), решаемую с помощью NP-полных SAT-солверов или агрессивного подтягивания свежих версий. В отличие от них, MVS в EasyP ориентирован на предсказуемость, детерминированность и независимость от состояния удалённых реестров. +Коммит нельзя считать «новее» минимальной версии по дате или истории Git. Совместимость SemVer/SHA проверяется по точному коммиту выбранного тега. Если более сильное ограничение заменяет предварительный HEAD, его рёбра зависимостей пересобираются; ошибки и зависимости отброшенного HEAD не остаются в выбранном графе. Циклические неустойчивые ограничения без версии отклоняются. -### Почему EasyP выбирает MVS +## Ромбовидная зависимость -| Проблема при работе с Proto | Подход Buf v2 / Традиционный | Подход EasyP MVS | -| --- | --- | --- | -| **Рассинхрон версий («diamond»)** | Резолюция на весь workspace целиком: единая версия пакета на всех потребителей, конфликты между командами разруливаются вручную. | Per-module (помодульная) резолюция. Каждый модуль резолвит свои зависимости независимо. | -| **Зависимость от состояния реестра** | Стратегия `latest` или изменения в реестре могут неявно изменить результат повторной сборки. | Для SemVer выбирается `max(запрошенных минимумов)`; требование без версии закрепляется в lock при первом tidy. Повторные запуски используют lock. | -| **Коллизии Proto-схем** | Несколько мажорных/минорных версий в одном proto-root ломают уникальность FQN. | Ровно одна версия каждой зависимости в графе модуля, строго зафиксированная в `protobuf.lock`. | +~~~text +user +├── common v1.2.0 +└── weather v2.1.0 + └── common v1.3.0 +~~~ -### Базовые принципы алгоритма +Граф user выбирает common v1.3.0 и weather v2.1.0. Численно v1.3.0 удовлетворяет обоим минимумам common; разрешение версий само по себе не доказывает совместимость схем. Для этого отдельно запускают easyp breaking. -1. **Границы версий или Git HEAD**: SemVer-требование (например, `github.com/acme/weather v1.2.0`) задаёт минимальную версию. Требование без версии разрешается в Git HEAD и записывает коммит в lock. -2. **Максимум из минимумов**: Если несколько модулей в графе требуют разные минимальные версии одной и той же зависимости, MVS выбирает **максимальную** из запрошенных минимальных версий. -3. **Детерминизм High-Water Mark**: Выбранная версия гарантированно удовлетворяет всем объявленным минимальным требованиям без возвратов (backtracking) и неожиданных мажорных обновлений. +Если user закрепляет SHA, выбранный тег common v1.3.0 должен указывать именно на него. Самого наличия тега v1.2.0 на этом SHA недостаточно, если максимум требований — v1.3.0. Если требование user к common не содержит версии, минимум weather определяет выбор. ---- +## Границы модулей и дескрипторов -## 2. Пошаговый разбор разрешения ромбовидных зависимостей (Diamond Dependency) - -Классическая проблема управления зависимостями — ромбовидная зависимость. Рассмотрим случай, когда корневой модуль `user` напрямую зависит от `common` и `weather`, а `weather` транзитивно требует более новую версию `common`. - -### Структура графа - -```text - +-------------------+ - | proto/user | (Корневой модуль) - +---------+---------+ - | - +-------------+-------------+ - | | - v v -+---------------------+ +---------------------+ -| github.com/acme/ | | github.com/acme/ | -| common v1.2.0 | | weather v2.1.0 | -+---------------------+ +----------+----------+ - | - v - +---------------------+ - | github.com/acme/ | - | common v1.3.0 | - +---------------------+ -``` - -### Пошаговый алгоритм MVS - - - - EasyP начинает с чтения `protobuf.mod` корневого модуля (`proto/user/protobuf.mod`) и рекурсивно обходит все транзитивные `require`: - - Корень `user` требует `github.com/acme/common v1.2.0`. - - Корень `user` требует `github.com/acme/weather v2.1.0`. - - Обход читает `protobuf.mod` зависимости `github.com/acme/weather v2.1.0` и находит требование `github.com/acme/common v1.3.0`. - - - Алгоритм формирует список всех запрошенных минимальных версий для каждого уникального URL модуля: - - Модуль: `github.com/acme/common` - - Запрошенные минимумы: `[ v1.2.0 (от user), v1.3.0 (от weather) ]` - - - MVS сравнивает запрошенные минимальные версии по правилам SemVer: - `Итоговая версия = max(v1.2.0, v1.3.0) = v1.3.0` - Поскольку `v1.3.0` обратимо совместима с `v1.2.0`, выбор `v1.3.0` удовлетворяет требованиям и `user`, и `weather`. - - - Итоговый набор версий (`common v1.3.0`, `weather v2.1.0`) записывается в `protobuf.lock` вместе с хешами коммитов и контрольными суммами содержимого. - - - -### Изоляция версий per-module - -В отличие от единого резолвера на весь workspace, EasyP выполняет резолюцию **помодульно (per-module)**. Если в монорепозитории есть два разных сервиса в `proto/user` и `proto/order`: - -- `proto/user` может резолвить `common v1.3.0`. -- `proto/order` может независимо использовать `common v2.0.0`. - -Каждый proto-модуль имеет собственный `protobuf.mod` и `protobuf.lock`, поэтому команды могут обновлять зависимости независимых сервисов в своём темпе. - -Правило выбора максимума применяется к требованиям SemVer. Требование без версии при первом `mod tidy` разрешается в текущий HEAD репозитория; следующие запуски `tidy` используют коммит из lock, а `mod update` обновляет его. Полный хеш Git-коммита закрепляет конкретную ревизию без тега. Если один модуль требуется по двум разным коммитам либо одновременно по коммиту и SemVer-тегу, резолвер сообщает о конфликте: для этих требований нет общего порядка версий. +Каждый модуль имеет свой protobuf.mod и protobuf.lock. Например, proto/user может выбрать common v1.3.0, а proto/order — common v2.0.0 в независимых графах. ---- +При генерации независимость графов не гарантирует совместимость объединённого результата: -## 3. Директивы DSL `protobuf.mod` +| Вывод | Проверка | +| --- | --- | +| --descriptor_set_out | Объединяет совместимые графы; конфликт определения по import path или символов — ошибка | +| --descriptor_set_out_dir | Отдельный набор для каждой пары проект/модуль; графы не объединяются | +| Результаты плагинов | Одинаковые общие файлы объединяются; разное содержимое по одному пути или разные Go-пакеты в одном каталоге — ошибка | -Файл `protobuf.mod` располагается в корне proto-модуля и является tool-neutral спецификацией, сфокусированной только на объявлении зависимостей. +Managed-опции сохраняются при проверке совместимости. Разные версии зависимостей могут иметь совместимые дескрипторы, а разные настройки потребителей — сделать их несовместимыми. --include_imports меняет только содержимое экспорта; полный граф проверяется в любом случае. Генерация импортов плагином отдельно управляется with_imports, по умолчанию false. -```protobuf -// proto/user/protobuf.mod +## Манифест и локальные замены +~~~text module github.com/acme/user - -roots ( - proto -) - +roots proto require ( - github.com/googleapis/googleapis v1.5.0 - github.com/acme/weather v1.2.3 - github.com/grpc-ecosystem/grpc-gateway v2.19.0 // indirect + github.com/acme/common v1.2.0 + github.com/acme/weather v2.1.0 ) - -// Локальная отладка зависимости replace github.com/acme/weather => ../weather-fork -``` +~~~ -### Справочник директив +roots считается от каталога манифеста и по умолчанию равен .. Команды get и mod находят ближайший манифест в предках в пределах workspace. Транзитивные требования записываются с // indirect. -- **`module`**: Объявляет канонический идентификатор (URL/путь) модуля. -- **`roots`**: Задаёт корневую поддиректорию с `.proto` файлами внутри репозитория (по умолчанию `.`). Это позволяет корректно резолвить импорты без срезания путей вручную. -- **`require`**: Прямые и транзитивные зависимости. Версию можно опустить для автоматического разрешения Git HEAD либо указать SemVer-тег или полный хеш Git-коммита. - - **`// indirect`**: Автоматически дописывается командой `easyp mod tidy` для транзитивных зависимостей, не импортируемых напрямую `.proto` файлами модуля. -- **`replace`**: Переопределяет зависимость локальным путем (`../weather-fork`) для разработки. +Относительная цель replace считается от содержащего её protobuf.mod, абсолютная используется напрямую. Генерация и линтинг поддерживают локальные замены. get, mod tidy, mod update и mod vendor отклоняют их: уберите замены перед созданием или использованием воспроизводимого Git lock этими командами. Это проверка команд, а не запрет коммитов со стороны CI. - -Директива `replace` предназначена исключительно для локальной разработки. CI-пайплайны EasyP отклоняют коммиты с активными `replace`. - +Для вложенных Git-модулей каждое требование использует имя из соответствующего манифеста. Требование без версии не нуждается в теге. Версия v1.2.3 модуля в proto/user использует тег proto/user/v1.2.3. ---- +## Lock и неизменность опубликованных версий -## 4. Механизм герметичной фиксации `protobuf.lock` +protobuf.lock записывает источник, выбранный тег или SHA, точный коммит и хеш содержимого. Его создают get, mod tidy и mod update. mod download использует точные коммиты из lock. Пример ниже показывает формат, а не реальные данные репозитория. -Файл `protobuf.lock` генерируется и обновляется командами `easyp mod tidy` и `easyp mod update`. - -```yaml -# protobuf.lock - СГЕНЕРИРОВАННЫЙ ФАЙЛ, НЕ РЕДАКТИРОВАТЬ РУКАМИ +~~~yaml version: 1 modules: - - source: github.com/googleapis/googleapis - version: v1.5.0 - commit: 8f3a1c94b2e10a84e - hash: h1:a9F8zK... - - source: github.com/acme/weather - version: v1.2.3 - commit: 51d2e071c89f33b11 - hash: h1:x7B3mL... - - source: github.com/grpc-ecosystem/grpc-gateway - version: v2.19.0 - commit: c4f88aa91024e12c4 - hash: h1:p0Q1wK... -``` - -### Гарантии герметичности сборки - -1. **Строгая фиксация**: Сборка в CI выполняется через `easyp mod download` строго по `protobuf.lock`. Состояние кэшей и удалённых реестров не влияет на результат. -2. **Контроль целостности**: Поле `hash` проверяет совпадение содержимого, защищая от подмены Git-тегов или кэша. -3. **Предсказуемый жизненный цикл**: `protobuf.lock` изменяется только при явном вызове `easyp mod tidy` или `easyp mod update`. + - source: github.com/acme/common + version: v1.3.0 + commit: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + hash: h1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= +~~~ ---- +При tidy, get и update повторно полученный ранее зафиксированный SemVer должен совпасть с записанными коммитом и хешем. Несовпадение вызывает ErrLockedVersionChanged до установки нового графа и записи манифеста или lock, в том числе для транзитивных требований и прогретого кеша. Новая версия может быть выбрана; неограниченные требования без версии по-прежнему обновляются до HEAD, явные SHA сохраняются. -## 5. Сравнительный анализ архитектур +mod download может получить старый коммит после переноса тега, если коммит остаётся доступным. Хеш Go dirhash.Hash1 охватывает обычные файлы, отслеживаемые Git, с путями относительно репозитория. Проверка выполняется и для новых загрузок, и для установленных файлов кеша. -| Модель | EasyP MVS | Go Modules (MVS) | Cargo / Rust (PubGrub SAT) | Buf v2 (Workspace SVS) | -| --- | --- | --- | --- | --- | -| **Алгоритм** | Minimal Version Selection | Minimal Version Selection | SAT Solver (PubGrub) | Workspace Single Version | -| **Правило выбора** | `max(минимумов)` | `max(минимумов)` | Сложные SemVer диапазоны (`^1.2.3`) | Единая версия на весь workspace | -| **Скоуп резолюции** | Per-module | Per-module | Per-crate | Весь Workspace | -| **Несколько версий в сборке** | Запрещено (коллизия FQN) | Разрешено для разных major версий | Разрешено для разных major версий | Запрещено | -| **Lock-файл** | `protobuf.lock` | `go.sum` | `Cargo.lock` | `buf.lock` | -| **Локальный оверрайд** | Директива `replace` | Директива `replace` | `[patch]` / `path` | Локальный workspace модуль | +## Повторное использование Git-объектов -### Почему MVS идеально подходит для Protobuf +Для каждого remote используется общее хранилище объектов. Известный точный коммит повторно используется без обращения к remote. Первая попытка — загрузка нужного коммита с глубиной один. Если сервер запрещает исторический SHA, EasyP получает доступную историю объявленных ссылок и всё равно требует исходный коммит; HEAD вместо него не подставляется. Поэтому холодная загрузка не всегда остаётся shallow. Проверки тегов обновляются отдельно, чтобы кеш не скрывал перепубликацию. -Схемы Protobuf требуют строгой уникальности имён пакетов и полных имён сообщений (Fully Qualified Name, FQN) в рамках единицы компиляции. В отличие от Rust (где Cargo может переименовать crate) или Go (где `v2` имеет другой путь импорта), компиляция двух разных версий одного proto-файла в единый descriptor set приводит к немедленным ошибкам коллизии FQN. +Воспроизводимость зависит от доступности зафиксированных коммитов и совпадения хешей. При breaking-проверке каждая ревизия использует собственные манифесты и lock; база берётся из изолированного Git-снимка, а не из текущего рабочего дерева. -MVS в EasyP предоставляет идеальный баланс для Protobuf: детерминированный выбор единой версии внутри графа каждого модуля и полную независимость версий между отдельными сервисами. +Подробности: [protobuf.mod](/ru/docs/reference/protobuf-mod), [protobuf.lock](/ru/docs/reference/protobuf-lock) и [генерация](/ru/docs/cli/generator). diff --git a/content/docs/ci-cd/github-actions.mdx b/content/docs/ci-cd/github-actions.mdx index 52bbe57..ccd969b 100644 --- a/content/docs/ci-cd/github-actions.mdx +++ b/content/docs/ci-cd/github-actions.mdx @@ -1,5 +1,117 @@ --- -title: "Github Actions" +title: "GitHub Actions" +description: "Verify v1 dependency locks, lint schemas, compare a Git baseline, and check generated output in CI." --- -## Work in progress +Run dependency verification, linting, breaking checks, and generation as separate steps so failures identify the stage that needs attention. + +## Prerequisites and Toolchain + +This example assumes a root protobuf.mod and committed protobuf.lock, a root easyp.yaml, schemas in proto, and a root easyp.gen.yaml writing to tracked files under gen. + +The workflow uses a prepared self-hosted Linux runner with the custom label easyp-v1. Assign that label only after provisioning your chosen v1-capable EasyP binary and required local plugins on PATH. For a hosted runner, supply your project's pinned toolchain setup before the EasyP steps. The example does not assume a particular published v1 release artifact. + +Local and bundled plugins cannot use a YAML version pin; their versions are controlled by the installed executables and EasyP binary. Remote plugins require a separate pinned semantic version in easyp.gen.yaml. + +## Pull Request Workflow + +~~~yaml +name: protobuf-ci + +on: + pull_request: + +permissions: + contents: read + +jobs: + verify: + runs-on: [self-hosted, linux, x64, easyp-v1] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Verify toolchain + run: easyp --version + + - name: Verify locked dependencies + run: easyp mod download + + - name: Lint schemas + run: easyp lint --path proto + + - name: Check compatibility + env: + BASE_REF: ${{ github.event.pull_request.base.sha }} + run: easyp breaking --path proto --against "$BASE_REF" + + - name: Generate code + run: easyp generate --project . + + - name: Check committed generated files + run: | + git diff --exit-code -- gen + test -z "$(git ls-files --others --exclude-standard -- gen)" +~~~ + +The final step detects tracked changes and new untracked files under gen. Adapt the paths for your project; ignored generated files are outside this check. Also run your normal consumer tests after generation. + +## Lint and Breaking Policies + +A simple root easyp.yaml is: + +~~~yaml +version: v1 +linters: + default: STANDARD +breaking: + baseline: git:main + categories: [FILE] + ignore_unstable: false + ignore: [proto/experimental] +~~~ + +The workflow's explicit --against overrides this baseline with the PR base SHA. Use a ref directly, without git-ref= or git: in the flag. Branches, lightweight and annotated tags, full SHAs, and locally resolvable Git revisions are supported; the required refs and objects must exist locally. A bare branch name wins over an identically named tag. + +For a release comparison, select an existing release tag explicitly: + +~~~bash +easyp breaking --path proto --against refs/tags/v1.2.0 +~~~ + +Choose the intended previous release rather than assuming tag creation order defines compatibility history. Each revision uses its own module manifests, locks, and dependencies, so a breaking check can fetch dependencies beyond those needed by the current checkout. + +FILE is the only supported additional category. ignore_unstable works for the supported package suffixes. Ignore paths are relative to the policy file defining the breaking section: here proto/experimental is relative to the root policy. Nested sections replace whole sections; nonempty extends is unsupported. + +## Selecting Generation Projects + +With backend and frontend generator files, use: + +~~~bash +easyp generate --project ./backend --project ./frontend +~~~ + +Use easyp generate --all for explicit recursive selection. A plain easyp generate selects the nearest enclosing generator file. --project and --all cannot be combined. + +To split generation into matrix jobs, set the matrix to project directories and pass the selected directory to --project. Each job needs the relevant plugins and output checks; language names alone do not select a generation configuration. + +## Dependency Cache and Private Sources + +Dependencies belong in protobuf.mod, with resolved commits and hashes in protobuf.lock. easyp mod download verifies that lock without updating it. Do dependency updates in a reviewed change before the verification job. + +EasyP storage defaults to ~/.easyp and can be relocated with EASYPPATH. If you cache it, include the OS, EasyP toolchain version, and relevant lockfile hashes in the cache key. A restored cache is an optimization; dependency verification still runs. + +For private dependencies, provision the Git authentication required by your sources before the dependency step. Keep credentials in the runner's approved secret mechanism and out of logs. A local replacement does not eliminate downloads unless the entire dependency graph is local or already verified in cache; remote plugins still need the network. tidy and update reject active local replacements and are not read-only verification commands. + +## Troubleshooting + +| Symptom | Check | +| --- | --- | +| Baseline cannot be resolved | Fetch the intended ref and its objects; use full history or an explicit fetch. | +| Unknown policy field or rule | Match configuration to the installed v1 binary and supported schema. | +| Plugin is missing or output differs | Verify the executable selected from PATH and the pinned toolchain. | +| Dependency verification fails | Check the committed manifest, lock, source access, and reported hash mismatch. | +| Generated-output check fails | Regenerate with the same project selection and toolchain, review the diff, and commit intended changes. | + +For diagnostics, record easyp --version, the failing command, and the relevant Git ref. See [breaking checks in CI](/docs/guides/breaking-checks-ci) and [build reproducibility](/docs/guides/reproducibility). diff --git a/content/docs/ci-cd/github-actions.ru.mdx b/content/docs/ci-cd/github-actions.ru.mdx index 8b06ce9..daecd4b 100644 --- a/content/docs/ci-cd/github-actions.ru.mdx +++ b/content/docs/ci-cd/github-actions.ru.mdx @@ -1,413 +1,117 @@ --- title: "GitHub Actions" +description: "Проверка lock-файлов v1, линтинг схем, сравнение с Git-базой и контроль сгенерированного кода в CI." --- -Полное руководство по интеграции EasyP в конвейеры GitHub Actions для линтинга, проверки несовместимых изменений, генерации кода и автоматизации релизов. +Запускайте проверку зависимостей, линтинг, breaking-проверки и генерацию отдельными шагами: так ошибка укажет на этап, требующий внимания. -## Зачем использовать EasyP в CI +## Предварительные требования и инструменты -Встраивание EasyP в GitHub Actions даёт: +Пример предполагает корневые protobuf.mod и закоммиченный protobuf.lock, корневой easyp.yaml, схемы в proto и корневой easyp.gen.yaml, записывающий отслеживаемые файлы в gen. -- Единообразие правил линтинга и генерации между разработчиками. -- Автоматическое выявление несовместимых изменений (breaking changes) до мержа. -- Гарантию, что сгенерированный код не «устарел» относительно .proto. -- Возможность централизованной проверки зависимостей и версии конфигурации. +Workflow использует подготовленный self-hosted Linux runner с пользовательской меткой easyp-v1. Назначайте её после подготовки выбранного бинарника EasyP с поддержкой v1 и необходимых локальных плагинов в PATH. Для hosted runner добавьте принятую в проекте установку фиксированных версий инструментов до шагов EasyP. Пример не предполагает существования конкретного опубликованного артефакта релиза v1. -## Предварительные требования +Локальные и встроенные плагины не принимают фиксацию через YAML-поле version: их версии определяются установленными исполняемыми файлами и бинарником EasyP. Удалённым плагинам нужна отдельная фиксированная семантическая version в easyp.gen.yaml. -1. Репозиторий содержит файл конфигурации `easyp.yaml` (или находится в корне, если запускается без `--cfg`). -2. Установлены / определены зависимости в секции `deps` (если нужны внешние импорты). -3. Для приватных Git-репозиториев настроен доступ (SSH key / deploy key / токен). -4. В workflow есть шаги по установке Go (если EasyP поставляется через `go install`) или заранее подготовленный бинарь. +## Workflow для Pull Request -## Базовый пример (быстрый старт) - -Минимальный workflow для проверки линта и несовместимых изменений при открытия Pull Request: - -```yaml -name: easyp-ci +~~~yaml +name: protobuf-ci on: pull_request: - paths: - - '**/*.proto' - - 'easyp.yaml' - -jobs: - lint-and-breaking: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Go - uses: actions/setup-go@v5 - with: - go-version: '1.22' - - - name: Install EasyP - run: go install github.com/easyp-tech/easyp/cmd/easyp@latest - - - name: Verify EasyP version - run: | - which easyp - easyp --version - - - name: Lint - run: easyp lint - - - name: Breaking changes check (against main) - run: easyp breaking --against git-ref=origin/main -``` - -## Установка EasyP - -Варианты: - -1. Через `go install` (как в примере выше). -2. Использование заранее собранного бинаря (артефакт релиза). - -```yaml -- name: Download EasyP binary - run: | - curl -sL https://github.com/easyp-tech/easyp/releases/download/v1.0.0/easyp_linux_amd64 -o /usr/local/bin/easyp - chmod +x /usr/local/bin/easyp -``` - -## Кэширование - -Для ускорения повторных сборок можно кэшировать: - -- Go модульный кеш (если используете генерацию с плагинами Go). -- Внешние зависимые Git-клонирования (папки `vendor` или содержимое `deps` при использовании `easyp mod download` / `easyp mod update`). -- Сгенерированный код (если он тяжёлый, но чаще генерируется заново). - -Пример кэширования Go: - -```yaml -- name: Cache Go build - uses: actions/cache@v4 - with: - path: | - ~/go/pkg/mod - ~/.cache/go-build - key: go-${{ runner.os }}-${{ hashFiles('**/go.sum') }} - restore-keys: | - go-${{ runner.os }}- -``` - -Пример кэширования каталога зависимостей EasyP (если вы используете локальный vendor-подход): - -```yaml -- name: Cache proto deps - uses: actions/cache@v4 - with: - path: .easyp/deps - key: deps-${{ runner.os }}-${{ hashFiles('easyp.yaml') }} - restore-keys: | - deps-${{ runner.os }}- -``` - -(Создайте `.easyp/deps` как целевой каталог, если ваша стратегия скачивания такова.) - -## Линтинг - -Команда: - -```bash -easyp lint -``` - -Рекомендуется: - -- В PR: всегда запускать. -- На main: можно запускать для верификации перед релизом. - -Расширенный пример с выводом подробностей и игнорированием комментариев (если включено в конфиг): - -```yaml -- name: Lint proto files - run: | - set -e - easyp lint -v -``` - -## Проверка несовместимых изменений (Breaking Changes) - -EasyP может сравнивать текущее состояние против ветки / коммита / тега. - -Примеры: - -```bash -# Сравнить против origin/main -easyp breaking --against git-ref=origin/main - -# Сравнить против тега релиза -easyp breaking --against git-ref=v1.5.2 - -# Игнорировать определённые правила (если у вас настроено в easyp.yaml) -easyp breaking -``` - -Workflow шаг: - -```yaml -- name: Breaking changes check - run: easyp breaking --against git-ref=origin/main -``` - -Если нужно «мягко» пропустить (например, выводить предупреждения, но не падать билд): - -```yaml -- name: Breaking changes (soft) - run: | - if ! easyp breaking --against git-ref=origin/main; then - echo "::warning title=Breaking Changes Detected::Обнаружены потенциально несовместимые изменения" - fi -``` - -## Генерация кода - -Обычно для генерации: -```bash -easyp generate -``` +permissions: + contents: read -Если нужно явно указать конфиг: - -```bash -easyp --cfg easyp.yaml generate -``` - -Пример шага: - -```yaml -- name: Generate code - run: | - easyp generate - git status --short -``` - -Можно добавить проверку «не осталось ли не закоммиченных изменений» (гарантия, что сгенерированный код актуален): - -```yaml -- name: Ensure generated code is up-to-date - run: | - easyp generate - if [ -n "$(git status --porcelain)" ]; then - echo "Generated code is outdated. Please commit changes." - git diff --name-only - exit 1 - fi -``` - -## Матрица (Matrix strategy) - -Если у вас несколько вариантов конфигураций или разных языков генерации (через плагины), можно использовать matrix: - -```yaml jobs: - generate: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - lang: [go, python] + verify: + runs-on: [self-hosted, linux, x64, easyp-v1] steps: - uses: actions/checkout@v4 - - - name: Setup Go (only for go) - if: matrix.lang == 'go' - uses: actions/setup-go@v5 with: - go-version: '1.22' - - - name: Install EasyP - run: go install github.com/easyp-tech/easyp/cmd/easyp@latest - - - name: Generate - run: | - if [ "${{ matrix.lang }}" = "go" ]; then - easyp generate - elif [ "${{ matrix.lang }}" = "python" ]; then - easyp generate --plugin python - fi -``` - -## Работа с приватными репозиториями (deps) - -Если вы указываете приватные Git-пакеты в секции `deps`: - -1. Настройте deploy key или используйте `GIT_SSH_COMMAND` с токеном. -2. Добавьте known_hosts (либо установите `StrictHostKeyChecking=no` для внутренних систем, но осознанно). - -Пример: - -```yaml -- name: Prepare SSH - run: | - mkdir -p ~/.ssh - echo "${{ secrets.DEPLOY_KEY }}" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - ssh-keyscan github.com >> ~/.ssh/known_hosts + fetch-depth: 0 -- name: Update deps - run: easyp mod update -``` + - name: Verify toolchain + run: easyp --version -## Оптимизация времени сборки + - name: Verify locked dependencies + run: easyp mod download -- Используйте кэш для Go / deps. -- Запускайте линт/брейкинг только если изменились `.proto` или `easyp.yaml` (paths фильтр). -- Разделяйте workflow: быстрый линт в PR, тяжелая генерация в push на main. -- Выносите генерацию OpenAPI / gRPC-Gateway в отдельный job (параллелизм). + - name: Lint schemas + run: easyp lint --path proto -## Продвинутый workflow (многостадийный) + - name: Check compatibility + env: + BASE_REF: ${{ github.event.pull_request.base.sha }} + run: easyp breaking --path proto --against "$BASE_REF" -```yaml -name: easyp-pipeline + - name: Generate code + run: easyp generate --project . -on: - pull_request: - paths: - - '**/*.proto' - - 'easyp.yaml' - push: - branches: - - main - -jobs: - validate: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-go@v5 - with: - go-version: '1.22' - - - name: Install EasyP - run: go install github.com/easyp-tech/easyp/cmd/easyp@latest - - - name: Lint - run: easyp lint - - - name: Breaking check (against main) - if: github.event_name == 'pull_request' - run: easyp breaking --against git-ref=origin/main - - generate: - needs: validate - if: github.event_name == 'push' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 - with: - go-version: '1.22' - - name: Install EasyP - run: go install github.com/easyp-tech/easyp/cmd/easyp@latest - - name: Generate Code - run: easyp generate - - name: Check diffs + - name: Check committed generated files run: | - if [ -n "$(git status --porcelain)" ]; then - echo "Generated files changed after generate step." - git diff --name-only - exit 1 - fi -``` + git diff --exit-code -- gen + test -z "$(git ls-files --others --exclude-standard -- gen)" +~~~ -## Автоматизация релиза (пример) +Последний шаг обнаруживает изменения отслеживаемых файлов и новые неотслеживаемые файлы в gen. Адаптируйте пути под проект; игнорируемые сгенерированные файлы эта проверка не охватывает. После генерации также запускайте обычные тесты потребителей. -Можно добавить workflow, который по тегу создаёт релиз и валидирует proto: +## Политики линтинга и совместимости -```yaml -name: release-verify +Простой корневой easyp.yaml: -on: - push: - tags: - - 'v*.*.*' +~~~yaml +version: v1 +linters: + default: STANDARD +breaking: + baseline: git:main + categories: [FILE] + ignore_unstable: false + ignore: [proto/experimental] +~~~ -jobs: - release-check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-go@v5 - with: - go-version: '1.22' +Явный --against из workflow заменяет эту базу SHA базового коммита PR. Передавайте ссылку напрямую, без git-ref= и git: во флаге. Поддерживаются ветки, лёгкие и аннотированные теги, полные SHA и разрешимые локально Git-ревизии; необходимые ссылки и объекты должны присутствовать локально. Короткое имя ветки приоритетнее одноимённого тега. - - name: Install EasyP - run: go install github.com/easyp-tech/easyp/cmd/easyp@latest +Для сравнения релиза явно выберите существующий тег: - - name: Lint - run: easyp lint +~~~bash +easyp breaking --path proto --against refs/tags/v1.2.0 +~~~ - - name: Breaking vs previous tag - run: | - PREV_TAG=$(git tag --sort=-creatordate | grep -v "${GITHUB_REF_NAME}" | head -n1 || true) - if [ -n "$PREV_TAG" ]; then - echo "Comparing against $PREV_TAG" - easyp breaking --against git-ref=$PREV_TAG - else - echo "No previous tag, skipping breaking check" - fi - - - name: Generate to ensure consistency - run: easyp generate -``` - -## Отладка +Выбирайте нужный предыдущий релиз явно: порядок создания тегов не обязательно задаёт историю совместимости. Каждая ревизия использует свои манифесты модулей, lock-файлы и зависимости, поэтому breaking-проверка может загрузить зависимости, которые не нужны текущему checkout. -Если нужно больше логов: +FILE — единственная поддерживаемая дополнительная категория. ignore_unstable работает для поддерживаемых суффиксов пакетов. Пути исключений отсчитываются от файла политики с секцией breaking: здесь proto/experimental задан относительно корневой политики. Вложенные секции заменяют секции целиком; непустое extends не поддерживается. -```bash -easyp lint -v -easyp breaking -v --against git-ref=origin/main -easyp generate -v -``` +## Выбор проектов генерации -Добавьте вывод окружения для диагностики: +Для файлов генератора бэкенда и фронтенда используйте: -```yaml -- name: Debug environment - run: | - env | sort - easyp --version -``` +~~~bash +easyp generate --project ./backend --project ./frontend +~~~ -## Переменные окружения (примерно) +Для явного рекурсивного выбора используйте easyp generate --all. Обычный easyp generate выбирает ближайший вышестоящий файл генератора. Сочетать --project и --all нельзя. -| Переменная | Назначение | -|------------|-----------| -| `EASYP_CFG` | Путь к файлу конфигурации, если он не в корне репозитория | -| `GIT_SSH_COMMAND` | Кастомная команда SSH (частные репозитории) | -| `GOFLAGS` | Можно выставить `-mod=readonly` для Go генерации | +Чтобы разделить генерацию на matrix jobs, задайте в матрице каталоги проектов и передавайте выбранный каталог в --project. Каждой job нужны соответствующие плагины и проверки вывода; одни имена языков не выбирают конфигурацию генерации. -(Используйте только те, что действительно нужны вашему проекту.) +## Кеш зависимостей и приватные источники -## Частые ошибки +Зависимости задаются в protobuf.mod, выбранные коммиты и хеши — в protobuf.lock. easyp mod download проверяет lock, не обновляя его. Обновляйте зависимости в отдельном проверяемом изменении до проверочной job. -| Симптом | Причина | Решение | -|---------|---------|---------| -| Линт падает на неизвестных правилах | Правила указаны в `easyp.yaml`, но версия EasyP их не поддерживает | Обновить EasyP (`go install ...@latest`) | -| `breaking` сравнение ничего не находит | Неверный `--against` (нет fetch удалённой ветки) | Добавить шаг `git fetch --all --tags` | -| Сгенерированный код в PR отличается от main | Отсутствует проверка генерации в CI | Добавить шаг «Ensure generated code is up-to-date» | -| Приватные deps не скачиваются | Нет SSH ключа или токена | Настроить secrets + шаг подготовки SSH | -| Долгое выполнение | Отсутствует кеш | Добавить кэширование модулей и deps | +По умолчанию хранилище EasyP находится в ~/.easyp; его можно перенести через EASYPPATH. Если кешируете его, включайте в ключ кеша ОС, версию инструментов EasyP и хеши нужных lock-файлов. Восстановленный кеш — оптимизация, проверка зависимостей всё равно выполняется. -## Рекомендации по поддержке +До шага зависимостей настройте Git-аутентификацию, необходимую приватным источникам. Храните учётные данные в принятом для runner механизме секретов и не выводите их в логи. Локальная замена не устраняет загрузки, если весь граф зависимостей не локальный и не находится в проверенном кеше; удалённым плагинам всё ещё нужна сеть. tidy и update отклоняют активные локальные замены и не являются проверками только для чтения. -- Заготовить шаблон workflow и копировать между сервисами (DRY). -- Включить `paths` фильтры, чтобы не тратить минуты на нерелевантные изменения. -- Проверять `easyp.yaml` при изменениях отдельно — можно запускать «конфигурационный тест» (например, `easyp lint` без файлов, чтобы убедиться, что конфиг валиден). -- При появлении новых правил линтера обновляйте конфиг и фиксируйте ошибки сразу в одной ветке. +## Отладка ---- +| Симптом | Что проверить | +| --- | --- | +| База не разрешается | Получите нужную ссылку и объекты через полную историю или явный fetch. | +| Неизвестное поле политики или правило | Согласуйте конфигурацию с установленным бинарником v1 и поддерживаемой схемой. | +| Плагин отсутствует или вывод отличается | Проверьте исполняемый файл, выбранный из PATH, и фиксированные версии инструментов. | +| Проверка зависимостей падает | Проверьте закоммиченные манифест и lock, доступ к источникам и сообщение о несовпадении хеша. | +| Проверка сгенерированных файлов падает | Повторите генерацию с теми же проектами и инструментами, проверьте diff и закоммитьте нужные изменения. | -Готово: вы можете расширять разделы генерации, добавлять OpenAPI / grpc-gateway / validate плагины, матрицы по языкам и интегрировать тесты поверх сгенерированного кода, если требуется. +Для диагностики сохраняйте easyp --version, упавшую команду и нужную Git-ссылку. См. [breaking-проверки в CI](/ru/docs/guides/breaking-checks-ci) и [воспроизводимость сборок](/ru/docs/guides/reproducibility). diff --git a/content/docs/ci-cd/gitlab.mdx b/content/docs/ci-cd/gitlab.mdx index c6d7849..077b2f8 100644 --- a/content/docs/ci-cd/gitlab.mdx +++ b/content/docs/ci-cd/gitlab.mdx @@ -1,5 +1,28 @@ --- -title: "Gitlab" +title: "GitLab CI" --- -## Work in progress +Set EASYP_CI_IMAGE to a pinned image containing a reviewed EasyP v1 build, Git and the required plugins. Commit configs and the lock. This example has one module and a root generation config; in a monorepo run module commands per module and explicitly select generation projects. + +~~~yaml +image: $EASYP_CI_IMAGE + +variables: + GIT_DEPTH: "0" + +stages: [validate] + +contracts: + stage: validate + script: + - easyp validate-config + - easyp mod download + - easyp lint + - git fetch origin +refs/heads/main:refs/remotes/origin/main + - easyp breaking --against refs/remotes/origin/main + - easyp generate + - git diff --exit-code + - test -z "$(git status --porcelain --untracked-files=normal -- gen)" +~~~ + +Adjust main and gen to the project baseline and output directory. The last assertion catches newly generated untracked files. Do not mask breaking failures with || echo. Configure private Git access through the runner; do not put credentials into EasyP YAML. diff --git a/content/docs/ci-cd/gitlab.ru.mdx b/content/docs/ci-cd/gitlab.ru.mdx index b4295b8..3880e7e 100644 --- a/content/docs/ci-cd/gitlab.ru.mdx +++ b/content/docs/ci-cd/gitlab.ru.mdx @@ -2,60 +2,27 @@ title: "GitLab CI" --- -## В процессе разработки +Для примера ниже задайте EASYP_CI_IMAGE: закреплённый образ с проверенной сборкой EasyP v1, Git и нужными плагинами. Конфиги и lock должны быть закоммичены. Здесь показан один модуль с generation-конфигом в корне; в монорепозитории команды модулей запускаются для каждого модуля, а генерация выбирается явно. -Документация по интеграции EasyP с GitLab CI находится в процессе подготовки. -Планируемые разделы: - -- Быстрый старт (пример `.gitlab-ci.yml` для линтинга и проверки несовместимых изменений) -- Кэширование зависимостей и ускорение сборок -- Генерация кода и проверка актуальности артефактов -- Работа с приватными Git-репозиториями в `deps` -- Матрицы (parallel jobs) для разных языков и плагинов -- Автоматизация релизов по тегам - -Если вам нужен пример прямо сейчас, базовый минимальный вариант может выглядеть так: - -```yaml -stages: - - validate - - generate +~~~yaml +image: $EASYP_CI_IMAGE variables: - GO_VERSION: "1.22" + GIT_DEPTH: "0" + +stages: [validate] -validate: +contracts: stage: validate - image: golang:${GO_VERSION} - before_script: - - go install github.com/easyp-tech/easyp/cmd/easyp@latest - - echo "EasyP version:" - - easyp --version - # При необходимости: git fetch --all --tags script: + - easyp validate-config + - easyp mod download - easyp lint - - easyp breaking --against git-ref=origin/main - only: - changes: - - "**/*.proto" - - "easyp.yaml" - -generate: - stage: generate - image: golang:${GO_VERSION} - before_script: - - go install github.com/easyp-tech/easyp/cmd/easyp@latest - script: + - git fetch origin +refs/heads/main:refs/remotes/origin/main + - easyp breaking --against refs/remotes/origin/main - easyp generate - - | - if [ -n "$(git status --porcelain)" ]; then - echo "Сгенерированный код не актуален. Закоммитьте изменения локально." - git diff --name-only - exit 1 - fi - only: - - main - -``` + - git diff --exit-code + - test -z "$(git status --porcelain --untracked-files=normal -- gen)" +~~~ -Дополнительные рекомендации будут добавлены позже. +Замените main и gen на baseline и каталог результатов проекта. Последняя проверка учитывает новые неотслеживаемые generated-файлы. Не маскируйте ошибку breaking через || echo. Доступ к приватным Git-источникам настраивается средствами runner; секреты не записываются в YAML-конфиги EasyP. diff --git a/content/docs/cli/breaking-changes/index.mdx b/content/docs/cli/breaking-changes/index.mdx index 5ba8927..781b333 100644 --- a/content/docs/cli/breaking-changes/index.mdx +++ b/content/docs/cli/breaking-changes/index.mdx @@ -1,25 +1,48 @@ --- title: "Breaking Changes Detection" -description: "Compare protobuf schemas with a Git ref using EasyP v1." +description: "Compare protobuf schemas with a Git baseline and revision-local dependencies in EasyP v1." --- -`easyp breaking` compares current `.proto` files with a Git reference and reports incompatible changes detected by the existing checker. +easyp breaking compares selected current .proto files with a Git baseline and reports incompatible changes. -```yaml -# easyp.yaml +~~~yaml version: v1 breaking: baseline: git:main + categories: [FILE] + ignore_unstable: true ignore: [experimental] -``` +~~~ -```bash +~~~bash easyp breaking --path proto --against main easyp --format json breaking --path proto -``` +~~~ -`breaking.baseline` selects the Git ref. If it is absent, `--against` supplies the ref (default `master`). `--path` selects a directory relative to the scan root; `--root` changes that root from the policy file's directory. `breaking.ignore` excludes directories from the check. +## Select a baseline and files -The v1 pilot keeps the existing breaking check set. `breaking.categories`, `breaking.ignore_unstable`, and `breaking.extends` are not implemented and return an error instead of silently changing behavior. The old `breaking_check.against_git_ref` key is not accepted by the v1 CLI. +Precedence is explicit --against, then breaking.baseline, then master. Even explicit --against master overrides configuration. An empty or whitespace-only flag is an error; a missing explicit Git baseline never falls back to the configured one. -See the [`easyp.yaml` reference](/docs/reference/easyp-yaml) for the policy format. For imports, the checker uses the module and dependency roots resolved for the scan root; a policy can also run without a module manifest. +The baseline can name a local branch, a lightweight or annotated tag, a full commit SHA, or another locally resolvable Git revision such as HEAD. Required refs and objects must already be present in the checkout. A bare branch name takes precedence over an identically named tag; use refs/tags/v1.2.0 to select the tag explicitly. In YAML use git:refs/tags/v1.2.0; for the CLI pass --against refs/tags/v1.2.0 without a git: or git-ref= prefix. + +--path selects a file or directory relative to the scan root; --root changes that root from the policy directory. Checked file identities remain repository-relative. breaking.ignore excludes directories; vendored sources are excluded from targets. + +breaking.ignore paths are relative to the file supplying the effective breaking section, not the Git root or --root. For example, ignore: [generated] in api/easyp.yaml excludes api/generated, including when that section is inherited. Entries must be nonempty local relative paths; absolute paths and paths escaping the policy directory or repository are rejected. + +Policies come from current configuration. Each nearest defined breaking section applies as a whole; nested policies may select different baselines. Repeated identical findings are emitted once. + +## Revision-local contexts + +Each selected module is compared separately. Current and baseline revisions use their own module roots, protobuf.mod, protobuf.lock, and dependencies. Baseline sources, manifests, and locks are read from an isolated Git snapshot. The caller's checkout, manifest, and lock are unchanged; the verified dependency cache may be populated. Temporary snapshots are removed after use. + +Baseline-only files and deleted modules remain checkable, including through --path. Dependency findings use the policy of the selected files. A policy can also run without a module manifest. + +Local replacements inside the repository use the contents of the corresponding revision; absolute paths inside the repository are mapped into the baseline snapshot. External local replacements are rejected because they have no recoverable historical identity. Use a locked dependency for a reproducible baseline. + +## Categories and unstable packages + +Existing compatibility checks remain enabled. The only supported additional category is FILE, which adds declaration-move checks between files. PACKAGE, WIRE, WIRE_JSON, and other categories are reserved and unimplemented; they cannot be selected. + +breaking.ignore_unstable defaults to false. When true, it excludes packages on both sides whose final component matches vNtest..., vNalpha, vNbeta, vNpMalpha, or vNpMbeta. N and M are positive numbers without leading zeros; alpha/beta may have a similarly positive sequence number, and test may have any suffix. For example, acme.v1beta1 is skipped, while acme.v1beta1.service and acme.v0alpha1 are not. Stable packages and their references to unstable types remain checked; source reading and import resolution precede filtering. + +breaking.extends is reserved: omit it or leave it empty. Nonempty shared-policy references are unsupported. The old breaking_check.against_git_ref key is not accepted by the v1 CLI. See the [policy reference](/docs/reference/easyp-yaml) for all fields. diff --git a/content/docs/cli/breaking-changes/index.ru.mdx b/content/docs/cli/breaking-changes/index.ru.mdx index c42fea4..3b776ab 100644 --- a/content/docs/cli/breaking-changes/index.ru.mdx +++ b/content/docs/cli/breaking-changes/index.ru.mdx @@ -1,25 +1,48 @@ --- title: "Проверка несовместимых изменений" -description: "Сравнение protobuf-схем с Git-ссылкой в EasyP v1." +description: "Сравнение protobuf-схем с Git-базой и зависимостями каждой ревизии в EasyP v1." --- -`easyp breaking` сравнивает текущие `.proto` с Git-ссылкой и выводит несовместимые изменения, обнаруженные существующим механизмом проверки. +easyp breaking сравнивает выбранные текущие .proto с Git-базой и выводит несовместимые изменения. -```yaml -# easyp.yaml +~~~yaml version: v1 breaking: baseline: git:main + categories: [FILE] + ignore_unstable: true ignore: [experimental] -``` +~~~ -```bash +~~~bash easyp breaking --path proto --against main easyp --format json breaking --path proto -``` +~~~ -`breaking.baseline` выбирает Git-ссылку. Если поле не задано, используется `--against` (по умолчанию `master`). `--path` указывает каталог относительно корня проверки; `--root` меняет этот корень с каталога файла политики. `breaking.ignore` исключает каталоги из проверки. +## Выбор базы и файлов -Пилотная версия v1 сохраняет существующий набор breaking-проверок. `breaking.categories`, `breaking.ignore_unstable` и `breaking.extends` не реализованы и возвращают ошибку, чтобы не менять поведение незаметно. Старый ключ `breaking_check.against_git_ref` CLI v1 не принимает. +Приоритет: явный --against, затем breaking.baseline, затем master. Даже явный --against master перекрывает конфигурацию. Пустое или пробельное значение флага — ошибка; отсутствующая явная Git-база не заменяется конфигурационной. -Формат политики описан в [справочнике `easyp.yaml`](/ru/docs/reference/easyp-yaml). Для импортов проверка использует корни модуля и зависимостей, найденные для корня проверки. Политика может работать и без манифеста модуля. +База может указывать на локальную ветку, лёгкий или аннотированный тег, полный SHA коммита или другую разрешимую локально Git-ревизию, например HEAD. Нужные ссылки и объекты должны уже присутствовать в checkout. Короткое имя ветки приоритетнее одноимённого тега; для явного выбора тега используйте refs/tags/v1.2.0. В YAML задавайте git:refs/tags/v1.2.0, а в CLI — --against refs/tags/v1.2.0 без префикса git: или git-ref=. + +--path выбирает файл или каталог относительно корня проверки; --root меняет этот корень с каталога политики. Идентичность проверяемых файлов остаётся относительно Git-репозитория. breaking.ignore исключает каталоги; вендорные исходники не становятся целями проверки. + +Пути breaking.ignore отсчитываются от файла, задающего эффективную секцию breaking, а не от корня Git или --root. Например, ignore: [generated] в api/easyp.yaml исключает api/generated, в том числе при наследовании этой секции. Допустимы непустые локальные относительные пути; абсолютные пути и выход за каталог политики или репозиторий отклоняются. + +Политики берутся из текущей конфигурации. Ближайшая определённая секция breaking применяется целиком; вложенные политики могут выбирать разные базы. Повторяющиеся одинаковые замечания выводятся один раз. + +## Контекст каждой ревизии + +Каждый выбранный модуль сравнивается отдельно. Текущая ревизия и база используют собственные корни модулей, protobuf.mod, protobuf.lock и зависимости. Исходники, манифесты и lock базы читаются из изолированного Git-снимка. Рабочее дерево, манифест и lock пользователя не меняются; проверенный кеш зависимостей может пополняться. Временные снимки удаляются после проверки. + +Файлы, существующие только в базе, и удалённые модули остаются доступными для проверки, в том числе через --path. Политика выбранных файлов определяет и политику замечаний о зависимостях. Проверка возможна и без манифеста модуля. + +Локальная замена внутри репозитория использует содержимое соответствующей ревизии; абсолютный путь внутри репозитория отображается в снимок базы. Внешняя локальная замена отклоняется: у неё нет восстановимой исторической идентичности. Для воспроизводимой базы используйте зафиксированную зависимость. + +## Категории и нестабильные пакеты + +Существующие проверки совместимости всегда остаются включёнными. Единственная поддерживаемая дополнительная категория — FILE: она добавляет проверки перемещений объявлений между файлами. Категории PACKAGE, WIRE, WIRE_JSON и другие зарезервированы и не реализованы; выбирать их нельзя. + +breaking.ignore_unstable по умолчанию равен false. При true на обеих сторонах сравнения исключаются пакеты, последний компонент имени которых соответствует vNtest..., vNalpha, vNbeta, vNpMalpha или vNpMbeta. N и M — положительные числа без ведущего нуля; после alpha/beta допустим такой же положительный номер, после test — любой суффикс. Например, acme.v1beta1 пропускается, а acme.v1beta1.service и acme.v0alpha1 — нет. Стабильные пакеты и их ссылки на нестабильные типы всё ещё проверяются; чтение исходников и разрешение импортов происходят до фильтрации. + +breaking.extends зарезервировано: поле нужно опустить или оставить пустым. Непустые ссылки на общие политики не поддерживаются. Старый ключ breaking_check.against_git_ref CLI v1 не принимает. Все поля описаны в [справочнике политики](/ru/docs/reference/easyp-yaml). diff --git a/content/docs/cli/configuration.mdx b/content/docs/cli/configuration.mdx index 8e8d167..5f60eee 100644 --- a/content/docs/cli/configuration.mdx +++ b/content/docs/cli/configuration.mdx @@ -7,76 +7,80 @@ The v1 pilot separates module dependencies, generation, and lint and breaking po | File | Purpose | |------|---------| -| [`protobuf.mod`](/docs/reference/protobuf-mod) | Module identity, source roots, requirements, and local replacements | -| [`protobuf.lock`](/docs/reference/protobuf-lock) | Resolved Git commits and content hashes; generated by `easyp mod tidy` | -| [`easyp.gen.yaml`](/docs/reference/easyp-gen-yaml) | Modules to generate, plugins, outputs, and managed options | -| [`easyp.yaml`](/docs/reference/easyp-yaml) | Lint and breaking policies | +| [protobuf.mod](/docs/reference/protobuf-mod) | Module identity, source roots, requirements, and local replacements | +| [protobuf.lock](/docs/reference/protobuf-lock) | Resolved Git commits and content hashes; generated by easyp mod tidy | +| [easyp.gen.yaml](/docs/reference/easyp-gen-yaml) | Modules to generate, plugins, outputs, and managed options | +| [easyp.yaml](/docs/reference/easyp-yaml) | Lint and breaking policies | The CLI commands use the v1 files directly. They do not fall back to the older EasyP generation, lint, breaking, or module-management configuration. A Git dependency can still use older EasyP or Buf configuration: the dependency reader extracts its requirements and proto roots for import resolution. ## Typical workflow -```bash +~~~bash easyp init --module github.com/acme/contracts easyp mod tidy easyp mod download easyp generate easyp lint --path proto easyp breaking --path proto --against main -``` +~~~ -`mod tidy` resolves requirements and writes `protobuf.lock`. `mod download` fetches exactly the locked commits. `mod update` refreshes required versions within their current major versions, then updates the lock. Local `replace` directives work for generation and linting; remove them before `mod tidy` or `mod update` writes a reproducible lock. +mod tidy resolves requirements and writes protobuf.lock. mod download fetches exactly the locked commits. mod update refreshes required versions within their current major versions, then updates the lock. Local replace directives work for generation and linting; remove them before mod tidy or mod update writes a reproducible lock. ## Command flags | Command | Relevant flags | |---------|----------------| -| `generate` | `--project`, `--descriptor_set_out`, `--include_imports` | -| `lint` | `--path` (`-p`), `--root` (`-r`) | -| `breaking` | `--path` (`-p`), `--root` (`-r`), `--against` | -| `init` | `--dir` (`-d`), `--module` | -| `validate-config` | `--config` (alias of `--cfg`), `--format` | -| `mod vendor` | No command-specific flags | -| `ls-files` | `--include-imports` (default `true`), `--format` (`json` or `text`) | -| `schema-gen` | `--out-dir` (default `schemas`) | +| generate | --project (repeatable), --all, --workspace, --descriptor_set_out, --descriptor_set_out_dir, --include_imports | +| lint | --path (-p), --root (-r) | +| breaking | --path (-p), --root (-r), --against | +| init | --dir (-d), --module | +| validate-config | --config (alias of --cfg), --format | +| mod vendor | No command-specific flags | +| ls-files | --include-imports (default true), --format (json or text) | +| schema-gen | --out-dir (default schemas) | -The global flags are `--cfg` (alias `--config`, default `easyp.yaml`), `--debug` (`-d`), and `--format` (`-f`, `text` or `json`). `EASYP_CFG`, `EASYP_DEBUG`, and `EASYP_FORMAT` set their respective defaults. The module cache uses `EASYPPATH` or `$HOME/.easyp`. +The global flags are --cfg (alias --config, default easyp.yaml), --debug (-d), and --format (-f, text or json). EASYP_CFG, EASYP_DEBUG, and EASYP_FORMAT set their respective defaults. The module cache uses EASYPPATH or $HOME/.easyp. -`generate` discovers `easyp.gen.yaml` files beneath the current directory. Use `--project` to choose one consumer project. Modules and their source roots come from `protobuf.mod`; `generate.packages` is reserved and currently returns an error if nonempty. The old `generate --path` and `generate --root` flags are unavailable. +By default, generate selects the closest easyp.gen.yaml in the current directory or a workspace ancestor. Repeat --project for multiple explicit consumers. --all separately opts into recursive selection below the invocation directory and is mutually exclusive with --project. --workspace sets the boundary for module paths and inheritance; by default this is the nearest Git repository or enclosing EasyP files. Modules and roots come from protobuf.mod; generate.packages is reserved and rejects nonempty values. The generate --path and generate --root flags are unavailable. -`lint` and `breaking` read the v1 `easyp.yaml`. They use the nearest module's declared roots and locked or local dependency roots for imports. A policy may exist without a `protobuf.mod`; in that case the commands use the scanned files and built-in imports. +--descriptor_set_out merges compatible graphs into one file; --descriptor_set_out_dir produces an independent file per project/module pair. The flags are mutually exclusive and destinations are invocation-relative. --include_imports defaults to false and affects exports only. plugins[].with_imports also defaults to false but separately enables imported code generation for an individual plugin. options.go.package_prefix changes Go only; full managed mode requires explicit generate.managed.enabled: true. -`generate` and `ls-files` also work without `protobuf.mod` when there are no module dependencies: the current project directory is treated as the source root. +lint and breaking read the v1 easyp.yaml. They use the nearest module's declared roots and locked or local dependency roots for imports. A policy may exist without a protobuf.mod; in that case the commands use the scanned files and built-in imports. -EasyP expands environment variables in `easyp.yaml` and `easyp.gen.yaml` before parsing or validation. `${NAME}` uses the variable value, `${NAME:-default}` supplies a fallback, and `$${NAME}` leaves a literal `${NAME}`. An unset variable without a fallback becomes an empty string. YAML comments are ignored during expansion. `protobuf.mod` and `protobuf.lock` do not use this substitution. +generate and ls-files also work without protobuf.mod when there are no module dependencies: the current project directory is treated as the source root. -`breaking` applies the nearest `breaking` section to each reported file. When nested policies select different Git baselines, it compares against each baseline and reports an issue only under the policy that selected it. +EasyP expands environment variables in easyp.yaml and easyp.gen.yaml before parsing or validation. ${NAME} uses the variable value, ${NAME:-default} supplies a fallback, and $${NAME} leaves a literal ${NAME}. An unset variable without a fallback becomes an empty string. YAML comments are ignored during expansion. protobuf.mod and protobuf.lock do not use this substitution. -`validate-config` recursively checks every `easyp.yaml`, `easyp.gen.yaml`, `protobuf.mod`, and `protobuf.lock` below the current directory. Pass `--cfg ` to check one file or `--cfg ` to scan another directory. JSON errors identify the file; YAML structure errors also include line and column. Invalid lock versions, incomplete entries, and malformed hashes are reported as validation errors. +For breaking, explicit --against overrides breaking.baseline, followed by the default master. Each revision uses its own roots, manifests, and locks; the baseline comes from an isolated Git snapshot. Policies come from current configuration and sections are inherited as a whole. The additional category FILE is supported; package-related and other categories are reserved and rejected. breaking.ignore_unstable defaults to false; its exact unstable suffix forms are in the [reference](/docs/reference/easyp-yaml#unstable-packages). -```bash +issues.exclude-rules.path is relative to the file supplying the issues section and supports *, ?, [], and complete ** segments. Literal directories cover their subtree. An empty rule {} explicitly ignores all files. linters.allow_comment_ignores defaults to true per policy. linters.extends and breaking.extends are reserved: omit them or leave them empty. + +validate-config recursively checks every easyp.yaml, easyp.gen.yaml, protobuf.mod, and protobuf.lock below the current directory. Pass --cfg <file> to check one file or --cfg <directory> to scan another directory. JSON errors identify the file; YAML structure errors also include line and column. Invalid lock versions, incomplete entries, and malformed hashes are reported as validation errors. + +~~~bash easyp validate-config easyp validate-config --cfg ./services --format json easyp validate-config --cfg ./services/api/easyp.gen.yaml -``` +~~~ -`mod vendor` verifies the locked Git dependencies and copies their `.proto` files into `easyp_vendor` using their import paths. It replaces a previous vendor tree only after all files have been copied successfully. Duplicate import paths are errors. Run `mod tidy` first; local `replace` directives cannot be vendored. +mod vendor verifies the locked Git dependencies and copies their .proto files into easyp_vendor using their import paths. It replaces a previous vendor tree only after all files have been copied successfully. Duplicate import paths are errors. Run mod tidy first; local replace directives cannot be vendored. -`ls-files` lists local `.proto` files from `protobuf.mod` roots. By default it also includes reachable imports from dependencies and bundled well-known protos, resolving dependencies through the v1 lock or local replacements. Use `--include-imports=false` to list only local files without resolving dependencies. JSON output contains `files`, `roots`, and any import `errors`. +ls-files lists local .proto files from protobuf.mod roots. By default it also includes reachable imports from dependencies and bundled well-known protos, resolving dependencies through the v1 lock or local replacements. Use --include-imports=false to list only local files without resolving dependencies. JSON output contains files, roots, and any import errors. -`schema-gen --out-dir schemas` writes separate JSON Schemas for `easyp.yaml`, `easyp.gen.yaml`, and `protobuf.lock`, each with a `-v1.schema.json` filename and an unversioned alias. `protobuf.mod` is a text manifest, so validate it with `validate-config` instead. CLI validation also checks semantic rules beyond the JSON Schemas. +schema-gen --out-dir schemas writes separate JSON Schemas for easyp.yaml, easyp.gen.yaml, and protobuf.lock, each with a -v1.schema.json filename and an unversioned alias. protobuf.mod is a text manifest, so validate it with validate-config instead. CLI validation also checks semantic rules beyond the JSON Schemas. -The exported `github.com/easyp-tech/easyp/mcp/easypconfig` package registers `easyp_config_describe` with an MCP server through `easypconfig.RegisterTool(server)`. The tool describes the two editable YAML files and reads the same JSON Schemas as `schema-gen`. It does not describe `protobuf.mod` or `protobuf.lock`. +The exported github.com/easyp-tech/easyp/mcp/easypconfig package registers easyp_config_describe with an MCP server through easypconfig.RegisterTool(server). The tool describes the two editable YAML files and reads the same JSON Schemas as schema-gen. It does not describe protobuf.mod or protobuf.lock. ## Minimal files -```text +~~~text module github.com/acme/contracts roots proto require github.com/acme/shared v1.2.0 -``` +~~~ -```yaml +~~~yaml # easyp.gen.yaml version: v1 generate: @@ -84,15 +88,15 @@ generate: plugins: - name: go out: ./gen/go -``` +~~~ -```yaml +~~~yaml # easyp.yaml version: v1 linters: default: STANDARD breaking: baseline: git:main -``` +~~~ For the exact fields and current limits, use the linked reference pages above. diff --git a/content/docs/cli/configuration.ru.mdx b/content/docs/cli/configuration.ru.mdx index e2e788b..efeb0f2 100644 --- a/content/docs/cli/configuration.ru.mdx +++ b/content/docs/cli/configuration.ru.mdx @@ -7,76 +7,80 @@ description: "Файлы и команды CLI пилотной версии Eas | Файл | Назначение | |------|------------| -| [`protobuf.mod`](/ru/docs/reference/protobuf-mod) | Имя модуля, корни исходников, зависимости и локальные замены | -| [`protobuf.lock`](/ru/docs/reference/protobuf-lock) | Зафиксированные Git-коммиты и хеши содержимого; создаётся командой `easyp mod tidy` | -| [`easyp.gen.yaml`](/ru/docs/reference/easyp-gen-yaml) | Модули для генерации, плагины, выходные каталоги и managed mode | -| [`easyp.yaml`](/ru/docs/reference/easyp-yaml) | Правила линтинга и проверки совместимости | +| [protobuf.mod](/ru/docs/reference/protobuf-mod) | Имя модуля, корни исходников, зависимости и локальные замены | +| [protobuf.lock](/ru/docs/reference/protobuf-lock) | Зафиксированные Git-коммиты и хеши содержимого; создаётся командой easyp mod tidy | +| [easyp.gen.yaml](/ru/docs/reference/easyp-gen-yaml) | Модули для генерации, плагины, выходные каталоги и managed mode | +| [easyp.yaml](/ru/docs/reference/easyp-yaml) | Правила линтинга и проверки совместимости | -Команды CLI читают формат v1 напрямую и не переходят на старую логику генерации, линтинга, проверки совместимости или управления модулями. Зависимость в Git при этом может использовать старый формат EasyP или Buf: адаптер извлекает её требования и корни `.proto` для разрешения импортов. +Команды CLI читают формат v1 напрямую и не переходят на старую логику генерации, линтинга, проверки совместимости или управления модулями. Зависимость в Git при этом может использовать старый формат EasyP или Buf: адаптер извлекает её требования и корни .proto для разрешения импортов. ## Обычный порядок работы -```bash +~~~bash easyp init --module github.com/acme/contracts easyp mod tidy easyp mod download easyp generate easyp lint --path proto easyp breaking --path proto --against main -``` +~~~ -`mod tidy` разрешает зависимости и записывает `protobuf.lock`. `mod download` скачивает только зафиксированные коммиты. `mod update` обновляет версии в пределах текущей мажорной версии и пересоздаёт lock. Локальные `replace` работают при генерации и линтинге; перед `mod tidy` или `mod update` их нужно убрать, чтобы получить воспроизводимый lock. +mod tidy разрешает зависимости и записывает protobuf.lock. mod download скачивает только зафиксированные коммиты. mod update обновляет версии в пределах текущей мажорной версии и пересоздаёт lock. Локальные replace работают при генерации и линтинге; перед mod tidy или mod update их нужно убрать, чтобы получить воспроизводимый lock. ## Флаги команд | Команда | Основные флаги | |---------|----------------| -| `generate` | `--project`, `--descriptor_set_out`, `--include_imports` | -| `lint` | `--path` (`-p`), `--root` (`-r`) | -| `breaking` | `--path` (`-p`), `--root` (`-r`), `--against` | -| `init` | `--dir` (`-d`), `--module` | -| `validate-config` | `--config` (псевдоним `--cfg`), `--format` | -| `mod vendor` | Нет собственных флагов | -| `ls-files` | `--include-imports` (по умолчанию `true`), `--format` (`json` или `text`) | -| `schema-gen` | `--out-dir` (по умолчанию `schemas`) | +| generate | --project (повторяемый), --all, --workspace, --descriptor_set_out, --descriptor_set_out_dir, --include_imports | +| lint | --path (-p), --root (-r) | +| breaking | --path (-p), --root (-r), --against | +| init | --dir (-d), --module | +| validate-config | --config (псевдоним --cfg), --format | +| mod vendor | Нет собственных флагов | +| ls-files | --include-imports (по умолчанию true), --format (json или text) | +| schema-gen | --out-dir (по умолчанию schemas) | -Общие флаги: `--cfg` (псевдоним `--config`, по умолчанию `easyp.yaml`), `--debug` (`-d`) и `--format` (`-f`, `text` или `json`). Переменные `EASYP_CFG`, `EASYP_DEBUG` и `EASYP_FORMAT` задают значения по умолчанию. Кеш модулей находится в `EASYPPATH` или `$HOME/.easyp`. +Общие флаги: --cfg (псевдоним --config, по умолчанию easyp.yaml), --debug (-d) и --format (-f, text или json). Переменные EASYP_CFG, EASYP_DEBUG и EASYP_FORMAT задают значения по умолчанию. Кеш модулей находится в EASYPPATH или $HOME/.easyp. -`generate` ищет `easyp.gen.yaml` внутри текущего каталога. Флаг `--project` выбирает один проект-потребитель. Список модулей и корни исходников берутся из `protobuf.mod`. Поле `generate.packages` зарезервировано: непустое значение пока вызывает ошибку. Старые флаги `generate --path` и `generate --root` удалены. +По умолчанию generate выбирает ближайший easyp.gen.yaml в текущем или родительском каталоге workspace. --project можно повторять для нескольких явных потребителей. --all отдельно включает рекурсивный выбор внутри каталога запуска и несовместим с --project. --workspace задаёт границу для путей модулей и наследования; по умолчанию используется ближайший Git-репозиторий или охватывающие файлы EasyP. Модули и корни исходников берутся из protobuf.mod; generate.packages зарезервировано и отклоняется при непустом значении. Флагов generate --path и generate --root нет. -`lint` и `breaking` читают `easyp.yaml` версии v1. Для импортов они используют корни ближайшего модуля и его зафиксированных или локальных зависимостей. Политика может существовать без `protobuf.mod`; тогда используются проверяемые файлы и встроенные импорты. +--descriptor_set_out объединяет совместимые графы в один файл; --descriptor_set_out_dir создаёт независимый файл для каждой пары проект/модуль. Флаги взаимоисключающие, пути считаются от каталога запуска. --include_imports по умолчанию равен false и влияет только на экспорт. plugins[].with_imports также по умолчанию равен false, но отдельно включает генерацию импортов для конкретного плагина. options.go.package_prefix меняет только Go; полный managed mode требует явного generate.managed.enabled: true. -`generate` и `ls-files` тоже работают без `protobuf.mod`, если у проекта нет модульных зависимостей: текущий каталог проекта считается корнем исходников. +lint и breaking читают easyp.yaml версии v1. Для импортов они используют корни ближайшего модуля и его зафиксированных или локальных зависимостей. Политика может существовать без protobuf.mod; тогда используются проверяемые файлы и встроенные импорты. -Перед разбором и проверкой `easyp.yaml` и `easyp.gen.yaml` EasyP подставляет переменные окружения. `${NAME}` берёт значение переменной, `${NAME:-default}` задаёт запасное значение, а `$${NAME}` оставляет буквальную строку `${NAME}`. Отсутствующая переменная без запасного значения превращается в пустую строку. Подстановки в комментариях YAML игнорируются. В `protobuf.mod` и `protobuf.lock` такой подстановки нет. +generate и ls-files тоже работают без protobuf.mod, если у проекта нет модульных зависимостей: текущий каталог проекта считается корнем исходников. -`breaking` применяет ближайшую секцию `breaking` к каждому файлу с ошибкой. Если вложенные политики выбирают разные Git-базы, команда сравнивает файлы с каждой базой и относит ошибку только к выбравшей её политике. +Перед разбором и проверкой easyp.yaml и easyp.gen.yaml EasyP подставляет переменные окружения. ${NAME} берёт значение переменной, ${NAME:-default} задаёт запасное значение, а $${NAME} оставляет буквальную строку ${NAME}. Отсутствующая переменная без запасного значения превращается в пустую строку. Подстановки в комментариях YAML игнорируются. В protobuf.mod и protobuf.lock такой подстановки нет. -`validate-config` рекурсивно проверяет все `easyp.yaml`, `easyp.gen.yaml`, `protobuf.mod` и `protobuf.lock` внутри текущего каталога. Передайте `--cfg <файл>`, чтобы проверить один файл, или `--cfg <каталог>`, чтобы проверить другой каталог. В JSON-ошибках указан файл, а для ошибок структуры YAML — строка и столбец. Некорректная версия lock-файла, неполные записи и неверные хеши выдаются как ошибки проверки. +В breaking явный --against перекрывает breaking.baseline, затем применяется значение по умолчанию master. Каждая ревизия использует собственные корни, манифесты и lock; база читается из изолированного Git-снимка. Политики берутся из текущей конфигурации, секции наследуются целиком. Поддерживается дополнительная категория FILE; пакетные и другие категории зарезервированы и не принимаются. breaking.ignore_unstable по умолчанию равен false; точные формы нестабильных суффиксов описаны в [справочнике](/ru/docs/reference/easyp-yaml#нестабильные-пакеты). -```bash +Пути issues.exclude-rules.path считаются от файла, предоставляющего секцию issues, и поддерживают *, ?, [] и полные сегменты **. Буквальный каталог охватывает поддерево. Пустое правило {} явно исключает все файлы. linters.allow_comment_ignores по умолчанию равен true для каждой политики. linters.extends и breaking.extends зарезервированы: их нужно опустить или оставить пустыми. + +validate-config рекурсивно проверяет все easyp.yaml, easyp.gen.yaml, protobuf.mod и protobuf.lock внутри текущего каталога. Передайте --cfg <файл>, чтобы проверить один файл, или --cfg <каталог>, чтобы проверить другой каталог. В JSON-ошибках указан файл, а для ошибок структуры YAML — строка и столбец. Некорректная версия lock-файла, неполные записи и неверные хеши выдаются как ошибки проверки. + +~~~bash easyp validate-config easyp validate-config --cfg ./services --format json easyp validate-config --cfg ./services/api/easyp.gen.yaml -``` +~~~ -`mod vendor` проверяет зафиксированные Git-зависимости и копирует их `.proto` в `easyp_vendor` по import path. Старый каталог заменяется только после успешного копирования всех файлов. Совпадающие import path вызывают ошибку. Сначала выполните `mod tidy`; локальные `replace` нельзя вендорить. +mod vendor проверяет зафиксированные Git-зависимости и копирует их .proto в easyp_vendor по import path. Старый каталог заменяется только после успешного копирования всех файлов. Совпадающие import path вызывают ошибку. Сначала выполните mod tidy; локальные replace нельзя вендорить. -`ls-files` показывает локальные `.proto` из корней `protobuf.mod`. По умолчанию команда также включает достижимые импорты из зависимостей и встроенных well-known proto, разрешая зависимости через v1 lock или локальные замены. `--include-imports=false` показывает только локальные файлы без разрешения зависимостей. В JSON есть поля `files`, `roots` и, при проблемах с импортами, `errors`. +ls-files показывает локальные .proto из корней protobuf.mod. По умолчанию команда также включает достижимые импорты из зависимостей и встроенных well-known proto, разрешая зависимости через v1 lock или локальные замены. --include-imports=false показывает только локальные файлы без разрешения зависимостей. В JSON есть поля files, roots и, при проблемах с импортами, errors. -`schema-gen --out-dir schemas` создаёт отдельные JSON Schema для `easyp.yaml`, `easyp.gen.yaml` и `protobuf.lock`: файлы с суффиксом `-v1.schema.json` и псевдонимы без версии. `protobuf.mod` — текстовый манифест; проверяйте его командой `validate-config`. CLI также проверяет семантические правила, не выраженные в JSON Schema. +schema-gen --out-dir schemas создаёт отдельные JSON Schema для easyp.yaml, easyp.gen.yaml и protobuf.lock: файлы с суффиксом -v1.schema.json и псевдонимы без версии. protobuf.mod — текстовый манифест; проверяйте его командой validate-config. CLI также проверяет семантические правила, не выраженные в JSON Schema. -Экспортируемый пакет `github.com/easyp-tech/easyp/mcp/easypconfig` регистрирует инструмент `easyp_config_describe` в MCP-сервере через `easypconfig.RegisterTool(server)`. Инструмент описывает два редактируемых YAML-файла и использует те же JSON Schema, что и `schema-gen`. Он не описывает `protobuf.mod` и `protobuf.lock`. +Экспортируемый пакет github.com/easyp-tech/easyp/mcp/easypconfig регистрирует инструмент easyp_config_describe в MCP-сервере через easypconfig.RegisterTool(server). Инструмент описывает два редактируемых YAML-файла и использует те же JSON Schema, что и schema-gen. Он не описывает protobuf.mod и protobuf.lock. ## Минимальный пример -```text +~~~text module github.com/acme/contracts roots proto require github.com/acme/shared v1.2.0 -``` +~~~ -```yaml +~~~yaml # easyp.gen.yaml version: v1 generate: @@ -84,15 +88,15 @@ generate: plugins: - name: go out: ./gen/go -``` +~~~ -```yaml +~~~yaml # easyp.yaml version: v1 linters: default: STANDARD breaking: baseline: git:main -``` +~~~ Точные поля и текущие ограничения описаны в справочниках по ссылкам выше. diff --git a/content/docs/cli/generator/index.mdx b/content/docs/cli/generator/index.mdx index 784d47b..fe5303f 100644 --- a/content/docs/cli/generator/index.mdx +++ b/content/docs/cli/generator/index.mdx @@ -1,24 +1,22 @@ --- title: "Generator" -description: "Generate code from complete protobuf modules with the EasyP v1 pilot." +description: "Select consumer projects, generate protobuf code, and export descriptor sets in EasyP v1." --- -`easyp generate` finds `easyp.gen.yaml` files beneath the current directory, selects complete modules, compiles their `.proto` files, and runs the listed plugins. Module identities, roots, and dependency versions come from `protobuf.mod` and `protobuf.lock`. +easyp generate selects the closest easyp.gen.yaml in the current directory or an ancestor within the workspace. It compiles the selected modules and runs that project's plugins. Module identities, roots, and dependency versions come from protobuf.mod and protobuf.lock. ## Configure a module -```text +~~~text # protobuf.mod module github.com/acme/contracts roots proto require github.com/acme/shared v1.2.0 -``` +~~~ -```yaml +~~~yaml # easyp.gen.yaml version: v1 -generate: - modules: [github.com/acme/contracts] plugins: - name: go out: ./gen/go @@ -28,28 +26,56 @@ plugins: out: ./gen/go opts: paths: source_relative -``` +options: + go: + package_prefix: github.com/acme/contracts/gen/go +~~~ -```bash +~~~bash easyp mod tidy easyp generate -``` +~~~ -If `generate.modules` is omitted, the generator uses `protobuf.mod` beside this `easyp.gen.yaml`, or the repository-root `protobuf.mod` when there is no sibling manifest. A locked dependency identity in `generate.modules` is resolved through that same selected manifest and its lock. A module entry may also be a repository-relative local module path. `generate.packages` is reserved for future package filtering and currently returns an error when nonempty. +If generate.modules is omitted, EasyP selects the nearest protobuf.mod beside or above the generator file within the workspace; without a manifest, the project directory is the source root. Explicit entries select local module identities, workspace-relative module paths, or dependencies resolved through the consumer manifest and lock. generate.packages is reserved and must be omitted or empty. -## Select a project and output descriptors +## Select projects -```bash -easyp generate --project backend -easyp generate --descriptor_set_out descriptors.pb --include_imports -``` +~~~bash +# Closest project only +easyp generate +# Exactly these two projects +easyp generate --project backend --project frontend +# Explicit recursive selection beneath the invocation directory +easyp generate --all +# Explicit workspace boundary, useful in a non-Git tree +easyp generate --workspace ../.. --project .. +~~~ + +--project is repeatable and cannot be combined with --all. Recursive discovery skips hidden directories, easyp_vendor, node_modules, and nested Git repositories. Select a project in a skipped directory explicitly. Automatic selection rejects a symlink configuration file; an explicit project selection is required to use it. Choosing --all authorizes plugins in the discovered projects, including command plugins. + +The nearest Git repository, including a worktree with a .git file, supplies the workspace boundary. Without Git, enclosing EasyP configuration and manifest files establish the boundary; --workspace sets it explicitly. Project paths and descriptor destinations are relative to the invocation directory. Plugin output paths are relative to their easyp.gen.yaml. The command has no --path or --root flag. + +## Export descriptors + +~~~bash +easyp generate --project backend --descriptor_set_out build/backend.pb --include_imports +easyp generate --all --descriptor_set_out_dir build/descriptors --include_imports +~~~ -`--project` selects one consumer directory containing `easyp.gen.yaml`. `--include_imports` adds transitive imports to the descriptor set. The v1 command has no `--path` or `--root` flag; source roots are declared in `protobuf.mod`. +--descriptor_set_out combines the selected graphs into one binary FileDescriptorSet. Identical descriptors are deduplicated; conflicting definitions under one import path or conflicting symbols cause an error. Managed options remain part of compatibility checks. + +--descriptor_set_out_dir writes an independent descriptor set for each selected project/module pair, so different consumers can retain different options or dependency versions. Project paths are mirrored below the destination; filenames contain a sanitized module basename and the first 12 hex digits of the full module identity's SHA-256. External projects use an _external namespace. Existing unrelated files are retained. + +The two destination flags are mutually exclusive. --include_imports defaults to false and includes transitive imports in exported files only. Compilation and compatibility validation always use the complete graph. + +All requested graphs and export destinations pass preflight before any plugin runs. Configured plugins still run; a pluginless project can also export descriptors. Descriptor files are written after all selected plugin executions succeed, with atomic replacement per file. This does not provide a transaction across arbitrary plugin side effects or filesystem failures. ## Plugins and managed options -`plugins[].name` selects a local executable or a bundled WASM plugin. EasyP selects bundled plugins through the existing plugin resolver. `plugins[].path` runs a binary at an explicit path, while `plugins[].command` runs a command with arguments. Each plugin sets exactly one of `name`, `path`, `command`, or `remote`. A remote plugin uses `remote` with a separate pinned semantic `version`. Relative binary paths and commands run from the directory where EasyP starts; plugin outputs are relative to the generator file. +Each plugin sets exactly one source: name, path, command, or remote. Local binaries and commands run from the invocation directory. Remote plugins require a pinned semantic version; local and bundled plugins reject a separate version field. + +plugins[].with_imports defaults to false. Set it to true for a particular plugin to generate code for transitive imports as well as the selected files. Other plugins still receive dependency descriptors for linking. This setting is independent of descriptor export's --include_imports. Keep Go import paths and output directories aligned: different Go packages must not share one generated directory. Identical shared outputs are deduplicated; conflicting file contents or Go package declarations fail before generated files are written. -The existing managed rules remain available under `generate.managed`, including module, package, path, and field selectors. `options.go.package_prefix` can provide a Go package prefix; a repository-root generator file can supply a default for nested generator files. See the full [`easyp.gen.yaml` reference](/docs/reference/easyp-gen-yaml). +options.go.package_prefix changes Go options only. Defaults for other languages and field-option transformations require explicit generate.managed.enabled: true. An inherited Go prefix precedes explicit managed Go overrides; a prefix in the current file has the highest priority. Go disable selectors still apply. See the full [configuration reference](/docs/reference/easyp-gen-yaml). -Dependency repositories may use v1 EasyP, older EasyP, Buf v1, or Buf v2 metadata for their proto roots. The consumer's generator still uses the v1 files. +Dependency repositories may use v1 EasyP, older EasyP, Buf v1, or Buf v2 metadata. EasyP reads dependency metadata without executing dependency plugins. diff --git a/content/docs/cli/generator/index.ru.mdx b/content/docs/cli/generator/index.ru.mdx index 3628af3..20ceca5 100644 --- a/content/docs/cli/generator/index.ru.mdx +++ b/content/docs/cli/generator/index.ru.mdx @@ -1,24 +1,22 @@ --- title: "Генератор" -description: "Генерация кода из целых protobuf-модулей в пилотной версии EasyP v1." +description: "Выбор проектов-потребителей, генерация protobuf-кода и экспорт дескрипторов в EasyP v1." --- -`easyp generate` ищет `easyp.gen.yaml` внутри текущего каталога, выбирает целые модули, компилирует их `.proto` и запускает перечисленные плагины. Имена модулей, корни исходников и версии зависимостей берутся из `protobuf.mod` и `protobuf.lock`. +easyp generate выбирает ближайший easyp.gen.yaml в текущем или родительском каталоге в пределах workspace. Команда компилирует выбранные модули и запускает плагины этого проекта. Имена модулей, корни исходников и версии зависимостей берутся из protobuf.mod и protobuf.lock. ## Настройка модуля -```text +~~~text # protobuf.mod module github.com/acme/contracts roots proto require github.com/acme/shared v1.2.0 -``` +~~~ -```yaml +~~~yaml # easyp.gen.yaml version: v1 -generate: - modules: [github.com/acme/contracts] plugins: - name: go out: ./gen/go @@ -28,28 +26,56 @@ plugins: out: ./gen/go opts: paths: source_relative -``` +options: + go: + package_prefix: github.com/acme/contracts/gen/go +~~~ -```bash +~~~bash easyp mod tidy easyp generate -``` +~~~ -Если `generate.modules` не указан, используется `protobuf.mod` рядом с этим `easyp.gen.yaml`, а при его отсутствии — корневой `protobuf.mod` репозитория. Идентификатор зависимости в `generate.modules` разрешается через тот же выбранный манифест и его lock. Элемент списка также может быть путём к локальному модулю относительно репозитория. Поле `generate.packages` оставлено для будущей фильтрации пакетов; непустое значение пока вызывает ошибку. +Если generate.modules не указан, EasyP выбирает ближайший protobuf.mod рядом с файлом генератора или выше в пределах workspace; без манифеста корнем исходников становится каталог проекта. Явные элементы выбирают локальный модуль по имени, путь относительно workspace или зависимость из манифеста и lock потребителя. Поле generate.packages зарезервировано: его нужно опустить или оставить пустым. -## Выбор проекта и дескрипторы +## Выбор проектов -```bash -easyp generate --project backend -easyp generate --descriptor_set_out descriptors.pb --include_imports -``` +~~~bash +# Только ближайший проект +easyp generate +# Ровно два указанных проекта +easyp generate --project backend --project frontend +# Явный рекурсивный выбор внутри каталога запуска +easyp generate --all +# Явная граница workspace, полезная вне Git +easyp generate --workspace ../.. --project .. +~~~ + +--project можно повторять, но нельзя сочетать с --all. Рекурсивный поиск пропускает скрытые каталоги, easyp_vendor, node_modules и вложенные Git-репозитории. Проект в пропускаемом каталоге можно выбрать явно. Автоматический выбор отклоняет конфигурацию-симлинк; для неё нужен явный выбор проекта. Флаг --all разрешает запуск плагинов найденных проектов, включая command-плагины. + +Границу workspace задаёт ближайший Git-репозиторий, включая worktree с файлом .git. Без Git граница определяется по охватывающим конфигам и манифестам EasyP; --workspace задаёт её явно. Пути проектов и дескрипторов считаются от каталога запуска. Пути результатов плагинов считаются от их easyp.gen.yaml. Флагов --path и --root у команды нет. + +## Экспорт дескрипторов + +~~~bash +easyp generate --project backend --descriptor_set_out build/backend.pb --include_imports +easyp generate --all --descriptor_set_out_dir build/descriptors --include_imports +~~~ -`--project` выбирает один каталог потребителя с `easyp.gen.yaml`. `--include_imports` добавляет транзитивные импорты в набор дескрипторов. Флагов `--path` и `--root` у команды v1 нет: корни исходников объявляются в `protobuf.mod`. +--descriptor_set_out объединяет выбранные графы в один бинарный FileDescriptorSet. Одинаковые дескрипторы объединяются; разные определения под одним import path или конфликтующие символы вызывают ошибку. Managed-опции участвуют в проверке совместимости. + +--descriptor_set_out_dir записывает отдельный набор для каждой выбранной пары проект/модуль, позволяя потребителям сохранять разные опции и версии зависимостей. Пути проектов повторяются внутри каталога назначения; имя файла содержит безопасное имя модуля и первые 12 hex-символов SHA-256 его полного идентификатора. Внешние проекты размещаются в _external. Посторонние существующие файлы сохраняются. + +Флаги назначения взаимоисключающие. --include_imports по умолчанию равен false и добавляет транзитивные импорты только в экспортируемые файлы. Компиляция и проверка совместимости всегда используют полный граф. + +Все выбранные графы и пути экспорта проверяются до запуска плагинов. Настроенные плагины всё равно запускаются; проект без плагинов тоже может экспортировать дескрипторы. Дескрипторы записываются после успешного выполнения всех выбранных плагинов с атомарной заменой каждого файла. Общей транзакции для побочных эффектов плагинов и ошибок файловой системы нет. ## Плагины и managed mode -`plugins[].name` выбирает локальный исполняемый файл или встроенный WASM-плагин. Встроенные плагины выбираются существующим resolver. `plugins[].path` запускает бинарь по явному пути, а `plugins[].command` — команду со списком аргументов. В каждом плагине задаётся ровно одно из `name`, `path`, `command` и `remote`. Для удалённого плагина указываются `remote` и отдельный зафиксированный SemVer в `version`. Относительный путь к бинарю и команда выполняются из каталога запуска EasyP; выходные каталоги задаются относительно файла генерации. +Каждый плагин задаёт ровно один источник: name, path, command или remote. Локальные бинарные файлы и команды запускаются из каталога вызова EasyP. Удалённому плагину нужен зафиксированный SemVer в version; локальные и встроенные плагины отдельную версию не принимают. + +plugins[].with_imports по умолчанию равен false. Значение true включает генерацию транзитивных импортов только для этого плагина. Остальные плагины по-прежнему получают дескрипторы зависимостей для связывания. Настройка независима от --include_imports при экспорте дескрипторов. Согласуйте Go import path и выходные каталоги: разные Go-пакеты не должны попадать в один каталог. Одинаковые общие результаты объединяются; конфликт содержимого файлов или объявлений Go-пакетов обнаруживается до записи сгенерированных файлов. -Прежние правила managed mode доступны в `generate.managed`, в том числе селекторы по модулю, пакету, пути и полю. `options.go.package_prefix` задаёт префикс Go-пакетов; корневой `easyp.gen.yaml` может предоставить значение по умолчанию вложенным конфигам. Подробности — в [справочнике `easyp.gen.yaml`](/ru/docs/reference/easyp-gen-yaml). +options.go.package_prefix меняет только Go-опции. Значения по умолчанию для других языков и преобразования опций полей требуют явного generate.managed.enabled: true. Унаследованный Go-префикс применяется до явных managed-переопределений Go; префикс текущего файла имеет наивысший приоритет. Go-селекторы disable продолжают действовать. Подробнее — в [справочнике конфигурации](/ru/docs/reference/easyp-gen-yaml). -Репозитории зависимостей могут описывать корни `.proto` в EasyP v1, старом EasyP, Buf v1 или Buf v2. Конфиг потребителя при этом остаётся v1. +Зависимости могут использовать метаданные EasyP v1, старого EasyP, Buf v1 или Buf v2. EasyP читает метаданные зависимостей, не запуская их плагины. diff --git a/content/docs/cli/linter/index.mdx b/content/docs/cli/linter/index.mdx index bb09152..1ab8c9b 100644 --- a/content/docs/cli/linter/index.mdx +++ b/content/docs/cli/linter/index.mdx @@ -3,33 +3,65 @@ title: "Linter" description: "Configure and run the EasyP v1 protobuf linter." --- -`easyp lint` checks `.proto` files using the v1 policy in `easyp.yaml`. It reports source locations and rule names for findings. +easyp lint checks .proto files using the v1 policy in easyp.yaml, reporting source locations and rule names. -```yaml -# easyp.yaml +~~~yaml version: v1 linters: default: STANDARD enable: [COMMENT_SERVICE] disable: [SERVICE_SUFFIX] + allow_comment_ignores: true linters-settings: ENUM_ZERO_VALUE_SUFFIX: suffix: UNSPECIFIED issues: exclude-rules: - - linters: [COMMENT_FIELD] -``` + - path: legacy/**/*.proto + linters: [COMMENT_FIELD] + - path: generated +~~~ -The available presets are `MINIMAL`, `BASIC`, `STANDARD`, and `COMMENTS`. `enable` and `disable` add or remove individual rules. The pilot supports `ENUM_ZERO_VALUE_SUFFIX.suffix` and `SERVICE_SUFFIX.suffix` settings. Pathless `issues.exclude-rules` apply to every scanned file; path globs and `linters.extends` are not implemented yet and produce an error. +Presets are MINIMAL, BASIC, STANDARD, and COMMENTS. Enable/disable and exclusion lists accept implemented rules and groups. Repetition is idempotent; disabling wins. Unknown names are errors, including when repeated in the opposite list. PACKAGE_NO_IMPORT_CYCLE is reserved and cannot be selected. Supported settings are ENUM_ZERO_VALUE_SUFFIX.suffix and SERVICE_SUFFIX.suffix. linters.extends is reserved and must be omitted or empty. -```bash +~~~bash easyp lint --path proto easyp --format json lint --path proto easyp lint --root ./contracts --path proto -``` +~~~ -`--path` is relative to the scan root. By default the scan root is the directory of the selected policy file; `--root` changes it. The linter uses the nearest module's source roots and local or locked dependency roots to resolve imports. A policy can also be used without `protobuf.mod`. +--path is relative to the scan root, which defaults to the selected policy's directory; --root changes it. Policy lookup searches upward within the workspace. Without an ancestor policy, one unambiguous outermost descendant policy can be selected; multiple independent policies require --cfg. An explicit config takes precedence. Each nested policy section replaces the nearest inherited section as a whole. -Nested `easyp.yaml` files may override policy sections for files beneath their directories. See the [`easyp.yaml` reference](/docs/reference/easyp-yaml) for the supported fields and merging rules. +The linter resolves imports using the nearest module's source roots and local or locked dependencies. A policy can also run without protobuf.mod. Vendored sources and hidden storage/Git directories are excluded from lint target discovery, including explicit vendor paths; dependency sources remain available for imports. -The older `lint.use`, `lint.except`, and `lint.ignore_only` configuration is not accepted by the v1 CLI. +## Exclude paths + +issues.exclude-rules.path is relative to the policy file supplying the effective issues section, even when that section is inherited. Patterns support *, ?, [], and complete ** segments. Single-segment wildcards do not cross /; ** matches zero or more segments. Literal directories include their subtree. A literal .proto path matches that file only. Absolute paths, backslashes, traversal, and malformed patterns are rejected. + +A pathless rule applies to all files covered by that issues section. An empty or omitted linters list excludes matching files entirely. An empty rule {} explicitly ignores all files. A nested issues: {} clears inherited exclusions. The example suppresses only COMMENT_FIELD in legacy files and excludes the generated subtree entirely. + +## Suppress with comments + +~~~proto +// easyp:disable FIELD_LOWER_SNAKE_CASE +message Example { + string legacyField = 1; +} + +message Another { + string legacyField = 1; // easyp:disable FIELD_LOWER_SNAKE_CASE +} + +// easyp:disable MESSAGE_PASCAL_CASE +message old_name {} +message another_old_name {} +// easyp:enable MESSAGE_PASCAL_CASE +~~~ + +An unpaired disable must annotate a declaration and covers that declaration's line or block. A paired disable/enable bounds a region in the same file; nested regions for the same rule are balanced. Suppressions do not leak to other files or policies. Rule names may be comma- or whitespace-separated; comment directives accept individual rules, not groups. + +Legacy nolint:RULE and buf:lint:ignore RULE remain declaration annotations. An explanation may follow a space-delimited -- or // separator. Only parsed comments are interpreted. Empty directives, unknown rules, unsupported actions, and unmatched enables are errors with source locations. + +linters.allow_comment_ignores defaults to true for each effective policy. Set it to false to disable comment suppression in that policy; malformed directives remain errors on files being linted. + +See the [policy reference](/docs/reference/easyp-yaml). The older lint.use, lint.except, and lint.ignore_only configuration is not accepted by the v1 CLI. diff --git a/content/docs/cli/linter/index.ru.mdx b/content/docs/cli/linter/index.ru.mdx index b340703..7c8064e 100644 --- a/content/docs/cli/linter/index.ru.mdx +++ b/content/docs/cli/linter/index.ru.mdx @@ -3,33 +3,65 @@ title: "Линтер" description: "Настройка и запуск protobuf-линтера EasyP v1." --- -`easyp lint` проверяет `.proto` по политике v1 из `easyp.yaml`. В найденных проблемах указываются положение в исходнике и имя правила. +easyp lint проверяет .proto по политике v1 из easyp.yaml, указывая положение в исходнике и имя правила. -```yaml -# easyp.yaml +~~~yaml version: v1 linters: default: STANDARD enable: [COMMENT_SERVICE] disable: [SERVICE_SUFFIX] + allow_comment_ignores: true linters-settings: ENUM_ZERO_VALUE_SUFFIX: suffix: UNSPECIFIED issues: exclude-rules: - - linters: [COMMENT_FIELD] -``` + - path: legacy/**/*.proto + linters: [COMMENT_FIELD] + - path: generated +~~~ -Доступные наборы: `MINIMAL`, `BASIC`, `STANDARD`, `COMMENTS`. Поля `enable` и `disable` добавляют или исключают отдельные правила. Пилотная версия поддерживает настройки `ENUM_ZERO_VALUE_SUFFIX.suffix` и `SERVICE_SUFFIX.suffix`. Правила `issues.exclude-rules` без пути действуют на все проверяемые файлы. Глобы путей и `linters.extends` пока не реализованы и вызывают ошибку. +Пресеты: MINIMAL, BASIC, STANDARD и COMMENTS. Списки enable/disable и исключений принимают реализованные правила и группы. Повторы не добавляют проверок; отключение приоритетнее включения. Неизвестные имена — ошибки, даже если повторены в противоположном списке. PACKAGE_NO_IMPORT_CYCLE зарезервировано и выбирать его нельзя. Поддерживаются настройки ENUM_ZERO_VALUE_SUFFIX.suffix и SERVICE_SUFFIX.suffix. Поле linters.extends зарезервировано: его нужно опустить или оставить пустым. -```bash +~~~bash easyp lint --path proto easyp --format json lint --path proto easyp lint --root ./contracts --path proto -``` +~~~ -`--path` задаётся относительно корня проверки. По умолчанию корень — каталог выбранного файла политики; `--root` меняет его. Для импортов линтер использует корни ближайшего модуля и его локальных либо зафиксированных зависимостей. Политика может работать и без `protobuf.mod`. +--path считается от корня проверки, по умолчанию — каталога выбранной политики; --root меняет его. Поиск политики идёт вверх в пределах workspace. Без политики в предках можно выбрать одну однозначную внешнюю политику в потомках; несколько независимых политик требуют --cfg. Явный конфиг имеет приоритет. Каждая вложенная секция целиком заменяет ближайшую унаследованную секцию. -Вложенные `easyp.yaml` могут переопределять секции политики для файлов в своих каталогах. Поддерживаемые поля и правила объединения описаны в [справочнике `easyp.yaml`](/ru/docs/reference/easyp-yaml). +Для импортов линтер использует корни ближайшего модуля и его локальные или зафиксированные зависимости. Политика может работать без protobuf.mod. Вендорные исходники и скрытые каталоги хранилищ/Git исключены из поиска целей линтинга, включая явные пути в vendor; зависимости остаются доступными для импортов. -Старые поля `lint.use`, `lint.except` и `lint.ignore_only` CLI v1 не принимает. +## Исключение путей + +issues.exclude-rules.path считается от файла политики, предоставляющего эффективную секцию issues, в том числе унаследованную. Поддерживаются *, ?, [] и полные сегменты **. Односегментные шаблоны не пересекают /; ** совпадает с нулём или более сегментами. Буквальный каталог включает своё поддерево. Буквальный путь с окончанием .proto совпадает только с файлом. Абсолютные пути, обратные слеши, переходы к родителю и некорректные шаблоны отклоняются. + +Правило без пути действует на все файлы этой секции issues. Пустой или отсутствующий linters исключает совпавшие файлы целиком. Пустое правило {} явно исключает все файлы. Вложенная issues: {} очищает унаследованные исключения. В примере у legacy-файлов подавляется только COMMENT_FIELD, а поддерево generated исключено полностью. + +## Подавление комментариями + +~~~proto +// easyp:disable FIELD_LOWER_SNAKE_CASE +message Example { + string legacyField = 1; +} + +message Another { + string legacyField = 1; // easyp:disable FIELD_LOWER_SNAKE_CASE +} + +// easyp:disable MESSAGE_PASCAL_CASE +message old_name {} +message another_old_name {} +// easyp:enable MESSAGE_PASCAL_CASE +~~~ + +Непарный disable должен аннотировать объявление и действует на его строку или блок. Пара disable/enable ограничивает регион в одном файле; вложенные регионы одного правила сбалансированы. Подавления не переходят в другие файлы или политики. Имена правил разделяются запятыми или пробелами; группы в директивах комментариев не принимаются. + +Старые nolint:RULE и buf:lint:ignore RULE остаются аннотациями объявлений. Пояснение можно добавить после отделённого пробелами -- или //. Интерпретируются только разобранные комментарии. Пустые директивы, неизвестные правила, неподдерживаемые действия и enable без пары — ошибки с координатами исходника. + +linters.allow_comment_ignores по умолчанию равен true для каждой эффективной политики. False отключает подавление комментариями в этой политике; некорректные директивы в проверяемых файлах остаются ошибками. + +См. [справочник политики](/ru/docs/reference/easyp-yaml). Старые поля lint.use, lint.except и lint.ignore_only CLI v1 не принимает. diff --git a/content/docs/cli/package-manager/easyp-vs-buf.mdx b/content/docs/cli/package-manager/easyp-vs-buf.mdx index 3764f4a..2308751 100644 --- a/content/docs/cli/package-manager/easyp-vs-buf.mdx +++ b/content/docs/cli/package-manager/easyp-vs-buf.mdx @@ -3,30 +3,32 @@ title: "Using Buf-configured Git dependencies" description: "How the EasyP v1 pilot reads proto roots from Git dependencies that use Buf configuration." --- -An EasyP v1 project lists Git modules in `protobuf.mod`. A dependency repository can use Buf configuration; EasyP reads that configuration to find its `.proto` source roots. The consumer does not need to copy those roots into `easyp.gen.yaml`. +An EasyP v1 project lists Git modules in protobuf.mod. A dependency repository can use Buf configuration; EasyP reads that configuration to find its .proto source roots. The consumer does not need to copy those roots into easyp.gen.yaml. | Dependency file | Roots used by EasyP | |-----------------|---------------------| -| `buf.work.yaml` v1 | `directories` | -| `buf.yaml` v2 | `modules[].path` | -| `buf.yaml` v1 | Repository root | -| `buf.yaml` v1beta1 | `build.roots`, or repository root if omitted | +| buf.work.yaml v1 | directories | +| buf.yaml v2 | modules[].path | +| buf.yaml v1 | Repository root | +| buf.yaml v1beta1 | build.roots, or repository root if omitted | -When a dependency has no EasyP or Buf configuration, EasyP uses its repository root. If it has an older EasyP `protobuf.mod` or `easyp.yaml`, EasyP also reads its transitive requirements and declared roots. +When a dependency has no EasyP or Buf configuration, EasyP uses its repository root. If it has an older EasyP protobuf.mod or easyp.yaml, EasyP also reads its transitive requirements and declared roots. -```text +When adapting an older easyp.yaml, both deps and generation Git inputs contribute requirements. Exact source/version duplicates are removed; different minimums remain visible to MVS, and malformed deps fail explicitly. A matching native protobuf.mod takes precedence. Only metadata is read; dependency plugins are never executed. + +~~~text # Consumer protobuf.mod module github.com/acme/service roots proto require github.com/acme/buf-contracts v1.2.0 -``` +~~~ -```bash +~~~bash easyp mod tidy easyp mod download easyp generate -``` +~~~ -`mod tidy` resolves the Git dependency and records the selected commit and content hash in `protobuf.lock`. Buf Registry dependency names are not converted into Git URLs automatically; declare a suitable Git source in the consumer manifest. Buf include/exclude filters are not yet supported for Git dependency import roots and produce an error. +mod tidy resolves the Git dependency and records the selected commit and content hash in protobuf.lock. Buf Registry dependency names are not converted into Git URLs automatically; declare a suitable Git source in the consumer manifest. Buf include/exclude filters are not yet supported for Git dependency import roots and produce an error. -After `mod tidy`, `mod vendor` can copy the locked Git dependency's `.proto` files into `easyp_vendor` using the roots extracted from its Buf configuration. See the [package manager guide](/docs/cli/package-manager). +After mod tidy, mod vendor can copy the locked Git dependency's .proto files into easyp_vendor using the roots extracted from its Buf configuration. See the [package manager guide](/docs/cli/package-manager). diff --git a/content/docs/cli/package-manager/easyp-vs-buf.ru.mdx b/content/docs/cli/package-manager/easyp-vs-buf.ru.mdx index edb8d0b..01ef92e 100644 --- a/content/docs/cli/package-manager/easyp-vs-buf.ru.mdx +++ b/content/docs/cli/package-manager/easyp-vs-buf.ru.mdx @@ -3,30 +3,32 @@ title: "Git-зависимости с конфигом Buf" description: "Как пилотная версия EasyP v1 извлекает корни proto из Git-зависимостей на Buf." --- -Проект EasyP v1 перечисляет Git-модули в `protobuf.mod`. Репозиторий зависимости может использовать конфигурацию Buf: EasyP читает её и находит корни исходных `.proto`. Дублировать эти корни в `easyp.gen.yaml` потребителя не нужно. +Проект EasyP v1 перечисляет Git-модули в protobuf.mod. Репозиторий зависимости может использовать конфигурацию Buf: EasyP читает её и находит корни исходных .proto. Дублировать эти корни в easyp.gen.yaml потребителя не нужно. | Файл зависимости | Корни, которые использует EasyP | |------------------|---------------------------------| -| `buf.work.yaml` v1 | `directories` | -| `buf.yaml` v2 | `modules[].path` | -| `buf.yaml` v1 | Корень репозитория | -| `buf.yaml` v1beta1 | `build.roots` или корень репозитория | +| buf.work.yaml v1 | directories | +| buf.yaml v2 | modules[].path | +| buf.yaml v1 | Корень репозитория | +| buf.yaml v1beta1 | build.roots или корень репозитория | -Если у зависимости нет конфигурации EasyP или Buf, её корнем считается каталог репозитория. Если есть старые EasyP `protobuf.mod` или `easyp.yaml`, EasyP также читает транзитивные требования и объявленные корни. +Если у зависимости нет конфигурации EasyP или Buf, её корнем считается каталог репозитория. Если есть старые EasyP protobuf.mod или easyp.yaml, EasyP также читает транзитивные требования и объявленные корни. -```text +При адаптации старого easyp.yaml требования берутся и из deps, и из Git-входов генерации. Точные дубликаты источник/версия удаляются, разные минимумы сохраняются для MVS; некорректные deps вызывают ошибку. Совпадающий нативный protobuf.mod имеет приоритет. Читаются только метаданные, плагины зависимости не запускаются. + +~~~text # protobuf.mod потребителя module github.com/acme/service roots proto require github.com/acme/buf-contracts v1.2.0 -``` +~~~ -```bash +~~~bash easyp mod tidy easyp mod download easyp generate -``` +~~~ -`mod tidy` разрешает Git-зависимость и записывает выбранный коммит и хеш содержимого в `protobuf.lock`. Имена зависимостей Buf Registry не превращаются в Git URL автоматически: подходящий Git-источник надо объявить в манифесте потребителя. Фильтры Buf include/exclude для корней Git-зависимостей пока не поддерживаются и вызывают ошибку. +mod tidy разрешает Git-зависимость и записывает выбранный коммит и хеш содержимого в protobuf.lock. Имена зависимостей Buf Registry не превращаются в Git URL автоматически: подходящий Git-источник надо объявить в манифесте потребителя. Фильтры Buf include/exclude для корней Git-зависимостей пока не поддерживаются и вызывают ошибку. -После `mod tidy` команда `mod vendor` может скопировать `.proto` зафиксированной Git-зависимости в `easyp_vendor`, используя корни из её конфигурации Buf. Подробнее — в [руководстве менеджера пакетов](/ru/docs/cli/package-manager). +После mod tidy команда mod vendor может скопировать .proto зафиксированной Git-зависимости в easyp_vendor, используя корни из её конфигурации Buf. Подробнее — в [руководстве менеджера пакетов](/ru/docs/cli/package-manager). diff --git a/content/docs/cli/package-manager/index.mdx b/content/docs/cli/package-manager/index.mdx index fe7038c..02a1d81 100644 --- a/content/docs/cli/package-manager/index.mdx +++ b/content/docs/cli/package-manager/index.mdx @@ -3,11 +3,11 @@ title: "Package Manager" description: "Resolve and lock Git-based protobuf dependencies in EasyP v1." --- -The v1 package manager reads `protobuf.mod` and writes `protobuf.lock`. It records each selected Git commit and an `h1:` content hash, then verifies the hash when downloading or reusing a cached module. +The v1 package manager reads protobuf.mod and writes protobuf.lock. It records each selected Git commit and an h1: content hash, then verifies the hash when downloading or reusing a cached module. ## Declare dependencies -```text +~~~text module github.com/acme/contracts roots proto @@ -15,36 +15,48 @@ require ( github.com/acme/shared v1.2.0 github.com/acme/weather v2.1.0 ) -``` +~~~ -`roots` defaults to `.` when omitted. A requirement may omit its version: `mod tidy` resolves the Git repository's current HEAD and locks its exact commit. Repeating `tidy` keeps that commit; `mod update` refreshes versionless requirements to HEAD. You may instead give a SemVer tag or a full 40- or 64-character Git commit hash. `replace module => ../local-copy` points generation and linting at a local checkout. Remove local replacements before writing a reproducible lock with `mod tidy` or `mod update`. +roots defaults to .. SemVer requirements select the maximum requested minimum. A full 40- or 64-hex-character commit specifies an exact revision. A tag and SHA are compatible when the selected tag resolves to that same commit; different commits conflict. SHA values are not ordered as SemVer by date or Git ancestry. -For a Git repository with multiple `protobuf.mod` files, require each nested module separately by the identity declared in its manifest. For untagged modules, write `require repo/foo` and `require repo/bar`; EasyP finds both manifests and locks the resolved commits without module-specific tags. Explicit commit hashes stay pinned during `mod update`. Tagged releases remain optional: a module in `foo/` uses a tag such as `foo/v1.2.3`. EasyP resolves each module's source roots independently. +A versionless requirement adds no constraint when the graph supplies a SemVer or exact commit. Only a still-unconstrained requirement uses current HEAD on the first mod tidy; subsequent tidy runs preserve the lock pin, while mod update refreshes HEAD. Explicit commits stay pinned. -Run `easyp get ` from the directory containing your `protobuf.mod` to add a requirement without editing the file. Use `@v1.2.3` or `@` to select a specific version. A newly added requirement without a suffix resolves the current Git HEAD; repeating the command keeps its existing lock pin. The chosen module is a direct requirement; dependencies discovered through it are added to `protobuf.mod` with `// indirect`. Repeating the command does not duplicate requirements. If resolution fails, the manifest and lock are not changed. +replace module => ../local-copy points generation and linting at a local directory. Relative paths use the owning protobuf.mod directory; absolute paths are used directly. Remove local replacements before get, mod tidy, or mod update writes a reproducible Git lock. + +For a Git repository with several manifests, require each nested module separately by its identity. For example, require repo/foo and require repo/bar need no module-specific tags if HEAD is suitable. A v1.2.3 release of the module in foo/ uses tag foo/v1.2.3. Each module's roots are resolved independently. + +Module commands and get find the nearest ancestor protobuf.mod within the workspace. easyp get <module> adds a direct requirement; @v1.2.3 or @<full-commit> selects a version. Without a suffix, the unconstrained-requirement rules above apply. Transitive requirements are added with // indirect, and repeated calls do not duplicate entries. Resolution errors leave the manifest and lock unchanged. ## Commands | Command | Behavior | |---------|----------| -| `easyp get [@version\|@commit]` | Adds or promotes a direct requirement, resolves transitive requirements, and writes `protobuf.lock` | -| `easyp mod tidy` | Resolves direct and transitive requirements and writes `protobuf.lock` | -| `easyp mod download` | Downloads the exact commits in `protobuf.lock` and verifies their hashes | -| `easyp mod update` | Refreshes requirements within their current major versions, then updates the lock | -| `easyp mod vendor` | Verifies locked dependencies and copies their `.proto` files into `easyp_vendor` | +| easyp get <module>[@version|@commit] | Adds or promotes a direct requirement, resolves transitive requirements, and writes protobuf.lock | +| easyp mod tidy | Resolves direct and transitive requirements and writes protobuf.lock | +| easyp mod download | Downloads the exact commits in protobuf.lock and verifies their hashes | +| easyp mod update | Refreshes requirements within their current major versions, then updates the lock | +| easyp mod vendor | Verifies locked dependencies and copies their .proto files into easyp_vendor | -```bash +~~~bash easyp get github.com/acme/contracts/proto/user easyp mod vendor easyp generate -``` +~~~ + +Commit protobuf.mod and protobuf.lock for repeatable builds. The module cache is under $HOME/.easyp/v1/git by default; set EASYPPATH to change its parent directory. mod vendor requires the lock and rejects local replacements and duplicate import paths. The easyp_vendor directory is a copy of dependency sources, not a replacement for the lock. -Commit `protobuf.mod` and `protobuf.lock` for repeatable builds. The module cache is under `$HOME/.easyp/v1/git` by default; set `EASYPPATH` to change its parent directory. `mod vendor` requires the lock and rejects local replacements and duplicate import paths. The `easyp_vendor` directory is a copy of dependency sources, not a replacement for the lock. +## Immutable tags and cache reuse + +tidy, get, and update verify each fetched previously locked SemVer against its recorded commit and hash. A republished tag raises ErrLockedVersionChanged before installing the new graph or writing the manifest or lock, including for transitive dependencies and warm caches. Selecting a new version and refreshing unconstrained HEAD requirements remain available. + +mod download retrieves the locked commit even after a tag moves, if that commit remains available. Reused Git objects let known exact commits avoid remote access. A cold request first tries a depth-one fetch of the exact commit and falls back to reachable history when needed; it never substitutes HEAD. Tag lookups are refreshed separately, and installed contents remain hash-verified. ## Dependencies using Buf or older EasyP -A Git dependency may declare its proto roots in `buf.work.yaml`, Buf v1 or v2 `buf.yaml`, or an older EasyP `easyp.yaml`. Older EasyP `protobuf.mod` requirements are also read transitively. If none of those files exists, its repository root is used. This compatibility applies to dependency metadata; the consuming project uses v1 `protobuf.mod`. +A Git dependency may declare its proto roots in buf.work.yaml, Buf v1 or v2 buf.yaml, or an older EasyP easyp.yaml. Older EasyP protobuf.mod requirements are also read transitively. If none of those files exists, its repository root is used. This compatibility applies to dependency metadata; the consuming project uses v1 protobuf.mod. + +When adapting an older easyp.yaml, both deps and generation Git inputs contribute requirements. Exact source/version duplicates are removed; different minimums remain visible to MVS, and malformed deps fail explicitly. A matching native protobuf.mod takes precedence. Only metadata is read; dependency plugins are never executed. -Buf Registry dependencies have no automatic Git identity. Declare the corresponding Git module in the consuming `protobuf.mod` when those imports are needed. Buf include/exclude filters are not supported as Git import roots and produce an explicit error. +Buf Registry dependencies have no automatic Git identity. Declare the corresponding Git module in the consuming protobuf.mod when those imports are needed. Buf include/exclude filters are not supported as Git import roots and produce an explicit error. -See [`protobuf.mod`](/docs/reference/protobuf-mod) and [`protobuf.lock`](/docs/reference/protobuf-lock) for their field-level formats. +See [protobuf.mod](/docs/reference/protobuf-mod) and [protobuf.lock](/docs/reference/protobuf-lock) for their field-level formats. diff --git a/content/docs/cli/package-manager/index.ru.mdx b/content/docs/cli/package-manager/index.ru.mdx index a88ab99..b1c893f 100644 --- a/content/docs/cli/package-manager/index.ru.mdx +++ b/content/docs/cli/package-manager/index.ru.mdx @@ -3,11 +3,11 @@ title: "Менеджер пакетов" description: "Разрешение и фиксация Git-зависимостей protobuf в EasyP v1." --- -Менеджер пакетов v1 читает `protobuf.mod` и записывает `protobuf.lock`. Для каждого выбранного модуля lock содержит точный Git-коммит и хеш содержимого `h1:`. Хеш проверяется при скачивании и повторном использовании кеша. +Менеджер пакетов v1 читает protobuf.mod и записывает protobuf.lock. Для каждого выбранного модуля lock содержит точный Git-коммит и хеш содержимого h1:. Хеш проверяется при скачивании и повторном использовании кеша. ## Объявление зависимостей -```text +~~~text module github.com/acme/contracts roots proto @@ -15,36 +15,48 @@ require ( github.com/acme/shared v1.2.0 github.com/acme/weather v2.1.0 ) -``` +~~~ -Если `roots` не указан, используется `.`. Версию в требовании можно опустить: `mod tidy` найдёт текущий HEAD Git-репозитория и закрепит точный коммит. Повторный `tidy` сохранит его, а `mod update` обновит требование без версии до HEAD. При необходимости можно указать SemVer-тег или полный хеш Git-коммита из 40 или 64 символов. `replace module => ../local-copy` направляет генерацию и линтинг на локальный каталог. Перед записью воспроизводимого lock через `mod tidy` или `mod update` локальные замены нужно убрать. +Если roots не указан, используется .. SemVer-требования выбирают максимум запрошенных минимумов. Полный хеш коммита из 40 или 64 hex-символов задаёт точную ревизию. Тег и SHA совместимы, если выбранный тег разрешается в этот же коммит; разные коммиты конфликтуют. SHA не получает SemVer-порядка по дате или истории Git. -Если в Git-репозитории несколько `protobuf.mod`, объявляйте каждый вложенный модуль отдельным `require` по имени из его манифеста. Для модулей без тегов достаточно `require repo/foo` и `require repo/bar`: EasyP найдёт оба манифеста и закрепит найденные коммиты без отдельных тегов. Явно указанные хеши останутся закреплёнными при `mod update`. Теги для релизов необязательны; для модуля в `foo/` версия `v1.2.3` использует тег `foo/v1.2.3`. Корни исходников каждого модуля разрешаются независимо. +Требование без версии не ограничивает выбор, если в графе есть SemVer или точный коммит. Только оставшееся неограниченным требование использует текущий HEAD при первом mod tidy; следующие tidy сохраняют lock, а mod update освежает HEAD. Явные коммиты остаются закреплёнными. -Выполните `easyp get <модуль>` из каталога с вашим `protobuf.mod`, чтобы добавить зависимость без ручного редактирования файла. Суффикс `@v1.2.3` или `@<полный-коммит>` задаёт конкретную версию. Новое требование без суффикса фиксирует текущий HEAD Git; повторный вызов сохраняет уже выбранный коммит. Выбранный модуль становится прямой зависимостью, а найденные через него зависимости дописываются в `protobuf.mod` с пометкой `// indirect`. Повторный вызов не создаёт дубликатов. При ошибке разрешения манифест и lock не меняются. +replace module => ../local-copy направляет генерацию и линтинг на локальный каталог. Относительный путь считается от владеющего protobuf.mod, абсолютный используется напрямую. Уберите локальные замены перед get, mod tidy или mod update, записывающими воспроизводимый Git lock. + +Если в Git-репозитории несколько манифестов, объявляйте каждый вложенный модуль отдельно по его имени. Например, require repo/foo и require repo/bar не требуют отдельных тегов, если HEAD подходит. Для релиза v1.2.3 модуля в foo/ используется тег foo/v1.2.3. Корни каждого модуля разрешаются независимо. + +Команды mod и get находят ближайший protobuf.mod в предках в пределах workspace. easyp get <модуль> добавляет прямое требование; @v1.2.3 или @<полный-коммит> задаёт версию. Без суффикса применяется описанное выше неограниченное требование. Транзитивные требования дописываются с // indirect, повторный вызов не создаёт дубликаты. При ошибке разрешения манифест и lock не меняются. ## Команды | Команда | Поведение | |---------|-----------| -| `easyp get <модуль>[@версия\|@коммит]` | Добавляет или делает прямой зависимостью модуль, разрешает транзитивные зависимости и записывает `protobuf.lock` | -| `easyp mod tidy` | Разрешает прямые и транзитивные требования и записывает `protobuf.lock` | -| `easyp mod download` | Скачивает точные коммиты из lock и проверяет хеши | -| `easyp mod update` | Обновляет требования в пределах текущих мажорных версий и пересоздаёт lock | -| `easyp mod vendor` | Проверяет зафиксированные зависимости и копирует их `.proto` в `easyp_vendor` | +| easyp get <модуль>[@версия|@коммит] | Добавляет или делает прямой зависимостью модуль, разрешает транзитивные зависимости и записывает protobuf.lock | +| easyp mod tidy | Разрешает прямые и транзитивные требования и записывает protobuf.lock | +| easyp mod download | Скачивает точные коммиты из lock и проверяет хеши | +| easyp mod update | Обновляет требования в пределах текущих мажорных версий и пересоздаёт lock | +| easyp mod vendor | Проверяет зафиксированные зависимости и копирует их .proto в easyp_vendor | -```bash +~~~bash easyp get github.com/acme/contracts/proto/user easyp mod vendor easyp generate -``` +~~~ + +Храните protobuf.mod и protobuf.lock в репозитории для воспроизводимой сборки. Кеш по умолчанию расположен в $HOME/.easyp/v1/git; переменная EASYPPATH меняет его родительский каталог. mod vendor требует lock и отклоняет локальные замены и повторяющиеся import path. Каталог easyp_vendor — копия исходников зависимостей, а не замена lock-файла. -Храните `protobuf.mod` и `protobuf.lock` в репозитории для воспроизводимой сборки. Кеш по умолчанию расположен в `$HOME/.easyp/v1/git`; переменная `EASYPPATH` меняет его родительский каталог. `mod vendor` требует lock и отклоняет локальные замены и повторяющиеся import path. Каталог `easyp_vendor` — копия исходников зависимостей, а не замена lock-файла. +## Неизменность тегов и повторное использование кеша + +tidy, get и update сверяют каждый повторно полученный зафиксированный SemVer с записанными коммитом и хешем. Перепубликованный тег вызывает ErrLockedVersionChanged до установки нового графа и записи манифеста или lock, в том числе для транзитивных зависимостей и прогретого кеша. Выбор новой версии и обновление неограниченных HEAD-требований остаются доступны. + +mod download получает коммит из lock даже после переноса тега, если он доступен. Кеш повторно использует Git-объекты: известный точный коммит не требует обращения к remote. Холодный запрос сначала пробует загрузку точного коммита с глубиной один, затем при необходимости доступную историю; HEAD вместо коммита не подставляется. Проверки тегов обновляются отдельно, а установленные файлы по-прежнему проверяются по хешу. ## Зависимости на Buf или старом EasyP -Git-зависимость может объявлять корни `.proto` через `buf.work.yaml`, Buf v1/v2 `buf.yaml` или старый EasyP `easyp.yaml`. Транзитивные требования из старого EasyP `protobuf.mod` также читаются. Если ни одного такого файла нет, корнем считается каталог репозитория. Совместимость относится к метаданным зависимости; проект-потребитель использует v1 `protobuf.mod`. +Git-зависимость может объявлять корни .proto через buf.work.yaml, Buf v1/v2 buf.yaml или старый EasyP easyp.yaml. Транзитивные требования из старого EasyP protobuf.mod также читаются. Если ни одного такого файла нет, корнем считается каталог репозитория. Совместимость относится к метаданным зависимости; проект-потребитель использует v1 protobuf.mod. + +При адаптации старого easyp.yaml требования берутся и из deps, и из Git-входов генерации. Точные дубликаты источник/версия удаляются, разные минимумы сохраняются для MVS; некорректные deps вызывают ошибку. Совпадающий нативный protobuf.mod имеет приоритет. Читаются только метаданные, плагины зависимости не запускаются. -Зависимости Buf Registry не имеют автоматического Git-идентификатора. Если их импорты нужны, объявите соответствующий Git-модуль в `protobuf.mod` потребителя. Фильтры Buf include/exclude для корней Git-зависимостей пока не поддерживаются и вызывают явную ошибку. +Зависимости Buf Registry не имеют автоматического Git-идентификатора. Если их импорты нужны, объявите соответствующий Git-модуль в protobuf.mod потребителя. Фильтры Buf include/exclude для корней Git-зависимостей пока не поддерживаются и вызывают явную ошибку. -Форматы полей описаны в справочниках [`protobuf.mod`](/ru/docs/reference/protobuf-mod) и [`protobuf.lock`](/ru/docs/reference/protobuf-lock). +Форматы полей описаны в справочниках [protobuf.mod](/ru/docs/reference/protobuf-mod) и [protobuf.lock](/ru/docs/reference/protobuf-lock). diff --git a/content/docs/guides/breaking-checks-ci.mdx b/content/docs/guides/breaking-checks-ci.mdx index dd064a6..b9b5e17 100644 --- a/content/docs/guides/breaking-checks-ci.mdx +++ b/content/docs/guides/breaking-checks-ci.mdx @@ -1,37 +1,51 @@ --- title: "Breaking checks in CI" -description: "Run the EasyP v1 breaking checker against a Git baseline in CI." +description: "Run the EasyP v1 breaking checker against a locally available Git baseline in CI." --- -The v1 breaking checker compares current `.proto` files with a Git ref. Configure the baseline in `easyp.yaml`: +The v1 breaking checker compares current .proto files with a Git revision. For a repository with schemas under proto, put this policy in the root easyp.yaml: -```yaml +~~~yaml version: v1 breaking: baseline: git:origin/main - ignore: [experimental] -``` + categories: [FILE] + ignore_unstable: false + ignore: [proto/experimental] +~~~ -Then run the check from a checkout containing the comparison ref: +FILE adds declaration-move checks; existing compatibility checks stay enabled. Other categories are unsupported. Set ignore_unstable: true only if you intend to skip packages with supported unstable version suffixes; see the [breaking checker](/docs/cli/breaking-changes) for the exact forms. -```bash +The ignore path is relative to the file defining the effective breaking section. In proto/easyp.yaml, the same directory would be ignore: [experimental]. Changing --root does not change that base. + +## Run the checks + +From the repository root, with the dependency lock prepared: + +~~~bash easyp mod download easyp lint --path proto easyp breaking --path proto -``` +~~~ + +mod download verifies the commits and content hashes recorded in protobuf.lock. The breaking checker uses each revision's own manifests, locks, and dependency context; the baseline may need additional downloads. Keep manifests and locks committed and resolve dependency updates before the CI check. -`mod download` verifies the commits and content hashes already recorded in `protobuf.lock`. Fetch the baseline ref in CI before the breaking check. If no `breaking.baseline` is set, pass the ref through `--against origin/main`; the command's default is `master`. +## Make the baseline available -For example, a GitHub Actions checkout step can use full history: +The baseline can be a branch, lightweight or annotated tag, full commit SHA, or another locally resolvable Git revision such as HEAD. Fetch the required refs and objects first. Bare branch names take precedence over identically named tags; use refs/tags/v1.2.0 to select a tag explicitly. -```yaml +An explicit --against overrides breaking.baseline; without either, the default is master. Pass the ref directly to the flag, without git: or git-ref=. + +After provisioning a v1-capable EasyP binary, these GitHub Actions steps compare with the pull request's base commit: + +~~~yaml - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Check protobuf compatibility - run: easyp breaking --path proto --against origin/main -``` - -Install the v1 pilot binary earlier in the job. Keep `protobuf.mod` and `protobuf.lock` committed, and resolve dependency updates before CI rather than rewriting the lock during a check. + env: + BASE_REF: ${{ github.event.pull_request.base.sha }} + run: easyp breaking --path proto --against "$BASE_REF" +~~~ -The pilot uses the existing breaking rule set. `breaking.categories` and `breaking.ignore_unstable` are not supported yet and cause an error. See [breaking checks](/docs/cli/breaking-changes). +Use this snippet in a pull_request job. Full history makes the baseline available in ordinary PR checkouts; a missing revision fails the check instead of selecting a different baseline. See the complete [GitHub Actions workflow](/docs/ci-cd/github-actions). diff --git a/content/docs/guides/breaking-checks-ci.ru.mdx b/content/docs/guides/breaking-checks-ci.ru.mdx index 52274ea..19f2b02 100644 --- a/content/docs/guides/breaking-checks-ci.ru.mdx +++ b/content/docs/guides/breaking-checks-ci.ru.mdx @@ -1,37 +1,51 @@ --- title: "Breaking-проверки в CI" -description: "Запуск проверки совместимости EasyP v1 относительно Git-базы в CI." +description: "Запуск проверки совместимости EasyP v1 относительно доступной локально Git-базы в CI." --- -Проверка v1 сравнивает текущие `.proto` с Git-ссылкой. Укажите базу в `easyp.yaml`: +Проверка v1 сравнивает текущие .proto с Git-ревизией. Для репозитория со схемами в proto сохраните эту политику в корневом easyp.yaml: -```yaml +~~~yaml version: v1 breaking: baseline: git:origin/main - ignore: [experimental] -``` + categories: [FILE] + ignore_unstable: false + ignore: [proto/experimental] +~~~ -Запустите проверку из рабочего каталога, где доступна ссылка для сравнения: +FILE добавляет проверки перемещения объявлений; существующие проверки совместимости остаются включёнными. Другие категории не поддерживаются. Задавайте ignore_unstable: true, только если нужно пропускать пакеты с поддерживаемыми нестабильными суффиксами версий; точные формы описаны в [справочнике breaking-проверок](/ru/docs/cli/breaking-changes). -```bash +Путь исключения отсчитывается от файла, задающего эффективную секцию breaking. В proto/easyp.yaml тот же каталог задавался бы как ignore: [experimental]. Изменение --root не меняет эту базу. + +## Запуск проверок + +Из корня репозитория с подготовленным lock-файлом зависимостей: + +~~~bash easyp mod download easyp lint --path proto easyp breaking --path proto -``` +~~~ + +mod download проверяет коммиты и хеши содержимого из protobuf.lock. Breaking-проверка использует собственные манифесты, lock-файлы и зависимости каждой ревизии; для базы могут потребоваться дополнительные загрузки. Храните манифесты и lock-файлы в репозитории и разрешайте обновления зависимостей до проверки в CI. -`mod download` проверяет коммиты и хеши содержимого из уже созданного `protobuf.lock`. Перед breaking-проверкой получите базовую Git-ссылку в CI. Если `breaking.baseline` не указан, передайте ссылку как `--against origin/main`; значение команды по умолчанию — `master`. +## Доступность базовой ревизии -Например, в GitHub Actions можно получить полную историю: +Базой может быть ветка, лёгкий или аннотированный тег, полный SHA коммита или другая разрешимая локально Git-ревизия, например HEAD. Сначала получите нужные ссылки и объекты. Короткое имя ветки приоритетнее одноимённого тега; для явного выбора тега используйте refs/tags/v1.2.0. -```yaml +Явный --against перекрывает breaking.baseline; без обоих значений используется master. Передавайте ссылку прямо во флаг, без git: и git-ref=. + +После подготовки бинарника EasyP с поддержкой v1 эти шаги GitHub Actions сравнят схемы с базовым коммитом pull request: + +~~~yaml - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Check protobuf compatibility - run: easyp breaking --path proto --against origin/main -``` - -Установите бинарный файл пилотной версии v1 в предыдущем шаге job. Храните `protobuf.mod` и `protobuf.lock` в репозитории, а обновления зависимостей разрешайте до CI, не переписывая lock во время проверки. + env: + BASE_REF: ${{ github.event.pull_request.base.sha }} + run: easyp breaking --path proto --against "$BASE_REF" +~~~ -Пилотная версия использует существующий набор breaking-правил. `breaking.categories` и `breaking.ignore_unstable` пока не поддерживаются и вызывают ошибку. См. [breaking-проверки](/ru/docs/cli/breaking-changes). +Используйте фрагмент в job для pull_request. Полная история обеспечивает доступность базы в обычном checkout PR; отсутствие ревизии завершает проверку ошибкой, а не выбирает другую базу. См. полный [workflow GitHub Actions](/ru/docs/ci-cd/github-actions). diff --git a/content/docs/guides/buf-migration.mdx b/content/docs/guides/buf-migration.mdx index 1426b8f..dcb0102 100644 --- a/content/docs/guides/buf-migration.mdx +++ b/content/docs/guides/buf-migration.mdx @@ -3,7 +3,7 @@ title: "Migrating from Buf to EasyP" description: "Step-by-step migration guide for transitioning configurations and commands from Buf CLI to EasyP." --- -This guide provides a comprehensive migration walkthrough for transitioning existing projects from **Buf** to **EasyP**. +This guide maps Buf configuration to the EasyP v1 files and commands. Review each setting against the v1 schema rather than copying the old configuration unchanged. --- @@ -11,49 +11,49 @@ This guide provides a comprehensive migration walkthrough for transitioning exis | Buf Construct | EasyP Equivalent | Key Distinction | | --- | --- | --- | -| `buf.yaml` (deps section) | `protobuf.mod` | Tool-neutral dependency DSL; uses Git URLs instead of proprietary BSR names. | -| `buf.yaml` (lint section) | `easyp.yaml` (linters) | Follows golangci-lint syntax; supports directory cascading & `extends`. | -| `buf.yaml` (breaking section) | `easyp.yaml` (breaking) | Explicit git baseline comparison (e.g. `git:main`). | -| `buf.gen.yaml` | `easyp.gen.yaml` | Resides at consumer project level; zero duplicated source input paths. | -| `buf.gen.yaml` (managed) | `easyp.gen.yaml` (options) | Grouped logically by target language (e.g., `options.go.package_prefix`). | -| `buf.lock` | `protobuf.lock` | Includes Git commit SHAs and content hashes. | -| `buf dep update` | `easyp mod tidy` | Resolves minimal versions (MVS) per-module. | -| `buf lint` | `easyp lint` | Cascades through nearest `easyp.yaml`. | -| `buf breaking` | `easyp breaking` | CI gate against explicit baseline. | -| `buf generate` | `easyp generate` | Auto-discovers all `easyp.gen.yaml` files. | +| buf.yaml (deps section) | protobuf.mod | Tool-neutral dependency DSL; uses Git URLs instead of proprietary BSR names. | +| buf.yaml (lint section) | easyp.yaml (linters) | Uses presets and rule lists; each policy section comes whole from its nearest definition. Nonempty extends is unsupported. | +| buf.yaml (breaking section) | easyp.yaml (breaking) | Explicit git baseline comparison (e.g. git:main). | +| buf.gen.yaml | easyp.gen.yaml | Resides at consumer project level and selects complete modules. | +| buf.gen.yaml (managed) | easyp.gen.yaml (generate.managed) | Explicit managed mode; options.go.package_prefix is a separate Go-only convenience. | +| buf.lock | protobuf.lock | Includes Git commit SHAs and content hashes. | +| buf dep update | easyp mod tidy | Resolves declared requirements with MVS and writes the lock; review version updates separately. | +| buf lint | easyp lint | Cascades through nearest easyp.yaml. | +| buf breaking | easyp breaking | CI gate against explicit baseline. | +| buf generate | easyp generate | Selects the nearest enclosing generator file; use --project or explicit recursive --all. | --- ## Step-by-Step Migration Steps -### Step 1: Automatic Initial Migration +### Step 1: Initial Setup -Run `easyp init` in a new project root to create `protobuf.mod`, `easyp.yaml`, and `easyp.gen.yaml`. Pass `--module` when the canonical Git module identity cannot be derived from the repository's `origin` remote. +Run easyp init in a new project root to create protobuf.mod, easyp.yaml, and easyp.gen.yaml. Pass --module when the canonical Git module identity cannot be derived from the repository's origin remote. -```bash +~~~bash easyp init --module github.com/acme/my-service -``` +~~~ -Automatic Buf Registry dependency conversion is deferred. If `buf.yaml` or `buf.yml` exists, `easyp init` stops before writing files because a `buf.build/...` identity cannot be safely treated as a Git module URL. Choose the Git source for each dependency, then create the v1 files explicitly. +Automatic Buf Registry dependency conversion is deferred. If buf.yaml or buf.yml exists, easyp init stops before writing files because a buf.build/... identity cannot be safely treated as a Git module URL. Choose the Git source for each dependency, then create the v1 files explicitly. -### Step 2: Separate Dependencies into `protobuf.mod` +### Step 2: Separate Dependencies into protobuf.mod -Extract module dependencies from `buf.yaml` into `protobuf.mod`: +Extract module dependencies from buf.yaml into protobuf.mod: -```protobuf +~~~protobuf // protobuf.mod module github.com/acme/my-service require ( github.com/googleapis/googleapis v1.5.0 ) -``` +~~~ -### Step 3: Convert Lint & Breaking Rules to `easyp.yaml` +### Step 3: Convert Lint & Breaking Rules to easyp.yaml -Convert `buf.yaml` lint/breaking configurations into `easyp.yaml`: +Convert buf.yaml lint/breaking configurations into easyp.yaml: -```yaml +~~~yaml # easyp.yaml version: v1 @@ -62,34 +62,39 @@ linters: breaking: baseline: git:main -``` +~~~ -### Step 4: Remove Inputs from Generator Configs +### Step 4: Select Modules for Generation -In `easyp.gen.yaml`, remove `inputs` blocks (such as `directory` or `git_repo`). EasyP infers schema sources directly from `protobuf.mod`: +Replace legacy inputs blocks with module selection. In this example, the root protobuf.mod owns the schemas, and backend/easyp.gen.yaml selects that root module using .. Module roots come from the manifest: -```yaml +~~~yaml # backend/easyp.gen.yaml version: v1 generate: modules: - - proto/user + - . plugins: - name: go - version: v1.34.2 out: ./gen/go opts: paths: source_relative -``` +~~~ + +The local go plugin requires protoc-gen-go in the build environment. Fix its version there; local plugins reject a YAML version. Remote plugins require a separate pinned semantic version. generate.packages is reserved and cannot filter packages. ### Step 5: Tidy and Verify -Run `easyp mod tidy`, followed by `easyp lint` and `easyp generate`: +From the repository root, resolve dependencies, lint schemas, and generate the selected project: -```bash +~~~bash easyp mod tidy easyp lint -easyp generate -``` +easyp generate --project ./backend +~~~ + +Review and commit protobuf.mod and protobuf.lock. Active local replacements must be removed before tidy or update; both commands reject them. In CI, use easyp mod download to verify locked dependencies and run easyp breaking --against main with the baseline available locally. + +Only FILE is supported in breaking.categories; ignore_unstable is available. Check the [policy reference](/docs/reference/easyp-yaml) before translating Buf breaking settings, and compare generated output and consumer tests before retiring the old workflow. diff --git a/content/docs/guides/buf-migration.ru.mdx b/content/docs/guides/buf-migration.ru.mdx index 90b031d..d4a4696 100644 --- a/content/docs/guides/buf-migration.ru.mdx +++ b/content/docs/guides/buf-migration.ru.mdx @@ -3,7 +3,7 @@ title: "Миграция с Buf на EasyP" description: "Пошаговое руководство по миграции конфигураций и команд с Buf на EasyP." --- -В данном руководстве подробно рассматривается процесс перехода существующих проектов с **Buf** на **EasyP**. +Это руководство сопоставляет конфигурацию Buf с файлами и командами EasyP v1. Проверяйте каждую настройку по схеме v1, а не переносите прежнюю конфигурацию без изменений. --- @@ -11,16 +11,16 @@ description: "Пошаговое руководство по миграции к | Конструкция Buf | Эквивалент в EasyP | Ключевое отличие | | --- | --- | --- | -| `buf.yaml` (секция deps) | `protobuf.mod` | Независимый от инструментов DSL; использует Git URL вместо BSR. | -| `buf.yaml` (секция lint) | `easyp.yaml` (linters) | Использует синтаксис golangci-lint; поддерживает каскадирование и `extends`. | -| `buf.yaml` (секция breaking) | `easyp.yaml` (breaking) | Явное сравнение с git-baseline (например, `git:main`). | -| `buf.gen.yaml` | `easyp.gen.yaml` | Находится у потребителя; не содержит дублирующих путей к источникам. | -| `buf.gen.yaml` (managed) | `easyp.gen.yaml` (options) | Сгруппирован по языкам (например, `options.go.package_prefix`). | -| `buf.lock` | `protobuf.lock` | Включает SHA коммитов Git и хеши содержимого. | -| `buf dep update` | `easyp mod tidy` | Вычисляет минимальные версии (MVS) помодульно. | -| `buf lint` | `easyp lint` | Каскадируется через ближайший `easyp.yaml`. | -| `buf breaking` | `easyp breaking` | CI-гейт против явного baseline. | -| `buf generate` | `easyp generate` | Автоматически находит все `easyp.gen.yaml`. | +| buf.yaml (секция deps) | protobuf.mod | Независимый от инструментов DSL; использует Git URL вместо BSR. | +| buf.yaml (секция lint) | easyp.yaml (linters) | Использует пресеты и списки правил; каждая секция политики берётся целиком из ближайшего определения. Непустое extends не поддерживается. | +| buf.yaml (секция breaking) | easyp.yaml (breaking) | Явное сравнение с git-baseline (например, git:main). | +| buf.gen.yaml | easyp.gen.yaml | Находится у потребителя и выбирает целые модули. | +| buf.gen.yaml (managed) | easyp.gen.yaml (generate.managed) | Явный managed mode; options.go.package_prefix — отдельная настройка только для Go. | +| buf.lock | protobuf.lock | Включает SHA коммитов Git и хеши содержимого. | +| buf dep update | easyp mod tidy | Разрешает объявленные требования через MVS и записывает lock; обновления версий проверяйте отдельно. | +| buf lint | easyp lint | Каскадируется через ближайший easyp.yaml. | +| buf breaking | easyp breaking | CI-гейт против явного baseline. | +| buf generate | easyp generate | Выбирает ближайший вышестоящий файл генератора; используйте --project или явный рекурсивный --all. | --- @@ -28,32 +28,32 @@ description: "Пошаговое руководство по миграции к ### Шаг 1: Первичная инициализация -В новом проекте `easyp init` создаёт `protobuf.mod`, `easyp.yaml` и `easyp.gen.yaml`. Укажите `--module`, если идентификатор Git-модуля нельзя получить из удалённого репозитория `origin`. +В новом проекте easyp init создаёт protobuf.mod, easyp.yaml и easyp.gen.yaml. Укажите --module, если идентификатор Git-модуля нельзя получить из удалённого репозитория origin. -```bash +~~~bash easyp init --module github.com/acme/my-service -``` +~~~ -Автоматический перенос зависимостей Buf Registry отложен. При наличии `buf.yaml` или `buf.yml` команда `easyp init` завершится до записи файлов: имя `buf.build/...` нельзя безопасно считать URL Git-модуля. Выберите Git-источник для каждой зависимости и создайте v1-файлы явно. +Автоматический перенос зависимостей Buf Registry отложен. При наличии buf.yaml или buf.yml команда easyp init завершится до записи файлов: имя buf.build/... нельзя безопасно считать URL Git-модуля. Выберите Git-источник для каждой зависимости и создайте v1-файлы явно. -### Шаг 2: Вынос зависимостей в `protobuf.mod` +### Шаг 2: Вынос зависимостей в protobuf.mod -Перенесите зависимости модулей из `buf.yaml` в `protobuf.mod`: +Перенесите зависимости модулей из buf.yaml в protobuf.mod: -```protobuf +~~~protobuf // protobuf.mod module github.com/acme/my-service require ( github.com/googleapis/googleapis v1.5.0 ) -``` +~~~ -### Шаг 3: Конвертация правил в `easyp.yaml` +### Шаг 3: Конвертация правил в easyp.yaml -Перенесите конфигурацию линтера и breaking-проверок в `easyp.yaml`: +Перенесите конфигурацию линтера и breaking-проверок в easyp.yaml: -```yaml +~~~yaml # easyp.yaml version: v1 @@ -62,33 +62,39 @@ linters: breaking: baseline: git:main -``` +~~~ -### Шаг 4: Удаление блоков источников из генератора +### Шаг 4: Выбор модулей для генерации -В `easyp.gen.yaml` удалите блоки `inputs` (такие как `directory` или `git_repo`). EasyP берёт источники схем напрямую из `protobuf.mod`: +Замените старые блоки inputs выбором модулей. В примере корневой protobuf.mod владеет схемами, а backend/easyp.gen.yaml выбирает этот корневой модуль через .. Корни исходников определяются манифестом: -```yaml +~~~yaml # backend/easyp.gen.yaml version: v1 generate: modules: - - proto/user + - . plugins: - name: go out: ./gen/go opts: paths: source_relative -``` +~~~ + +Локальному плагину go нужен protoc-gen-go в окружении сборки. Фиксируйте версию там: локальные плагины отклоняют version в YAML. Удалённым плагинам нужна отдельная фиксированная семантическая версия. generate.packages зарезервировано и не фильтрует пакеты. ### Шаг 5: Наведение порядка и проверка -Запустите `easyp mod tidy`, затем `easyp lint` и `easyp generate`: +Из корня репозитория разрешите зависимости, проверьте схемы линтером и запустите выбранный проект генерации: -```bash +~~~bash easyp mod tidy easyp lint -easyp generate -``` +easyp generate --project ./backend +~~~ + +Проверьте и закоммитьте protobuf.mod и protobuf.lock. Перед tidy или update нужно убрать активные локальные замены: обе команды их отклоняют. В CI проверяйте зафиксированные зависимости через easyp mod download и запускайте easyp breaking --against main с доступной локально базой. + +В breaking.categories поддерживается только FILE; ignore_unstable доступно. Перед переносом breaking-настроек Buf сверьтесь со [справочником политики](/ru/docs/reference/easyp-yaml), сравните результат генерации и запустите тесты потребителей до отказа от старого workflow. diff --git a/content/docs/guides/debugging-replace.mdx b/content/docs/guides/debugging-replace.mdx index f667628..ebf9c73 100644 --- a/content/docs/guides/debugging-replace.mdx +++ b/content/docs/guides/debugging-replace.mdx @@ -1,55 +1,55 @@ --- title: "Debugging with Replace Directives" -description: "Using the replace directive in protobuf.mod for local multi-module debugging, and understanding CI build guards." +description: "Use local module replacements for development and understand their lockfile and network limits." --- -During active multi-module development, you often need to modify a dependency locally alongside your consuming project. This guide explains how to use the `replace` directive in `protobuf.mod` for local debugging, and how EasyP prevents accidental production leaks. - ---- +A local replace in protobuf.mod lets you edit a dependency alongside its consumer without publishing each intermediate change. ## Setting Up a Local Replace -Suppose your module `proto/user` depends on `github.com/acme/weather`. To debug local changes in `weather` without publishing Git tags: - -1. Clone or fork `weather` to a local directory (e.g. `../weather-fork`). -2. Add a `replace` directive to `proto/user/protobuf.mod`: +Suppose proto/user requires github.com/acme/weather. Put the dependency checkout at proto/weather-fork, next to proto/user, and add: -```protobuf +~~~protobuf // proto/user/protobuf.mod - module github.com/acme/user require ( github.com/acme/weather v1.2.3 ) -// Overrides remote dependency with local disk path replace github.com/acme/weather => ../weather-fork -``` +~~~ ---- +The relative replacement path is resolved from the directory containing this protobuf.mod, so it points to proto/weather-fork, regardless of the shell's working directory. Keep the replacement's module roots and imports valid. ## Local Development Workflow -When `replace` is active: -- `easyp generate` resolves imports directly from `../weather-fork`. -- You can iterate on proto schema changes in both modules simultaneously. -- No remote Git tags or network downloads are required. +With a generator file in proto/user, run from the repository root: ---- +~~~bash +easyp generate --project ./proto/user +~~~ -## Reproducible Lock Guardrail +Generation uses the replacement's local sources for the replaced dependency. You can iterate on both schemas without publishing a new dependency tag for every edit. + + +Dependency downloads are unnecessary only when the whole dependency graph is local or already in verified cache. One local replacement does not make unreplaced dependencies or their transitive imports local. Required remote dependencies still need valid locks and may need downloads; remote plugins still need network access. + -To prevent a local path from entering the reproducible dependency lock, EasyP requires the replacement to be removed before resolving the lock: +## Reproducible Lock Guardrail -`easyp mod tidy` and `easyp mod update` reject an active local `replace` directive. Run one of these commands in CI to enforce the guard. +easyp mod tidy and easyp mod update explicitly reject active local replacements, even when generation can run with them. Remove the replacements before resolving a reproducible dependency lock. +These are mutating dependency commands, not read-only CI checks. Use easyp mod download to install and verify an already prepared lock; it is not a blanket check forbidding local replacements. Review the manifest before release. + ### Preparing for PR Submission -Before opening a pull request: -1. Publish your changes in the dependency repository to Git. -2. Update `require` in `protobuf.mod` to reference the published version. -3. Remove the `replace` directive. -4. Run `easyp mod tidy` to update `protobuf.lock`. +1. Publish the dependency changes in Git at the intended version. +2. Update require in the consumer's protobuf.mod. +3. Remove the replace directive. +4. Run easyp mod tidy in that module to update protobuf.lock. +5. Regenerate the selected project, run consumer tests, and commit the reviewed manifest, lock, and generated changes. + +For breaking checks, replacements inside the Git repository use each revision's own contents. External local replacements are rejected because the baseline has no recoverable historical copy. See [breaking checks](/docs/cli/breaking-changes). diff --git a/content/docs/guides/debugging-replace.ru.mdx b/content/docs/guides/debugging-replace.ru.mdx index 6f1664b..a6278b0 100644 --- a/content/docs/guides/debugging-replace.ru.mdx +++ b/content/docs/guides/debugging-replace.ru.mdx @@ -1,55 +1,55 @@ --- title: "Отладка через replace" -description: "Использование директивы replace в protobuf.mod для локальной отладки нескольких модулей и защита от попадания локальных путей в CI." +description: "Локальные замены модулей при разработке и их ограничения для lock-файла и сети." --- -В процессе разработки часто требуется править зависимый модуль локально одновременно с основным проектом. В данном руководстве рассматривается использование директивы `replace` в `protobuf.mod` для отладки и механизмы защиты EasyP от случайного попадания локальных путей в продакшн. - ---- +Локальный replace в protobuf.mod позволяет менять зависимость вместе с потребителем, не публикуя каждое промежуточное изменение. ## Настройка локального replace -Предположим, ваш модуль `proto/user` зависит от `github.com/acme/weather`. Для отладки изменений в `weather` без публикации Git-тегов: - -1. Клонируйте репозиторий `weather` в соседнюю директорию (например, `../weather-fork`). -2. Добавьте директиву `replace` в `proto/user/protobuf.mod`: +Предположим, proto/user требует github.com/acme/weather. Разместите checkout зависимости в proto/weather-fork, рядом с proto/user, и добавьте: -```protobuf +~~~protobuf // proto/user/protobuf.mod - module github.com/acme/user require ( github.com/acme/weather v1.2.3 ) -// Переопределяет удалённую зависимость локальным путем на диске replace github.com/acme/weather => ../weather-fork -``` +~~~ ---- +Относительный путь замены отсчитывается от каталога с этим protobuf.mod и указывает на proto/weather-fork независимо от рабочего каталога shell. Корни модуля и импорты замены должны оставаться корректными. ## Процесс локальной разработки -При активной директиве `replace`: -- `easyp generate` резолвит импорты напрямую из `../weather-fork`. -- Вы можете параллельно править `.proto` файлы в обоих модулях. -- Публикация Git-тегов и обращение к сети не требуются. +Если файл генератора расположен в proto/user, запустите из корня репозитория: ---- +~~~bash +easyp generate --project ./proto/user +~~~ -## Защита воспроизводимого lock-файла +Генерация использует локальные исходники заменённой зависимости. Можно менять обе схемы, не публикуя новый тег зависимости после каждой правки. + + +Загрузки зависимостей не нужны, только если весь граф локальный или уже находится в проверенном кеше. Одна локальная замена не делает локальными остальные зависимости и их транзитивные импорты. Нужным удалённым зависимостям по-прежнему требуются корректные lock-файлы и, возможно, загрузки; удалённым плагинам нужна сеть. + -Чтобы локальный путь не попал в воспроизводимый граф зависимостей, перед обновлением lock-файла нужно убрать замену: +## Защита воспроизводимого lock-файла -`easyp mod tidy` и `easyp mod update` отклоняют активный локальный `replace`. Запускайте одну из этих команд в CI для проверки. +easyp mod tidy и easyp mod update явно отклоняют активные локальные замены, даже если генерация с ними работает. Перед разрешением воспроизводимого lock-файла зависимостей удалите замены. +Эти команды изменяют зависимости, а не выполняют проверку CI только для чтения. Для установки и проверки подготовленного lock используйте easyp mod download; команда не является универсальным запретом локальных замен. Проверяйте манифест перед релизом. + ### Подготовка к отправке PR -Перед созданием pull request: -1. Опубликуйте изменения зависимого модуля в Git. -2. Обновите версию в блоке `require` файла `protobuf.mod`. -3. Удалите директиву `replace`. -4. Запустите `easyp mod tidy` для обновления `protobuf.lock`. +1. Опубликуйте изменения зависимости в Git под нужной версией. +2. Обновите require в protobuf.mod потребителя. +3. Удалите директиву replace. +4. В этом модуле запустите easyp mod tidy для обновления protobuf.lock. +5. Повторите генерацию выбранного проекта, запустите тесты потребителей и закоммитьте проверенные изменения манифеста, lock и сгенерированных файлов. + +При breaking-проверках замены внутри Git-репозитория используют содержимое соответствующей ревизии. Внешние локальные замены отклоняются: у базы нет восстановимой исторической копии. См. [breaking-проверки](/ru/docs/cli/breaking-changes). diff --git a/content/docs/guides/microservice-isolation.mdx b/content/docs/guides/microservice-isolation.mdx index 3e685ff..a0f48af 100644 --- a/content/docs/guides/microservice-isolation.mdx +++ b/content/docs/guides/microservice-isolation.mdx @@ -53,5 +53,5 @@ require ( ## Key Benefits 1. **Independent Release Cycles**: Team `order` can upgrade to `common v2.0.0` without waiting for Team `user`. -2. **Zero Monorepo Friction**: Separate lockfiles (`proto/user/protobuf.lock` vs `proto/order/protobuf.lock`) mean pull requests in one service never pollute lockfiles in another. -3. **Clean Schema Namespaces**: Because FQNs in `user` and `order` do not collide during code generation, each consumer target compiles against its expected dependency version. +2. **Independent version decisions**: module lockfiles can change independently. Shared configuration or contract changes still require cross-service review. +3. **Isolated dependency graphs**: each module compiles against its selected version. Generated package namespaces may still collide; configure distinct output/import paths. Incompatible graphs cannot share one descriptor set; use independent exports. diff --git a/content/docs/guides/microservice-isolation.ru.mdx b/content/docs/guides/microservice-isolation.ru.mdx index 0253f4b..e0c0a9f 100644 --- a/content/docs/guides/microservice-isolation.ru.mdx +++ b/content/docs/guides/microservice-isolation.ru.mdx @@ -53,5 +53,5 @@ require ( ## Ключевые преимущества 1. **Независимые релизные циклы**: Команда `order` может обновиться до `common v2.0.0`, не дожидаясь команды `user`. -2. **Отсутствие конфликтов в монорепе**: Раздельные lock-файлы (`proto/user/protobuf.lock` и `proto/order/protobuf.lock`) гарантируют, что PR одного сервиса никогда не затрагивают зависимости другого. -3. **Чистые пространства имён**: Полные имена типов (FQN) в `user` и `order` не сталкиваются при генерации кода, поскольку каждый потребитель компилируется со своими версиями. +2. **Отдельные решения о версиях**: lock-файлы модулей обновляются независимо. Изменения общей конфигурации или самих контрактов всё равно требуют межкомандной проверки. +3. **Изолированные графы зависимостей**: каждый модуль компилируется со своей выбранной версией. Это не гарантирует отсутствие коллизий сгенерированных пакетов: настройте отдельные output/import paths. Несовместимые графы нельзя объединять в один descriptor set; используйте раздельный экспорт. diff --git a/content/docs/guides/multi-target-generation.mdx b/content/docs/guides/multi-target-generation.mdx index 3254ffa..29d1903 100644 --- a/content/docs/guides/multi-target-generation.mdx +++ b/content/docs/guides/multi-target-generation.mdx @@ -1,141 +1,104 @@ --- title: "Multi-Target Code Generation" -description: "Configuring independent per-project generation specs for backend microservices and web frontends with unified versioning in EasyP." +description: "Select independent backend and frontend generation projects that consume the same protobuf modules." --- -In modern polyglot architectures, multiple applications (such as Go microservices, TypeScript frontends, and Python data pipelines) consume code generated from the same Protocol Buffer schemas. EasyP uses a file-per-project generation model (`easyp.gen.yaml`) that keeps generation targets isolated while guaranteeing version alignment through `protobuf.mod` and `protobuf.lock`. - - -Unlike legacy tools where generation inputs and dependency source versions are mixed into generator files, EasyP strictly decouples generation configuration (`easyp.gen.yaml`) from dependency manifests (`protobuf.mod`). Generation target files contain zero version specifications for proto dependencies. - +Go services and TypeScript clients can consume the same Protocol Buffer schemas while keeping separate easyp.gen.yaml files. Dependency identities and requirements belong in protobuf.mod; resolved dependency commits and hashes belong in protobuf.lock. ## Project Architecture & Configuration -Each consuming project defines its own `easyp.gen.yaml` file inside its project directory. EasyP automatically discovers all `easyp.gen.yaml` files in the repository hierarchy when executing `easyp generate`. - - - - ```yaml - # backend/easyp.gen.yaml - Go Backend Services - version: v1 - - generate: - modules: - - proto/user - - proto/order - - plugins: - - name: go - version: v1.34.2 - out: ./gen/go - opts: - paths: source_relative - - name: go-grpc - version: v1.4.0 - out: ./gen/go - opts: - paths: source_relative - require_unimplemented_servers: false - - options: - go: - package_prefix: github.com/uzum/delivery/backend/gen/go - ``` - - - ```yaml - # frontend/easyp.gen.yaml - Web Client Application - version: v1 - - generate: - modules: - - proto/user - - plugins: - - remote: gen.easyp.tech/es - version: v2.0.0 - out: ./src/gen - opts: - target: ts - ``` - - - ```yaml - # easyp.gen.yaml (Repository Root) - version: v1 - - # Root configuration holds repository-wide defaults for managed options - options: - go: - package_prefix: github.com/uzum/delivery/gen/go - ``` - - - -### Key Configuration Elements - -- **`generate.modules`**: List of module paths (local path or canonical repository URL without version) to include in generation. If omitted, EasyP defaults to generating all protocols owned by the current module. -- **`generate.packages`**: Selective package filter when only a subset of a module's packages are required. -- **`plugins`**: Array of code generator plugins to execute: - - `name`: Local binary or WASM module identifier. - - `remote`: Cloud generation service endpoint. - - `version`: Exact pinned plugin version. `:latest` tags are prohibited to ensure build reproducibility. - - `out`: Output directory path relative to the project file. - - `opts`: Key-value map or list of plugin-specific option flags. -- **`options`**: Language-scoped managed options (e.g. `options.go.package_prefix`). Managed options apply consistently across all plugins for a given language to prevent import path mismatches. +This example has modules at proto/user and proto/order, each with its own protobuf.mod. The backend selects both modules; the frontend selects only the user module. Paths in generate.modules are relative to the repository root. + +### Backend project + +~~~yaml +# backend/easyp.gen.yaml +version: v1 +generate: + modules: + - proto/user + - proto/order +plugins: + - name: go + out: ./gen/go + opts: + paths: source_relative + - name: go-grpc + out: ./gen/go + opts: + paths: source_relative + require_unimplemented_servers: false +options: + go: + package_prefix: github.com/acme/app/backend/gen/go +~~~ + +Install the required protoc-gen-go and protoc-gen-go-grpc executables in the build environment. Control their versions there; a local plugin cannot declare version in this file. + +### Frontend project + +~~~yaml +# frontend/easyp.gen.yaml +version: v1 +generate: + modules: + - proto/user +plugins: + - name: es + out: ./src/gen + opts: + target: ts +~~~ + +This project requires protoc-gen-es on PATH. Output directories are relative to the project file, so backend and frontend output stay separate. Give modules distinct proto-relative output paths if they share an output directory. + +### Shared Go option + +An ancestor generator file can supply a Go package prefix: + +~~~yaml +# easyp.gen.yaml at the repository root +version: v1 +options: + go: + package_prefix: github.com/acme/app/gen/go +~~~ + +The nearest explicit options.go.package_prefix wins. The backend above overrides this value. This inheritance does not copy generate or plugins into child projects. The prefix sets go_package; full managed mode is configured separately through generate.managed. + +## Key Configuration Elements + +- generate.modules selects complete local modules or canonical module identities available in the selected dependency context. With no list, generation uses the nearest enclosing module, or the project directory when no manifest exists. +- generate.packages is reserved. Omit it or leave it empty; package filtering is not implemented. +- Each plugin selects exactly one source: name, path, command, or remote, and requires out. +- opts accepts a map or a list of option strings. with_imports: true also generates transitive imports for that plugin. ## Plugin Execution Sources -EasyP supports three execution mechanisms for code generator plugins, allowing teams to balance local performance with build hermeticity: - - - - ```yaml - plugins: - - name: go - version: v1.34.2 - out: ./gen/go - opts: - paths: source_relative - ``` - EasyP locates the `protoc-gen-go` binary on the host system `$PATH`. The declared version is verified against the installed binary. - - - ```yaml - plugins: - - name: go - version: v1.34.2 - out: ./gen/go - opts: - paths: source_relative - ``` - When configured for WASM execution, EasyP executes the plugin inside an embedded WebAssembly runtime, providing complete OS and toolchain independence. - - - ```yaml - plugins: - - remote: gen.easyp.tech/es - version: v2.0.0 - out: ./src/gen - opts: - target: ts - ``` - EasyP streams protocol descriptors to a remote generation service, receiving pre-compiled source files. Zero local toolchain installation is required. - - +| Source | Version control | +| --- | --- | +| name | Uses the installed executable; supported built-in names fall back to bundled WASM when no matching executable is on PATH. Pin the build environment and EasyP binary. | +| path or command | Uses the executable you provide. Manage its version outside the generator YAML. | +| remote | Requires a separate pinned semantic version; do not embed the version in the remote name. | + +Local and bundled plugins reject a nonempty version because EasyP cannot verify it against the executable. Remote execution requires network access. Neither WASM nor a remote version pin alone guarantees identical output bytes. ## Execution Workflow -Run `easyp generate` from the repository root to trigger code generation across all configured projects: +From the repository root, select the projects explicitly: + +~~~bash +easyp generate --project ./backend --project ./frontend +~~~ + +Or recursively select every project below the working directory: -```bash -# Discover and execute all easyp.gen.yaml files in workspace -easyp generate +~~~bash +easyp generate --all +~~~ -# Target a specific project directory only -easyp generate --project ./backend -``` +Do not combine --all and --project. Without either flag, easyp generate selects the nearest enclosing easyp.gen.yaml; it does not recurse through child projects. -Because all projects consume proto versions locked in `protobuf.lock`, the Go backend and TypeScript frontend generated code are guaranteed to be in sync. +Projects selecting the same module use that module's manifest and dependency lock. Separate modules can have different dependency graphs, so review their locks and test the generated clients together. -For complete generator options, see the [EasyP Generator Reference](/docs/cli/generator) and [Build Reproducibility Guide](/docs/guides/build-reproducibility). +See the [generator reference](/docs/reference/easyp-gen-yaml) and [build reproducibility guide](/docs/guides/reproducibility). diff --git a/content/docs/guides/multi-target-generation.ru.mdx b/content/docs/guides/multi-target-generation.ru.mdx index 33631a0..5afbd62 100644 --- a/content/docs/guides/multi-target-generation.ru.mdx +++ b/content/docs/guides/multi-target-generation.ru.mdx @@ -1,141 +1,104 @@ --- title: "Многоцелевая генерация кода" -description: "Настройка независимых конфигураций генерации для бэкенда и фронтенда при едином версионировании модулей в EasyP." +description: "Явный выбор независимых проектов генерации для бэкенда и фронтенда, использующих одни protobuf-модули." --- -В современных полиглотных архитектурах несколько приложений (например, Go-микросервисы, TypeScript-фронтенд и Python-сервисы аналитики) используют код, сгенерированный из одних и тех же схем Protocol Buffer. EasyP использует модель генерации «файл-на-проект» (`easyp.gen.yaml`), которая изолирует цели генерации и при этом гарантирует согласованность версий через `protobuf.mod` и `protobuf.lock`. - - -В отличие от устаревших инструментов, где источники генерации и версии зависимостей смешивались в одном файле генератора, EasyP строго разделяет конфигурацию генерации (`easyp.gen.yaml`) и манифест зависимостей (`protobuf.mod`). Файлы генерации не содержат указаний версий proto-зависимостей. - +Go-сервисы и TypeScript-клиенты могут использовать одни схемы Protocol Buffer с отдельными файлами easyp.gen.yaml. Идентификаторы и требования зависимостей задаются в protobuf.mod, а выбранные коммиты и хеши — в protobuf.lock. ## Архитектура проектов и конфигурация -Каждый проект-потребитель определяет собственный файл `easyp.gen.yaml` внутри своей директории. При запуске `easyp generate` EasyP автоматически находит все файлы `easyp.gen.yaml` в дереве репозитория. - - - - ```yaml - # backend/easyp.gen.yaml - Go Бэкенд Сервисы - version: v1 - - generate: - modules: - - proto/user - - proto/order - - plugins: - - name: go - version: v1.34.2 - out: ./gen/go - opts: - paths: source_relative - - name: go-grpc - version: v1.4.0 - out: ./gen/go - opts: - paths: source_relative - require_unimplemented_servers: false - - options: - go: - package_prefix: github.com/uzum/delivery/backend/gen/go - ``` - - - ```yaml - # frontend/easyp.gen.yaml - Веб-приложение - version: v1 - - generate: - modules: - - proto/user - - plugins: - - remote: gen.easyp.tech/es - version: v2.0.0 - out: ./src/gen - opts: - target: ts - ``` - - - ```yaml - # easyp.gen.yaml (Корень репозитория) - version: v1 - - # Корневой файл содержит общие managed-опции для всех проектов репозитория - options: - go: - package_prefix: github.com/uzum/delivery/gen/go - ``` - - - -### Ключевые элементы конфигурации - -- **`generate.modules`**: Список путей к модулям (локальный путь или URL репозитория без версии) для генерации. Если не указан, EasyP генерирует все протоколы своего модуля. -- **`generate.packages`**: Точечный фильтр пакетов, если требуется только часть пакетов модуля. -- **`plugins`**: Массив плагинов кодогенерации: - - `name`: Идентификатор локального бинарника или WASM-модуля. - - `remote`: Эндпоинт удалённого сервиса генерации. - - `version`: Точно зафиксированная версия плагина. Использование `:latest` запрещено для обеспечения воспроизводимости. - - `out`: Путь к директории назначения относительно проектного файла. - - `opts`: Опции плагина в виде словаря или списка строк. -- **`options`**: Управляемые опции для конкретного языка (например, `options.go.package_prefix`). Они единообразно применяются ко всем плагинам языка, предотвращая расхождения в путях импорта. +В примере модули находятся в proto/user и proto/order, каждый со своим protobuf.mod. Бэкенд выбирает оба модуля, фронтенд — только пользовательский. Пути в generate.modules отсчитываются от корня репозитория. + +### Проект бэкенда + +~~~yaml +# backend/easyp.gen.yaml +version: v1 +generate: + modules: + - proto/user + - proto/order +plugins: + - name: go + out: ./gen/go + opts: + paths: source_relative + - name: go-grpc + out: ./gen/go + opts: + paths: source_relative + require_unimplemented_servers: false +options: + go: + package_prefix: github.com/acme/app/backend/gen/go +~~~ + +Установите нужные исполняемые файлы protoc-gen-go и protoc-gen-go-grpc в окружении сборки. Их версии фиксируются там; локальный плагин не может задавать version в этом файле. + +### Проект фронтенда + +~~~yaml +# frontend/easyp.gen.yaml +version: v1 +generate: + modules: + - proto/user +plugins: + - name: es + out: ./src/gen + opts: + target: ts +~~~ + +Проекту нужен protoc-gen-es в PATH. Каталоги вывода задаются относительно проектного файла, поэтому результаты бэкенда и фронтенда разделены. Если несколько модулей пишут в один каталог, используйте разные относительные пути proto-файлов, определяющие пути вывода. + +### Общая Go-опция + +Вышестоящий файл генератора может задавать префикс Go-пакетов: + +~~~yaml +# easyp.gen.yaml в корне репозитория +version: v1 +options: + go: + package_prefix: github.com/acme/app/gen/go +~~~ + +Побеждает ближайшее явно заданное значение options.go.package_prefix. Бэкенд выше переопределяет его. Такое наследование не копирует generate или plugins в дочерние проекты. Префикс задаёт go_package; полный managed mode настраивается отдельно через generate.managed. + +## Ключевые элементы конфигурации + +- generate.modules выбирает целые локальные модули или канонические идентификаторы модулей, доступные в выбранном контексте зависимостей. Без списка используется ближайший вышестоящий модуль, а при отсутствии манифеста — каталог проекта. +- generate.packages зарезервировано. Опустите поле или оставьте пустой список: фильтрация пакетов не реализована. +- Каждый плагин выбирает ровно один источник: name, path, command или remote, и обязательно задаёт out. +- opts принимает словарь или список строк опций. with_imports: true дополнительно генерирует транзитивные импорты для этого плагина. ## Источники плагинов -EasyP поддерживает три механизма выполнения плагинов кодогенерации: - - - - ```yaml - plugins: - - name: go - version: v1.34.2 - out: ./gen/go - opts: - paths: source_relative - ``` - EasyP находит бинарный файл `protoc-gen-go` в системной переменной `$PATH`. Объявленная версия сверяется с установленной. - - - ```yaml - plugins: - - name: go - version: v1.34.2 - out: ./gen/go - opts: - paths: source_relative - ``` - При использовании WASM-режима EasyP запускает плагин внутри встроенной WebAssembly-песочницы, обеспечивая полную независимость от ОС и окружения. - - - ```yaml - plugins: - - remote: gen.easyp.tech/es - version: v2.0.0 - out: ./src/gen - opts: - target: ts - ``` - EasyP отправляет описатели протоколов на удаленный сервис генерации и получает готовые исходные файлы. Установка локального инструментария не требуется. - - - -## Процесс выполнения - -Запустите `easyp generate` из корня репозитория для выполнения генерации по всем проектам: - -```bash -# Автоматическое обнаружение и выполнение всех easyp.gen.yaml в проекте -easyp generate - -# Ограничение генерации конкретным проектом -easyp generate --project ./backend -``` - -Поскольку все проекты получают версии протоколов из зафиксированного `protobuf.lock`, сгенерированный код для Go и TypeScript гарантированно находится в синхронном состоянии. - -Подробную информацию о генераторе смотрите в [Справочнике генератора EasyP](/ru/docs/cli/generator) и [Руководстве по воспроизводимости сборок](/ru/docs/guides/build-reproducibility). +| Источник | Управление версией | +| --- | --- | +| name | Использует установленный исполняемый файл; поддерживаемые встроенные имена переходят на комплектный WASM, если соответствующего файла нет в PATH. Фиксируйте окружение сборки и бинарник EasyP. | +| path или command | Использует предоставленный исполняемый файл. Управляйте его версией вне YAML генератора. | +| remote | Требует отдельную фиксированную семантическую version; не включайте версию в имя удалённого плагина. | + +Локальные и встроенные плагины отклоняют непустое поле version: EasyP не может проверить его соответствие исполняемому файлу. Удалённая генерация требует сети. Ни WASM, ни фиксация удалённой версии сами по себе не гарантируют побайтовую идентичность результата. + +## Запуск генерации + +Из корня репозитория явно выберите проекты: + +~~~bash +easyp generate --project ./backend --project ./frontend +~~~ + +Или рекурсивно выберите все проекты ниже рабочего каталога: + +~~~bash +easyp generate --all +~~~ + +Не сочетайте --all и --project. Без этих флагов easyp generate выбирает ближайший вышестоящий easyp.gen.yaml, а не обходит дочерние проекты. + +Проекты, выбравшие один модуль, используют его манифест и lock зависимостей. У разных модулей графы зависимостей могут отличаться: проверяйте их lock-файлы и тестируйте сгенерированные клиенты вместе. + +См. [справочник генератора](/ru/docs/reference/easyp-gen-yaml) и [руководство по воспроизводимости](/ru/docs/guides/reproducibility). diff --git a/content/docs/guides/organization-lint-style.mdx b/content/docs/guides/organization-lint-style.mdx index 4414593..0c608dc 100644 --- a/content/docs/guides/organization-lint-style.mdx +++ b/content/docs/guides/organization-lint-style.mdx @@ -1,20 +1,16 @@ --- -title: "Organizational Lint Policy Sharing" -description: "How to centralize linter rules using extends, and handle legacy directories via cascading configurations." +title: "Organizational Lint Policies" +description: "Keep explicit repository policies consistent and use whole-section cascading for local exceptions." --- -Maintaining consistent Protobuf linting rules across hundreds of microservice repositories is a common challenge. This guide demonstrates how to share organizational base policies using `linters.extends` and manage exceptions cleanly. +Teams can keep a reviewed lint policy in each repository and use directory policies for exceptions. EasyP v1 does not fetch shared policies: linters.extends and breaking.extends are reserved, and nonempty values are rejected. There is no built-in shared-policy delivery mechanism. ---- - -## 1. Defining a Shared Base Policy +## 1. Defining a Repository Policy -Platform engineering teams can publish a centralized linting policy repository (e.g. `github.com/uzum/proto-policy/lint-base`). +Store the complete policy in proto/easyp.yaml: -```yaml -# Shared policy repo: github.com/uzum/proto-policy/lint-base/easyp.yaml +~~~yaml version: v1 - linters: default: STANDARD enable: @@ -22,58 +18,62 @@ linters: - RPC_REQUEST_RESPONSE_UNIQUE disable: - PACKAGE_VERSION_SUFFIX - linters-settings: ENUM_ZERO_VALUE_SUFFIX: suffix: UNSPECIFIED -``` - ---- - -## 2. Inheriting Policies via `extends` - -Individual service repositories inherit the central policy using `linters.extends`. They can also override individual rules locally: - -```yaml -# Service repo: proto/easyp.yaml -version: v1 - -linters: - extends: github.com/uzum/proto-policy/lint-base - disable: - - PACKAGE_VERSION_SUFFIX # Local exception to shared policy - breaking: baseline: git:main - categories: - - WIRE -``` + categories: [FILE] +~~~ ---- +Review policy changes alongside schema changes. FILE adds declaration-move checks to the existing compatibility checks; categories such as WIRE are not supported. -## 3. Handling Legacy Subtrees via Directory Cascading +## 2. Understanding Section Cascading -If your repository contains legacy Protobuf files that cannot yet adhere to corporate standards, create a targeted `easyp.yaml` inside the legacy directory: +Each of linters, linters-settings, issues, and breaking comes as a whole from the nearest file defining that section. Fields within a section are not partially merged. -```text +For example, a child linters section containing only disable does not retain the parent's enable list. Write the complete intended linter selection in the child. Sections omitted by the child still come from the nearest ancestor that defines them. + +## 3. Handling Legacy Subtrees + +~~~text proto/ -├── easyp.yaml # Standard corporate policy for active services +├── easyp.yaml ├── user/v1/user.proto └── legacy/ - ├── easyp.yaml # MINIMAL policy override strictly for legacy/ + ├── easyp.yaml └── old.proto -``` +~~~ -`proto/legacy/easyp.yaml`: +To apply a reduced lint policy only to proto/legacy, put this in proto/legacy/easyp.yaml: -```yaml +~~~yaml version: v1 - linters: default: MINIMAL disable: - FIELD_LOWER_SNAKE_CASE - ENUM_VALUE_PREFIX -``` +~~~ + +The child replaces the complete linters section. The ancestor's linters-settings and breaking sections still apply because the child does not define them. + +If only one rule needs an exception, keep the parent linter selection and add an issues section to the parent policy instead: + +~~~yaml +# Add to proto/easyp.yaml +issues: + exclude-rules: + - path: legacy/**/*.proto + linters: [FIELD_LOWER_SNAKE_CASE] +~~~ + +This path is relative to proto/easyp.yaml, including when the section is inherited by a deeper directory. A child issues: {} clears inherited exclusions. + +Run the policy explicitly from the repository root: + +~~~bash +easyp --cfg proto/easyp.yaml lint --path . +~~~ -Due to EasyP's nearest-file cascading rule, the relaxed policy applies exclusively to `.proto` files under `proto/legacy/`, while the rest of the repository adheres to corporate standards. +See the [policy reference](/docs/reference/easyp-yaml) for supported rules, path patterns, and comment suppressions. diff --git a/content/docs/guides/organization-lint-style.ru.mdx b/content/docs/guides/organization-lint-style.ru.mdx index 528558f..50cdb89 100644 --- a/content/docs/guides/organization-lint-style.ru.mdx +++ b/content/docs/guides/organization-lint-style.ru.mdx @@ -1,20 +1,16 @@ --- -title: "Общий стиль линта в организации" -description: "Централизация правил линтинга через extends и обработка legacy-директорий с помощью каскадных конфигов." +title: "Организационные политики линтинга" +description: "Согласованные политики репозиториев и каскадирование целых секций для локальных исключений." --- -Поддержание единых правил линтинга Protobuf в сотнях репозиториев микросервисов — частая задача. В данном руководстве объясняется, как шарить единые политики организации с помощью `linters.extends` и корректно управлять исключениями. +Команды могут хранить согласованную политику линтинга в каждом репозитории и задавать исключения для отдельных каталогов. EasyP v1 не загружает общие политики: linters.extends и breaking.extends зарезервированы, непустые значения отклоняются. Встроенного механизма доставки общих политик нет. ---- - -## 1. Определение базовой политики организации +## 1. Политика репозитория -Платформенная команда публикует репозиторий с централизованной политикой линтинга (например, `github.com/uzum/proto-policy/lint-base`). +Сохраните полную политику в proto/easyp.yaml: -```yaml -# Базовая политика: github.com/uzum/proto-policy/lint-base/easyp.yaml +~~~yaml version: v1 - linters: default: STANDARD enable: @@ -22,58 +18,62 @@ linters: - RPC_REQUEST_RESPONSE_UNIQUE disable: - PACKAGE_VERSION_SUFFIX - linters-settings: ENUM_ZERO_VALUE_SUFFIX: suffix: UNSPECIFIED -``` - ---- - -## 2. Наследование политик через `extends` - -Репозитории отдельных сервисов подключают центральную политику через `linters.extends`. Также они могут переопределять отдельные правила локально: - -```yaml -# Сервисный репозиторий: proto/easyp.yaml -version: v1 - -linters: - extends: github.com/uzum/proto-policy/lint-base - disable: - - PACKAGE_VERSION_SUFFIX # Локальное отклонение от общей базы - breaking: baseline: git:main - categories: - - WIRE -``` + categories: [FILE] +~~~ ---- +Проверяйте изменения политики вместе с изменениями схем. FILE добавляет проверки перемещения объявлений к существующим проверкам совместимости; категории вроде WIRE не поддерживаются. -## 3. Обработка legacy-кода через каскадирование +## 2. Каскадирование секций -Если в вашем репозитории есть старые `.proto` файлы, которые пока не соответствуют стандартам компании, создайте локальный `easyp.yaml` внутри legacy-директории: +Каждая секция linters, linters-settings, issues и breaking берётся целиком из ближайшего файла, где она определена. Поля внутри секции не сливаются частично. -```text +Например, дочерняя секция linters только с disable не сохраняет родительский список enable. Укажите в дочернем файле весь нужный набор правил. Отсутствующие секции по-прежнему берутся из ближайшего предка, который их определяет. + +## 3. Исключения для устаревших поддеревьев + +~~~text proto/ -├── easyp.yaml # Стандартная политика организации +├── easyp.yaml ├── user/v1/user.proto └── legacy/ - ├── easyp.yaml # Ослабленная политика MINIMAL только для legacy/ + ├── easyp.yaml └── old.proto -``` +~~~ -`proto/legacy/easyp.yaml`: +Чтобы ослабить линтинг только в proto/legacy, создайте proto/legacy/easyp.yaml: -```yaml +~~~yaml version: v1 - linters: default: MINIMAL disable: - FIELD_LOWER_SNAKE_CASE - ENUM_VALUE_PREFIX -``` +~~~ + +Дочерний файл заменяет всю секцию linters. Родительские linters-settings и breaking продолжают действовать: дочерний файл их не определяет. + +Если исключение нужно только для одного правила, сохраните родительский набор линтеров и вместо этого добавьте в родительскую политику секцию issues: + +~~~yaml +# Добавьте в proto/easyp.yaml +issues: + exclude-rules: + - path: legacy/**/*.proto + linters: [FIELD_LOWER_SNAKE_CASE] +~~~ + +Путь отсчитывается от proto/easyp.yaml, даже когда секция наследуется более глубоким каталогом. Дочерняя issues: {} очищает унаследованные исключения. + +Из корня репозитория запустите проверку с явной политикой: + +~~~bash +easyp --cfg proto/easyp.yaml lint --path . +~~~ -Благодаря правилу ближайшего файла ослабленная политика применяется исключительно к файлам в `proto/legacy/`, в то время как остальное дерево репозитория проверяется по полному стандарту. +Поддерживаемые правила, шаблоны путей и подавление замечаний комментариями описаны в [справочнике политики](/ru/docs/reference/easyp-yaml). diff --git a/content/docs/guides/reproducibility.mdx b/content/docs/guides/reproducibility.mdx index 3e461bd..9ea8493 100644 --- a/content/docs/guides/reproducibility.mdx +++ b/content/docs/guides/reproducibility.mdx @@ -1,38 +1,46 @@ --- -title: "Hermetic Build Reproducibility" -description: "Achieving 100% bit-for-bit reproducible Protobuf builds with lockfiles, pinned plugin versions, and prohibition of floating latest tags." +title: "Build Reproducibility" +description: "Control schema dependencies, generator executables, and build inputs without assuming byte-identical output." --- -Build reproducibility ensures that checking out a commit today produces the exact same generated output as building it months or years later. This guide explains how EasyP guarantees hermetic, reproducible builds. +Reproducible generation requires control over schema sources, dependency versions, generator executables, options, and the build environment. EasyP's lockfile verifies dependency inputs; it does not by itself guarantee hermetic or byte-for-byte reproducible output. ---- - -## 3 Pillars of EasyP Reproducibility +## Three Inputs to Control -1. **`protobuf.lock`**: Locks transitive dependency Git commit SHAs and cryptographic content hashes (`h1:...`). -2. **Pinned Plugin Versions**: Generator plugins in `easyp.gen.yaml` require explicit semantic version tags. Floating `:latest` tags are prohibited. -3. **WASM / Remote Executors**: Eliminates system environment dependencies (such as locally installed `protoc` or plugin binaries) by running plugins inside deterministic WASM sandboxes or remote generation environments. - ---- +1. **Schema dependencies:** protobuf.lock records selected dependency versions, Git commits, and h1: content hashes. Commit it together with protobuf.mod and your own schemas. +2. **Generator versions:** Remote plugins require a pinned semantic version. Local and bundled plugins reject that field: pin local executables in your build environment and pin the EasyP binary that contains bundled generators. +3. **Execution environment:** Keep plugin options and relevant environment variables consistent. A named built-in plugin can use an executable on PATH instead of the bundled WASM implementation. WASM and remote execution do not independently prove output determinism. ## Workflow for Clean Repositories -When cloning a repository on a fresh machine or CI runner: +After preparing the same EasyP and plugin versions used by the project, run from a fresh checkout with a root module and generator file: -```bash -# 1. Download exact schema versions locked in protobuf.lock +~~~bash easyp mod download +easyp generate --project . +~~~ -# 2. Execute code generation using pinned plugin versions -easyp generate -``` +mod download installs and verifies the locked dependencies without selecting newer versions or rewriting the lock. Missing dependencies may require downloads. If locked content cannot be retrieved or verified, the command fails; it cannot guarantee that remote repositories remain available forever. -Because `easyp mod download` reads strictly from `protobuf.lock`, remote registry updates or force-pushed Git tags cannot alter your build output. +For multiple consumer projects, select them with repeated --project flags or explicitly use --all. Compare generated output in CI and run tests against it. When generated files are committed, a simple check is: ---- +~~~bash +git diff --exit-code -- gen +test -z "$(git ls-files --others --exclude-standard -- gen)" +~~~ + +Adapt gen to your tracked output directories. The second command catches new untracked files; ignored output is outside this check. + +## Local Replacements and Network Access + +A local replace redirects one dependency to disk. It avoids dependency downloads only when the whole dependency graph is local or already present in verified cache. Unreplaced dependencies can still require downloads, and a remote generator still needs network access. + +Local replacement contents are editable and are not pinned by a reproducible dependency lock. easyp mod tidy and easyp mod update explicitly reject active local replacements. Remove replacements and publish the intended versions before resolving a release lock. + +## CI Practices -## Prohibited Patterns in CI +- Resolve intended dependency changes in a reviewed update, then use easyp mod download in verification jobs. tidy and update are mutating commands, not a frozen verification mode. +- Pin the EasyP binary, local plugin executables, and remote plugin versions using the mechanisms appropriate to each source. +- Keep generated-output checks and consumer tests: valid locks and semantic versions do not prove schema compatibility or identical output bytes. -- ❌ Running `easyp mod update` inside CI pipelines (updates should only occur locally via PRs). -- ❌ Using floating plugin tags like `version: latest`. -- ❌ Leaving uncommitted `replace` directives in `protobuf.mod`. +See [local replacement debugging](/docs/guides/debugging-replace) and [GitHub Actions](/docs/ci-cd/github-actions). diff --git a/content/docs/guides/reproducibility.ru.mdx b/content/docs/guides/reproducibility.ru.mdx index f3a2153..0f13799 100644 --- a/content/docs/guides/reproducibility.ru.mdx +++ b/content/docs/guides/reproducibility.ru.mdx @@ -1,38 +1,46 @@ --- title: "Воспроизводимость сборок" -description: "Достижение 100% герметичных и воспроизводимых сборок Protobuf с помощью lock-файлов, пина версий плагинов и запрета плавающих тегов latest." +description: "Контроль зависимостей схем, исполняемых файлов генераторов и входов сборки без обещания побайтово идентичного результата." --- -Воспроизводимость сборки гарантирует, что клон коммита сегодня даст байт-в-байт тот же результат кодогенерации, что и сборка спустя месяцы или годы. В данном руководстве объясняется, как EasyP обеспечивает герметичность сборок. +Для воспроизводимой генерации нужно контролировать исходники схем, версии зависимостей, исполняемые файлы генераторов, опции и окружение сборки. Lock-файл EasyP проверяет входные зависимости, но сам по себе не гарантирует герметичность или побайтовую воспроизводимость результата. ---- - -## 3 кита воспроизводимости EasyP +## Три группы входных данных -1. **`protobuf.lock`**: Фиксирует точные SHA коммитов Git и криптографические хеши содержимого (`h1:...`). -2. **Пины версий плагинов**: Плагины в `easyp.gen.yaml` требуют явных тегов версий. Использование плавающих тегов `:latest` запрещено. -3. **WASM / Remote исполнители**: Исключают зависимость от окружения хоста (установленных бинарников `protoc` и системных плагинов), заново выполняя генерацию в детерминированном песке WASM или удалённом сервисе. - ---- +1. **Зависимости схем:** protobuf.lock хранит выбранные версии зависимостей, Git-коммиты и хеши содержимого h1:. Коммитьте его вместе с protobuf.mod и собственными схемами. +2. **Версии генераторов:** Удалённые плагины требуют фиксированную семантическую version. Локальные и встроенные плагины отклоняют это поле: фиксируйте локальные исполняемые файлы в окружении сборки и бинарник EasyP со встроенными генераторами. +3. **Окружение выполнения:** Сохраняйте одинаковые опции плагинов и значимые переменные окружения. Встроенный плагин, выбранный по имени, может использовать исполняемый файл из PATH вместо комплектного WASM. WASM и удалённое выполнение сами по себе не доказывают детерминированность результата. ## Процесс работы на свежем окружении -При клонировании репозитория на новом компьютере или в CI: +Подготовив те же версии EasyP и плагинов, что использует проект, запустите команды в свежем checkout с корневым модулем и файлом генератора: -```bash -# 1. Скачивание точных версий схем строго по protobuf.lock +~~~bash easyp mod download +easyp generate --project . +~~~ -# 2. Выполнение генерации кода с использованием запиненных версий плагинов -easyp generate -``` +mod download устанавливает и проверяет зафиксированные зависимости, не выбирая новые версии и не переписывая lock. Отсутствующие зависимости могут потребовать загрузки. Если зафиксированное содержимое нельзя получить или проверить, команда завершается ошибкой; она не гарантирует вечную доступность удалённых репозиториев. -Поскольку `easyp mod download` читает данные строго из `protobuf.lock`, изменения в удалённых репозиториях или подмена Git-тегов не влияют на результат. +Для нескольких проектов-потребителей повторяйте флаг --project или явно используйте --all. Сравнивайте результат генерации в CI и запускайте тесты. Если сгенерированные файлы хранятся в Git, простая проверка выглядит так: ---- +~~~bash +git diff --exit-code -- gen +test -z "$(git ls-files --others --exclude-standard -- gen)" +~~~ + +Замените gen своими отслеживаемыми каталогами вывода. Вторая команда обнаруживает новые неотслеживаемые файлы; игнорируемый вывод эта проверка не охватывает. + +## Локальные замены и сеть + +Локальный replace перенаправляет одну зависимость на диск. Загрузки зависимостей не нужны, только если весь граф локальный или уже находится в проверенном кеше. Незаменённым зависимостям всё ещё может потребоваться загрузка, а удалённому генератору — сеть. + +Содержимое локальных замен изменяемо и не фиксируется воспроизводимым lock-файлом. easyp mod tidy и easyp mod update явно отклоняют активные локальные замены. Уберите замены и опубликуйте нужные версии до разрешения lock для релиза. + +## Практика CI -## Запрещённые паттерны в CI +- Разрешайте намеренные обновления зависимостей в проверяемом изменении, а в проверочных job используйте easyp mod download. tidy и update изменяют файлы, а не предоставляют режим frozen-проверки. +- Фиксируйте бинарник EasyP, локальные исполняемые файлы плагинов и версии удалённых плагинов подходящим для каждого источника способом. +- Сохраняйте проверки сгенерированных файлов и тесты потребителей: корректный lock и семантические версии не доказывают совместимость схем или побайтовую идентичность вывода. -- ❌ Запуск `easyp mod update` внутри CI (обновление версий должно производиться только локально через PR). -- ❌ Использование плавающих версий плагинов, таких как `version: latest`. -- ❌ Наличие незакоммиченных директив `replace` в `protobuf.mod`. +См. [отладку с локальными заменами](/ru/docs/guides/debugging-replace) и [GitHub Actions](/ru/docs/ci-cd/github-actions). diff --git a/content/docs/guides/version-diamond.mdx b/content/docs/guides/version-diamond.mdx index bdd3e99..ba15967 100644 --- a/content/docs/guides/version-diamond.mdx +++ b/content/docs/guides/version-diamond.mdx @@ -1,21 +1,21 @@ --- title: "Resolving Diamond Dependencies" -description: "How Minimal Version Selection (MVS) deterministically resolves diamond version conflicts across direct and indirect requirements without manual intervention." +description: "How Minimal Version Selection (MVS) chooses a version in a dependency diamond, and what still needs compatibility testing." --- -A common conflict in module package management is the **Diamond Dependency Problem**. This guide explains how EasyP's MVS algorithm resolves version discrepancies deterministically without human intervention or SAT solver backtracking. +The **diamond dependency problem** occurs when direct and transitive requirements request different versions of the same module. EasyP uses MVS to select a version within each module's dependency graph. --- ## Scenario Description -Consider a service module `user` that relies on two dependencies: `common` and `weather`. +Consider a service module user that relies on two dependencies: common and weather. -- `user` explicitly requires `common v1.2.0`. -- `user` explicitly requires `weather v2.1.0`. -- `weather v2.1.0` transitively requires `common v1.3.0`. +- user explicitly requires common v1.2.0. +- user explicitly requires weather v2.1.0. +- weather v2.1.0 transitively requires common v1.3.0. -```text +~~~text +-------------------+ | proto/user | +---------+---------+ @@ -33,26 +33,26 @@ Consider a service module `user` that relies on two dependencies: `common` and ` | github.com/acme/ | | common v1.3.0 | +---------------------+ -``` +~~~ --- ## The MVS Resolution Rule -Unlike traditional resolvers that attempt complex range matching or halt with a manual version conflict error, MVS applies a simple high-water mark rule: +For semantic-version requirements on the same module, MVS selects the highest requested minimum: -`Resolved Version = max(Requested Minimums)` +Resolved Version = max(Requested Minimums) -1. **Collect requested minimums**: `[ v1.2.0 (from user), v1.3.0 (from weather) ]` -2. **Select maximum**: $\max(v1.2.0, v1.3.0) = v1.3.0$ -3. **Outcome**: `common v1.3.0` is selected for the module resolution graph. +1. **Collect requested minimums**: [ v1.2.0 (from user), v1.3.0 (from weather) ] +2. **Select maximum**: max(v1.2.0, v1.3.0) = v1.3.0 +3. **Outcome**: common v1.3.0 is selected for the module resolution graph. -Because `v1.3.0` is backwards-compatible with `v1.2.0` under Semantic Versioning guidelines, both `user` and `weather` compile successfully against `v1.3.0`. +MVS selects v1.3.0 from these requirements; it does not test whether either consumer compiles. Semantic version labels express maintainer intent and do not prove schema or generated-code compatibility. Separate root modules resolve independently and can select different versions. --- ## What If Breaking Changes Occur? -If `v1.3.0` introduced an incompatible schema modification, this represents a semantic versioning violation on the part of `common`'s maintainers. +If the selected version is incompatible, the graph can resolve successfully while generation or consumer tests fail. Run easyp breaking against an appropriate available baseline before release, then test generated clients. The checker covers its implemented rules and configured scope; it cannot guarantee every consumer remains compatible. -EasyP catches such violations on the producer side via `easyp breaking` checks before release, ensuring that minor version upgrades remain 100% backwards-compatible. +This maximum-of-minimums example applies to semantic versions. Different exact commit requirements conflict. An exact commit can coexist with semantic-version requirements only when the selected tag resolves to that same commit. See [dependency resolution](/docs/architecture/mvs-dependency-resolution). diff --git a/content/docs/guides/version-diamond.ru.mdx b/content/docs/guides/version-diamond.ru.mdx index b08cf42..6d39219 100644 --- a/content/docs/guides/version-diamond.ru.mdx +++ b/content/docs/guides/version-diamond.ru.mdx @@ -1,21 +1,21 @@ --- title: "Разрешение ромбовидных зависимостей (Diamond Dependency)" -description: "Как алгоритм Minimal Version Selection (MVS) детерминированно решает конфликты ромбовидных зависимостей без ручного вмешательства." +description: "Как Minimal Version Selection (MVS) выбирает версию в ромбе зависимостей и какие проверки совместимости всё ещё нужны." --- -Распространённая проблема в управлении пакетами — **проблема ромбовидной зависимости (Diamond Dependency)**. В данном руководстве объясняется, как алгоритм MVS в EasyP детерминированно разрешает расхождения версий без вмешательства человека и без возвратов (backtracking) SAT-солвера. +**Ромбовидная зависимость** возникает, когда прямые и транзитивные требования задают разные версии одного модуля. EasyP использует MVS для выбора версии внутри графа зависимостей каждого модуля. --- ## Описание сценария -Рассмотрим модуль сервиса `user`, который зависит от двух пакетов: `common` и `weather`. +Рассмотрим модуль сервиса user, который зависит от двух пакетов: common и weather. -- `user` напрямую требует `common v1.2.0`. -- `user` напрямую требует `weather v2.1.0`. -- `weather v2.1.0` транзитивно требует `common v1.3.0`. +- user напрямую требует common v1.2.0. +- user напрямую требует weather v2.1.0. +- weather v2.1.0 транзитивно требует common v1.3.0. -```text +~~~text +-------------------+ | proto/user | +---------+---------+ @@ -33,26 +33,26 @@ description: "Как алгоритм Minimal Version Selection (MVS) детер | github.com/acme/ | | common v1.3.0 | +---------------------+ -``` +~~~ --- ## Правило выбора MVS -В отличие от традиционных менеджер пакетов, пытающихся сопоставлять сложные диапазоны версий или падающих с ошибкой конфликта, MVS применяет правило максимума из минимумов: +Для семантических требований к одному модулю MVS выбирает наибольший из запрошенных минимумов: -`Итоговая версия = max(Запрошенных минимумов)` +Итоговая версия = max(Запрошенных минимумов) -1. **Сбор требований**: `[ v1.2.0 (от user), v1.3.0 (от weather) ]` -2. **Выбор максимума**: $\max(v1.2.0, v1.3.0) = v1.3.0$ -3. **Результат**: Для графа модуля выбирается `common v1.3.0`. +1. **Сбор требований**: [ v1.2.0 (от user), v1.3.0 (от weather) ] +2. **Выбор максимума**: max(v1.2.0, v1.3.0) = v1.3.0 +3. **Результат**: Для графа модуля выбирается common v1.3.0. -Поскольку `v1.3.0` обратимо совместима с `v1.2.0` по правилам SemVer, и `user`, и `weather` успешно компилируются с версией `v1.3.0`. +MVS выбирает v1.3.0 по этим требованиям, но не проверяет компиляцию потребителей. Семантические версии выражают намерение сопровождающих и не доказывают совместимость схем или сгенерированного кода. Отдельные корневые модули разрешаются независимо и могут выбрать разные версии. --- ## Что если возникло ломающее изменение? -Если бы версия `v1.3.0` содержала несовместимые изменения, это являлось бы нарушением семантического версионирования со стороны разработчиков `common`. +При несовместимой выбранной версии граф может успешно разрешиться, а генерация или тесты потребителей — упасть. Перед релизом запускайте easyp breaking относительно подходящей доступной базы, затем тестируйте сгенерированные клиенты. Проверка охватывает реализованные правила и настроенную область; она не гарантирует совместимость каждого потребителя. -EasyP отлавливает такие нарушения на стороне продюсера с помощью команды `easyp breaking` ещё до релиза, гарантируя совместимость минорных обновлений. +Пример максимума из минимумов относится к семантическим версиям. Разные точные коммиты конфликтуют. Точный коммит может сосуществовать с семантическими требованиями, только если выбранный тег указывает на тот же коммит. См. [разрешение зависимостей](/ru/docs/architecture/mvs-dependency-resolution). diff --git a/content/docs/migration/easyp-v0.mdx b/content/docs/migration/easyp-v0.mdx new file mode 100644 index 0000000..b7fb93a --- /dev/null +++ b/content/docs/migration/easyp-v0.mdx @@ -0,0 +1,63 @@ +--- +title: "EasyP v0 to v1" +description: "Preview-first migration that preserves configuration and verifies historical dependency pins." +--- + +The v1 CLI does not execute the old combined configuration. Use the explicit migration command for supported, unambiguous v0 projects. Keep the project in version control and stop other writers before applying changes. + +## Preview first + +~~~bash +easyp migrate --dir . --module github.com/acme/contracts +~~~ + +Without --write, the command prints actual candidate files and warnings. It does not change the project or execute plugins. A plain preview does not resolve dependencies or write their cache. + +The candidate files are easyp.yaml for policies, easyp.gen.yaml for generation, protobuf.mod for module metadata, and a verified protobuf.lock when dependency conversion is required. The supplied module identity is literal and must match the intended local module. + +## Verify dependencies and apply + +~~~bash +# Explicitly permit dependency access/cache writes while still previewing. +easyp migrate --dir . --module github.com/acme/contracts --resolve-lock + +# Apply only after the complete candidate set passes validation. +easyp migrate --dir . --module github.com/acme/contracts --resolve-lock --write +~~~ + +For a dependency-free project, --resolve-lock is unnecessary. With dependencies, --write without completed lock verification fails before writing the candidate configuration. No generation plugin is run by either command. + +Modified legacy policy and manifest files receive byte-identical .v0.bak backups. Existing conflicting v1 files or backups are not overwritten. Original permissions are preserved when replacing a legacy file. The old easyp.lock remains unchanged as a historical record. A repeated migration of a validated v1 project is a no-op; it does not update dependencies. + +## What is preserved + +The converter preserves the effective selected lint rules, exceptions, rule settings, and explicit legacy comment-suppression setting. It converts literal ignores and rule-specific prefix ignores to the corresponding v1 exclusions. Generation preserves plugin sources, argv, options, with_imports, and supported managed settings. Relative paths remain relative to the configuration directory. + +Legacy direct and indirect requirements are converted to native require directives. The tool checks that whole v1 source roots would select the same local protobuf files with the same import paths. It does not silently expand a sliced input into an entire module. + +Variable placeholders are not expanded into saved values. If a placeholder or selector prevents safe analysis, conversion fails rather than persisting credentials or guessing its meaning. + +## Historical lock integrity + +A full commit SHA is preserved, including a full SHA embedded in an old pseudo-version. For a legacy lock entry containing a tag but no SHA, conversion resolves that tag and verifies the historical installed-tree hash before accepting the revision. A moved tag or mismatched historical hash is an error. + +The v1 content hash is then calculated independently over the tracked repository files. Old and new hashes cover different path layouts and cannot be copied or compared as interchangeable values. A missing historical dependency pin is not replaced with current HEAD. + +## Explicit limitations + +Unknown fields, invalid or multi-document YAML, ambiguous source selection, unsupported references, and conflicting native outputs are rejected. Custom Git-input roots/subdirectories, external or sliced local inputs whose exact selection cannot be preserved, unsafe managed selectors, and full lock conversion with local replacements may require manual migration. Buf configurations are not inputs to this v0 converter. + +The command stages all outputs and checks observed inputs again before applying. Ordinary application failures are rolled back. Several file replacements are not one process-crash-atomic transaction: after a machine or process failure, inspect the preserved backups and Git state before continuing. Uncooperative concurrent writers cannot be made safe by this command. + +## Verify the result + +~~~bash +easyp validate-config +easyp mod download +easyp lint +easyp generate +~~~ + +Run mod download when the migrated project has a lock. Check real generated code, not only the exit status of configuration validation. Recursive multi-project generation now requires explicit --all or repeated --project; migration does not authorize unrelated projects. + +Command plugins now receive literal argv rather than an implicitly assembled shell command. Review legacy commands that relied on shell operators; use an explicit shell invocation only when that is intentional. Migration does not prove equivalence of arbitrary plugin side effects. diff --git a/content/docs/migration/easyp-v0.ru.mdx b/content/docs/migration/easyp-v0.ru.mdx new file mode 100644 index 0000000..64af196 --- /dev/null +++ b/content/docs/migration/easyp-v0.ru.mdx @@ -0,0 +1,63 @@ +--- +title: "Переход с EasyP v0 на v1" +description: "Миграция с предварительным просмотром, сохранением настроек и проверкой исторических зависимостей." +--- + +CLI v1 не исполняет старый объединённый конфиг. Для поддерживаемых однозначных v0-проектов предусмотрена отдельная команда миграции. Перед применением сохраните проект в Git и остановите другие процессы, изменяющие его файлы. + +## Сначала предварительный просмотр + +~~~bash +easyp migrate --dir . --module github.com/acme/contracts +~~~ + +Без --write команда показывает фактическое содержимое будущих файлов и предупреждения. Файлы проекта не меняются, плагины не запускаются. Обычный предварительный просмотр не разрешает зависимости и не записывает их кэш. + +Подготавливаются easyp.yaml с политиками, easyp.gen.yaml с генерацией, protobuf.mod с метаданными модуля и проверенный protobuf.lock, когда требуется перенос зависимостей. Явно указанный идентификатор должен соответствовать локальному модулю. + +## Проверка зависимостей и применение + +~~~bash +# Разрешить доступ к зависимостям и запись кэша, но не менять проект. +easyp migrate --dir . --module github.com/acme/contracts --resolve-lock + +# Применить только после проверки всего набора файлов. +easyp migrate --dir . --module github.com/acme/contracts --resolve-lock --write +~~~ + +Проекту без зависимостей --resolve-lock не требуется. При наличии зависимостей применение без завершённой проверки lock-файла отклоняется до записи конфигурации. Ни одна из этих команд не запускает плагины генерации. + +Для заменяемых legacy-политики и manifest создаются побайтовые резервные копии .v0.bak. Конфликтующие v1-файлы и существующие резервные копии не перезаписываются. При замене legacy-файла сохраняются его права. Старый easyp.lock остаётся неизменным историческим свидетельством. Повторная миграция проверенного v1-проекта ничего не меняет и не обновляет зависимости. + +## Что переносится + +Сохраняются фактически выбранные lint-правила, исключения, параметры правил и прежняя явная настройка подавления комментариями. Буквальные исключения и префиксные исключения отдельных правил преобразуются в соответствующие правила v1. В генерации сохраняются источники плагинов, argv, options, with_imports и поддерживаемые managed-настройки. Относительные пути остаются привязанными к каталогу конфигурации. + +Legacy-требования direct и indirect преобразуются в require. Проверяется, что новые корни целиком выбирают те же локальные protobuf-файлы с теми же import-путями. Выбранная часть каталога не расширяется молча до всего модуля. + +Подстановки переменных не сохраняются в раскрытом виде. Если переменная или selector мешает безопасному анализу, перенос останавливается, а не записывает секреты и не угадывает смысл настройки. + +## Целостность исторического lock-файла + +Полный SHA коммита сохраняется, в том числе когда он встроен в старую псевдоверсию. Если запись содержит только тег, миграция разрешает его и проверяет исторический хеш установленного дерева перед принятием ревизии. Перенос тега или несовпадение прежнего хеша приводит к ошибке. + +После проверки новый хеш v1 рассчитывается независимо по отслеживаемым файлам репозитория. Старый и новый хеши относятся к разным раскладкам путей; их нельзя просто копировать или считать взаимозаменяемыми. Отсутствующий исторический pin не заменяется текущим HEAD. + +## Явные ограничения + +Неизвестные поля, некорректный YAML или несколько YAML-документов, неоднозначный набор исходников, неподдерживаемые refs и конфликтующие native-файлы отклоняются. Нестандартные root/sub_directory Git-input, внешние или частичные локальные inputs с непереносимой выборкой, неоднозначные managed selectors и полный перенос lock при локальных заменах могут потребовать ручной миграции. Buf-конфигурация не является входом этого v0-конвертера. + +Все результаты сначала подготавливаются, затем состояние входов проверяется повторно. Обычные ошибки применения вызывают откат. Несколько замен файлов не образуют общую транзакцию, атомарную при падении процесса или компьютера: после такого сбоя нужно проверить резервные копии и Git-состояние. Команда не гарантирует безопасность при записи файлов посторонними несогласованными процессами. + +## Проверка результата + +~~~bash +easyp validate-config +easyp mod download +easyp lint +easyp generate +~~~ + +Запускайте mod download, когда у мигрированного проекта есть lock-файл. Проверяйте реально сгенерированный код, а не только успешную валидацию. Для рекурсивной генерации нескольких проектов теперь нужны явный --all или повторяемый --project; миграция не разрешает запуск посторонних проектов. + +Command-плагины теперь получают буквальный argv, а не неявно собранную shell-команду. Проверьте старые команды, использовавшие shell-операторы; явный shell нужен только при намеренном исполнении скрипта. Миграция не доказывает эквивалентность произвольных побочных эффектов плагинов. diff --git a/content/docs/migration/meta.json b/content/docs/migration/meta.json index 55dbd09..f4cd277 100644 --- a/content/docs/migration/meta.json +++ b/content/docs/migration/meta.json @@ -1,6 +1,7 @@ { "title": "Migration", "pages": [ + "easyp-v0", "buf-cli", "protoc", "protolock", diff --git a/content/docs/migration/protoc.mdx b/content/docs/migration/protoc.mdx index b4c04c3..f67e643 100644 --- a/content/docs/migration/protoc.mdx +++ b/content/docs/migration/protoc.mdx @@ -1,5 +1,64 @@ --- -title: "Protoc" +title: "Moving from protoc to EasyP v1" --- -## Work in progress +Map the existing source roots, plugins and checks to v1 explicitly. The easyp migrate command accepts EasyP v0 configuration, not arbitrary scripts or another tool's configuration. Keep the original inputs and generated output for comparison. + +## Module and source roots + +protobuf.mod: + +~~~text +module github.com/acme/contracts +roots proto +~~~ + +A file at proto/hello/v1/hello.proto has the import name hello/v1/hello.proto. If the previous invocation selected only part of a root, do not silently broaden it: v1 generates complete selected modules. + +## Generation + +easyp.gen.yaml: + +~~~yaml +version: v1 +plugins: + - name: go + out: gen/go + opts: [paths=source_relative] + - name: go-grpc + out: gen/go + opts: [paths=source_relative] +~~~ + +Pin the actual plugin executables in the environment. Preserve existing go_package values and align them with the physical output. Set with_imports: true per plugin when imported contracts also need generated code; this is independent of descriptor export. + +## Check policy + +easyp.yaml: + +~~~yaml +version: v1 +linters: + default: BASIC +breaking: + baseline: git:main + categories: [FILE] +~~~ + +Map individual checks by their actual identifiers and results; similarly named presets in different tools do not prove equivalence. breaking.ignore contains paths, not rule names. + +## Dependencies and result verification + +Declare external dependencies with easyp get or manifest require directives. An arbitrary proto import does not uniquely identify a Git source. Run mod tidy for initial resolution and commit the lock; subsequent checks use mod download, not an implicit version update. + +~~~bash +easyp validate-config +easyp mod tidy +easyp lint +easyp breaking --against main +easyp generate +~~~ + +The selected baseline must exist locally. Compare filenames, import paths and contents with the old generator, then build and test the consumer. Keep the old scripts until this comparison succeeds. Multiple projects require repeated --project or explicit --all. + +For an existing EasyP v0 project, start with the [migration preview](/docs/migration/easyp-v0). diff --git a/content/docs/migration/protoc.ru.mdx b/content/docs/migration/protoc.ru.mdx index 79b288d..2b6c12a 100644 --- a/content/docs/migration/protoc.ru.mdx +++ b/content/docs/migration/protoc.ru.mdx @@ -1,250 +1,64 @@ --- -title: "Миграция с protoc на EasyP" +title: "Переход с protoc на EasyP v1" --- -> Исходная англоязычная версия файла содержала только заголовок и пометку “Work in progress”. Ниже — полноценный русскоязычный черновик раздела миграции. Уточни, если требуется сократить или изменить уровень детализации. - -## 1. Краткое сравнение - -| Аспект | `protoc` | EasyP | -|--------|----------|-------| -| Базовая роль | Базовый компилятор `.proto` файлов | Инструмент “всё в одном”: линтинг, проверка несовместимых изменений, менеджер пакетов, генерация | -| Конфигурация | Чаще shell‑скрипты / Makefile / вручную передаваемые флаги | Единый файл `easyp.yaml` (YAML или JSON) | -| Управление зависимостями | Ручной `git clone`, `submodule`, vendoring | Секция `deps` с Git‑репозиториями | -| Набор правил линтера | Нет встроенного | Встроенный линтер с правилами (можно включать/исключать) | -| Проверка breaking changes | Отсутствует из коробки | Команда `easyp breaking` | -| Расширенные плагины | Установка и вызов через флаги `--plugin` | Плагины через конфиг; поддержка удалённого выполнения (API Service) и стандартного локального | -| Единообразие в CI | Нужно собирать вручную | Консистентные команды: `lint`, `breaking`, `generate` | - -## 2. Когда имеет смысл мигрировать - -Миграция на EasyP особенно полезна если: -- Есть потребность в автоматической проверке качества (стиль, именование) `.proto` файлов. -- Нужна защита от нелегитимных несовместимых изменений при эволюции схем. -- В проекте используется несколько языков генерации и растёт число скриптов вокруг `protoc`. -- Вы хотите единый конфиг вместо множества shell/Makefile комбинаций. -- Планируется централизованное исполнение плагинов (через API Service) или унификация окружения в CI. - -## 3. Типичный сценарий “до” (только protoc) - -Пример: локальные скрипты / Makefile: - -```makefile -protoc \ - -I . \ - -I third_party \ - --go_out=./gen/go --go_opt=paths=source_relative \ - --go-grpc_out=./gen/go --go-grpc_opt=paths=source_relative \ - api/echo/v1/echo.proto -``` - -Дополнительные зависимости (googleapis, validate, grpc-gateway) скачиваются вручную или через submodules. - -## 4. Типичный сценарий “после” (EasyP) - -Единый файл `easyp.yaml`: - -```yaml -deps: - - github.com/googleapis/googleapis - - github.com/envoyproxy/protoc-gen-validate - -generate: - plugins: - - name: go - out: gen/go - opts: - paths: source_relative - - name: go-grpc - out: gen/go - opts: - paths: source_relative - require_unimplemented_servers: false - - name: validate - out: gen/go - opts: - paths: source_relative - lang: "go" -``` - -Команды: -```bash -easyp mod update # Скачивание/обновление deps -easyp lint # Линтинг .proto -easyp breaking --against git-ref=origin/main -easyp generate # Генерация кода -``` - -## 5. Пошаговая миграция - -1. Инвентаризация: - - Соберите список всех вызовов `protoc` (скрипты, Makefile, CI). - - Зафиксируйте используемые плагины и их версии. -2. Создание `easyp.yaml`: - - Поле `version` не обязательно (можете оставить его только для обратной совместимости). - - Перенесите плагины в секцию `generate.plugins`. - - Укажите опции, которые ранее передавались в командной строке. -3. Зависимости: - - Все внешние каталоги (googleapis, validate, grpc-gateway и т.п.) занесите в `deps`. - - Удалите лишние submodules при необходимости. -4. Линтер: - - Запустите `easyp lint` и посмотрите на предупреждения. - - При необходимости добавьте `lint.use`, `lint.ignore`, `lint.except`. -5. Проверка breaking changes: - - Выберите референс (обычно `origin/main` или предыдущий тег). - - Запустите `easyp breaking --against git-ref=origin/main`. - - Настройте игнорируемые изменения (`breaking.ignore`), если нужно. -6. Обновление CI: - - Замените прямые вызовы `protoc` на `easyp generate`. - - Добавьте отдельные шаги `lint` и `breaking`. -7. Очистка: - - Удалите устаревшие генерационные скрипты, если они дублируют функционал EasyP. -8. Документация: - - Обновите README / CONTRIBUTING (новый способ генерации). -9. Верификация: - - Сравните результат генерации до и после (git diff). - - Убедитесь, что имена файлов и пути совпадают или скорректируйте структуру. - -## 6. Замена в CI (пример GitHub Actions) - -```yaml -- name: Install EasyP - run: go install github.com/easyp-tech/easyp/cmd/easyp@latest - -- name: Lint - run: easyp lint - -- name: Breaking - run: easyp breaking --against git-ref=origin/main - -- name: Generate - run: easyp generate -``` - -## 7. Работа с плагинами - -| Тип | В protoc | В EasyP | -|-----|----------|---------| -| Стандартные (`protoc-gen-go`) | Указание через `--go_out` | `plugins: - name: go ...` | -| gRPC | `--go-grpc_out` | Второй плагин `go-grpc` | -| Validate | Доп. установка + `--validate_out` | `- name: validate` с opts | -| gRPC-Gateway / OpenAPI | `--grpc-gateway_out` / `--openapiv2_out` | Плагины `grpc-gateway`, `openapiv2` | -| Кастомные | Путь к бинарю / `--plugin=protoc-gen-xxx` | `- name: xxx` или удалённый `remote:` (если используется API Service) | - -Если вы переходите на удалённое выполнение (API Service), записи в конфиге могут выглядеть так: - -```yaml -generate: - plugins: - - remote: api.easyp.tech/protobuf/go:v1.36.10 - out: gen/go - opts: - paths: source_relative -``` - -## 8. Проверка корректности после миграции - -1. `git diff` после `easyp generate` — не должно быть неожиданных изменений. -2. Сравнить размер и содержимое каталога сгенерированных файлов. -3. Запустить ваш потребляющий код (сборка, тесты). -4. Проверить, что плагины (validate, grpc-gateway) продолжают вставлять необходимые аннотации / опции. -5. Линт не должен выдавать критичных ошибок — скорректируйте стиль .proto, если требуется. - -## 9. Частые проблемы - -| Проблема | Причина | Решение | -|----------|---------|---------| -| Плагин не найден | Не установлен или не указан в PATH | Выполнить `go install ...` или добавить в конфиг как remote | -| Ошибка импорта `.proto` | Отсутствует репозиторий в `deps` | Добавить адрес в секцию `deps` и `easyp mod update` | -| Несовместимые изменения на каждом PR | Отсутствует игнор/настройка сравнения | Уточнить ветку/тег в `--against` или настроить `breaking.ignore` | -| Локально работает, в CI падает | В CI нет зависимостей (не вызван update) | Добавить шаг `easyp mod update` перед `generate` | -| Дубликаты сгенерированных файлов | Изменена структура путей или `out` | Синхронизировать `out` и `paths: source_relative` опции | - -## 10. Минимальный пример конфигурации (только Go) - -```yaml -generate: - plugins: - - name: go - out: gen/go - opts: - paths: source_relative -``` - -Команды: -```bash -easyp generate -``` - -## 11. Расширенный пример (Go + gRPC + Gateway + Validate + Breaking и Lint) - -```yaml -lint: - use: - - ENUM_FIRST_VALUE_ZERO - - SERVICE_SUFFIX - allow_comment_ignores: false - enum_zero_value_suffix: _NONE - service_suffix: Service - -deps: - - github.com/googleapis/googleapis - - github.com/envoyproxy/protoc-gen-validate - -generate: - plugins: - - name: go - out: gen/go - opts: - paths: source_relative - - name: go-grpc - out: gen/go - opts: - paths: source_relative - require_unimplemented_servers: false - - name: validate - out: gen/go - opts: - paths: source_relative - lang: "go" - - name: grpc-gateway - out: gen/go - opts: - paths: source_relative - - name: openapiv2 - out: gen/openapi - opts: - simple_operation_ids: true +Это ручное сопоставление существующих исходников, плагинов и правил с v1. Команда easyp migrate принимает конфигурацию EasyP v0, а не произвольные скрипты или конфигурацию другого инструмента. Сохраните исходные файлы и результаты прежней генерации для сравнения. -breaking: - against_git_ref: main - ignore: - - ENUM_VALUE_SAME_NAME -``` +## Модуль и исходники -## 12. Checklist миграции +protobuf.mod: -- [ ] Собраны все текущие вызовы `protoc`. -- [ ] Создан `easyp.yaml` с секциями `generate` и (опционально) `lint`, `breaking`. -- [ ] Добавлены все внешние зависимости в `deps`. -- [ ] Успешно выполнен `easyp mod update`. -- [ ] `easyp generate` даёт идентичный или ожидаемо обновлённый результат. -- [ ] `easyp lint` проходит без критичных ошибок (или ошибки обработаны). -- [ ] `easyp breaking --against git-ref=origin/main` не выдаёт неожиданных блокирующих нарушений. -- [ ] CI обновлён (заменены прямые вызовы `protoc`). -- [ ] Документация проекта обновлена (README: как генерировать). +~~~text +module github.com/acme/contracts +roots proto +~~~ -## 13. Дополнительные рекомендации +Путь proto/hello/v1/hello.proto имеет import-имя hello/v1/hello.proto. Если прежний запуск выбирал только часть корня, не переносите его механически на весь модуль: v1 генерирует целые выбранные модули. -- Сначала мигрируйте один сервис / пакет — снизит риск массовых конфликтов. -- Закоммитьте `easyp.yaml` отдельно, затем выполните генерацию и линт — проще ревью. -- Если нужны разные наборы плагинов для разных микросервисов — используйте несколько конфигов (например: `easyp.microservice-a.yaml` + `easyp.microservice-b.yaml`). -- Внедрите проверку актуальности генерации: шаг CI, который валидирует отсутствие diff после `easyp generate`. +## Генерация -## 14. Статус +easyp.gen.yaml: -Этот файл — русская расширенная версия, заменяющая placeholder “Work in progress”. При появлении новых возможностей EasyP (дополнительные поля в конфиге, новые плагины, расширения breaking‑проверок) обновите соответствующие разделы. +~~~yaml +version: v1 +plugins: + - name: go + out: gen/go + opts: [paths=source_relative] + - name: go-grpc + out: gen/go + opts: [paths=source_relative] +~~~ ---- +Зафиксируйте версии используемых исполняемых плагинов в окружении. Сохраните прежние go_package и согласуйте их с физическим output. При необходимости генерировать также импорты включите with_imports: true у конкретного плагина. Это не параметр descriptor export. + +## Политика проверок + +easyp.yaml: + +~~~yaml +version: v1 +linters: + default: BASIC +breaking: + baseline: git:main + categories: [FILE] +~~~ + +Сопоставляйте отдельные правила по фактическим именам и результатам; одинаковые названия пресетов разных инструментов не доказывают эквивалентность. breaking.ignore содержит пути, а не имена правил. + +## Зависимости и проверка результата + +Объявите внешние зависимости через easyp get или require в manifest. Git-источник нельзя однозначно угадать по произвольному proto-import. Для первоначального разрешения выполните mod tidy и закоммитьте lock; в последующих проверках используйте mod download, а не обновление версий. + +~~~bash +easyp validate-config +easyp mod tidy +easyp lint +easyp breaking --against main +easyp generate +~~~ + +Указанный baseline должен быть доступен локально. Сравните с прежней генерацией имена файлов, import paths и содержимое, затем соберите и протестируйте потребляющий проект. Не удаляйте прежние скрипты до этого сравнения. Для нескольких проектов используйте повторяемый --project или явно разрешённый --all. -Если нужен упрощённый вариант (только перевод без расширения), сообщи — могу сократить до минимальных двух блоков. +Если исходный проект уже использует EasyP v0, начните с [предварительного просмотра миграции](/docs/migration/easyp-v0). diff --git a/content/docs/migration/prototool.mdx b/content/docs/migration/prototool.mdx index 7ee311d..4d6480b 100644 --- a/content/docs/migration/prototool.mdx +++ b/content/docs/migration/prototool.mdx @@ -1,5 +1,64 @@ --- -title: "Prototool" +title: "Moving from prototool to EasyP v1" --- -## Work in progress +Map the existing source roots, plugins and checks to v1 explicitly. The easyp migrate command accepts EasyP v0 configuration, not arbitrary scripts or another tool's configuration. Keep the original inputs and generated output for comparison. + +## Module and source roots + +protobuf.mod: + +~~~text +module github.com/acme/contracts +roots proto +~~~ + +A file at proto/hello/v1/hello.proto has the import name hello/v1/hello.proto. If the previous invocation selected only part of a root, do not silently broaden it: v1 generates complete selected modules. + +## Generation + +easyp.gen.yaml: + +~~~yaml +version: v1 +plugins: + - name: go + out: gen/go + opts: [paths=source_relative] + - name: go-grpc + out: gen/go + opts: [paths=source_relative] +~~~ + +Pin the actual plugin executables in the environment. Preserve existing go_package values and align them with the physical output. Set with_imports: true per plugin when imported contracts also need generated code; this is independent of descriptor export. + +## Check policy + +easyp.yaml: + +~~~yaml +version: v1 +linters: + default: BASIC +breaking: + baseline: git:main + categories: [FILE] +~~~ + +Map individual checks by their actual identifiers and results; similarly named presets in different tools do not prove equivalence. breaking.ignore contains paths, not rule names. + +## Dependencies and result verification + +Declare external dependencies with easyp get or manifest require directives. An arbitrary proto import does not uniquely identify a Git source. Run mod tidy for initial resolution and commit the lock; subsequent checks use mod download, not an implicit version update. + +~~~bash +easyp validate-config +easyp mod tidy +easyp lint +easyp breaking --against main +easyp generate +~~~ + +The selected baseline must exist locally. Compare filenames, import paths and contents with the old generator, then build and test the consumer. Keep the old scripts until this comparison succeeds. Multiple projects require repeated --project or explicit --all. + +For an existing EasyP v0 project, start with the [migration preview](/docs/migration/easyp-v0). diff --git a/content/docs/migration/prototool.ru.mdx b/content/docs/migration/prototool.ru.mdx index eafeaae..747b982 100644 --- a/content/docs/migration/prototool.ru.mdx +++ b/content/docs/migration/prototool.ru.mdx @@ -1,242 +1,64 @@ --- -title: "Prototool" +title: "Переход с prototool на EasyP v1" --- -## Состояние -Этот раздел был помечен как “Work in progress” в оригинальной английской версии. Ниже — переведённое и дополненное практическое руководство по миграции с Prototool на EasyP. Имя инструмента Prototool не переводится. +Это ручное сопоставление существующих исходников, плагинов и правил с v1. Команда easyp migrate принимает конфигурацию EasyP v0, а не произвольные скрипты или конфигурацию другого инструмента. Сохраните исходные файлы и результаты прежней генерации для сравнения. ---- - -## Цель миграции -Перейти от конфигурации и рабочих процессов Prototool к эквиваленту на EasyP с минимальными изменениями, сохранив: -- Линтинг .proto файлов. -- Генерацию кода через protoc-плагины. -- Управление зависимостями. -- Проверку несовместимых изменений (в Prototool это приходилось реализовывать внешними инструментами; в EasyP встроено). - ---- - -## Кратко о различиях - -| Область | Prototool | EasyP | Комментарий | -|---------|-----------|-------|-------------| -| Конфигурация | `prototool.yaml` | `easyp.yaml` | Форматы YAML/JSON поддерживаются; структура отличается. | -| Линтинг | Встроенные наборы + кастомные правила | Наборы через `lint.use`, тонкая настройка ignore/except | EasyP даёт больше гибкости группировки. | -| Генерация | Раздел `generate` + плагины через Docker/локально | `generate.plugins` (локальные/WASM/удалённые) | EasyP может выполнять плагины удалённо (API Service). | -| Зависимости | Обычно через include-пути / внешние git clone вручную | Секция `deps` (Git репозитории) + `mod update` | Более декларативно. | -| Breaking Changes | Нет встроенного механизма | Секция `breaking` + команда `easyp breaking` | Из коробки. | -| Lock-in | Зависимость от модели Prototool | Минималистичный формат, «любой Git — пакет» | Облегчает выход / интеграцию с другими экосистемами. | - ---- - -## Типовая структура Prototool (упрощённо) - -```yaml -# prototool.yaml (пример) -protoc: - include_paths: - - api - - third_party -lint: - group: basic - rules: - add: - - ENUM_VALUE_PREFIX -generate: - plugins: - - name: go - out: gen/go - - name: go-grpc - out: gen/go -``` - -Особенности: -- `include_paths` задаёт пути поиска импортов. -- `lint.group` + `rules.add/remove` регулируют активные проверки. -- `generate.plugins` описывает плагины для protoc. - ---- - -## Эквивалент на EasyP - -```yaml -# easyp.yaml (пример) -deps: - - github.com/org/common-protos # вместо manual include - - github.com/org/third-party-protos - -lint: - use: - - MINIMAL - - BASIC - enum_zero_value_suffix: "_NONE" - service_suffix: "Service" - ignore: - - COMMENT_FIELD - except: - - ENUM_VALUE_PREFIX - allow_comment_ignores: true - -generate: - plugins: - - name: go - out: gen/go - opts: - paths: source_relative - - name: go-grpc - out: gen/go - opts: - paths: source_relative - require_unimplemented_servers: false - -breaking: - against_git_ref: main - ignore: - - FIELD_SAME_TYPE -``` - -Комментарии: -- `deps` заменяет необходимость вручную прописывать include paths: EasyP подтянет их через git. -- `lint.use` активирует наборы правил (MINIMAL/BASIC/DEFAULT и т.д.). -- Дополнительные настройки (`enum_zero_value_suffix`, `service_suffix`) задают политики нейминга. -- `breaking` позволяет сразу контролировать несовместимые изменения. - ---- - -## Шаги миграции - -1. Инвентаризация: - - Соберите текущий `prototool.yaml`, списки include paths и плагины. - - Зафиксируйте используемые кастомные правила, если есть. - -2. Зависимости: - - Любые каталоги, которые вы вручную добавляли в `include_paths`, преобразуйте в git-репозитории (если ещё нет). - - Добавьте их в `deps` (формат: `github.com/owner/repo` или путь к вашей приватной системе Git). - -3. Линтинг: - - Определите какой group использовался (`basic`, `default`, …) → сопоставьте с наборами EasyP (`MINIMAL`, `BASIC`, `DEFAULT`). - - Индивидуальные добавления (`rules.add`) перенесите в `lint.use` или `except`/`ignore`: -``` - - Если правило нужно активировать — включите через набор или явно. - - Если нужно отключить — добавьте в `ignore`. -``` - -4. Генерация: - - Сохраните список плагинов. В большинстве случаев имена совпадут (`go`, `go-grpc`, др.). - - Если раньше использовали Docker-окружение Prototool — проверьте поддержку удалённых плагинов через API Service EasyP (опционально). - - Перепишите в секцию `generate.plugins`. - -5. Дополнительные опции: - - Настройки нейминга enum/service перенести в `enum_zero_value_suffix`, `service_suffix`. - - Если были внешние скрипты для проверки breaking changes — удалите их и включите `breaking` с `against_git_ref`. +## Модуль и исходники -6. Верификация: - - Запустите: `easyp mod update` (скачивание deps). - - Затем: `easyp lint`. - - Далее: `easyp generate`. - - И, если нужно: `easyp breaking --against git-ref=origin/main`. +protobuf.mod: -7. CI/CD: - - Обновите workflow (GitHub Actions / GitLab) — замените вызовы Prototool на EasyP команды. - - Добавьте шаг проверки несовместимых изменений. +~~~text +module github.com/acme/contracts +roots proto +~~~ ---- - -## Сопоставление правил (общая идея) - -| Prototool концепт | EasyP | -|-------------------|------| -| lint.group | lint.use (наборы) | -| rules.add/remove | except / ignore | -| include_paths | deps (git источники) | -| plugins | generate.plugins | -| (внешние скрипты для breaking) | breaking секция + команда | +Путь proto/hello/v1/hello.proto имеет import-имя hello/v1/hello.proto. Если прежний запуск выбирал только часть корня, не переносите его механически на весь модуль: v1 генерирует целые выбранные модули. ---- - -## Приватные репозитории +## Генерация -Если ранее Prototool просто видел локальные каталоги, теперь: -- Добавьте SSH ключи/токены в CI для доступа к приватным Git. -- Укажите их в `deps` как обычные git-URL (формат зависит от реализации EasyP; для публичных — стандартный). +easyp.gen.yaml: ---- +~~~yaml +version: v1 +plugins: + - name: go + out: gen/go + opts: [paths=source_relative] + - name: go-grpc + out: gen/go + opts: [paths=source_relative] +~~~ -## Типовые проблемы при миграции +Зафиксируйте версии используемых исполняемых плагинов в окружении. Сохраните прежние go_package и согласуйте их с физическим output. При необходимости генерировать также импорты включите with_imports: true у конкретного плагина. Это не параметр descriptor export. -| Проблема | Причина | Решение | -|----------|---------|---------| -| Правила линтера не совпадают | Неверное сопоставление групп | Проверить документацию EasyP по наборам правил | -| Импорты не находятся | Забыли добавить репозиторий в deps | Добавить в `deps` и выполнить `easyp mod update` | -| Генерация падает на опциях | Плагин требует другие flags | Проверить `opts` и документацию плагина | -| breaking сообщает слишком много | Слишком строгий базовый набор | Добавить конкретные правила в `breaking.ignore` | -| Долгая генерация | Нет кеша/много deps | Включить кэширование в CI (vendor/.easyp/deps) | +## Политика проверок ---- +easyp.yaml: -## Минимальная конфигурация после миграции - -```yaml -lint: - use: - - MINIMAL -generate: - plugins: - - name: go - out: gen/go - opts: - paths: source_relative +~~~yaml +version: v1 +linters: + default: BASIC breaking: - against_git_ref: main -``` - ---- + baseline: git:main + categories: [FILE] +~~~ -## Рекомендации по упрощению - -- Начните с минимального `lint.use` (MINIMAL), затем постепенно включайте дополнительные наборы. -- Не переносите слепо все ignore — часть правил может уже быть улучшена в EasyP. -- Сначала настроить deps и генерацию, затем усложнять линт/нейминг. -- Фиксируйте миграцию по шагам (коммиты: deps → lint → generate → breaking → CI). - ---- +Сопоставляйте отдельные правила по фактическим именам и результатам; одинаковые названия пресетов разных инструментов не доказывают эквивалентность. breaking.ignore содержит пути, а не имена правил. -## Проверка результата +## Зависимости и проверка результата -Скрипт локальной быстрой проверки (пример): +Объявите внешние зависимости через easyp get или require в manifest. Git-источник нельзя однозначно угадать по произвольному proto-import. Для первоначального разрешения выполните mod tidy и закоммитьте lock; в последующих проверках используйте mod download, а не обновление версий. -```bash -#!/usr/bin/env bash -set -euo pipefail - -echo "[1] deps update" -easyp mod update - -echo "[2] lint" +~~~bash +easyp validate-config +easyp mod tidy easyp lint - -echo "[3] breaking vs main" -easyp breaking --against git-ref=origin/main || echo "Breaking changes detected (review needed)" - -echo "[4] generate" +easyp breaking --against main easyp generate +~~~ -echo "Done." -``` - ---- - -## Заключение - -Миграция с Prototool на EasyP сводится к: -1. Переносу путей и внешних каталогов в декларативные `deps`. -2. Переформатированию линта под `lint.use` + `ignore/except`. -3. Переносу генерации в `generate.plugins`. -4. Добавлению встроенного механизма `breaking`. -5. Адаптации CI. - -После этого конфигурация становится более прозрачной, а проверка несовместимых изменений — из коробки. - ---- +Указанный baseline должен быть доступен локально. Сравните с прежней генерацией имена файлов, import paths и содержимое, затем соберите и протестируйте потребляющий проект. Не удаляйте прежние скрипты до этого сравнения. Для нескольких проектов используйте повторяемый --project или явно разрешённый --all. -*Готово: базовый перевод и расширенное руководство по миграции с Prototool на EasyP.* +Если исходный проект уже использует EasyP v0, начните с [предварительного просмотра миграции](/docs/migration/easyp-v0). diff --git a/content/docs/reference/easyp-gen-yaml.mdx b/content/docs/reference/easyp-gen-yaml.mdx index 02fad14..5d977b0 100644 --- a/content/docs/reference/easyp-gen-yaml.mdx +++ b/content/docs/reference/easyp-gen-yaml.mdx @@ -3,9 +3,9 @@ title: "easyp.gen.yaml Reference" description: "Complete specification for easyp.gen.yaml, configuring consumer-side code generation, plugin outputs, WASM/remote execution, and managed package options." --- -The `easyp.gen.yaml` file specifies **consumer-side code generation rules**. Residing alongside consuming applications or service projects, it defines which modules to compile, which plugins to invoke, where generated artifacts should be written, and managed options. +The easyp.gen.yaml file specifies **consumer-side code generation rules**. Residing alongside consuming applications or service projects, it defines which modules to compile, which plugins to invoke, where generated artifacts should be written, and managed options. -In accordance with EasyP's zero-duplication principles, `easyp.gen.yaml` **never** contains dependency URLs or version numbers for Protobuf schemas—schema sources and versions are resolved strictly through `protobuf.mod` and `protobuf.lock`. +generate.modules selects module identities or local paths. Schema version requirements are declared in protobuf.mod; selected commits and hashes are recorded in protobuf.lock. --- @@ -19,11 +19,11 @@ In accordance with EasyP's zero-duplication principles, `easyp.gen.yaml` **never default: "v1" }, generate: { - description: "Module and package selection block.", + description: "Complete-module selection; package filtering is reserved.", type: "object" }, "generate.modules": { - description: "Module identities or repository-relative local module paths to generate. Dependency identities use protobuf.mod and its lock beside this config; when no sibling manifest exists, they use the repository-root module and lock. If omitted, that local module is selected.", + description: "Module identities or workspace-relative local module paths. Dependencies use the nearest protobuf.mod beside or above this config within the workspace and its lock. If omitted, that module is selected; without a manifest, the project directory is used.", type: "string[]" }, "generate.packages": { @@ -47,7 +47,7 @@ In accordance with EasyP's zero-duplication principles, `easyp.gen.yaml` **never type: "string[]" }, "plugins[].remote": { - description: "gRPC or HTTP remote code generation service URL.", + description: "Remote plugin URL for gRPC execution; set the version separately.", type: "string" }, "plugins[].version": { @@ -58,16 +58,21 @@ In accordance with EasyP's zero-duplication principles, `easyp.gen.yaml` **never description: "Destination directory relative to easyp.gen.yaml where generated code is written.", type: "string" }, + "plugins[].with_imports": { + description: "Generate transitive imports with this plugin only. Independent of descriptor export --include_imports.", + type: "boolean", + default: "false" + }, "plugins[].opts": { description: "Plugin-specific key-value options or flag strings.", type: "object | string[]" }, options: { - description: "Language-scoped managed options for package prefixes.", + description: "Go package-prefix options.", type: "object" }, "options.go.package_prefix": { - description: "Base Go package prefix automatically prepended to generated go_package imports.", + description: "Computes go_package, changing Go options only. Full managed mode requires generate.managed.enabled: true.", type: "string" }, "generate.managed": { @@ -81,35 +86,39 @@ In accordance with EasyP's zero-duplication principles, `easyp.gen.yaml` **never ## Example Configurations -### Project-Level Generator (`backend/easyp.gen.yaml`) +### Project-Level Generator (backend/easyp.gen.yaml) -```yaml +~~~yaml version: v1 - generate: - modules: - - proto/user - - proto/order - + modules: [proto/user, proto/order] + managed: + enabled: true + override: + - file_option: go_package_prefix + value: github.com/acme/backend/gen + - file_option: go_package_prefix + module: github.com/acme/user + value: github.com/acme/backend/gen/user + - file_option: go_package_prefix + module: github.com/acme/order + value: github.com/acme/backend/gen/order plugins: - name: go - out: ./gen/go - opts: - paths: source_relative + out: . + with_imports: true + opts: [module=github.com/acme/backend] - name: go-grpc - out: ./gen/go - opts: - paths: source_relative - require_unimplemented_servers: false + out: . + with_imports: true + opts: [module=github.com/acme/backend, require_unimplemented_servers=false] +~~~ -options: - go: - package_prefix: github.com/acme/backend/gen/go -``` +This example assumes the consumer Go module is github.com/acme/backend. The local modules declare github.com/acme/user and github.com/acme/order, exposing v1/user.proto and v1/order.proto; their shared dependency exposes common/v1/common.proto. Outputs go to separate directories gen/user/v1, gen/order/v1, and gen/common/v1. Different Go packages need different output directories; EasyP does not insert an implicit module-name prefix. -### Remote Web Generator (`frontend/easyp.gen.yaml`) +### Remote Web Generator (frontend/easyp.gen.yaml) -```yaml +~~~yaml version: v1 generate: @@ -122,19 +131,19 @@ plugins: out: ./src/gen opts: target: ts -``` +~~~ --- -## Managed Options (`options`) +## Managed Options (options) -Instead of requiring explicit file-level options (like `option go_package = "..."`) inside every individual `.proto` schema file, EasyP's managed `options` block groups settings logically by target language. +Instead of requiring explicit file-level options (like option go_package = "...") inside every individual .proto schema file, EasyP's managed options block groups settings logically by target language. -For example, setting `options.go.package_prefix: github.com/acme/backend/gen/go` automatically computes import paths based on the module directory layout without mutating source `.proto` files. +options.go.package_prefix computes go_package from the proto file path without changing the source. The prefix alone changes Go options only: it does not enable Java, C#, PHP, Ruby, Objective-C, or C++ defaults. Full managed mode and field-option transformations require explicit generate.managed.enabled: true. Go disable selectors, including go_package, suppress the prefix. -The existing managed-mode rules remain available under `generate.managed`. For example, a package-specific override can be written as: +The existing managed-mode rules remain available under generate.managed. For example, a package-specific override can be written as: -```yaml +~~~yaml version: v1 generate: managed: @@ -146,23 +155,29 @@ generate: plugins: - name: go out: ./gen/go -``` +~~~ -A repository-root `easyp.gen.yaml` may provide `options.go.package_prefix` as a default for nested generator files. Nested `generate.managed` rules take precedence over that inherited default. A prefix declared in the same generator file has the highest priority. Plugin lists stay local to each generator file. +A repository-root easyp.gen.yaml may provide options.go.package_prefix as a default for nested generator files. Nested generate.managed rules take precedence over that inherited default. A prefix declared in the same generator file has the highest priority. Plugin lists stay local to each generator file. -The current v1 generator selects complete modules. `generate.packages` is reserved for a later release, once its matching syntax is specified. +The v1 generator selects complete modules. generate.packages is reserved and unimplemented: omit it or leave it empty; nonempty values cause an error. -Remote plugins require a `version` such as `v2.0.0`. EasyP sends that exact version to the remote generator. For local `protoc-gen-*` executables and bundled WASM plugins, the executable selected at runtime determines the version; the separate `version` field is rejected because EasyP cannot verify it. +Remote plugins require a version such as v2.0.0. EasyP sends that exact version to the remote generator. For local protoc-gen-* executables and bundled WASM plugins, the executable selected at runtime determines the version; the separate version field is rejected because EasyP cannot verify it. -Each plugin declares exactly one source: `name`, `path`, `command`, or `remote`. Use `path` for a specific binary and `command` for an executable plus arguments. Both run from the directory where `easyp generate` starts and, like any Protobuf plugin, must read a `CodeGeneratorRequest` from stdin and write a `CodeGeneratorResponse` to stdout. +Each plugin declares exactly one source: name, path, command, or remote. Use path for a specific binary and command for an executable plus arguments. Both run from the directory where easyp generate starts and, like any Protobuf plugin, must read a CodeGeneratorRequest from stdin and write a CodeGeneratorResponse to stdout. -```yaml +~~~yaml version: v1 plugins: - path: ./tools/protoc-gen-custom out: ./gen/custom - command: [sh, ./tools/protoc-plugin.sh] out: ./gen/script -``` +~~~ + +The separate version field is also unavailable for path and command. + +## Project selection and imports + +By default, easyp generate selects the closest config in the current directory or a workspace ancestor. Repeat --project to choose multiple consumers explicitly; --all separately opts into recursive selection. --workspace sets the boundary for module paths and inheritance. -The separate `version` field is also unavailable for `path` and `command`. +plugins[].with_imports defaults to false. True adds transitive imports to that plugin's files to generate. Import descriptors remain available for linking when false. The --descriptor_set_out and --descriptor_set_out_dir flags are mutually exclusive; --include_imports controls exported contents only, independently of with_imports. See [project selection and descriptor export](/docs/cli/generator). diff --git a/content/docs/reference/easyp-gen-yaml.ru.mdx b/content/docs/reference/easyp-gen-yaml.ru.mdx index 8e7d0bd..e905f25 100644 --- a/content/docs/reference/easyp-gen-yaml.ru.mdx +++ b/content/docs/reference/easyp-gen-yaml.ru.mdx @@ -3,9 +3,9 @@ title: "Справочник easyp.gen.yaml" description: "Полная спецификация файла easyp.gen.yaml, управляющего кодогенерацией на стороне потребителя, выводами плагинов, WASM/remote запуском и managed-опциями." --- -Файл `easyp.gen.yaml` задаёт **правила генерации кода на стороне потребителя**. Находясь рядом с приложением или сервисом, он определяет, какие модули компилировать, какие плагины вызывать, куда записывать сгенерированный код и какие managed-опции применять. +Файл easyp.gen.yaml задаёт **правила генерации кода на стороне потребителя**. Находясь рядом с приложением или сервисом, он определяет, какие модули компилировать, какие плагины вызывать, куда записывать сгенерированный код и какие managed-опции применять. -В соответствии с принципом недублирования источников EasyP, `easyp.gen.yaml` **никогда** не содержит URL репозиториев или версий зависимостей — источники и версии протоколов определяются строго через `protobuf.mod` и `protobuf.lock`. +Список generate.modules выбирает модули по имени или локальному пути. Требования к версиям схем объявляются в protobuf.mod, а выбранные коммиты и хеши сохраняются в protobuf.lock. --- @@ -19,11 +19,11 @@ description: "Полная спецификация файла easyp.gen.yaml, default: "v1" }, generate: { - description: "Блок выбора модулей и пакетов для генерации.", + description: "Выбор целых модулей; фильтрация пакетов зарезервирована.", type: "object" }, "generate.modules": { - description: "Идентификаторы модулей или локальные пути относительно корня репозитория. Зависимости разрешаются через protobuf.mod и его lock рядом с этим конфигом; если соседнего манифеста нет, используются корневые модуль и lock. Если поле отсутствует, выбирается этот локальный модуль.", + description: "Идентификаторы модулей или локальные пути относительно workspace. Зависимости используют ближайший protobuf.mod рядом с конфигом или выше в пределах workspace и его lock. Без списка выбирается этот модуль; без манифеста — каталог проекта.", type: "string[]" }, "generate.packages": { @@ -47,7 +47,7 @@ description: "Полная спецификация файла easyp.gen.yaml, type: "string[]" }, "plugins[].remote": { - description: "URL удалённого сервиса генерации кода (gRPC или HTTP).", + description: "URL удалённого плагина для выполнения через gRPC; версия задаётся отдельно.", type: "string" }, "plugins[].version": { @@ -58,16 +58,21 @@ description: "Полная спецификация файла easyp.gen.yaml, description: "Директория назначения относительно easyp.gen.yaml для результатов.", type: "string" }, + "plugins[].with_imports": { + description: "Генерирует транзитивные импорты только этим плагином. Независимо от флага экспорта --include_imports.", + type: "boolean", + default: "false" + }, "plugins[].opts": { description: "Параметры и флаги плагина (словарь или список строк).", type: "object | string[]" }, options: { - description: "Managed-опции пакетов, сгруппированные по целевым языкам.", + description: "Настройки префикса Go-пакетов.", type: "object" }, "options.go.package_prefix": { - description: "Базовый префикс Go-пакета, автоматически добавляемый к go_package.", + description: "Вычисляет go_package, меняя только Go-опции. Полный managed mode требует generate.managed.enabled: true.", type: "string" }, "generate.managed": { @@ -81,35 +86,39 @@ description: "Полная спецификация файла easyp.gen.yaml, ## Примеры конфигураций -### Проектный генератор (`backend/easyp.gen.yaml`) +### Проектный генератор (backend/easyp.gen.yaml) -```yaml +~~~yaml version: v1 - generate: - modules: - - proto/user - - proto/order - + modules: [proto/user, proto/order] + managed: + enabled: true + override: + - file_option: go_package_prefix + value: github.com/acme/backend/gen + - file_option: go_package_prefix + module: github.com/acme/user + value: github.com/acme/backend/gen/user + - file_option: go_package_prefix + module: github.com/acme/order + value: github.com/acme/backend/gen/order plugins: - name: go - out: ./gen/go - opts: - paths: source_relative + out: . + with_imports: true + opts: [module=github.com/acme/backend] - name: go-grpc - out: ./gen/go - opts: - paths: source_relative - require_unimplemented_servers: false + out: . + with_imports: true + opts: [module=github.com/acme/backend, require_unimplemented_servers=false] +~~~ -options: - go: - package_prefix: github.com/acme/backend/gen/go -``` +В примере Go-модуль потребителя называется github.com/acme/backend. Локальные модули объявляют имена github.com/acme/user и github.com/acme/order; их import path — v1/user.proto и v1/order.proto. Общая зависимость экспортирует common/v1/common.proto. Результаты попадают в отдельные каталоги gen/user/v1, gen/order/v1 и gen/common/v1. Разным Go-пакетам нужны разные выходные каталоги; EasyP не добавляет неявный префикс имени модуля. -### Удалённая веб-генерация (`frontend/easyp.gen.yaml`) +### Удалённая веб-генерация (frontend/easyp.gen.yaml) -```yaml +~~~yaml version: v1 generate: @@ -122,19 +131,19 @@ plugins: out: ./src/gen opts: target: ts -``` +~~~ --- -## Managed Options (`options`) +## Managed Options (options) -Вместо явного прописывания опций вроде `option go_package = "..."` внутри каждого `.proto` файла, блок `options` в EasyP группирует настройки по целевым языкам программирования. +Вместо явного прописывания опций вроде option go_package = "..." внутри каждого .proto файла, блок options в EasyP группирует настройки по целевым языкам программирования. -Например, указание `options.go.package_prefix: github.com/acme/backend/gen/go` автоматически вычисляет пути импортов на основе структуры директорий модуля без модификации исходных `.proto` файлов. +Например, options.go.package_prefix вычисляет go_package по пути proto-файла без изменения исходника. Сам префикс меняет только Go-опции: он не включает значения по умолчанию для Java, C#, PHP, Ruby, Objective-C или C++. Для полного managed mode и преобразований опций полей явно задайте generate.managed.enabled: true. Go-селекторы disable, включая go_package, подавляют префикс. -Существующие правила managed mode доступны в `generate.managed`. Например, переопределение для конкретного Protobuf-пакета: +Существующие правила managed mode доступны в generate.managed. Например, переопределение для конкретного Protobuf-пакета: -```yaml +~~~yaml version: v1 generate: managed: @@ -146,23 +155,29 @@ generate: plugins: - name: go out: ./gen/go -``` +~~~ -Корневой `easyp.gen.yaml` может задавать `options.go.package_prefix` по умолчанию для вложенных генераторов. Локальные правила `generate.managed` имеют приоритет над унаследованным префиксом. Префикс, заданный в том же файле генератора, имеет наивысший приоритет. Списки плагинов не наследуются. +Корневой easyp.gen.yaml может задавать options.go.package_prefix по умолчанию для вложенных генераторов. Локальные правила generate.managed имеют приоритет над унаследованным префиксом. Префикс, заданный в том же файле генератора, имеет наивысший приоритет. Списки плагинов не наследуются. -Сейчас v1 генерирует модули целиком. `generate.packages` оставлено для будущей версии после определения синтаксиса выбора пакетов. +Сейчас v1 генерирует модули целиком. Поле generate.packages зарезервировано и не реализовано: его нужно опустить или оставить пустым; непустое значение вызывает ошибку. -Удалённому плагину нужен `version`, например `v2.0.0`. EasyP передаёт именно эту версию удалённому генератору. Для локального `protoc-gen-*` и встроенного WASM версию определяет выбранный исполняемый файл; отдельное поле `version` отклоняется, поскольку EasyP не может его проверить. +Удалённому плагину нужен version, например v2.0.0. EasyP передаёт именно эту версию удалённому генератору. Для локального protoc-gen-* и встроенного WASM версию определяет выбранный исполняемый файл; отдельное поле version отклоняется, поскольку EasyP не может его проверить. -Для каждого плагина указывают ровно один источник: `name`, `path`, `command` или `remote`. `path` запускает конкретный бинарный файл, а `command` принимает список из программы и её аргументов. Оба варианта работают из каталога запуска `easyp generate` и, как любой плагин Protobuf, должны принимать `CodeGeneratorRequest` из stdin и возвращать `CodeGeneratorResponse` в stdout. +Для каждого плагина указывают ровно один источник: name, path, command или remote. path запускает конкретный бинарный файл, а command принимает список из программы и её аргументов. Оба варианта работают из каталога запуска easyp generate и, как любой плагин Protobuf, должны принимать CodeGeneratorRequest из stdin и возвращать CodeGeneratorResponse в stdout. -```yaml +~~~yaml version: v1 plugins: - path: ./tools/protoc-gen-custom out: ./gen/custom - command: [sh, ./tools/protoc-plugin.sh] out: ./gen/script -``` +~~~ + +Для path и command отдельное поле version также не указывается. + +## Выбор проекта и импорты + +По умолчанию easyp generate выбирает ближайший конфиг в текущем или родительском каталоге workspace. Повторяйте --project для явного выбора нескольких потребителей; --all отдельно включает рекурсивный выбор. --workspace задаёт границу для путей модулей и наследования. -Для `path` и `command` отдельное поле `version` также не указывается. +plugins[].with_imports по умолчанию равен false. Значение true добавляет транзитивные импорты в список файлов для генерации только этого плагина. Дескрипторы импортов для связывания доступны и при false. Флаги --descriptor_set_out и --descriptor_set_out_dir взаимоисключающие; --include_imports меняет только содержимое экспорта, независимо от with_imports. См. [выбор проектов и экспорт дескрипторов](/ru/docs/cli/generator). diff --git a/content/docs/reference/easyp-yaml.mdx b/content/docs/reference/easyp-yaml.mdx index 1346e4b..46dd204 100644 --- a/content/docs/reference/easyp-yaml.mdx +++ b/content/docs/reference/easyp-yaml.mdx @@ -3,9 +3,7 @@ title: "easyp.yaml Reference" description: "Complete specification for easyp.yaml, configuring producer-side linting rules, breaking change detection, path exclusions, and policy inheritance." --- -The `easyp.yaml` file defines **producer-side policy configuration** for Protocol Buffer schema repositories. It specifies linting standards, breaking change checks against Git baselines, and issue exclusions. Directory cascading is available; explicit `extends` references are reserved until their resolution rules are specified. - -`easyp.yaml` files cascade hierarchically down directory structures: for any given `.proto` file, EasyP traverses up the directory tree to find the nearest `easyp.yaml` and applies its configuration. +easyp.yaml defines lint and compatibility policies for protobuf schemas. Each section uses its nearest definition in the directory tree. Explicit policy loading through linters.extends and breaking.extends is reserved and unimplemented: omit these fields or leave them empty. --- @@ -19,7 +17,7 @@ The `easyp.yaml` file defines **producer-side policy configuration** for Protoco default: "v1" }, linters: { - description: "Linter presets, explicit rule enable/disable, and inheritance.", + description: "Linter presets, rule/group selection, and per-policy comment suppressions.", type: "object" }, "linters.default": { @@ -28,19 +26,24 @@ The `easyp.yaml` file defines **producer-side policy configuration** for Protoco default: "STANDARD" }, "linters.enable": { - description: "List of additional linter rules to enable on top of preset.", + description: "Additional implemented rule or group names to enable.", type: "string[]" }, "linters.disable": { - description: "List of linter rules to disable from the active preset.", + description: "Implemented rule or group names to disable; disabling wins over enabling.", type: "string[]" }, + "linters.allow_comment_ignores": { + description: "Allow scoped easyp:disable/enable and legacy markers within the effective policy.", + type: "boolean", + default: "true" + }, "linters.extends": { - description: "Reserved for explicit policy inheritance; currently rejected because ref, path, and merge rules are unspecified.", + description: "Reserved and unimplemented. Omit or leave empty; nonempty values are rejected.", type: "string" }, "linters-settings": { - description: "Rule-specific settings and custom parameter definitions.", + description: "Supported settings: ENUM_ZERO_VALUE_SUFFIX.suffix and SERVICE_SUFFIX.suffix.", type: "object" }, issues: { @@ -48,33 +51,37 @@ The `easyp.yaml` file defines **producer-side policy configuration** for Protoco type: "object" }, "issues.exclude-rules": { - description: "Pathless rules disable the named linters for all files under the selected policy. An empty pathless rule suppresses all issues. Path globs are reserved until their base directory is specified.", + description: "Suppress named rules/groups for matching paths. Omitted or empty linters suppress all lint issues in matching files; a completely empty rule explicitly ignores all files covered by the effective issues section.", type: "object[]" }, + "issues.exclude-rules[].path": { + description: "Relative to the policy file supplying the issues section. Supports *, ?, [], and complete ** segments; a literal directory covers its subtree.", + type: "string" + }, breaking: { description: "Breaking change detection settings for CI verification.", type: "object" }, "breaking.baseline": { - description: "Git branch to compare schema changes against (e.g. git:main). When omitted, the existing --against flag applies.", + description: "Locally available Git branch, tag, full commit SHA, or revision prefixed with git:. Explicit --against wins; otherwise this field applies, then master.", type: "string", - default: "--against flag" + default: "master" }, "breaking.categories": { - description: "Reserved for future category-specific checks; currently rejected when configured.", + description: "Only FILE is supported: adds declaration-move checks while existing checks remain enabled. Other categories, including package-related categories, are reserved and rejected.", type: "string[]" }, "breaking.ignore_unstable": { - description: "Reserved for future unstable-package filtering; currently rejected when true.", + description: "Skip packages with a supported unstable version in their final component on both sides of comparison. See exact forms below.", type: "boolean", default: "false" }, "breaking.ignore": { - description: "Directories ignored by the existing breaking checker.", + description: "Ignored paths relative to the policy file supplying breaking, not the Git root or --root.", type: "string[]" }, "breaking.extends": { - description: "Reserved for explicit policy inheritance; currently rejected because ref, path, and merge rules are unspecified.", + description: "Reserved and unimplemented. Omit or leave empty; nonempty values are rejected.", type: "string" } }} @@ -82,52 +89,75 @@ The `easyp.yaml` file defines **producer-side policy configuration** for Protoco --- -## Example Configuration +## Example configuration -```yaml +~~~yaml version: v1 - linters: default: STANDARD - enable: - - ENUM_VALUE_PREFIX - - RPC_REQUEST_RESPONSE_UNIQUE - disable: - - PACKAGE_VERSION_SUFFIX - + enable: [ENUM_VALUE_PREFIX, RPC_REQUEST_RESPONSE_UNIQUE] + disable: [PACKAGE_VERSION_SUFFIX] + allow_comment_ignores: true linters-settings: ENUM_ZERO_VALUE_SUFFIX: suffix: UNSPECIFIED SERVICE_SUFFIX: suffix: Service - issues: exclude-rules: - - linters: - - FIELD_LOWER_SNAKE_CASE - + - path: legacy/**/*.proto + linters: [FIELD_LOWER_SNAKE_CASE] + - path: generated breaking: baseline: git:main - ignore: - - gen -``` + categories: [FILE] + ignore_unstable: true + ignore: [gen] +~~~ ---- +## Section cascading + +The linters, linters-settings, issues, and breaking sections each come as a whole from the nearest file defining that section; fields are not partially merged. A child issues: {} clears inherited exclusions. An inherited exclusion path stays relative to the file defining issues, even when the invocation directory or --root is deeper. + +Policy discovery searches ancestors within the workspace. If no ancestor policy exists, one unambiguous outermost descendant policy may be selected; multiple independent policies require explicit --cfg. Explicit --cfg takes precedence, and explicit --root supplies the default lookup start. + +## Rule selection and exclusions + +Repeated rule or group names are idempotent, and disabling wins over enabling. Unknown names in enable, disable, and exclusions are errors even if also listed on the opposite side. The reserved PACKAGE_NO_IMPORT_CYCLE rule is unimplemented and cannot be selected. + +issues.exclude-rules[].path uses / separators and is anchored to the directory of the file supplying the effective issues section: + +| Pattern | Matches | +| --- | --- | +| generated | The directory and its whole subtree | +| api/file.proto | That file | +| api/*.proto | Files directly inside api | +| api/?.proto | One character before .proto | +| api/[a-c].proto | a.proto, b.proto, or c.proto | +| api/**/file.proto | Zero or more intermediate directories | + +** must occupy an entire segment. Absolute paths, backslashes, .. traversal, and malformed patterns are rejected. A literal path ending in .proto matches that file only; other literal paths cover their subtree. These rules apply to issue exclusions only, not every configuration path. + +Without path, the rule applies to all files covered by the effective issues section. linters accepts implemented rule or group names; an omitted or empty list excludes matching files from linting entirely. A completely empty rule {} retains its explicit all-ignore meaning. In the example, the whole generated subtree is excluded, while only the named rule is suppressed in legacy. + +## Comment suppressions + +linters.allow_comment_ignores defaults to true per effective policy. False disables comment-based suppressions. easyp:disable/easyp:enable provide annotations or bounded regions; legacy nolint:RULE and buf:lint:ignore RULE remain annotations. Unknown names, empty directives, and unmatched enables remain errors even when suppressions are disabled. See the [linter guide](/docs/cli/linter) for examples and scope. + +## Breaking checks + +Explicit --against wins over breaking.baseline; without either, the default is master. This includes explicit --against master. An empty explicit flag is an error, and a missing Git baseline does not fall back to the configured one. + +The baseline can name a local branch, a lightweight or annotated tag, a full commit SHA, or another locally resolvable Git revision such as HEAD. Required refs and objects must already be present in the checkout. A bare branch name takes precedence over an identically named tag; use refs/tags/v1.2.0 to select the tag explicitly. In YAML use git:refs/tags/v1.2.0; for the CLI pass --against refs/tags/v1.2.0 without a git: or git-ref= prefix. + +breaking.ignore paths are relative to the file supplying the effective breaking section, not the Git root or --root. For example, ignore: [generated] in api/easyp.yaml excludes api/generated, including when that section is inherited. Entries must be nonempty local relative paths; absolute paths and paths escaping the policy directory or repository are rejected. -## Directory Cascading +Each selected module uses revision-local roots, manifests, and locks for its current and baseline revisions. The baseline is read from an isolated Git snapshot; the caller's checkout, manifest, and lock are unchanged. Policies come from current configuration and may each select a different baseline. See the [breaking guide](/docs/cli/breaking-changes) for local replacement limits. -EasyP applies the **nearest file rule**: when evaluating a `.proto` file, EasyP searches upward through parent directories for an `easyp.yaml`. +The only supported additional category is FILE, which checks declarations moved between files. Existing checks remain enabled. PACKAGE, WIRE, WIRE_JSON, and other categories are unimplemented and cannot be selected. linters.extends and breaking.extends likewise do not load local or remote shared policies: nonempty values are rejected. -```text -proto/ -├── easyp.yaml # STANDARD policy applies to root & user/ -├── user/ -│ └── v1/user.proto -└── legacy/ - ├── easyp.yaml # MINIMAL policy override applies strictly to legacy/ - └── old.proto -``` +## Unstable packages -Sections are inherited as whole units from the nearest declaring file, preventing confusing partial merges. +breaking.ignore_unstable defaults to false. When true, it filters packages by their final protobuf package-name component on both sides of comparison, including dependency packages. Supported forms are vNtest..., vNalpha, vNbeta, vNpMalpha, and vNpMbeta. Alpha/beta may have a positive sequence number; N, M, and that sequence start with 1–9 followed by digits. Test may have any trailing suffix, including none. -The v1 `breaking.baseline` selects the Git branch used by the existing EasyP breaking checker. Its rule set is unchanged. Category selection and unstable-package filtering need separate rule semantics and are not active yet. A path-bearing `issues.exclude-rules` entry currently produces an error; pathless entries work without choosing an implicit glob base. Explicit `linters.extends` and `breaking.extends` currently produce errors: the syntax does not yet define a Git ref, policy path, merge precedence, or lock/integrity behavior. +For example, acme.v1testFeature, acme.v2alpha3, and acme.v2p3beta are skipped. acme.v1, acme.v0alpha1, acme.v1beta0, and acme.v1beta1.service do not match. Stable packages remain checked, including their references to unstable types. Filtering does not excuse malformed sources: reading and import resolution happen before filtering. diff --git a/content/docs/reference/easyp-yaml.ru.mdx b/content/docs/reference/easyp-yaml.ru.mdx index 7e6fa6c..d6a8b21 100644 --- a/content/docs/reference/easyp-yaml.ru.mdx +++ b/content/docs/reference/easyp-yaml.ru.mdx @@ -3,9 +3,7 @@ title: "Справочник easyp.yaml" description: "Полная спецификация файла easyp.yaml, управляющего правилами линтинга продюсера, проверками ломающих изменений, исключениями путей и наследованием политик." --- -Файл `easyp.yaml` определяет **конфигурацию политик на стороне продюсера** для репозиториев Protobuf-схем. Он задаёт стандарты линтинга, проверки ломающих изменений относительно Git-baseline и исключения замечаний. Каскадирование по директориям работает; явные ссылки `extends` оставлены до определения правил разрешения. - -Файлы `easyp.yaml` каскадируются по иерархии директорий: для каждого файла `.proto` EasyP ищет ближайший `easyp.yaml` вверх по дереву каталогов и применяет его правила. +Файл easyp.yaml задаёт политики линтинга и совместимости для protobuf-схем. Для каждой секции применяется ближайшее определение в дереве каталогов. Явная загрузка политик через linters.extends и breaking.extends зарезервирована и не реализована: эти поля нужно опустить или оставить пустыми. --- @@ -19,7 +17,7 @@ description: "Полная спецификация файла easyp.yaml, уп default: "v1" }, linters: { - description: "Пресеты линтеров, точечное включение/отключение правил и наследование.", + description: "Пресеты, выбор правил/групп и подавление замечаний комментариями в пределах политики.", type: "object" }, "linters.default": { @@ -28,19 +26,24 @@ description: "Полная спецификация файла easyp.yaml, уп default: "STANDARD" }, "linters.enable": { - description: "Список дополнительных правил линтера, включаемых поверх пресета.", + description: "Дополнительные имена реализованных правил или групп для включения.", type: "string[]" }, "linters.disable": { - description: "Список правил линтера, отключаемых из активного пресета.", + description: "Имена реализованных правил или групп для отключения; отключение приоритетнее включения.", type: "string[]" }, + "linters.allow_comment_ignores": { + description: "Разрешает easyp:disable/enable и старые маркеры в пределах эффективной политики.", + type: "boolean", + default: "true" + }, "linters.extends": { - description: "Резерв для явного наследования политик; сейчас выдаёт ошибку, поскольку не определены ref, путь и правила слияния.", + description: "Зарезервировано и не реализовано. Опустите поле или оставьте пустым; непустые значения отклоняются.", type: "string" }, "linters-settings": { - description: "Параметры конкретных правил и пользовательские настройки.", + description: "Поддерживаются ENUM_ZERO_VALUE_SUFFIX.suffix и SERVICE_SUFFIX.suffix.", type: "object" }, issues: { @@ -48,33 +51,37 @@ description: "Полная спецификация файла easyp.yaml, уп type: "object" }, "issues.exclude-rules": { - description: "Правило без path отключает указанные линтеры для всех файлов выбранной политики. Пустое правило без path подавляет все замечания. Glob-пути оставлены до определения базовой директории.", + description: "Подавляет выбранные правила/группы на совпавших путях. Пустой или отсутствующий linters подавляет все замечания в совпавших файлах; полностью пустое правило явно исключает все файлы эффективной секции issues.", type: "object[]" }, + "issues.exclude-rules[].path": { + description: "Путь относительно файла, задающего секцию issues. Поддерживает *, ?, [] и полные сегменты **; буквальный каталог охватывает поддерево.", + type: "string" + }, breaking: { description: "Параметры проверки ломающих изменений для CI.", type: "object" }, "breaking.baseline": { - description: "Git-ветка для сравнения изменений (например, git:main). Если поле не задано, применяется существующий флаг --against.", + description: "Доступная локально Git-ветка, тег, полный SHA коммита или ревизия с префиксом git:. Явный --against имеет приоритет; далее это поле, затем master.", type: "string", - default: "флаг --against" + default: "master" }, "breaking.categories": { - description: "Резерв для будущих проверок по категориям; при указании сейчас выдаётся ошибка.", + description: "Поддерживается только FILE: добавляет проверки перемещения объявлений, сохраняя существующие проверки. Остальные категории, включая пакетные, зарезервированы и отклоняются.", type: "string[]" }, "breaking.ignore_unstable": { - description: "Резерв для будущей фильтрации нестабильных пакетов; true сейчас вызывает ошибку.", + description: "Пропускает пакеты с поддерживаемой нестабильной версией в последнем компоненте имени на обеих сторонах сравнения. Точные формы описаны ниже.", type: "boolean", default: "false" }, "breaking.ignore": { - description: "Директории, которые пропускает существующий breaking checker.", + description: "Исключаемые пути относительно файла политики, задающего breaking, а не корня Git или --root.", type: "string[]" }, "breaking.extends": { - description: "Резерв для явного наследования политик; сейчас выдаёт ошибку, поскольку не определены ref, путь и правила слияния.", + description: "Зарезервировано и не реализовано. Опустите поле или оставьте пустым; непустые значения отклоняются.", type: "string" } }} @@ -84,50 +91,73 @@ description: "Полная спецификация файла easyp.yaml, уп ## Пример конфигурации -```yaml +~~~yaml version: v1 - linters: default: STANDARD - enable: - - ENUM_VALUE_PREFIX - - RPC_REQUEST_RESPONSE_UNIQUE - disable: - - PACKAGE_VERSION_SUFFIX - + enable: [ENUM_VALUE_PREFIX, RPC_REQUEST_RESPONSE_UNIQUE] + disable: [PACKAGE_VERSION_SUFFIX] + allow_comment_ignores: true linters-settings: ENUM_ZERO_VALUE_SUFFIX: suffix: UNSPECIFIED SERVICE_SUFFIX: suffix: Service - issues: exclude-rules: - - linters: - - FIELD_LOWER_SNAKE_CASE - + - path: legacy/**/*.proto + linters: [FIELD_LOWER_SNAKE_CASE] + - path: generated breaking: baseline: git:main - ignore: - - gen -``` + categories: [FILE] + ignore_unstable: true + ignore: [gen] +~~~ ---- +## Каскадирование секций + +Секции linters, linters-settings, issues и breaking берутся целиком из ближайшего определяющего файла без частичного слияния. Вложенная issues: {} очищает унаследованные исключения. Унаследованный путь исключения остаётся относительно файла, где определена секция issues, даже если запуск или --root указывает глубже. + +При поиске политики команды идут вверх в пределах workspace. Если политики выше нет, допустима одна однозначная внешняя политика в потомках; несколько независимых политик требуют явного --cfg. Явный --cfg имеет приоритет, а явный --root задаёт начальную точку поиска по умолчанию. + +## Выбор правил и исключения + +Повторные имена правил или групп не добавляют проверок; отключение приоритетнее включения. Неизвестные имена в enable, disable и исключениях — ошибки, даже если имя есть в противоположном списке. Зарезервированное PACKAGE_NO_IMPORT_CYCLE не реализовано и выбирать его нельзя. + +Пути issues.exclude-rules[].path используют разделитель / и привязаны к каталогу файла, предоставившего эффективную секцию issues: + +| Шаблон | Совпадение | +| --- | --- | +| generated | Весь каталог и его поддерево | +| api/file.proto | Этот файл | +| api/*.proto | Файлы непосредственно в api | +| api/?.proto | Имя из одного символа перед .proto | +| api/[a-c].proto | a.proto, b.proto или c.proto | +| api/**/file.proto | Ноль или больше промежуточных каталогов | + +** должен занимать целый сегмент. Абсолютные пути, обратные слеши, переходы .. и некорректные шаблоны отклоняются. Путь без шаблонов с окончанием .proto совпадает только с файлом; остальные буквальные пути охватывают поддерево. Эти правила относятся только к исключениям issues, а не ко всем путям конфигурации. + +Без path правило действует на все файлы эффективной секции issues. linters может содержать реализованные правила или группы; пустой либо отсутствующий список исключает файл из линтинга целиком. Полностью пустое правило {} сохраняет значение явного исключения всех файлов. В примере исключается всё поддерево generated, а в legacy подавляется только указанное правило. + +## Подавление комментариями + +linters.allow_comment_ignores по умолчанию равен true для каждой эффективной политики. False отключает подавление через комментарии. Маркеры easyp:disable/easyp:enable задают аннотации или ограниченные регионы; старые nolint:RULE и buf:lint:ignore RULE остаются аннотациями. Неизвестные имена, пустые директивы и непарные enable остаются ошибками даже при отключённом подавлении. Примеры и области действия — в [руководстве линтера](/ru/docs/cli/linter). + +## Проверка совместимости + +Явный --against имеет приоритет над breaking.baseline; без обоих используется master. Это верно и для явного --against master. Пустой явный флаг вызывает ошибку, а отсутствующая Git-база не заменяется конфигурационной. + +База может указывать на локальную ветку, лёгкий или аннотированный тег, полный SHA коммита или другую разрешимую локально Git-ревизию, например HEAD. Нужные ссылки и объекты должны уже присутствовать в checkout. Короткое имя ветки приоритетнее одноимённого тега; для явного выбора тега используйте refs/tags/v1.2.0. В YAML задавайте git:refs/tags/v1.2.0, а в CLI — --against refs/tags/v1.2.0 без префикса git: или git-ref=. + +Пути breaking.ignore отсчитываются от файла, задающего эффективную секцию breaking, а не от корня Git или --root. Например, ignore: [generated] в api/easyp.yaml исключает api/generated, в том числе при наследовании этой секции. Допустимы непустые локальные относительные пути; абсолютные пути и выход за каталог политики или репозиторий отклоняются. -## Каскадирование по директориям +Для каждого выбранного модуля текущая и базовая ревизии используют собственные корни, манифесты и lock. База читается из изолированного Git-снимка; рабочее дерево, манифест и lock пользователя не изменяются. Политики берутся из текущей конфигурации; каждая может задавать свою базу. Подробности и ограничения локальных замен — в [руководстве breaking](/ru/docs/cli/breaking-changes). -EasyP использует **правило ближайшего файла**: при проверке `.proto` файла EasyP ищет `easyp.yaml` вверх по дереву директорий. +Единственная поддерживаемая дополнительная категория — FILE, проверяющая перемещения объявлений между файлами. Она не выключает существующие проверки. Категории PACKAGE, WIRE, WIRE_JSON и другие пока не реализованы; включать их нельзя. linters.extends и breaking.extends также не загружают локальные или удалённые общие политики: непустые значения отклоняются. -```text -proto/ -├── easyp.yaml # Политика STANDARD применяется к корню и user/ -├── user/ -│ └── v1/user.proto -└── legacy/ - ├── easyp.yaml # Ослабленная политика MINIMAL только для legacy/ - └── old.proto -``` +## Нестабильные пакеты -Секция берётся целиком из ближайшего определяющего файла без частичного слияния. +breaking.ignore_unstable по умолчанию равен false. При true фильтруется последний компонент имени protobuf-пакета на обеих сторонах сравнения, включая пакеты зависимостей. Поддерживаются формы vNtest..., vNalpha, vNbeta, vNpMalpha и vNpMbeta. После alpha/beta допустим положительный номер; N, M и этот номер начинаются с 1–9 и продолжаются цифрами. После test допустим любой суффикс, включая пустой. -В v1 `breaking.baseline` выбирает Git-ветку для существующего checker EasyP. Набор его проверок не меняется. Выбор категорий и фильтрация нестабильных пакетов требуют отдельного определения правил и пока не активны. `issues.exclude-rules` с `path` сейчас выдаёт ошибку; правила без `path` работают без неявного выбора базы для glob. `linters.extends` и `breaking.extends` тоже пока выдают ошибку: ещё не определены Git ref, путь к политике, приоритет слияния и способ фиксации зависимости. +Например, acme.v1testFeature, acme.v2alpha3 и acme.v2p3beta пропускаются. acme.v1, acme.v0alpha1, acme.v1beta0 и acme.v1beta1.service не совпадают. Стабильные пакеты по-прежнему проверяются, включая их ссылки на нестабильные типы. Фильтр не позволяет оставить некорректные исходники: чтение и разрешение импортов происходят до фильтрации. diff --git a/content/docs/reference/protobuf-lock.mdx b/content/docs/reference/protobuf-lock.mdx index f9968a0..5fab6bd 100644 --- a/content/docs/reference/protobuf-lock.mdx +++ b/content/docs/reference/protobuf-lock.mdx @@ -3,7 +3,7 @@ title: "protobuf.lock Reference" description: "Specification for protobuf.lock, the generated lockfile securing resolved Git commits, versions, and cryptographic hashes for hermetic builds." --- -The `protobuf.lock` file is an auto-generated artifact created by EasyP dependency commands (`easyp get`, `easyp mod tidy`, `easyp mod update`). It locks the exact transitive dependency graph to guarantee **100% hermetic, reproducible builds** across all local developer environments and CI pipelines. +protobuf.lock is generated by easyp get, easyp mod tidy, and easyp mod update. It records the selected Git dependency graph with exact commits and content hashes, making dependency sources reproducible while the pinned commits remain available and integrity checks succeed. --- @@ -25,7 +25,7 @@ The `protobuf.lock` file is an auto-generated artifact created by EasyP dependen type: "string" }, "modules[].version": { - description: "Resolved Semantic Version tag (for example v1.2.3) or the full Git commit hash requested without a tag.", + description: "Selected SemVer tag or full commit hash for an exact-commit or versionless requirement.", type: "string" }, "modules[].commit": { @@ -43,31 +43,31 @@ The `protobuf.lock` file is an auto-generated artifact created by EasyP dependen ## Example Lockfile -```yaml -# protobuf.lock - GENERATED FILE, DO NOT EDIT MANUALLY +~~~yaml +# Illustrative values only; real entries are written by EasyP. version: 1 modules: - - source: github.com/googleapis/googleapis - version: v1.5.0 - commit: 8f3a1c94b2e10a84e - hash: h1:a9F8zK9mB20... - - source: github.com/acme/weather + - source: github.com/acme/shared version: v1.2.3 - commit: 51d2e071c89f33b11 - hash: h1:x7B3mL4k90a... - - source: github.com/grpc-ecosystem/grpc-gateway - version: v2.19.0 - commit: c4f88aa91024e12c4 - hash: h1:p0Q1wK97ab1... -``` + commit: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + hash: h1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= +~~~ --- -## Lifecycle Commands +## Lifecycle commands -- `easyp get [@version|@commit]`: Adds a direct requirement, records its transitive requirements as indirect, and updates `protobuf.lock`. -- `easyp mod tidy`: Resolves required imports, updates indirect dependencies, and regenerates `protobuf.lock`. -- `easyp mod update`: Upgrades tagged dependencies to latest semver-compatible versions, refreshes versionless requirements to Git HEAD, preserves explicit commit pins, and updates `protobuf.lock`. -- `easyp mod download`: Populates local cache strictly using `protobuf.lock` without reaching out to remote registries or modifying locked versions. +- easyp get adds a direct requirement, records transitive requirements as indirect, and updates the lock. +- easyp mod tidy resolves declared requirements, updates indirect entries and the lock, and preserves an existing lock pin for a requirement that remains unconstrained. +- easyp mod update refreshes SemVer dependencies within their current major versions, refreshes still-unconstrained requirements to HEAD, and preserves explicit commit pins. +- easyp mod download downloads exact locked commits and verifies their contents without changing locked versions. -The `hash` is computed with Go's `dirhash.Hash1` over every regular file tracked by Git at `commit`, using repository-relative paths. EasyP verifies the same digest for a newly downloaded module and for an existing cache entry. A missing cached commit still requires access to its Git repository. +## Immutable versions and cache reuse + +During tidy, get, and update, every fetched previously locked SemVer is compared with its recorded commit and hash. A republished tag raises ErrLockedVersionChanged before installing the new graph or writing the manifest or lock. This includes transitive requirements and works independently of a warm installed-module cache. A new version may still be selected; unconstrained versionless requirements still refresh during mod update. + +mod download uses the locked commit even after a tag moves, provided that commit remains available. + +The hash uses Go's dirhash.Hash1 over all regular files tracked by Git at the commit, with repository-relative paths. EasyP verifies it on download and when reusing an installed module; corrupt installations are rejected. + +The v1 cache reuses an object store per Git remote. A known exact commit can be fetched without contacting the remote. A cold request first tries a depth-one fetch of the exact commit; if the server rejects that request, EasyP falls back to advertised reachable history. The original commit is still required: HEAD is never substituted. Tag lookups are refreshed separately so cache reuse cannot hide a retag. A commit absent from cache can still require access to its source. diff --git a/content/docs/reference/protobuf-lock.ru.mdx b/content/docs/reference/protobuf-lock.ru.mdx index 9bbcc49..4ad025c 100644 --- a/content/docs/reference/protobuf-lock.ru.mdx +++ b/content/docs/reference/protobuf-lock.ru.mdx @@ -3,7 +3,7 @@ title: "Справочник protobuf.lock" description: "Спецификация файла protobuf.lock, автоматически генерируемого lock-файла для фиксации коммитов Git, версий и криптографических хешей для воспроизводимых сборок." --- -Файл `protobuf.lock` — это автоматически генерируемый артефакт, создаваемый командами управления зависимостями EasyP (`easyp get`, `easyp mod tidy`, `easyp mod update`). Он фиксирует точный транзитивный граф зависимостей для обеспечения **100% герметичных и воспроизводимых сборок** во всех локальных окружениях и в CI. +Файл protobuf.lock создаётся командами easyp get, easyp mod tidy и easyp mod update. Он фиксирует выбранный граф Git-зависимостей точными коммитами и хешами содержимого. Это делает исходники зависимостей воспроизводимыми при доступности зафиксированных коммитов и успешной проверке целостности. --- @@ -25,7 +25,7 @@ description: "Спецификация файла protobuf.lock, автомат type: "string" }, "modules[].version": { - description: "Разрешённый тег Semantic Version (например, v1.2.3) или полный хеш Git-коммита, указанный вместо тега.", + description: "Выбранный SemVer-тег или полный хеш коммита для требования по SHA либо без версии.", type: "string" }, "modules[].commit": { @@ -43,31 +43,31 @@ description: "Спецификация файла protobuf.lock, автомат ## Пример lock-файла -```yaml -# protobuf.lock - СГЕНЕРИРОВАННЫЙ ФАЙЛ, НЕ РЕДАКТИРОВАТЬ РУКАМИ +~~~yaml +# Условные значения; реальные записи создаёт EasyP. version: 1 modules: - - source: github.com/googleapis/googleapis - version: v1.5.0 - commit: 8f3a1c94b2e10a84e - hash: h1:a9F8zK9mB20... - - source: github.com/acme/weather + - source: github.com/acme/shared version: v1.2.3 - commit: 51d2e071c89f33b11 - hash: h1:x7B3mL4k90a... - - source: github.com/grpc-ecosystem/grpc-gateway - version: v2.19.0 - commit: c4f88aa91024e12c4 - hash: h1:p0Q1wK97ab1... -``` + commit: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + hash: h1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= +~~~ --- ## Команды жизненного цикла -- `easyp get <модуль>[@версия|@коммит]`: Добавляет прямое требование, записывает его транзитивные требования как indirect и обновляет `protobuf.lock`. -- `easyp mod tidy`: Сканирует импорты, дописывает транзитивные зависимости и перегенерирует `protobuf.lock`. -- `easyp mod update`: Обновляет зависимости с тегами до свежих совместимых релизов, требования без версии — до Git HEAD, сохраняет явно закреплённые хеши и обновляет `protobuf.lock`. -- `easyp mod download`: Наполняет локальный кэш строго по `protobuf.lock` без обращения к внешним реестрам. +- easyp get добавляет прямое требование, записывает транзитивные требования как indirect и обновляет lock. +- easyp mod tidy разрешает объявленные требования, обновляет indirect-записи и lock. Для требования, оставшегося без ограничений версии, сохраняет прежний коммит из lock. +- easyp mod update обновляет SemVer-зависимости в пределах текущей мажорной версии, освежает всё ещё неограниченные требования до HEAD и сохраняет явные хеши коммитов. +- easyp mod download загружает точные коммиты из lock и проверяет содержимое, не меняя зафиксированные версии. -`hash` вычисляется алгоритмом Go `dirhash.Hash1` по всем обычным файлам, отслеживаемым Git в коммите `commit`, с путями относительно корня репозитория. EasyP проверяет этот дайджест при скачивании и при чтении существующего кэша. Если нужного коммита в кэше нет, доступ к Git-репозиторию всё ещё необходим. +## Неизменность версий и кеш + +При tidy, get и update повторно полученный ранее зафиксированный SemVer сравнивается с его записанными коммитом и хешем. Перепубликованный тег вызывает ErrLockedVersionChanged до установки нового графа и записи манифеста или lock. Проверка действует и для транзитивных требований, независимо от прогретого кеша. Новую версию по-прежнему можно выбрать; неограниченные требования без версии обновляются при mod update. + +mod download использует коммит из lock даже после переноса тега, если этот коммит доступен. + +hash вычисляется через Go dirhash.Hash1 по всем обычным файлам, отслеживаемым Git в коммите, с путями относительно репозитория. Хеш проверяется и при скачивании, и при повторном использовании установленного модуля; повреждённая установка отклоняется. + +Для каждого Git remote кеш v1 повторно использует хранилище объектов. Известный точный коммит можно получить без обращения к remote. При холодном запросе сначала выполняется shallow-загрузка точного коммита с глубиной один; если сервер её отклоняет, используется доступная история объявленных ссылок. Всё равно требуется исходный коммит: HEAD вместо него не подставляется. Проверки тегов обновляются отдельно, поэтому кеш не скрывает перенос тега. Отсутствующий в кеше коммит всё ещё может потребовать доступа к источнику. diff --git a/content/docs/reference/protobuf-mod.mdx b/content/docs/reference/protobuf-mod.mdx index 410e2fb..ae2b83f 100644 --- a/content/docs/reference/protobuf-mod.mdx +++ b/content/docs/reference/protobuf-mod.mdx @@ -3,7 +3,7 @@ title: "protobuf.mod Reference" description: "Specification for protobuf.mod, the tool-neutral DSL for defining Protocol Buffer module identities, roots, requirements, and local replace directives." --- -The `protobuf.mod` file resides at the root of a Protocol Buffer module. Designed as a **tool-neutral standard**, it contains zero tool-specific settings (no linter flags, generator plugins, or vendor extensions). It is strictly focused on module identity, inner root directories, dependency requirements, and local source overrides. +The protobuf.mod file resides at the root of a Protocol Buffer module. Designed as a **tool-neutral standard**, it contains zero tool-specific settings (no linter flags, generator plugins, or vendor extensions). It is strictly focused on module identity, inner root directories, dependency requirements, and local source overrides. --- @@ -12,7 +12,7 @@ The `protobuf.mod` file resides at the root of a Protocol Buffer module. Designe ../weather-fork -``` +~~~ --- ## Behavior Rules -1. **Git-Native Identity**: The canonical identity of a module is its Git URL (e.g., `github.com/acme/weather`). -2. **Per-Module Bounds**: Every module maintains its own independent `protobuf.mod`. MVS operates per-module rather than forcing global monorepo single-version constraints. -3. **Replace Guardrail**: Local `replace` directives work during generation. `easyp get`, `easyp mod tidy`, and `easyp mod update` reject them until they are removed, so a reproducible Git lock never records a local path. +1. **Git-Native Identity**: The canonical identity of a module is its Git URL (e.g., github.com/acme/weather). +2. **Per-Module Bounds**: Every module maintains its own independent protobuf.mod. MVS operates per-module rather than forcing global monorepo single-version constraints. +3. **Replace Guardrail**: Local replace directives work during generation. easyp get, easyp mod tidy, and easyp mod update reject them until they are removed, so a reproducible Git lock never records a local path. -For multiple modules in one repository, put a `protobuf.mod` in each module directory. Run `easyp mod tidy` from each local module directory; each writes its own `protobuf.lock`. `generate.modules` can select local modules by repository-relative path or module identity. A consumer declares each nested Git module separately by its declared identity. For example, `require github.com/acme/contracts/proto/user` needs no tag or manually supplied commit: `mod tidy` finds the repository's current HEAD and records its exact commit in `protobuf.lock`. Repeating `tidy` preserves that commit; `mod update` refreshes a versionless requirement to the current HEAD. An explicitly supplied full 40- or 64-character commit stays pinned during update. SemVer requirements remain supported for tagged releases; a nested module tagged `v1.2.3` uses `proto/user/v1.2.3`, matching the [Go multi-module tag convention](https://go.dev/ref/mod#mapping-versions-to-commits). Each required module has its own lock entry and source roots. A local `replace` can target a nested module directory. +For multiple modules, place a protobuf.mod in each module directory. Module commands and get select the nearest ancestor manifest within the workspace; each module keeps its own protobuf.lock. generate.modules selects local modules by identity or workspace-relative path. A consumer declares each nested Git module separately by its manifest identity. -For example, with `repo/foo/protobuf.mod` containing `roots proto`, EasyP reads files under the physical repository path `repo/foo/proto`. A file at `repo/foo/proto/user/v1/user.proto` has the protobuf import path `user/v1/user.proto`: import paths are relative to the resolved root, so the module directory and the root directory are not repeated in imports. With `roots .`, the physical root is `repo/foo`. +A version may be omitted, for example require github.com/acme/contracts/proto/user. This adds no constraint if the graph already supplies a SemVer or exact commit. Only a still-unconstrained requirement uses the existing lock pin during tidy, or current HEAD without a pin; mod update refreshes it to HEAD. An explicit full 40- or 64-hex-character commit remains an exact constraint. + +SemVer requirements select the maximum requested minimum. SemVer and SHA requirements are compatible only when the selected tag points to that exact commit. Different explicit commits or a selected tag at another commit conflict; SHA values, dates, and commit ancestry are not given a semantic version order. For a nested module in proto/user, version v1.2.3 uses tag proto/user/v1.2.3. Each module has its own lock entry and roots. + +A local replace can target a nested module. Relative paths are resolved from the owning protobuf.mod; absolute paths are used directly, regardless of the generation consumer's directory. Breaking comparisons use revision-local contents for replacements inside the repository and reject external local replacements. + +For example, with repo/foo/protobuf.mod containing roots proto, EasyP reads files under the physical repository path repo/foo/proto. A file at repo/foo/proto/user/v1/user.proto has the protobuf import path user/v1/user.proto: import paths are relative to the resolved root, so the module directory and the root directory are not repeated in imports. With roots ., the physical root is repo/foo. diff --git a/content/docs/reference/protobuf-mod.ru.mdx b/content/docs/reference/protobuf-mod.ru.mdx index 8ad20b4..06d8534 100644 --- a/content/docs/reference/protobuf-mod.ru.mdx +++ b/content/docs/reference/protobuf-mod.ru.mdx @@ -3,7 +3,7 @@ title: "Справочник protobuf.mod" description: "Спецификация файла protobuf.mod, независимого от инструментов DSL для объявления идентичности модулей Protocol Buffer, корневых каталогов, зависимостей и локальных замен." --- -Файл `protobuf.mod` располагается в корне proto-модуля. Задуманный как **tool-neutral стандарт**, он не содержит настроек конкретных инструментов (ни флагов линтеров, ни плагинов генерации). Файл сфокусирован исключительно на идентификации модуля, внутренних директориях, объявлениях зависимостей и локальных переопределениях источников. +Файл protobuf.mod располагается в корне proto-модуля. Задуманный как **tool-neutral стандарт**, он не содержит настроек конкретных инструментов (ни флагов линтеров, ни плагинов генерации). Файл сфокусирован исключительно на идентификации модуля, внутренних директориях, объявлениях зависимостей и локальных переопределениях источников. --- @@ -12,7 +12,7 @@ description: "Спецификация файла protobuf.mod, независи ../weather-fork -``` +~~~ --- ## Правила поведения -1. **Git-Native идентичность**: Каноническим идентификатором модуля является его Git URL (`github.com/acme/weather`). -2. **Помодульный скоуп**: Каждый модуль имеет собственный `protobuf.mod`. MVS работает помодульно (per-module), не навязывая глобальных ограничений версий в монорепозитории. -3. **Защита lock-файла**: Локальный `replace` работает при генерации. `easyp get`, `easyp mod tidy` и `easyp mod update` отклоняют его до удаления, чтобы в воспроизводимый Git lock не попал локальный путь. +1. **Git-Native идентичность**: Каноническим идентификатором модуля является его Git URL (github.com/acme/weather). +2. **Помодульный скоуп**: Каждый модуль имеет собственный protobuf.mod. MVS работает помодульно (per-module), не навязывая глобальных ограничений версий в монорепозитории. +3. **Защита lock-файла**: Локальный replace работает при генерации. easyp get, easyp mod tidy и easyp mod update отклоняют его до удаления, чтобы в воспроизводимый Git lock не попал локальный путь. -Если в одном репозитории несколько модулей, разместите `protobuf.mod` в каталоге каждого. Запускайте `easyp mod tidy` из каталога каждого локального модуля: у каждого будет свой `protobuf.lock`. `generate.modules` выбирает локальные модули по пути относительно репозитория или по имени. Потребитель объявляет каждый вложенный Git-модуль отдельным требованием по имени из его манифеста. Например, для `require github.com/acme/contracts/proto/user` не нужны ни тег, ни вручную указанный коммит: `mod tidy` найдёт текущий HEAD репозитория и запишет точный коммит в `protobuf.lock`. Повторный `tidy` сохранит его; `mod update` обновит требование без версии до текущего HEAD. Явно указанный полный хеш коммита из 40 или 64 символов останется закреплённым при обновлении. SemVer-теги также поддерживаются: для вложенного модуля с версией `v1.2.3` тег называется `proto/user/v1.2.3` по [правилу Go для репозиториев с несколькими модулями](https://go.dev/ref/mod#mapping-versions-to-commits). У каждого требуемого модуля своя запись lock и корни исходников. Локальный `replace` может указывать на каталог вложенного модуля. +Для нескольких модулей положите protobuf.mod в каталог каждого. Команды mod и get выбирают ближайший манифест в предках в пределах workspace; каждый модуль сохраняет свой protobuf.lock. generate.modules выбирает локальные модули по имени или пути относительно workspace. В потребителе каждый вложенный Git-модуль объявляется отдельно по имени из его манифеста. -Например, если в `repo/foo/protobuf.mod` указано `roots proto`, EasyP читает файлы из физического пути `repo/foo/proto` внутри репозитория. У файла `repo/foo/proto/user/v1/user.proto` protobuf import path будет `user/v1/user.proto`: путь импорта считается относительно вычисленного root, поэтому каталог модуля и сам root в импорте не повторяются. При `roots .` физический root — `repo/foo`. +Версию можно опустить, например require github.com/acme/contracts/proto/user. Такое требование не добавляет ограничения, если граф уже задаёт SemVer или точный коммит. Только оставшееся неограниченным требование использует прежний коммит lock при tidy либо текущий HEAD без lock; mod update освежает его до HEAD. Явный полный хеш из 40 или 64 hex-символов остаётся точным ограничением. + +SemVer-требования выбирают максимум запрошенных минимумов. SemVer и SHA совместимы, только если выбранный тег указывает на этот точный коммит. Разные явные коммиты или выбранный тег на другом коммите вызывают конфликт; порядок версий из SHA, даты или истории коммитов не выводится. Для вложенного модуля в proto/user версия v1.2.3 использует тег proto/user/v1.2.3. У каждого модуля своя запись lock и корни. + +Локальный replace может указывать на вложенный модуль. Относительный путь считается от содержащего его protobuf.mod, абсолютный используется напрямую; каталог потребителя генерации не меняет эту базу. При breaking-сравнении замена внутри репозитория берётся из соответствующей ревизии, а внешняя локальная замена отклоняется. + +Например, если в repo/foo/protobuf.mod указано roots proto, EasyP читает файлы из физического пути repo/foo/proto внутри репозитория. У файла repo/foo/proto/user/v1/user.proto protobuf import path будет user/v1/user.proto: путь импорта считается относительно вычисленного root, поэтому каталог модуля и сам root в импорте не повторяются. При roots . физический root — repo/foo. From e99c80c33a2aec3f02079468713a37c1adcebd20 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 30 Sep 2026 15:47:15 +0300 Subject: [PATCH 15/26] docs(migrate): describe the terminal wizard and explicit consent Cover default-no prompts, Ctrl+C/EOF, unchanged files, independent dependency authorization, historical integrity, source edits, and preserved noninteractive usage. --- content/docs/cli/configuration.mdx | 2 ++ content/docs/cli/configuration.ru.mdx | 2 ++ content/docs/migration/easyp-v0.mdx | 20 +++++++++++++++++++- content/docs/migration/easyp-v0.ru.mdx | 20 +++++++++++++++++++- 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/content/docs/cli/configuration.mdx b/content/docs/cli/configuration.mdx index 5f60eee..2457307 100644 --- a/content/docs/cli/configuration.mdx +++ b/content/docs/cli/configuration.mdx @@ -14,6 +14,8 @@ The v1 pilot separates module dependencies, generation, and lint and breaking po The CLI commands use the v1 files directly. They do not fall back to the older EasyP generation, lint, breaking, or module-management configuration. A Git dependency can still use older EasyP or Buf configuration: the dependency reader extracts its requirements and proto roots for import resolution. +For guided v0 migration, run easyp migrate in a terminal. Explicit --interactive starts the wizard with supplied values; --interactive=false disables it. Supplying --module without requesting the wizard preserves the original preview. See [v0 migration](/docs/migration/easyp-v0). + ## Typical workflow ~~~bash diff --git a/content/docs/cli/configuration.ru.mdx b/content/docs/cli/configuration.ru.mdx index efeb0f2..24ac810 100644 --- a/content/docs/cli/configuration.ru.mdx +++ b/content/docs/cli/configuration.ru.mdx @@ -14,6 +14,8 @@ description: "Файлы и команды CLI пилотной версии Eas Команды CLI читают формат v1 напрямую и не переходят на старую логику генерации, линтинга, проверки совместимости или управления модулями. Зависимость в Git при этом может использовать старый формат EasyP или Buf: адаптер извлекает её требования и корни .proto для разрешения импортов. +Для интерактивного перехода с v0 выполните easyp migrate в терминале. Явный --interactive включает мастер с уже заданными параметрами, --interactive=false отключает его. Вызов с --module без включения мастера сохраняет прежний предварительный просмотр. См. [миграцию v0](/ru/docs/migration/easyp-v0). + ## Обычный порядок работы ~~~bash diff --git a/content/docs/migration/easyp-v0.mdx b/content/docs/migration/easyp-v0.mdx index b7fb93a..b7de173 100644 --- a/content/docs/migration/easyp-v0.mdx +++ b/content/docs/migration/easyp-v0.mdx @@ -5,13 +5,31 @@ description: "Preview-first migration that preserves configuration and verifies The v1 CLI does not execute the old combined configuration. Use the explicit migration command for supported, unambiguous v0 projects. Keep the project in version control and stop other writers before applying changes. +## Interactive terminal wizard + +~~~bash +# Starts the wizard when both input and output are terminals. +easyp migrate + +# Explicit wizard with prefilled values. +easyp migrate --interactive --dir . --module github.com/acme/contracts +~~~ + +The wizard asks for the project directory and module identity when those flags are omitted. An existing native manifest or the current directory's local Git origin can supply an identity suggestion; accepting a suggestion is still an explicit input step. This lookup does not contact a server or display Git credentials. + +It shows the actual candidate files before asking to proceed. When dependencies need verification, it asks separately for permission to resolve them and write their cache. After verification, it shows the complete plan, including the lock, and asks whether to apply it and create backups. Enter means **no** at both confirmations. Even prefilled --write and --resolve-lock do not bypass wizard confirmations. No plugin is executed. + +Declining, Ctrl+C or EOF before application leaves project files unchanged. Cache entries from previously authorized resolution may remain. A change to the project during the prompts is detected instead of silently overwriting it. The existing restrictions and multi-file crash boundary still apply. + +For compatibility, supplying --module without --interactive keeps the existing flag-only behavior, including in a terminal. --interactive=false explicitly disables prompting. Redirected input or output never triggers the wizard, and forced --interactive requires both streams to be terminals; a pipe of yes answers is not accepted as interactive consent. Scripts must supply --module and the relevant explicit flags. + ## Preview first ~~~bash easyp migrate --dir . --module github.com/acme/contracts ~~~ -Without --write, the command prints actual candidate files and warnings. It does not change the project or execute plugins. A plain preview does not resolve dependencies or write their cache. +In flag-only mode, without --write, the command prints actual candidate files and warnings. It does not change the project or execute plugins. A plain preview does not resolve dependencies or write their cache. The candidate files are easyp.yaml for policies, easyp.gen.yaml for generation, protobuf.mod for module metadata, and a verified protobuf.lock when dependency conversion is required. The supplied module identity is literal and must match the intended local module. diff --git a/content/docs/migration/easyp-v0.ru.mdx b/content/docs/migration/easyp-v0.ru.mdx index 64af196..7a6a8f0 100644 --- a/content/docs/migration/easyp-v0.ru.mdx +++ b/content/docs/migration/easyp-v0.ru.mdx @@ -5,13 +5,31 @@ description: "Миграция с предварительным просмот CLI v1 не исполняет старый объединённый конфиг. Для поддерживаемых однозначных v0-проектов предусмотрена отдельная команда миграции. Перед применением сохраните проект в Git и остановите другие процессы, изменяющие его файлы. +## Интерактивный мастер в терминале + +~~~bash +# Мастер запускается, когда ввод и вывод подключены к терминалу. +easyp migrate + +# Явный запуск с заранее заполненными значениями. +easyp migrate --interactive --dir . --module github.com/acme/contracts +~~~ + +Мастер запрашивает каталог проекта и идентификатор модуля, если они не переданы флагами. Он может предложить идентификатор из существующего native-manifest или локального Git origin текущего каталога; предложение всё равно нужно принять явно. Для этой подсказки нет обращения к серверу и не выводятся учётные данные Git. + +Сначала показывается фактическое содержимое будущих файлов. Если необходима проверка зависимостей, мастер отдельно запрашивает разрешение на их загрузку и проверку с записью кэша. Затем показывает полный проверенный план, включая lock, и спрашивает, применять ли его с созданием резервных копий. Enter означает **нет** в обоих подтверждениях. Даже заранее переданные --write и --resolve-lock не обходят подтверждения мастера. Плагины не запускаются. + +Отказ, Ctrl+C или EOF до применения оставляют файлы проекта неизменными. Кэш ранее разрешённой загрузки может сохраниться. Изменения проекта во время вопросов обнаруживаются, а не перезаписываются молча. Прежние ограничения миграции и граница атомарности при падении процесса сохраняются. + +Для совместимости --module без --interactive сохраняет прежнее поведение через флаги, в том числе в терминале. --interactive=false явно отключает вопросы. Перенаправленный ввод или вывод не запускает мастер автоматически; принудительный --interactive требует терминала для обоих потоков. Передача yes через pipe не считается интерактивным согласием. Скриптам нужно задавать --module и необходимые явные флаги. + ## Сначала предварительный просмотр ~~~bash easyp migrate --dir . --module github.com/acme/contracts ~~~ -Без --write команда показывает фактическое содержимое будущих файлов и предупреждения. Файлы проекта не меняются, плагины не запускаются. Обычный предварительный просмотр не разрешает зависимости и не записывает их кэш. +В режиме явных флагов без --write команда показывает фактическое содержимое будущих файлов и предупреждения. Файлы проекта не меняются, плагины не запускаются. Обычный предварительный просмотр не разрешает зависимости и не записывает их кэш. Подготавливаются easyp.yaml с политиками, easyp.gen.yaml с генерацией, protobuf.mod с метаданными модуля и проверенный protobuf.lock, когда требуется перенос зависимостей. Явно указанный идентификатор должен соответствовать локальному модулю. From 73d926050c6478e1eae7d6cfe161871f501ce7cd Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 30 Sep 2026 16:38:40 +0300 Subject: [PATCH 16/26] docs(v1): clarify import integrity and configuration validation Document nonzero listing errors, reachable imports, indirect promotion, exact managed value types, init terminal requirements and declared Git identity in both locales. Type checks and production webpack build passed. No publishing configuration changed. --- content/docs/cli/configuration.mdx | 8 ++++++++ content/docs/cli/configuration.ru.mdx | 8 ++++++++ content/docs/cli/package-manager/index.mdx | 6 ++++++ content/docs/cli/package-manager/index.ru.mdx | 6 ++++++ content/docs/reference/easyp-gen-yaml.mdx | 6 ++++++ content/docs/reference/easyp-gen-yaml.ru.mdx | 6 ++++++ 6 files changed, 40 insertions(+) diff --git a/content/docs/cli/configuration.mdx b/content/docs/cli/configuration.mdx index 2457307..51d7e48 100644 --- a/content/docs/cli/configuration.mdx +++ b/content/docs/cli/configuration.mdx @@ -102,3 +102,11 @@ breaking: ~~~ For the exact fields and current limits, use the linked reference pages above. + +## Errors and noninteractive use + +ls-files prints its complete JSON or text result, then exits with a nonzero status when import traversal reported an error. A JSON errors array is not a successful build. --include-imports=false deliberately lists only local files; it is not an import-integrity check. + +init never opens a hidden controlling terminal behind redirected input or output. Supply --module when no identity can be read locally. An origin-based identity comes from the declared Git remote URL, before transport-only insteadOf rewriting. Overwriting a different existing configuration requires terminal confirmation; piped answers are not accepted. + +Policy syntax and supported setting names are checked by execution as well as validate-config. A nonempty breaking baseline must have the git: prefix. Lint groups checked files by effective policy and module while preserving per-file exclusions and diagnostic order. diff --git a/content/docs/cli/configuration.ru.mdx b/content/docs/cli/configuration.ru.mdx index 24ac810..bed449b 100644 --- a/content/docs/cli/configuration.ru.mdx +++ b/content/docs/cli/configuration.ru.mdx @@ -102,3 +102,11 @@ breaking: ~~~ Точные поля и текущие ограничения описаны в справочниках по ссылкам выше. + +## Ошибки и неинтерактивный запуск + +ls-files сначала выводит полный JSON или текстовый результат, затем возвращает ненулевой код, если при обходе импортов обнаружена ошибка. Наличие массива errors не означает успешную проверку. --include-imports=false намеренно перечисляет только локальные файлы и не проверяет целостность импортов. + +init не открывает скрытый управляющий терминал при перенаправленных вводе или выводе. Укажите --module, если идентификатор невозможно получить локально. Идентификатор по origin берётся из объявленного Git URL до транспортной подстановки insteadOf. Перезапись отличающегося существующего конфига требует подтверждения в терминале; ответ из pipe не принимается. + +Синтаксис политики и поддерживаемые настройки проверяются и при исполнении команды, и в validate-config. Непустой breaking baseline должен начинаться с git:. Lint группирует файлы по действующей политике и модулю, сохраняя исключения отдельных файлов и порядок диагностики. diff --git a/content/docs/cli/package-manager/index.mdx b/content/docs/cli/package-manager/index.mdx index 02a1d81..9a7e68a 100644 --- a/content/docs/cli/package-manager/index.mdx +++ b/content/docs/cli/package-manager/index.mdx @@ -60,3 +60,9 @@ When adapting an older easyp.yaml, both deps and gener Buf Registry dependencies have no automatic Git identity. Declare the corresponding Git module in the consuming protobuf.mod when those imports are needed. Buf include/exclude filters are not supported as Git import roots and produce an explicit error. See [protobuf.mod](/docs/reference/protobuf-mod) and [protobuf.lock](/docs/reference/protobuf-lock) for their field-level formats. + +## Reachable imports and direct requirements + +Before writing a new manifest or lock, mod tidy checks the import closure reachable from the local module, including imports inside dependency files. Missing files and invalid reachable protobuf syntax stop the operation. Unrelated files in a dependency are not all compiled or linted. An import under google/protobuf/ must actually exist; the prefix alone does not make it a bundled file. + +When a local source starts importing a previously indirect module, tidy removes the existing // indirect marker while preserving its version and unrelated comments. This does not discover an arbitrary Git repository from an unknown proto path. Registry-specific Buf dependency identities still require explicit Git mapping and are not silently converted into repository URLs. diff --git a/content/docs/cli/package-manager/index.ru.mdx b/content/docs/cli/package-manager/index.ru.mdx index b1c893f..2a26c81 100644 --- a/content/docs/cli/package-manager/index.ru.mdx +++ b/content/docs/cli/package-manager/index.ru.mdx @@ -60,3 +60,9 @@ Git-зависимость может объявлять корни .proto Зависимости Buf Registry не имеют автоматического Git-идентификатора. Если их импорты нужны, объявите соответствующий Git-модуль в protobuf.mod потребителя. Фильтры Buf include/exclude для корней Git-зависимостей пока не поддерживаются и вызывают явную ошибку. Форматы полей описаны в справочниках [protobuf.mod](/ru/docs/reference/protobuf-mod) и [protobuf.lock](/ru/docs/reference/protobuf-lock). + +## Достижимые импорты и прямые зависимости + +Перед записью manifest и lock команда mod tidy проверяет цепочку импортов, достижимых из локального модуля, включая импорты внутри файлов зависимостей. Отсутствующие файлы и некорректный синтаксис достижимого protobuf останавливают операцию. Неиспользуемые файлы зависимости не компилируются и не проходят lint целиком. Импорт из google/protobuf/ должен действительно существовать: одного префикса недостаточно. + +Когда локальный исходник начинает импортировать ранее косвенную зависимость, tidy удаляет существующую пометку // indirect, сохраняя версию и остальные комментарии. Это не поиск произвольного Git-репозитория по неизвестному proto-пути. Идентификаторам зависимостей реестра Buf по-прежнему нужно явное соответствие Git-модулям; они не преобразуются в URL репозитория автоматически. diff --git a/content/docs/reference/easyp-gen-yaml.mdx b/content/docs/reference/easyp-gen-yaml.mdx index 5d977b0..c2455ba 100644 --- a/content/docs/reference/easyp-gen-yaml.mdx +++ b/content/docs/reference/easyp-gen-yaml.mdx @@ -181,3 +181,9 @@ The separate version field is also unavailable for patheasyp generate selects the closest config in the current directory or a workspace ancestor. Repeat --project to choose multiple consumers explicitly; --all separately opts into recursive selection. --workspace sets the boundary for module paths and inheritance. plugins[].with_imports defaults to false. True adds transitive imports to that plugin's files to generate. Import descriptors remain available for linking when false. The --descriptor_set_out and --descriptor_set_out_dir flags are mutually exclusive; --include_imports controls exported contents only, independently of with_imports. See [project selection and descriptor export](/docs/cli/generator). + +## Managed-option validation + +Both configuration validation and generation reject unknown managed file or field options and values of the wrong type. Boolean options such as java_multiple_files require a YAML boolean, not a quoted string. String options require strings. optimize_for accepts SPEED, CODE_SIZE or LITE_RUNTIME; jstype accepts JS_NORMAL, JS_STRING or JS_NUMBER. Invalid rules cannot silently fall back to managed defaults. + +Place a remote version in the separate version field, not after a colon in the final plugin path. A server port in the host is allowed. For example, use remote: localhost:8080/go with version: v1.2.3. diff --git a/content/docs/reference/easyp-gen-yaml.ru.mdx b/content/docs/reference/easyp-gen-yaml.ru.mdx index e905f25..daa3bd2 100644 --- a/content/docs/reference/easyp-gen-yaml.ru.mdx +++ b/content/docs/reference/easyp-gen-yaml.ru.mdx @@ -181,3 +181,9 @@ plugins: По умолчанию easyp generate выбирает ближайший конфиг в текущем или родительском каталоге workspace. Повторяйте --project для явного выбора нескольких потребителей; --all отдельно включает рекурсивный выбор. --workspace задаёт границу для путей модулей и наследования. plugins[].with_imports по умолчанию равен false. Значение true добавляет транзитивные импорты в список файлов для генерации только этого плагина. Дескрипторы импортов для связывания доступны и при false. Флаги --descriptor_set_out и --descriptor_set_out_dir взаимоисключающие; --include_imports меняет только содержимое экспорта, независимо от with_imports. См. [выбор проектов и экспорт дескрипторов](/ru/docs/cli/generator). + +## Проверка managed-опций + +Валидация конфигурации и генерация отклоняют неизвестные file/field options и значения неподходящего типа. Булевым опциям вроде java_multiple_files нужен YAML boolean, а не строка в кавычках. Строковым опциям нужны строки. optimize_for принимает SPEED, CODE_SIZE или LITE_RUNTIME; jstype — JS_NORMAL, JS_STRING или JS_NUMBER. Неверное правило не должно незаметно заменяться стандартными managed-настройками. + +Версию remote-плагина указывайте отдельным полем version, а не после двоеточия в последнем сегменте пути. Порт сервера в имени хоста допустим. Например, remote: localhost:8080/go вместе с version: v1.2.3. From 13cc0fb8615eb0618141ba10fdfa475890227ef1 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 30 Sep 2026 17:19:46 +0300 Subject: [PATCH 17/26] docs: explain safe recovery from cache and Git access errors --- content/docs/cli/package-manager/index.mdx | 6 ++++++ content/docs/cli/package-manager/index.ru.mdx | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/content/docs/cli/package-manager/index.mdx b/content/docs/cli/package-manager/index.mdx index 9a7e68a..2e50e8e 100644 --- a/content/docs/cli/package-manager/index.mdx +++ b/content/docs/cli/package-manager/index.mdx @@ -66,3 +66,9 @@ See [protobuf.mod](/docs/reference/protobuf-mod) and [protobu Before writing a new manifest or lock, mod tidy checks the import closure reachable from the local module, including imports inside dependency files. Missing files and invalid reachable protobuf syntax stop the operation. Unrelated files in a dependency are not all compiled or linted. An import under google/protobuf/ must actually exist; the prefix alone does not make it a bundled file. When a local source starts importing a previously indirect module, tidy removes the existing // indirect marker while preserving its version and unrelated comments. This does not discover an arbitrary Git repository from an unknown proto path. Registry-specific Buf dependency identities still require explicit Git mapping and are not silently converted into repository URLs. + +## Cache and revision-access errors + +A hash mismatch in an installed module identifies the exact cache directory. Preserve it for investigation or quarantine only that entry, then retry easyp mod download. Do not rewrite protobuf.lock to hide the mismatch; the command does not automatically delete or repair the cache. + +An inaccessible Git repository is not evidence that a tag is absent. If history was fetched but the pinned commit is unavailable, restore access to the original revision instead of substituting HEAD. Tag revalidation and integrity checks remain enabled; no automatic offline fallback is introduced. diff --git a/content/docs/cli/package-manager/index.ru.mdx b/content/docs/cli/package-manager/index.ru.mdx index 2a26c81..e4a0a61 100644 --- a/content/docs/cli/package-manager/index.ru.mdx +++ b/content/docs/cli/package-manager/index.ru.mdx @@ -66,3 +66,9 @@ Git-зависимость может объявлять корни .proto Перед записью manifest и lock команда mod tidy проверяет цепочку импортов, достижимых из локального модуля, включая импорты внутри файлов зависимостей. Отсутствующие файлы и некорректный синтаксис достижимого protobuf останавливают операцию. Неиспользуемые файлы зависимости не компилируются и не проходят lint целиком. Импорт из google/protobuf/ должен действительно существовать: одного префикса недостаточно. Когда локальный исходник начинает импортировать ранее косвенную зависимость, tidy удаляет существующую пометку // indirect, сохраняя версию и остальные комментарии. Это не поиск произвольного Git-репозитория по неизвестному proto-пути. Идентификаторам зависимостей реестра Buf по-прежнему нужно явное соответствие Git-модулям; они не преобразуются в URL репозитория автоматически. + +## Ошибки кэша и доступа к ревизии + +При несовпадении хеша установленного модуля ошибка указывает точный каталог кэша. Сначала сохраните его для расследования или изолируйте только эту запись, затем повторите easyp mod download. Не переписывайте protobuf.lock, чтобы скрыть несовпадение; команда сама не удаляет и не исправляет повреждённый кэш. + +Недоступность Git-репозитория не означает, что тег отсутствует. Когда история получена, но закреплённого коммита в ней нет, восстановите доступ к исходной ревизии вместо замены на HEAD. Проверка тегов и защита от изменения их содержимого сохраняются; автоматического перехода на офлайн-разрешение нет. From 62b6dd012356ecbfacda5944b3c7bcca99e7f199 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 30 Sep 2026 18:13:41 +0300 Subject: [PATCH 18/26] docs: feat(mod): isolate local replacement graphs from published locks --- content/docs/cli/configuration.mdx | 4 +-- content/docs/cli/configuration.ru.mdx | 4 +-- content/docs/cli/package-manager/index.mdx | 4 +-- content/docs/cli/package-manager/index.ru.mdx | 4 +-- content/docs/guides/debugging-replace.mdx | 25 +++++++++++-------- content/docs/guides/debugging-replace.ru.mdx | 25 +++++++++++-------- content/docs/guides/reproducibility.mdx | 2 +- content/docs/guides/reproducibility.ru.mdx | 2 +- content/docs/reference/protobuf-mod.mdx | 4 +-- content/docs/reference/protobuf-mod.ru.mdx | 4 +-- 10 files changed, 42 insertions(+), 36 deletions(-) diff --git a/content/docs/cli/configuration.mdx b/content/docs/cli/configuration.mdx index 51d7e48..f37d1fd 100644 --- a/content/docs/cli/configuration.mdx +++ b/content/docs/cli/configuration.mdx @@ -27,7 +27,7 @@ easyp lint --path proto easyp breaking --path proto --against main ~~~ -mod tidy resolves requirements and writes protobuf.lock. mod download fetches exactly the locked commits. mod update refreshes required versions within their current major versions, then updates the lock. Local replace directives work for generation and linting; remove them before mod tidy or mod update writes a reproducible lock. +Without replacements, mod tidy writes the lock, mod download installs pinned commits, and mod update refreshes requirements within their current major versions and updates the lock. With replace, commands use a local effective graph and preserve protobuf.lock byte-for-byte; a missing lock is not created. mod tidy also leaves the manifest unchanged. get and mod update may edit explicit requirements without adding fork-only transitives. mod download installs only needed unreplaced snapshots. Remove replacements and run mod tidy to produce a publishable lock. See [local replacements](/docs/guides/debugging-replace). ## Command flags @@ -66,7 +66,7 @@ easyp validate-config --cfg ./services --format json easyp validate-config --cfg ./services/api/easyp.gen.yaml ~~~ -mod vendor verifies the locked Git dependencies and copies their .proto files into easyp_vendor using their import paths. It replaces a previous vendor tree only after all files have been copied successfully. Duplicate import paths are errors. Run mod tidy first; local replace directives cannot be vendored. +mod vendor verifies the locked Git dependencies and copies their .proto files into easyp_vendor using their import paths. It replaces a previous vendor tree only after all files have been copied successfully. Duplicate import paths are errors. With local replace directives it copies the effective local and verified remote graph without changing the published lock. ls-files lists local .proto files from protobuf.mod roots. By default it also includes reachable imports from dependencies and bundled well-known protos, resolving dependencies through the v1 lock or local replacements. Use --include-imports=false to list only local files without resolving dependencies. JSON output contains files, roots, and any import errors. diff --git a/content/docs/cli/configuration.ru.mdx b/content/docs/cli/configuration.ru.mdx index bed449b..9938a80 100644 --- a/content/docs/cli/configuration.ru.mdx +++ b/content/docs/cli/configuration.ru.mdx @@ -27,7 +27,7 @@ easyp lint --path proto easyp breaking --path proto --against main ~~~ -mod tidy разрешает зависимости и записывает protobuf.lock. mod download скачивает только зафиксированные коммиты. mod update обновляет версии в пределах текущей мажорной версии и пересоздаёт lock. Локальные replace работают при генерации и линтинге; перед mod tidy или mod update их нужно убрать, чтобы получить воспроизводимый lock. +Без замен mod tidy записывает lock, mod download устанавливает зафиксированные коммиты, а mod update обновляет требования в пределах текущей мажорной версии и lock. При наличии replace команды работают с локальным эффективным графом и сохраняют protobuf.lock побайтно; отсутствующий lock не создаётся. mod tidy также не меняет манифест. get и mod update могут менять явные требования, но не добавляют транзитивные зависимости только из форка. mod download устанавливает только нужные незаменённые снимки. Для публикуемого lock удалите замены и выполните mod tidy. Подробнее: [локальные замены](/ru/docs/guides/debugging-replace). ## Флаги команд @@ -66,7 +66,7 @@ easyp validate-config --cfg ./services --format json easyp validate-config --cfg ./services/api/easyp.gen.yaml ~~~ -mod vendor проверяет зафиксированные Git-зависимости и копирует их .proto в easyp_vendor по import path. Старый каталог заменяется только после успешного копирования всех файлов. Совпадающие import path вызывают ошибку. Сначала выполните mod tidy; локальные replace нельзя вендорить. +mod vendor проверяет зафиксированные Git-зависимости и копирует их .proto в easyp_vendor по import path. Старый каталог заменяется только после успешного копирования всех файлов. Совпадающие import path вызывают ошибку. При наличии локальных replace копируется эффективный граф локальных и проверенных удалённых исходников без изменения опубликованного lock. ls-files показывает локальные .proto из корней protobuf.mod. По умолчанию команда также включает достижимые импорты из зависимостей и встроенных well-known proto, разрешая зависимости через v1 lock или локальные замены. --include-imports=false показывает только локальные файлы без разрешения зависимостей. В JSON есть поля files, roots и, при проблемах с импортами, errors. diff --git a/content/docs/cli/package-manager/index.mdx b/content/docs/cli/package-manager/index.mdx index 2e50e8e..e13d20f 100644 --- a/content/docs/cli/package-manager/index.mdx +++ b/content/docs/cli/package-manager/index.mdx @@ -21,7 +21,7 @@ require ( A versionless requirement adds no constraint when the graph supplies a SemVer or exact commit. Only a still-unconstrained requirement uses current HEAD on the first mod tidy; subsequent tidy runs preserve the lock pin, while mod update refreshes HEAD. Explicit commits stay pinned. -replace module => ../local-copy points generation and linting at a local directory. Relative paths use the owning protobuf.mod directory; absolute paths are used directly. Remove local replacements before get, mod tidy, or mod update writes a reproducible Git lock. +replace module => ../local-copy applies only from the main protobuf.mod, including to transitive requirements. All relative replacement paths use the main manifest directory; absolute paths are used directly. With replace, commands use a local effective graph and preserve protobuf.lock byte-for-byte; a missing lock is not created. mod tidy also leaves the manifest unchanged. get and mod update may edit explicit requirements without adding fork-only transitives. mod download installs only needed unreplaced snapshots. Remove replacements and run mod tidy to produce a publishable lock. See [local replacements](/docs/guides/debugging-replace). For a Git repository with several manifests, require each nested module separately by its identity. For example, require repo/foo and require repo/bar need no module-specific tags if HEAD is suitable. A v1.2.3 release of the module in foo/ uses tag foo/v1.2.3. Each module's roots are resolved independently. @@ -43,7 +43,7 @@ easyp mod vendor easyp generate ~~~ -Commit protobuf.mod and protobuf.lock for repeatable builds. The module cache is under $HOME/.easyp/v1/git by default; set EASYPPATH to change its parent directory. mod vendor requires the lock and rejects local replacements and duplicate import paths. The easyp_vendor directory is a copy of dependency sources, not a replacement for the lock. +Commit protobuf.mod and protobuf.lock for repeatable builds. The module cache is under $HOME/.easyp/v1/git by default; set EASYPPATH to change its parent directory. Without replacements, mod vendor uses the published lock. With replacements it snapshots the effective graph without writing that lock. Duplicate import paths are errors. The easyp_vendor directory is a copy of dependency sources, not a replacement for the lock. ## Immutable tags and cache reuse diff --git a/content/docs/cli/package-manager/index.ru.mdx b/content/docs/cli/package-manager/index.ru.mdx index e4a0a61..143f0e3 100644 --- a/content/docs/cli/package-manager/index.ru.mdx +++ b/content/docs/cli/package-manager/index.ru.mdx @@ -21,7 +21,7 @@ require ( Требование без версии не ограничивает выбор, если в графе есть SemVer или точный коммит. Только оставшееся неограниченным требование использует текущий HEAD при первом mod tidy; следующие tidy сохраняют lock, а mod update освежает HEAD. Явные коммиты остаются закреплёнными. -replace module => ../local-copy направляет генерацию и линтинг на локальный каталог. Относительный путь считается от владеющего protobuf.mod, абсолютный используется напрямую. Уберите локальные замены перед get, mod tidy или mod update, записывающими воспроизводимый Git lock. +replace module => ../local-copy применяется только из главного protobuf.mod, в том числе к транзитивным требованиям. Все относительные пути замены считаются от главного манифеста; абсолютные используются напрямую. При наличии replace команды работают с локальным эффективным графом и сохраняют protobuf.lock побайтно; отсутствующий lock не создаётся. mod tidy также не меняет манифест. get и mod update могут менять явные требования, но не добавляют транзитивные зависимости только из форка. mod download устанавливает только нужные незаменённые снимки. Для публикуемого lock удалите замены и выполните mod tidy. Подробнее: [локальные замены](/ru/docs/guides/debugging-replace). Если в Git-репозитории несколько манифестов, объявляйте каждый вложенный модуль отдельно по его имени. Например, require repo/foo и require repo/bar не требуют отдельных тегов, если HEAD подходит. Для релиза v1.2.3 модуля в foo/ используется тег foo/v1.2.3. Корни каждого модуля разрешаются независимо. @@ -43,7 +43,7 @@ easyp mod vendor easyp generate ~~~ -Храните protobuf.mod и protobuf.lock в репозитории для воспроизводимой сборки. Кеш по умолчанию расположен в $HOME/.easyp/v1/git; переменная EASYPPATH меняет его родительский каталог. mod vendor требует lock и отклоняет локальные замены и повторяющиеся import path. Каталог easyp_vendor — копия исходников зависимостей, а не замена lock-файла. +Храните protobuf.mod и protobuf.lock в репозитории для воспроизводимой сборки. Кеш по умолчанию расположен в $HOME/.easyp/v1/git; переменная EASYPPATH меняет его родительский каталог. Без замен mod vendor использует опубликованный lock. С заменами он копирует эффективный граф без изменения lock. Повторяющиеся import path отклоняются. Каталог easyp_vendor — копия исходников зависимостей, а не замена lock-файла. ## Неизменность тегов и повторное использование кеша diff --git a/content/docs/guides/debugging-replace.mdx b/content/docs/guides/debugging-replace.mdx index ebf9c73..fbb3f77 100644 --- a/content/docs/guides/debugging-replace.mdx +++ b/content/docs/guides/debugging-replace.mdx @@ -20,7 +20,7 @@ require ( replace github.com/acme/weather => ../weather-fork ~~~ -The relative replacement path is resolved from the directory containing this protobuf.mod, so it points to proto/weather-fork, regardless of the shell's working directory. Keep the replacement's module roots and imports valid. +The relative replacement path is resolved from the directory containing this protobuf.mod, so it points to proto/weather-fork, regardless of the shell's working directory. Absolute paths also work. The replacement's native protobuf.mod must declare github.com/acme/weather; a missing directory or mismatched identity is an error. ## Local Development Workflow @@ -30,19 +30,22 @@ With a generator file in proto/user, run from the repository root: easyp generate --project ./proto/user ~~~ -Generation uses the replacement's local sources for the replaced dependency. You can iterate on both schemas without publishing a new dependency tag for every edit. +Only the main consumer's replacements apply, at every depth of the required graph. EasyP reads the replacement's protobuf.mod requirements and source roots; dependency-owned replacements are ignored. Relative paths always use the main manifest directory. A replacement alone does not add a dependency, and unused replacements are not read or fetched. Ordinary dependency cycles are deduplicated. Legacy dependency metadata remains supported through the existing compatibility reader; dependency plugins are not executed. - -Dependency downloads are unnecessary only when the whole dependency graph is local or already in verified cache. One local replacement does not make unreplaced dependencies or their transitive imports local. Required remote dependencies still need valid locks and may need downloads; remote plugins still need network access. - +Generate, selected dependency generation, both descriptor export modes, lint, ls-files and breaking import resolution use this same effective graph. Replaced modules need no remote fetch and may be unpublished. A fully local graph works offline without a lock. -## Reproducible Lock Guardrail +## Local Mode and the Published Lock - -easyp mod tidy and easyp mod update explicitly reject active local replacements, even when generation can run with them. Remove the replacements before resolving a reproducible dependency lock. - +While the main manifest contains replacements, EasyP leaves an existing protobuf.lock **byte-for-byte unchanged** and does not create one if absent. Local paths, local versions/hashes and fork-only transitive dependencies never enter the shared lock. This is an explicit EasyP invariant: protobuf.lock is not go.sum, and this does not mean Go never updates go.sum with replacements. The main-module replacement semantics follow [Go's replacement model](https://go.dev/ref/mod#go-mod-file-replace). -These are mutating dependency commands, not read-only CI checks. Use easyp mod download to install and verify an already prepared lock; it is not a blanket check forbidding local replacements. Review the manifest before release. +- mod tidy resolves and validates the effective graph and installs needed remote snapshots without editing the manifest or lock. +- get may edit the explicitly requested requirement. mod update refreshes unreplaced direct requirements using the existing version rules; replaced requirements keep their declared versions without a remote lookup. Neither command promotes fork-only transitives or writes a lock. +- mod download verifies/installs only needed unreplaced snapshots. It can resolve new remote requirements of the fork without adding them to the shared lock; replaced roots and unused lock entries are not downloaded. +- mod vendor copies current local and verified remote sources into easyp_vendor without writing the lock. This local artifact does not prove published reproducibility. + + +The effective graph exists only in memory. Matching published revisions and versionless pins use verified cached snapshots. A new remote requirement of a fork can need network access for resolution and installation; immutable-version and content checks still apply. Remote plugins also retain their network requirements. + ### Preparing for PR Submission @@ -52,4 +55,4 @@ These are mutating dependency commands, not read-only CI checks. Use easyp 4. Run easyp mod tidy in that module to update protobuf.lock. 5. Regenerate the selected project, run consumer tests, and commit the reviewed manifest, lock, and generated changes. -For breaking checks, replacements inside the Git repository use each revision's own contents. External local replacements are rejected because the baseline has no recoverable historical copy. See [breaking checks](/docs/cli/breaking-changes). +For breaking checks, replacements inside the Git repository use each revision's own contents. External local replacements are rejected because the baseline has no recoverable historical copy. A versionless remote requirement from a historical fork needs a historical lock pin; current HEAD cannot substitute for the baseline. See [breaking checks](/docs/cli/breaking-changes). diff --git a/content/docs/guides/debugging-replace.ru.mdx b/content/docs/guides/debugging-replace.ru.mdx index a6278b0..e2b3244 100644 --- a/content/docs/guides/debugging-replace.ru.mdx +++ b/content/docs/guides/debugging-replace.ru.mdx @@ -20,7 +20,7 @@ require ( replace github.com/acme/weather => ../weather-fork ~~~ -Относительный путь замены отсчитывается от каталога с этим protobuf.mod и указывает на proto/weather-fork независимо от рабочего каталога shell. Корни модуля и импорты замены должны оставаться корректными. +Относительный путь замены отсчитывается от каталога с этим protobuf.mod и указывает на proto/weather-fork независимо от рабочего каталога shell. Абсолютные пути также поддерживаются. Нативный protobuf.mod замены должен объявлять github.com/acme/weather; отсутствие каталога или несовпадение имени вызывает ошибку. ## Процесс локальной разработки @@ -30,19 +30,22 @@ replace github.com/acme/weather => ../weather-fork easyp generate --project ./proto/user ~~~ -Генерация использует локальные исходники заменённой зависимости. Можно менять обе схемы, не публикуя новый тег зависимости после каждой правки. +Применяются только замены главного модуля-потребителя, на любой глубине требуемого графа. EasyP читает требования и корни из protobuf.mod замены, но игнорирует директивы замены в зависимостях. Относительные пути всегда считаются от главного манифеста. Сама директива замены не добавляет зависимость; неиспользуемые замены не читаются и не скачиваются. Обычные циклы зависимостей обходятся без повторной обработки. Старые метаданные поддерживаются существующим адаптером совместимости; плагины зависимостей не запускаются. - -Загрузки зависимостей не нужны, только если весь граф локальный или уже находится в проверенном кеше. Одна локальная замена не делает локальными остальные зависимости и их транзитивные импорты. Нужным удалённым зависимостям по-прежнему требуются корректные lock-файлы и, возможно, загрузки; удалённым плагинам нужна сеть. - +Генерация, выбор зависимостей для генерации, оба режима экспорта дескрипторов, lint, ls-files и разрешение импортов breaking используют один эффективный граф. Заменённые модули не требуют удалённой загрузки и могут быть неопубликованными. Полностью локальный граф работает офлайн без lock-файла. -## Защита воспроизводимого lock-файла +## Локальный режим и публикуемый lock - -easyp mod tidy и easyp mod update явно отклоняют активные локальные замены, даже если генерация с ними работает. Перед разрешением воспроизводимого lock-файла зависимостей удалите замены. - +Пока в главном манифесте есть замены, EasyP оставляет существующий protobuf.lock **побайтно неизменным**, а отсутствующий не создаёт. Локальные пути, версии/хеши и транзитивные зависимости только из форка не попадают в общий lock. Это явный инвариант EasyP: protobuf.lock не является go.sum, и это не утверждение, что Go никогда не меняет go.sum при заменах. Правила применения замен главного модуля следуют [модели Go](https://go.dev/ref/mod#go-mod-file-replace). -Эти команды изменяют зависимости, а не выполняют проверку CI только для чтения. Для установки и проверки подготовленного lock используйте easyp mod download; команда не является универсальным запретом локальных замен. Проверяйте манифест перед релизом. +- mod tidy разрешает и проверяет эффективный граф и устанавливает нужные удалённые снимки без изменения манифеста или lock. +- get может изменить явно запрошенное требование. mod update обновляет незаменённые прямые требования по прежним правилам версий; заменённые требования сохраняют объявленные версии без удалённого поиска. Обе команды не добавляют транзитивные зависимости только из форка и не записывают lock. +- mod download проверяет/устанавливает только нужные незаменённые снимки. Новые удалённые требования форка разрешаются без записи в общий lock; заменённые модули и неиспользуемые записи lock не скачиваются. +- mod vendor копирует текущие локальные и проверенные удалённые исходники в easyp_vendor, не меняя lock. Этот локальный артефакт не доказывает воспроизводимость опубликованного графа. + + +Эффективный граф существует только в памяти. Совпадающие опубликованные ревизии и pins требований без версии используют проверенные снимки кеша. Для нового удалённого требования форка может понадобиться сеть при разрешении и установке; проверки неизменности версий и содержимого сохраняются. Удалённые плагины также могут требовать сеть. + ### Подготовка к отправке PR @@ -52,4 +55,4 @@ easyp generate --project ./proto/user 4. В этом модуле запустите easyp mod tidy для обновления protobuf.lock. 5. Повторите генерацию выбранного проекта, запустите тесты потребителей и закоммитьте проверенные изменения манифеста, lock и сгенерированных файлов. -При breaking-проверках замены внутри Git-репозитория используют содержимое соответствующей ревизии. Внешние локальные замены отклоняются: у базы нет восстановимой исторической копии. См. [breaking-проверки](/ru/docs/cli/breaking-changes). +При breaking-проверках замены внутри Git-репозитория используют содержимое соответствующей ревизии. Внешние локальные замены отклоняются: у базы нет восстановимой исторической копии. Удалённому требованию без версии из исторического форка нужен pin в историческом lock: текущий HEAD не подставляется вместо базы. См. [breaking-проверки](/ru/docs/cli/breaking-changes). diff --git a/content/docs/guides/reproducibility.mdx b/content/docs/guides/reproducibility.mdx index 9ea8493..876cc18 100644 --- a/content/docs/guides/reproducibility.mdx +++ b/content/docs/guides/reproducibility.mdx @@ -35,7 +35,7 @@ Adapt gen to your tracked output directories. The second command ca A local replace redirects one dependency to disk. It avoids dependency downloads only when the whole dependency graph is local or already present in verified cache. Unreplaced dependencies can still require downloads, and a remote generator still needs network access. -Local replacement contents are editable and are not pinned by a reproducible dependency lock. easyp mod tidy and easyp mod update explicitly reject active local replacements. Remove replacements and publish the intended versions before resolving a release lock. +Local replacement contents are editable and are not pinned by the published dependency lock. With replacements, mod tidy validates an ephemeral effective graph and leaves the shared manifest/lock unchanged; get/mod update may edit explicit requirements but never write a local-graph lock. Remove replacements and publish the intended versions, then run mod tidy to resolve a release lock. ## CI Practices diff --git a/content/docs/guides/reproducibility.ru.mdx b/content/docs/guides/reproducibility.ru.mdx index 0f13799..3a45246 100644 --- a/content/docs/guides/reproducibility.ru.mdx +++ b/content/docs/guides/reproducibility.ru.mdx @@ -35,7 +35,7 @@ test -z "$(git ls-files --others --exclude-standard -- gen)" Локальный replace перенаправляет одну зависимость на диск. Загрузки зависимостей не нужны, только если весь граф локальный или уже находится в проверенном кеше. Незаменённым зависимостям всё ещё может потребоваться загрузка, а удалённому генератору — сеть. -Содержимое локальных замен изменяемо и не фиксируется воспроизводимым lock-файлом. easyp mod tidy и easyp mod update явно отклоняют активные локальные замены. Уберите замены и опубликуйте нужные версии до разрешения lock для релиза. +Содержимое локальных замен изменяемо и не записывается в опубликованный lock. При наличии замен mod tidy проверяет временный эффективный граф без изменения manifest и lock; get/mod update могут менять явные требования, но не записывают lock локального графа. Уберите замены, опубликуйте нужные версии и выполните mod tidy, чтобы получить lock для релиза. ## Практика CI diff --git a/content/docs/reference/protobuf-mod.mdx b/content/docs/reference/protobuf-mod.mdx index ae2b83f..0af3213 100644 --- a/content/docs/reference/protobuf-mod.mdx +++ b/content/docs/reference/protobuf-mod.mdx @@ -63,7 +63,7 @@ replace github.com/acme/weather => ../weather-fork 1. **Git-Native Identity**: The canonical identity of a module is its Git URL (e.g., github.com/acme/weather). 2. **Per-Module Bounds**: Every module maintains its own independent protobuf.mod. MVS operates per-module rather than forcing global monorepo single-version constraints. -3. **Replace Guardrail**: Local replace directives work during generation. easyp get, easyp mod tidy, and easyp mod update reject them until they are removed, so a reproducible Git lock never records a local path. +3. **Local replacements**: Only main-module directives apply, including to transitive requirements; dependency-owned replacements are ignored. A replacement alone does not introduce a module. With replace, commands use a local effective graph and preserve protobuf.lock byte-for-byte; a missing lock is not created. mod tidy also leaves the manifest unchanged. get and mod update may edit explicit requirements without adding fork-only transitives. mod download installs only needed unreplaced snapshots. Remove replacements and run mod tidy to produce a publishable lock. See [local replacements](/docs/guides/debugging-replace). For multiple modules, place a protobuf.mod in each module directory. Module commands and get select the nearest ancestor manifest within the workspace; each module keeps its own protobuf.lock. generate.modules selects local modules by identity or workspace-relative path. A consumer declares each nested Git module separately by its manifest identity. @@ -71,6 +71,6 @@ A version may be omitted, for example require github.com/acme/contracts/pr SemVer requirements select the maximum requested minimum. SemVer and SHA requirements are compatible only when the selected tag points to that exact commit. Different explicit commits or a selected tag at another commit conflict; SHA values, dates, and commit ancestry are not given a semantic version order. For a nested module in proto/user, version v1.2.3 uses tag proto/user/v1.2.3. Each module has its own lock entry and roots. -A local replace can target a nested module. Relative paths are resolved from the owning protobuf.mod; absolute paths are used directly, regardless of the generation consumer's directory. Breaking comparisons use revision-local contents for replacements inside the repository and reject external local replacements. +A local replace may target a nested module directory. Its native manifest must declare the replaced identity, and its requirements participate in the effective graph. Relative paths always use the main manifest directory, even at transitive depths; absolute paths are used directly. Historical breaking comparisons map in-repository replacements to the corresponding revision snapshot and reject external local paths. Preserving the lock is an explicit EasyP invariant, not a claim that Go never changes go.sum. For example, with repo/foo/protobuf.mod containing roots proto, EasyP reads files under the physical repository path repo/foo/proto. A file at repo/foo/proto/user/v1/user.proto has the protobuf import path user/v1/user.proto: import paths are relative to the resolved root, so the module directory and the root directory are not repeated in imports. With roots ., the physical root is repo/foo. diff --git a/content/docs/reference/protobuf-mod.ru.mdx b/content/docs/reference/protobuf-mod.ru.mdx index 06d8534..d796537 100644 --- a/content/docs/reference/protobuf-mod.ru.mdx +++ b/content/docs/reference/protobuf-mod.ru.mdx @@ -63,7 +63,7 @@ replace github.com/acme/weather => ../weather-fork 1. **Git-Native идентичность**: Каноническим идентификатором модуля является его Git URL (github.com/acme/weather). 2. **Помодульный скоуп**: Каждый модуль имеет собственный protobuf.mod. MVS работает помодульно (per-module), не навязывая глобальных ограничений версий в монорепозитории. -3. **Защита lock-файла**: Локальный replace работает при генерации. easyp get, easyp mod tidy и easyp mod update отклоняют его до удаления, чтобы в воспроизводимый Git lock не попал локальный путь. +3. **Локальные замены**: Применяются только директивы главного модуля, включая транзитивные требования; замены в зависимостях игнорируются. Сама замена не добавляет модуль в граф. При наличии replace команды работают с локальным эффективным графом и сохраняют protobuf.lock побайтно; отсутствующий lock не создаётся. mod tidy также не меняет манифест. get и mod update могут менять явные требования, но не добавляют транзитивные зависимости только из форка. mod download устанавливает только нужные незаменённые снимки. Для публикуемого lock удалите замены и выполните mod tidy. Подробнее: [локальные замены](/ru/docs/guides/debugging-replace). Для нескольких модулей положите protobuf.mod в каталог каждого. Команды mod и get выбирают ближайший манифест в предках в пределах workspace; каждый модуль сохраняет свой protobuf.lock. generate.modules выбирает локальные модули по имени или пути относительно workspace. В потребителе каждый вложенный Git-модуль объявляется отдельно по имени из его манифеста. @@ -71,6 +71,6 @@ replace github.com/acme/weather => ../weather-fork SemVer-требования выбирают максимум запрошенных минимумов. SemVer и SHA совместимы, только если выбранный тег указывает на этот точный коммит. Разные явные коммиты или выбранный тег на другом коммите вызывают конфликт; порядок версий из SHA, даты или истории коммитов не выводится. Для вложенного модуля в proto/user версия v1.2.3 использует тег proto/user/v1.2.3. У каждого модуля своя запись lock и корни. -Локальный replace может указывать на вложенный модуль. Относительный путь считается от содержащего его protobuf.mod, абсолютный используется напрямую; каталог потребителя генерации не меняет эту базу. При breaking-сравнении замена внутри репозитория берётся из соответствующей ревизии, а внешняя локальная замена отклоняется. +Локальный replace может указывать на каталог вложенного модуля. Его нативный манифест должен объявлять заменяемое имя; требования замены участвуют в эффективном графе. Относительные пути всегда считаются от главного манифеста, даже на транзитивной глубине; абсолютные используются напрямую. Для исторических breaking-сравнений пути внутри репозитория отображаются в снимок соответствующей ревизии, внешние локальные пути отклоняются. Сохранение lock — явный инвариант EasyP, а не утверждение, что Go никогда не меняет go.sum. Например, если в repo/foo/protobuf.mod указано roots proto, EasyP читает файлы из физического пути repo/foo/proto внутри репозитория. У файла repo/foo/proto/user/v1/user.proto protobuf import path будет user/v1/user.proto: путь импорта считается относительно вычисленного root, поэтому каталог модуля и сам root в импорте не повторяются. При roots . физический root — repo/foo. From 5635b50cee6875334443e2fb2bcac129f3146077 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 30 Sep 2026 18:36:06 +0300 Subject: [PATCH 19/26] docs: feat: enforce explicit frozen dependency graphs --- content/docs/cli/configuration.mdx | 24 ++++++++++++++++--- content/docs/cli/configuration.ru.mdx | 24 ++++++++++++++++--- content/docs/cli/generator/index.mdx | 13 ++++++++++ content/docs/cli/generator/index.ru.mdx | 13 ++++++++++ content/docs/cli/package-manager/index.mdx | 21 ++++++++++++++++ content/docs/cli/package-manager/index.ru.mdx | 21 ++++++++++++++++ content/docs/guides/reproducibility.mdx | 9 +++++++ content/docs/guides/reproducibility.ru.mdx | 9 +++++++ 8 files changed, 128 insertions(+), 6 deletions(-) diff --git a/content/docs/cli/configuration.mdx b/content/docs/cli/configuration.mdx index f37d1fd..4ac8a1c 100644 --- a/content/docs/cli/configuration.mdx +++ b/content/docs/cli/configuration.mdx @@ -29,6 +29,24 @@ easyp breaking --path proto --against main Without replacements, mod tidy writes the lock, mod download installs pinned commits, and mod update refreshes requirements within their current major versions and updates the lock. With replace, commands use a local effective graph and preserve protobuf.lock byte-for-byte; a missing lock is not created. mod tidy also leaves the manifest unchanged. get and mod update may edit explicit requirements without adding fork-only transitives. mod download installs only needed unreplaced snapshots. Remove replacements and run mod tidy to produce a publishable lock. See [local replacements](/docs/guides/debugging-replace). +## Explicit frozen mode + +Use --frozen for builds that must use the committed dependency graph. It defaults to false and is never inferred from CI=true. Every selected native module whose dependency graph is used needs both protobuf.mod and protobuf.lock, including an empty lock when there are no dependencies. An explicit workspace-relative generate.modules path uses the selected module's manifest and lock, so a directory containing only easyp.gen.yaml needs no separate pair. Dependency identity selectors still require the consumer manifest and lock. The manifest-free source fallback described below applies only without frozen mode. + +~~~bash +easyp --frozen generate +easyp lint --frozen --path proto +easyp breaking --frozen --against main +easyp mod --frozen download +easyp mod vendor --frozen +~~~ + +The flag is accepted globally before the command; locally on generate, lint, breaking, ls-files, get, init, and migrate; and on mod or any of its four subcommands. A true value at any parent or command level enables it. A child --frozen=false cannot cancel a parent's true value. + +Frozen rejects every root replace, even unused entries, before accessing replacement paths or fetching dependencies. It checks direct and transitive requirements against the lock and verifies cached content. It never resolves versions, looks up dependency HEAD/tags, or writes either manifest or lock. Missing or stale locks cause an error. Exact locked commits may still be fetched into the cache: frozen is not offline. + +mod tidy, get, mod update, init, and migrate refuse frozen execution; migration preview and interactive mode are also refused. Prepare the files outside frozen mode. Generation checks every selected graph before any plugin runs. Lint keeps effective policy scoping; breaking uses the baseline revision's own manifest and lock. Local-only ls-files --include-imports=false still validates the frozen graph. See the [package manager](/docs/cli/package-manager#frozen-builds) for the full dependency contract. + ## Command flags | Command | Relevant flags | @@ -38,11 +56,11 @@ Without replacements, mod tidy writes the lock, mod download< | breaking | --path (-p), --root (-r), --against | | init | --dir (-d), --module | | validate-config | --config (alias of --cfg), --format | -| mod vendor | No command-specific flags | +| mod download/tidy/vendor/update | --frozen | | ls-files | --include-imports (default true), --format (json or text) | | schema-gen | --out-dir (default schemas) | -The global flags are --cfg (alias --config, default easyp.yaml), --debug (-d), and --format (-f, text or json). EASYP_CFG, EASYP_DEBUG, and EASYP_FORMAT set their respective defaults. The module cache uses EASYPPATH or $HOME/.easyp. +The global flags are --cfg (alias --config, default easyp.yaml), --debug (-d), --format (-f, text or json), and --frozen. EASYP_CFG, EASYP_DEBUG, and EASYP_FORMAT set their respective defaults. The module cache uses EASYPPATH or $HOME/.easyp. By default, generate selects the closest easyp.gen.yaml in the current directory or a workspace ancestor. Repeat --project for multiple explicit consumers. --all separately opts into recursive selection below the invocation directory and is mutually exclusive with --project. --workspace sets the boundary for module paths and inheritance; by default this is the nearest Git repository or enclosing EasyP files. Modules and roots come from protobuf.mod; generate.packages is reserved and rejects nonempty values. The generate --path and generate --root flags are unavailable. @@ -68,7 +86,7 @@ easyp validate-config --cfg ./services/api/easyp.gen.yaml mod vendor verifies the locked Git dependencies and copies their .proto files into easyp_vendor using their import paths. It replaces a previous vendor tree only after all files have been copied successfully. Duplicate import paths are errors. With local replace directives it copies the effective local and verified remote graph without changing the published lock. -ls-files lists local .proto files from protobuf.mod roots. By default it also includes reachable imports from dependencies and bundled well-known protos, resolving dependencies through the v1 lock or local replacements. Use --include-imports=false to list only local files without resolving dependencies. JSON output contains files, roots, and any import errors. +ls-files lists local .proto files from protobuf.mod roots. By default it also includes reachable imports from dependencies and bundled well-known protos, resolving dependencies through the v1 lock or local replacements. Use --include-imports=false to list only local files; outside frozen mode this skips dependency resolution. JSON output contains files, roots, and any import errors. schema-gen --out-dir schemas writes separate JSON Schemas for easyp.yaml, easyp.gen.yaml, and protobuf.lock, each with a -v1.schema.json filename and an unversioned alias. protobuf.mod is a text manifest, so validate it with validate-config instead. CLI validation also checks semantic rules beyond the JSON Schemas. diff --git a/content/docs/cli/configuration.ru.mdx b/content/docs/cli/configuration.ru.mdx index 9938a80..d8c076a 100644 --- a/content/docs/cli/configuration.ru.mdx +++ b/content/docs/cli/configuration.ru.mdx @@ -29,6 +29,24 @@ easyp breaking --path proto --against main Без замен mod tidy записывает lock, mod download устанавливает зафиксированные коммиты, а mod update обновляет требования в пределах текущей мажорной версии и lock. При наличии replace команды работают с локальным эффективным графом и сохраняют protobuf.lock побайтно; отсутствующий lock не создаётся. mod tidy также не меняет манифест. get и mod update могут менять явные требования, но не добавляют транзитивные зависимости только из форка. mod download устанавливает только нужные незаменённые снимки. Для публикуемого lock удалите замены и выполните mod tidy. Подробнее: [локальные замены](/ru/docs/guides/debugging-replace). +## Явный режим frozen + +Используйте --frozen, когда сборка должна опираться на сохранённый граф зависимостей. По умолчанию флаг выключен; CI=true его не включает. Каждому выбранному native-модулю, чей граф зависимостей используется, нужны protobuf.mod и protobuf.lock, в том числе пустой lock при отсутствии зависимостей. Явный путь от workspace в generate.modules использует манифест и lock выбранного модуля; каталогу только с easyp.gen.yaml отдельная пара не нужна. Выбор зависимости по идентификатору по-прежнему требует манифест и lock потребителя. Описанный ниже запуск исходников без манифеста доступен только без frozen. + +~~~bash +easyp --frozen generate +easyp lint --frozen --path proto +easyp breaking --frozen --against main +easyp mod --frozen download +easyp mod vendor --frozen +~~~ + +Флаг принимается глобально перед командой; локально у generate, lint, breaking, ls-files, get, init и migrate; у родительской команды mod и каждой из четырёх её подкоманд. Значение true на любом уровне включает режим. Дочерний --frozen=false не отменяет true у родителя. + +Frozen отклоняет все корневые replace, даже неиспользуемые, до обращения к путям замен или скачивания зависимостей. Проверяются прямые и транзитивные требования относительно lock и содержимое кеша. Режим не разрешает версии заново, не ищет HEAD/теги зависимостей и не записывает манифест или lock. Отсутствующий или устаревший lock вызывает ошибку. Точные коммиты из lock могут загружаться в кеш: frozen не означает автономную работу без сети. + +mod tidy, get, mod update, init и migrate отклоняют запуск в frozen; предварительный просмотр и интерактивная миграция тоже запрещены. Подготовьте файлы вне frozen. Генерация проверяет все выбранные графы до запуска любого плагина. Lint сохраняет действующую область политик; breaking использует собственные манифест и lock базовой ревизии. Даже ls-files --include-imports=false проверяет frozen-граф. Подробнее — в [менеджере пакетов](/ru/docs/cli/package-manager). + ## Флаги команд | Команда | Основные флаги | @@ -38,11 +56,11 @@ easyp breaking --path proto --against main | breaking | --path (-p), --root (-r), --against | | init | --dir (-d), --module | | validate-config | --config (псевдоним --cfg), --format | -| mod vendor | Нет собственных флагов | +| mod download/tidy/vendor/update | --frozen | | ls-files | --include-imports (по умолчанию true), --format (json или text) | | schema-gen | --out-dir (по умолчанию schemas) | -Общие флаги: --cfg (псевдоним --config, по умолчанию easyp.yaml), --debug (-d) и --format (-f, text или json). Переменные EASYP_CFG, EASYP_DEBUG и EASYP_FORMAT задают значения по умолчанию. Кеш модулей находится в EASYPPATH или $HOME/.easyp. +Общие флаги: --cfg (псевдоним --config, по умолчанию easyp.yaml), --debug (-d), --format (-f, text или json) и --frozen. Переменные EASYP_CFG, EASYP_DEBUG и EASYP_FORMAT задают значения по умолчанию. Кеш модулей находится в EASYPPATH или $HOME/.easyp. По умолчанию generate выбирает ближайший easyp.gen.yaml в текущем или родительском каталоге workspace. --project можно повторять для нескольких явных потребителей. --all отдельно включает рекурсивный выбор внутри каталога запуска и несовместим с --project. --workspace задаёт границу для путей модулей и наследования; по умолчанию используется ближайший Git-репозиторий или охватывающие файлы EasyP. Модули и корни исходников берутся из protobuf.mod; generate.packages зарезервировано и отклоняется при непустом значении. Флагов generate --path и generate --root нет. @@ -68,7 +86,7 @@ easyp validate-config --cfg ./services/api/easyp.gen.yaml mod vendor проверяет зафиксированные Git-зависимости и копирует их .proto в easyp_vendor по import path. Старый каталог заменяется только после успешного копирования всех файлов. Совпадающие import path вызывают ошибку. При наличии локальных replace копируется эффективный граф локальных и проверенных удалённых исходников без изменения опубликованного lock. -ls-files показывает локальные .proto из корней protobuf.mod. По умолчанию команда также включает достижимые импорты из зависимостей и встроенных well-known proto, разрешая зависимости через v1 lock или локальные замены. --include-imports=false показывает только локальные файлы без разрешения зависимостей. В JSON есть поля files, roots и, при проблемах с импортами, errors. +ls-files показывает локальные .proto из корней protobuf.mod. По умолчанию команда также включает достижимые импорты из зависимостей и встроенных well-known proto, разрешая зависимости через v1 lock или локальные замены. --include-imports=false показывает только локальные файлы; вне frozen это пропускает разрешение зависимостей. В JSON есть поля files, roots и, при проблемах с импортами, errors. schema-gen --out-dir schemas создаёт отдельные JSON Schema для easyp.yaml, easyp.gen.yaml и protobuf.lock: файлы с суффиксом -v1.schema.json и псевдонимы без версии. protobuf.mod — текстовый манифест; проверяйте его командой validate-config. CLI также проверяет семантические правила, не выраженные в JSON Schema. diff --git a/content/docs/cli/generator/index.mdx b/content/docs/cli/generator/index.mdx index fe5303f..f3d8d14 100644 --- a/content/docs/cli/generator/index.mdx +++ b/content/docs/cli/generator/index.mdx @@ -55,6 +55,19 @@ easyp generate --workspace ../.. --project .. The nearest Git repository, including a worktree with a .git file, supplies the workspace boundary. Without Git, enclosing EasyP configuration and manifest files establish the boundary; --workspace sets it explicitly. Project paths and descriptor destinations are relative to the invocation directory. Plugin output paths are relative to their easyp.gen.yaml. The command has no --path or --root flag. +## Frozen generation + +~~~bash +easyp generate --frozen --project backend --project frontend +easyp --frozen generate --all --descriptor_set_out_dir build/descriptors +~~~ + +Each selected local native module must have protobuf.mod and protobuf.lock, including an empty lock without dependencies. An explicit workspace-relative path uses the selected module's files: backend/easyp.gen.yaml with generate.modules: [proto/user] validates proto/user/protobuf.mod and proto/user/protobuf.lock. The generator-only backend directory needs neither file. Frozen rejects all root replacements, even unused ones, and validates the locked direct and transitive graph before any plugin executes. A failure in a later selected project therefore prevents plugins in earlier projects from running. The same preflight applies to both descriptor export modes and pluginless exports. + +A dependency selected by identity through generate.modules requires its consumer's manifest and lock; the downloaded dependency does not need its own lock. Unselected projects are ignored. --frozen does not change the existing --project/--all selection and plugin authorization rules. + +Exact locked commits may be downloaded into the cache and are hash-verified, including on cache reuse. Manifest and lock files are never rewritten, and dependency HEAD/tags are never resolved. Frozen is explicit, not inferred from CI, and does not make remote plugins offline or pin local plugin executables. See [frozen builds](/docs/cli/package-manager#frozen-builds). + ## Export descriptors ~~~bash diff --git a/content/docs/cli/generator/index.ru.mdx b/content/docs/cli/generator/index.ru.mdx index 20ceca5..3bbf08a 100644 --- a/content/docs/cli/generator/index.ru.mdx +++ b/content/docs/cli/generator/index.ru.mdx @@ -55,6 +55,19 @@ easyp generate --workspace ../.. --project .. Границу workspace задаёт ближайший Git-репозиторий, включая worktree с файлом .git. Без Git граница определяется по охватывающим конфигам и манифестам EasyP; --workspace задаёт её явно. Пути проектов и дескрипторов считаются от каталога запуска. Пути результатов плагинов считаются от их easyp.gen.yaml. Флагов --path и --root у команды нет. +## Генерация в режиме frozen + +~~~bash +easyp generate --frozen --project backend --project frontend +easyp --frozen generate --all --descriptor_set_out_dir build/descriptors +~~~ + +Каждому выбранному локальному native-модулю нужны protobuf.mod и protobuf.lock, в том числе пустой lock без зависимостей. Явный путь от workspace использует файлы выбранного модуля: backend/easyp.gen.yaml с generate.modules: [proto/user] проверяет proto/user/protobuf.mod и proto/user/protobuf.lock. Самому каталогу backend, содержащему только настройки генератора, эти файлы не нужны. Frozen отклоняет все корневые замены, даже неиспользуемые, и проверяет зафиксированный граф прямых и транзитивных зависимостей до запуска любого плагина. Ошибка в проекте, выбранном позже, поэтому не даст запустить плагины более ранних проектов. Проверка действует для обоих режимов экспорта дескрипторов, включая экспорт без плагинов. + +Зависимость, выбранная по идентификатору через generate.modules, требует манифест и lock потребителя; собственный lock в скачанной зависимости не требуется. Невыбранные проекты игнорируются. --frozen не меняет существующие правила выбора и разрешения запуска плагинов через --project/--all. + +Точные коммиты из lock могут скачиваться в кеш; хеши проверяются и при повторном использовании кеша. Манифест и lock никогда не переписываются, HEAD/теги зависимостей не разрешаются. Frozen включается явно, а не по окружению CI; он не отключает сеть удалённым плагинам и не фиксирует локальные исполняемые файлы плагинов. Подробнее — в [менеджере пакетов](/ru/docs/cli/package-manager). + ## Экспорт дескрипторов ~~~bash diff --git a/content/docs/cli/package-manager/index.mdx b/content/docs/cli/package-manager/index.mdx index e13d20f..012ee81 100644 --- a/content/docs/cli/package-manager/index.mdx +++ b/content/docs/cli/package-manager/index.mdx @@ -67,6 +67,27 @@ Before writing a new manifest or lock, mod tidy checks the import c When a local source starts importing a previously indirect module, tidy removes the existing // indirect marker while preserving its version and unrelated comments. This does not discover an arbitrary Git repository from an unknown proto path. Registry-specific Buf dependency identities still require explicit Git mapping and are not silently converted into repository URLs. +## Frozen builds + +Commit protobuf.mod and protobuf.lock, then opt into --frozen explicitly. Even a module with no dependencies needs an empty lock; a source directory without a native manifest is rejected. CI=true does not enable this mode. + +~~~bash +# Prepare and review the lock outside frozen mode +easyp mod tidy +# Use the committed graph; exact-commit cache fills are allowed +easyp mod download --frozen +easyp --frozen generate +easyp mod --frozen vendor +~~~ + +Global, mod-level, and leaf-command placement are supported. A true value anywhere in the command lineage stays enabled even if a child passes --frozen=false. See [all supported placements](/docs/cli/configuration#explicit-frozen-mode). + +Frozen rejects every root replace before accessing its path or fetching dependencies, including unused replacements. It verifies the manifest's direct requirements and the locked modules' transitive requirements; missing, invalid, incomplete, or stale locks fail instead of being repaired. Dependencies selected by identity use the consumer's manifest and lock and do not need their own lock files. Explicit workspace-relative generation module paths instead use the selected native module's manifest and lock; a generator-only directory needs no separate pair. Dependency-local replacement directives remain ignored. + +There is no dependency re-resolution, HEAD/tag lookup, or manifest/lock creation or rewriting. Missing cache entries may be fetched at their exact locked commits. Content hashes are verified on cold and warm caches; corrupted installed contents fail rather than silently replacing the recorded hash. Frozen is not offline, and remote plugins can still need network access. + +mod download installs the verified graph. mod vendor validates it before writing easyp_vendor. mod tidy, get, mod update, init, and migrate refuse frozen execution, including migration preview. Remove replacements and prepare the manifest/lock outside frozen mode. The normal local replacement and vendor behavior above is unchanged. + ## Cache and revision-access errors A hash mismatch in an installed module identifies the exact cache directory. Preserve it for investigation or quarantine only that entry, then retry easyp mod download. Do not rewrite protobuf.lock to hide the mismatch; the command does not automatically delete or repair the cache. diff --git a/content/docs/cli/package-manager/index.ru.mdx b/content/docs/cli/package-manager/index.ru.mdx index 143f0e3..7a6929f 100644 --- a/content/docs/cli/package-manager/index.ru.mdx +++ b/content/docs/cli/package-manager/index.ru.mdx @@ -67,6 +67,27 @@ Git-зависимость может объявлять корни .proto Когда локальный исходник начинает импортировать ранее косвенную зависимость, tidy удаляет существующую пометку // indirect, сохраняя версию и остальные комментарии. Это не поиск произвольного Git-репозитория по неизвестному proto-пути. Идентификаторам зависимостей реестра Buf по-прежнему нужно явное соответствие Git-модулям; они не преобразуются в URL репозитория автоматически. +## Сборки в режиме frozen + +Сохраните protobuf.mod и protobuf.lock в репозитории, затем явно включите --frozen. Даже модулю без зависимостей нужен пустой lock; каталог исходников без native-манифеста отклоняется. CI=true не включает этот режим. + +~~~bash +# Подготовьте и проверьте lock вне frozen +easyp mod tidy +# Используйте сохранённый граф; загрузка точных коммитов в кеш разрешена +easyp mod download --frozen +easyp --frozen generate +easyp mod --frozen vendor +~~~ + +Флаг можно поставить глобально, на уровне mod или конечной подкоманды. Значение true на любом уровне остаётся включённым, даже если дочерняя команда получила --frozen=false. Все варианты размещения описаны в [конфигурации](/ru/docs/cli/configuration). + +Frozen отклоняет все корневые replace до обращения к их путям или скачивания зависимостей, в том числе неиспользуемые замены. Проверяются прямые требования манифеста и транзитивные требования зафиксированных модулей; отсутствующий, некорректный, неполный или устаревший lock вызывает ошибку вместо исправления. Зависимости, выбранные по идентификатору, используют манифест и lock потребителя и не обязаны иметь собственные lock-файлы. Явный путь от workspace при выборе модуля для генерации использует манифест и lock выбранного native-модуля; каталогу только с настройками генератора отдельная пара не нужна. Замены из манифестов зависимостей по-прежнему игнорируются. + +Режим не разрешает зависимости заново, не ищет HEAD/теги, не создаёт и не переписывает манифест или lock. Недостающий кеш может загружаться по точным коммитам из lock. Хеши проверяются при холодном и прогретом кеше; повреждённое содержимое вызывает ошибку, а не незаметную замену сохранённого хеша. Frozen не означает работу без сети; удалённым плагинам также может понадобиться сетевой доступ. + +mod download устанавливает проверенный граф. mod vendor проверяет его перед записью easyp_vendor. mod tidy, get, mod update, init и migrate отклоняют запуск в frozen, включая предварительный просмотр миграции. Удалите замены и подготовьте манифест/lock вне frozen. Обычное поведение локальных замен и vendor, описанное выше, не меняется. + ## Ошибки кэша и доступа к ревизии При несовпадении хеша установленного модуля ошибка указывает точный каталог кэша. Сначала сохраните его для расследования или изолируйте только эту запись, затем повторите easyp mod download. Не переписывайте protobuf.lock, чтобы скрыть несовпадение; команда сама не удаляет и не исправляет повреждённый кэш. diff --git a/content/docs/guides/reproducibility.mdx b/content/docs/guides/reproducibility.mdx index 876cc18..463f84b 100644 --- a/content/docs/guides/reproducibility.mdx +++ b/content/docs/guides/reproducibility.mdx @@ -44,3 +44,12 @@ Local replacement contents are editable and are not pinned by the published depe - Keep generated-output checks and consumer tests: valid locks and semantic versions do not prove schema compatibility or identical output bytes. See [local replacement debugging](/docs/guides/debugging-replace) and [GitHub Actions](/docs/ci-cd/github-actions). + +## Explicit frozen verification + +~~~bash +easyp mod download --frozen +easyp generate --frozen +~~~ + +Frozen mode validates existing manifests and locks, refuses all main-module local replacements, and never resolves new dependency versions or writes either file. It may fetch exact locked commits into the cache. It is not enabled by the CI environment. Mutating commands such as tidy/update refuse frozen execution; prepare the published graph first. See [frozen configuration](/docs/cli/configuration#explicit-frozen-mode). diff --git a/content/docs/guides/reproducibility.ru.mdx b/content/docs/guides/reproducibility.ru.mdx index 3a45246..ac4c7d6 100644 --- a/content/docs/guides/reproducibility.ru.mdx +++ b/content/docs/guides/reproducibility.ru.mdx @@ -44,3 +44,12 @@ test -z "$(git ls-files --others --exclude-standard -- gen)" - Сохраняйте проверки сгенерированных файлов и тесты потребителей: корректный lock и семантические версии не доказывают совместимость схем или побайтовую идентичность вывода. См. [отладку с локальными заменами](/ru/docs/guides/debugging-replace) и [GitHub Actions](/ru/docs/ci-cd/github-actions). + +## Явная проверка frozen + +~~~bash +easyp mod download --frozen +easyp generate --frozen +~~~ + +Режим проверяет существующие manifest и lock, запрещает все локальные замены главного модуля и не выбирает новые версии зависимостей, не записывая оба файла. Загрузка точных закреплённых коммитов в кеш разрешена. Переменная CI не включает frozen автоматически. Команды изменения графа, включая tidy/update, отклоняют запуск в frozen; сначала подготовьте опубликованный граф. См. [конфигурацию frozen](/ru/docs/cli/configuration). From d876ab84492a8dc237b4c823ec91b8d372747781 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 30 Sep 2026 19:19:25 +0300 Subject: [PATCH 20/26] docs(v1): document Go-style module major semantics --- content/docs/cli/package-manager/index.mdx | 4 +++- content/docs/cli/package-manager/index.ru.mdx | 4 +++- content/docs/migration/easyp-v0.mdx | 2 ++ content/docs/migration/easyp-v0.ru.mdx | 2 ++ content/docs/reference/protobuf-lock.mdx | 2 ++ content/docs/reference/protobuf-lock.ru.mdx | 2 ++ content/docs/reference/protobuf-mod.mdx | 24 ++++++++++++++++++- content/docs/reference/protobuf-mod.ru.mdx | 24 ++++++++++++++++++- 8 files changed, 60 insertions(+), 4 deletions(-) diff --git a/content/docs/cli/package-manager/index.mdx b/content/docs/cli/package-manager/index.mdx index 012ee81..a6eff39 100644 --- a/content/docs/cli/package-manager/index.mdx +++ b/content/docs/cli/package-manager/index.mdx @@ -13,7 +13,7 @@ roots proto require ( github.com/acme/shared v1.2.0 - github.com/acme/weather v2.1.0 + github.com/acme/weather/v2 v2.1.0 ) ~~~ @@ -27,6 +27,8 @@ For a Git repository with several manifests, require each nested module separate Module commands and get find the nearest ancestor protobuf.mod within the workspace. easyp get <module> adds a direct requirement; @v1.2.3 or @<full-commit> selects a version. Without a suffix, the unconstrained-requirement rules above apply. Transitive requirements are added with // indirect, and repeated calls do not duplicate entries. Resolution errors leave the manifest and lock unchanged. +Major versions use Go-style identities: v0/v1 are unsuffixed; v2+ requires matching /vN. The +incompatible exception requires verified pre-native metadata; it never bypasses a native manifest. See [exact grammar and Git mapping](/docs/reference/protobuf-mod). + ## Commands | Command | Behavior | diff --git a/content/docs/cli/package-manager/index.ru.mdx b/content/docs/cli/package-manager/index.ru.mdx index 7a6929f..bcfa63f 100644 --- a/content/docs/cli/package-manager/index.ru.mdx +++ b/content/docs/cli/package-manager/index.ru.mdx @@ -13,7 +13,7 @@ roots proto require ( github.com/acme/shared v1.2.0 - github.com/acme/weather v2.1.0 + github.com/acme/weather/v2 v2.1.0 ) ~~~ @@ -27,6 +27,8 @@ require ( Команды mod и get находят ближайший protobuf.mod в предках в пределах workspace. easyp get <модуль> добавляет прямое требование; @v1.2.3 или @<полный-коммит> задаёт версию. Без суффикса применяется описанное выше неограниченное требование. Транзитивные требования дописываются с // indirect, повторный вызов не создаёт дубликаты. При ошибке разрешения манифест и lock не меняются. +Мажорные версии используют идентичность как в Go: v0/v1 — без суффикса, v2+ — с соответствующим /vN. Исключение +incompatible требует проверки домодульных метаданных и не обходит нативный manifest. См. [точную грамматику и Git mapping](/ru/docs/reference/protobuf-mod). + ## Команды | Команда | Поведение | diff --git a/content/docs/migration/easyp-v0.mdx b/content/docs/migration/easyp-v0.mdx index b7de173..b3073c4 100644 --- a/content/docs/migration/easyp-v0.mdx +++ b/content/docs/migration/easyp-v0.mdx @@ -79,3 +79,5 @@ easyp generate Run mod download when the migrated project has a lock. Check real generated code, not only the exit status of configuration validation. Recursive multi-project generation now requires explicit --all or repeated --project; migration does not authorize unrelated projects. Command plugins now receive literal argv rather than an implicitly assembled shell command. Review legacy commands that relied on shell operators; use an explicit shell invocation only when that is intentional. Migration does not prove equivalence of arbitrary plugin side effects. + +An unsuffixed native v2+ dependency cannot be converted automatically. Select a published /vN identity and matching version, or a valid v0/v1 release; migration never renames dependencies or substitutes versions. An explicit +incompatible requirement is eligible only when the exact revision has no native manifest; migration does not add the marker speculatively. Requirements from older metadata are also checked when used at the native source boundary. See [major version identities](/docs/reference/protobuf-mod). diff --git a/content/docs/migration/easyp-v0.ru.mdx b/content/docs/migration/easyp-v0.ru.mdx index 7a6a8f0..7118b20 100644 --- a/content/docs/migration/easyp-v0.ru.mdx +++ b/content/docs/migration/easyp-v0.ru.mdx @@ -79,3 +79,5 @@ easyp generate Запускайте mod download, когда у мигрированного проекта есть lock-файл. Проверяйте реально сгенерированный код, а не только успешную валидацию. Для рекурсивной генерации нескольких проектов теперь нужны явный --all или повторяемый --project; миграция не разрешает запуск посторонних проектов. Command-плагины теперь получают буквальный argv, а не неявно собранную shell-команду. Проверьте старые команды, использовавшие shell-операторы; явный shell нужен только при намеренном исполнении скрипта. Миграция не доказывает эквивалентность произвольных побочных эффектов плагинов. + +Нативный v2+ без мажорного суффикса не переносится автоматически. Выберите опубликованное имя /vN и соответствующую версию либо допустимый релиз v0/v1; миграция не переименовывает зависимости и не подменяет версии. Явная метка +incompatible допустима только при отсутствии нативного manifest в точной ревизии; миграция не добавляет её предположительно. Требования из старых метаданных также проходят проверку при использовании нативного источника. См. [идентичность мажорных версий](/ru/docs/reference/protobuf-mod). diff --git a/content/docs/reference/protobuf-lock.mdx b/content/docs/reference/protobuf-lock.mdx index 5fab6bd..9c38af4 100644 --- a/content/docs/reference/protobuf-lock.mdx +++ b/content/docs/reference/protobuf-lock.mdx @@ -71,3 +71,5 @@ During tidy, get, and update, every fetch The hash uses Go's dirhash.Hash1 over all regular files tracked by Git at the commit, with repository-relative paths. EasyP verifies it on download and when reusing an installed module; corrupt installations are rejected. The v1 cache reuses an object store per Git remote. A known exact commit can be fetched without contacting the remote. A cold request first tries a depth-one fetch of the exact commit; if the server rejects that request, EasyP falls back to advertised reachable history. The original commit is still required: HEAD is never substituted. Tag lookups are refreshed separately so cache reuse cannot hide a retag. A commit absent from cache can still require access to its source. + +The source identity and SemVer version must satisfy the [major-version rules](/docs/reference/protobuf-mod): unsuffixed v0/v1, matching /vN for v2+. Invalid suffixes fail before installation. An unsuffixed v2+ +incompatible entry additionally requires the exact revision to have no native manifest, including when installed content is already cached. Commit pins still verify the exact native module identity, including in frozen mode. diff --git a/content/docs/reference/protobuf-lock.ru.mdx b/content/docs/reference/protobuf-lock.ru.mdx index 4ad025c..4163ee8 100644 --- a/content/docs/reference/protobuf-lock.ru.mdx +++ b/content/docs/reference/protobuf-lock.ru.mdx @@ -71,3 +71,5 @@ modules: hash вычисляется через Go dirhash.Hash1 по всем обычным файлам, отслеживаемым Git в коммите, с путями относительно репозитория. Хеш проверяется и при скачивании, и при повторном использовании установленного модуля; повреждённая установка отклоняется. Для каждого Git remote кеш v1 повторно использует хранилище объектов. Известный точный коммит можно получить без обращения к remote. При холодном запросе сначала выполняется shallow-загрузка точного коммита с глубиной один; если сервер её отклоняет, используется доступная история объявленных ссылок. Всё равно требуется исходный коммит: HEAD вместо него не подставляется. Проверки тегов обновляются отдельно, поэтому кеш не скрывает перенос тега. Отсутствующий в кеше коммит всё ещё может потребовать доступа к источнику. + +Идентификатор source и SemVer в version должны соответствовать [правилам major-версий](/ru/docs/reference/protobuf-mod): v0/v1 без суффикса, v2+ с соответствующим /vN. Некорректные суффиксы отклоняются до установки. Для v2+ без суффикса пути запись +incompatible дополнительно требует отсутствия нативного manifest в точной ревизии, в том числе при уже заполненном кеше. Коммит проверяется по точному нативному имени модуля, включая frozen-режим. diff --git a/content/docs/reference/protobuf-mod.mdx b/content/docs/reference/protobuf-mod.mdx index 0af3213..408eeb4 100644 --- a/content/docs/reference/protobuf-mod.mdx +++ b/content/docs/reference/protobuf-mod.mdx @@ -50,7 +50,7 @@ roots ( require ( github.com/googleapis/googleapis v1.5.0 github.com/acme/weather v1.2.3 - github.com/grpc-ecosystem/grpc-gateway v2.19.0 // indirect + github.com/acme/gateway/v2 v2.19.0 // indirect ) // Local debug replacement @@ -74,3 +74,25 @@ SemVer requirements select the maximum requested minimum. SemVer and SHA require A local replace may target a nested module directory. Its native manifest must declare the replaced identity, and its requirements participate in the effective graph. Relative paths always use the main manifest directory, even at transitive depths; absolute paths are used directly. Historical breaking comparisons map in-repository replacements to the corresponding revision snapshot and reject external local paths. Preserving the lock is an explicit EasyP invariant, not a claim that Go never changes go.sum. For example, with repo/foo/protobuf.mod containing roots proto, EasyP reads files under the physical repository path repo/foo/proto. A file at repo/foo/proto/user/v1/user.proto has the protobuf import path user/v1/user.proto: import paths are relative to the resolved root, so the module directory and the root directory are not repeated in imports. With roots ., the physical root is repo/foo. + +## Major version identities + +v0 and v1 use the same unsuffixed module path. v2 and later require a final /vN component matching the SemVer major, with no leading zeros: require github.com/acme/weather/v2 v2.1.0. /v0, /v1, /v01 and /v2.0 are invalid module suffixes. Ordinary components such as /2024 and /v2beta are not suffixes. This does not restrict package directories or protobuf import paths. Go's special gopkg.in/name.vN spelling is recognized by the same suffix helpers. + +The rule applies to declared module identities, requirements, replacement source identities, fetched native metadata and lock entries. Full commits and omitted versions still require the exact requested native identity. Absolute local Git paths and explicit URLs are supported; the logical URL host/path is checked separately from transport credentials and ports. EasyP preserves the original identity spelling. + +| Identity | Physical directory containing protobuf.mod | Tag for the example release | +|---|---|---| +| repo | repository root | v1.2.0 | +| repo/v2 | root or v2/ | v2.0.0 | +| repo/sub/v2 | sub/ or sub/v2/ | sub/v2.0.0 | + +The major suffix is logical and is not included in the tag prefix: v2/v2.0.0 is not the release tag for repo/v2. Both lightweight and annotated tags work. The manifest at an allowed location must declare the exact requested identity; finding a tag alone is insufficient. + +repo and repo/v2 can coexist as distinct module, lock and replacement identities. MVS chooses the highest requested minimum per identity. You must provide distinct protobuf import paths yourself: EasyP never renames packages or imports, and duplicate import paths still fail. Same-major updates, exact SHA/tag agreement, immutable tags, local replacement lock preservation and frozen verification continue to apply. + +The pre-module +incompatible exception is supported only for unsuffixed v2+ revisions without a native protobuf.mod. EasyP reads the underlying tag without the suffix and verifies metadata on the exact fetched or cached commit before accepting the lock entry. It rejects native manifests even when the marker is present. Legacy updates retain the marker; local replacements remain unversioned overlays and never publish their graph to the lock. Migration never silently renames a source or changes its version. + +See [Go major version suffixes](https://go.dev/ref/mod#major-version-suffixes) and [mapping versions to commits](https://go.dev/ref/mod#vcs-version). + +As in Go, an unversioned local replacement may contain a native manifest with the same unsuffixed identity while replacing an explicit legacy +incompatible requirement. This does not certify the published revision: the overlay preserves the shared lock, and frozen mode rejects replacements. Published fetches and both cold and warm locked installations still enforce the pre-native metadata check. diff --git a/content/docs/reference/protobuf-mod.ru.mdx b/content/docs/reference/protobuf-mod.ru.mdx index d796537..fdfdba4 100644 --- a/content/docs/reference/protobuf-mod.ru.mdx +++ b/content/docs/reference/protobuf-mod.ru.mdx @@ -50,7 +50,7 @@ roots ( require ( github.com/googleapis/googleapis v1.5.0 github.com/acme/weather v1.2.3 - github.com/grpc-ecosystem/grpc-gateway v2.19.0 // indirect + github.com/acme/gateway/v2 v2.19.0 // indirect ) // Локальное переопределения для отладки @@ -74,3 +74,25 @@ SemVer-требования выбирают максимум запрошенн Локальный replace может указывать на каталог вложенного модуля. Его нативный манифест должен объявлять заменяемое имя; требования замены участвуют в эффективном графе. Относительные пути всегда считаются от главного манифеста, даже на транзитивной глубине; абсолютные используются напрямую. Для исторических breaking-сравнений пути внутри репозитория отображаются в снимок соответствующей ревизии, внешние локальные пути отклоняются. Сохранение lock — явный инвариант EasyP, а не утверждение, что Go никогда не меняет go.sum. Например, если в repo/foo/protobuf.mod указано roots proto, EasyP читает файлы из физического пути repo/foo/proto внутри репозитория. У файла repo/foo/proto/user/v1/user.proto protobuf import path будет user/v1/user.proto: путь импорта считается относительно вычисленного root, поэтому каталог модуля и сам root в импорте не повторяются. При roots . физический root — repo/foo. + +## Идентичность мажорных версий + +v0 и v1 используют один путь без суффикса. Для v2 и выше нужен последний компонент /vN, совпадающий с major в SemVer, без ведущих нулей: require github.com/acme/weather/v2 v2.1.0. Суффиксы модуля /v0, /v1, /v01 и /v2.0 недопустимы. Обычные компоненты /2024 и /v2beta не считаются суффиксами. Правило не ограничивает каталоги пакетов и protobuf import paths. Общие с Go функции проверки также распознают особую запись gopkg.in/name.vN. + +Проверяются объявленное имя модуля, требования, исходные имена в replace, загруженные нативные метаданные и записи lock. Полный коммит и отсутствие версии не отменяют точного совпадения нативного имени. Абсолютные локальные Git-пути и явные URL поддерживаются: логический host/path проверяется отдельно от учётных данных и порта транспорта. Исходное написание идентификатора сохраняется. + +| Идентификатор | Физический каталог с protobuf.mod | Тег примера релиза | +|---|---|---| +| repo | корень репозитория | v1.2.0 | +| repo/v2 | корень или v2/ | v2.0.0 | +| repo/sub/v2 | sub/ или sub/v2/ | sub/v2.0.0 | + +Мажорный суффикс логический и не входит в префикс тега: v2/v2.0.0 не является тегом релиза repo/v2. Поддерживаются обычные и аннотированные теги. Манифест в допустимом каталоге должен объявлять точный запрошенный идентификатор; одного совпадения тега недостаточно. + +repo и repo/v2 могут сосуществовать как разные идентификаторы модулей, записей lock и замен. MVS выбирает максимум запрошенных минимумов для каждого имени отдельно. Различные protobuf import paths задаёт автор: EasyP не переименовывает пакеты и импорты, а совпадение путей импорта остаётся ошибкой. Обновления внутри major, точное согласование SHA/тега, неизменность тегов, сохранение lock при локальных заменах и frozen-проверки сохраняются. + +Домодульное исключение +incompatible поддерживается только для v2+ без суффикса пути и без нативного protobuf.mod в выбранной ревизии. EasyP читает исходный Git-тег без этой метки и проверяет метаданные точного скачанного или кешированного коммита до принятия записи lock. При наличии нативного manifest метка не обходит проверку. Обновления старого модуля сохраняют метку; локальные замены остаются неверсионируемым наложением и не записывают свой граф в lock. Миграция не переименовывает источник и не меняет версию молча. + +См. [мажорные суффиксы Go](https://go.dev/ref/mod#major-version-suffixes) и [соответствие версий коммитам](https://go.dev/ref/mod#vcs-version). + +Как и в Go, локальная замена без опубликованной версии может содержать нативный манифест с тем же именем без суффикса для явного требования +incompatible. Это не подтверждает опубликованную ревизию: локальный граф сохраняет общий lock, а frozen-режим запрещает замены. Загрузка опубликованных версий и установка lock в холодном и прогретом кеше по-прежнему проверяют домодульные метаданные. From d7c4b70091dd948ff632b7d195073803c641a276 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 30 Sep 2026 19:29:19 +0300 Subject: [PATCH 21/26] docs(v1): document Buf registry metadata boundary --- content/docs/cli/package-manager/index.mdx | 2 +- content/docs/cli/package-manager/index.ru.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/content/docs/cli/package-manager/index.mdx b/content/docs/cli/package-manager/index.mdx index a6eff39..6cbaa7a 100644 --- a/content/docs/cli/package-manager/index.mdx +++ b/content/docs/cli/package-manager/index.mdx @@ -59,7 +59,7 @@ A Git dependency may declare its proto roots in buf.work.yaml, Buf When adapting an older easyp.yaml, both deps and generation Git inputs contribute requirements. Exact source/version duplicates are removed; different minimums remain visible to MVS, and malformed deps fail explicitly. A matching native protobuf.mod takes precedence. Only metadata is read; dependency plugins are never executed. -Buf Registry dependencies have no automatic Git identity. Declare the corresponding Git module in the consuming protobuf.mod when those imports are needed. Buf include/exclude filters are not supported as Git import roots and produce an explicit error. +EasyP reads Buf v1, v1beta1, and v2 deps as BSR references, including dependencies declared by modules selected through a v1 buf.work.yaml. A nonempty list is rejected explicitly with the declaring config and references instead of being silently discarded. Automatic BSR-to-Git mapping is intentionally not implemented yet; a Git dependency that uses BSR dependencies needs equivalent native protobuf.mod metadata before EasyP can resolve it. Buf include/exclude filters are also not supported as Git import roots and produce an explicit error. See [protobuf.mod](/docs/reference/protobuf-mod) and [protobuf.lock](/docs/reference/protobuf-lock) for their field-level formats. diff --git a/content/docs/cli/package-manager/index.ru.mdx b/content/docs/cli/package-manager/index.ru.mdx index bcfa63f..fac1f20 100644 --- a/content/docs/cli/package-manager/index.ru.mdx +++ b/content/docs/cli/package-manager/index.ru.mdx @@ -59,7 +59,7 @@ Git-зависимость может объявлять корни .proto При адаптации старого easyp.yaml требования берутся и из deps, и из Git-входов генерации. Точные дубликаты источник/версия удаляются, разные минимумы сохраняются для MVS; некорректные deps вызывают ошибку. Совпадающий нативный protobuf.mod имеет приоритет. Читаются только метаданные, плагины зависимости не запускаются. -Зависимости Buf Registry не имеют автоматического Git-идентификатора. Если их импорты нужны, объявите соответствующий Git-модуль в protobuf.mod потребителя. Фильтры Buf include/exclude для корней Git-зависимостей пока не поддерживаются и вызывают явную ошибку. +EasyP читает deps Buf v1, v1beta1 и v2 как ссылки BSR, в том числе зависимости модулей, выбранных через v1 buf.work.yaml. Непустой список теперь явно отклоняется с указанием исходного конфига и ссылок, а не молча теряется. Автоматическое сопоставление BSR→Git пока намеренно не реализовано: Git-зависимости с BSR-зависимостями нужны эквивалентные native-метаданные protobuf.mod, прежде чем EasyP сможет разрешить такой граф. Фильтры Buf include/exclude для корней Git-зависимостей также пока не поддерживаются и вызывают явную ошибку. Форматы полей описаны в справочниках [protobuf.mod](/ru/docs/reference/protobuf-mod) и [protobuf.lock](/ru/docs/reference/protobuf-lock). From d26241ed9dd9e1ca4da56676a951cb95a2eaf8f5 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 30 Sep 2026 21:52:03 +0300 Subject: [PATCH 22/26] docs(policy): document verified shared policy inheritance --- content/docs/ci-cd/github-actions.mdx | 2 +- content/docs/ci-cd/github-actions.ru.mdx | 2 +- content/docs/cli/breaking-changes/index.mdx | 2 +- .../docs/cli/breaking-changes/index.ru.mdx | 2 +- content/docs/cli/configuration.mdx | 2 +- content/docs/cli/configuration.ru.mdx | 2 +- content/docs/cli/linter/index.mdx | 2 +- content/docs/cli/linter/index.ru.mdx | 2 +- content/docs/guides/buf-migration.mdx | 2 +- content/docs/guides/buf-migration.ru.mdx | 2 +- .../docs/guides/organization-lint-style.mdx | 89 +++++++++--------- .../guides/organization-lint-style.ru.mdx | 91 ++++++++++--------- content/docs/reference/easyp-yaml.mdx | 8 +- content/docs/reference/easyp-yaml.ru.mdx | 8 +- 14 files changed, 111 insertions(+), 105 deletions(-) diff --git a/content/docs/ci-cd/github-actions.mdx b/content/docs/ci-cd/github-actions.mdx index ccd969b..2b348b8 100644 --- a/content/docs/ci-cd/github-actions.mdx +++ b/content/docs/ci-cd/github-actions.mdx @@ -82,7 +82,7 @@ easyp breaking --path proto --against refs/tags/v1.2.0 Choose the intended previous release rather than assuming tag creation order defines compatibility history. Each revision uses its own module manifests, locks, and dependencies, so a breaking check can fetch dependencies beyond those needed by the current checkout. -FILE is the only supported additional category. ignore_unstable works for the supported package suffixes. Ignore paths are relative to the policy file defining the breaking section: here proto/experimental is relative to the root policy. Nested sections replace whole sections; nonempty extends is unsupported. +FILE is the only supported additional category. ignore_unstable works for the supported package suffixes. Ignore paths are relative to the policy file defining the breaking section: here proto/experimental is relative to the root policy. Nested sections replace whole sections; extends explicitly loads a section base from a local file or an existing locked module. ## Selecting Generation Projects diff --git a/content/docs/ci-cd/github-actions.ru.mdx b/content/docs/ci-cd/github-actions.ru.mdx index daecd4b..9e78664 100644 --- a/content/docs/ci-cd/github-actions.ru.mdx +++ b/content/docs/ci-cd/github-actions.ru.mdx @@ -82,7 +82,7 @@ easyp breaking --path proto --against refs/tags/v1.2.0 Выбирайте нужный предыдущий релиз явно: порядок создания тегов не обязательно задаёт историю совместимости. Каждая ревизия использует свои манифесты модулей, lock-файлы и зависимости, поэтому breaking-проверка может загрузить зависимости, которые не нужны текущему checkout. -FILE — единственная поддерживаемая дополнительная категория. ignore_unstable работает для поддерживаемых суффиксов пакетов. Пути исключений отсчитываются от файла политики с секцией breaking: здесь proto/experimental задан относительно корневой политики. Вложенные секции заменяют секции целиком; непустое extends не поддерживается. +FILE — единственная поддерживаемая дополнительная категория. ignore_unstable работает для поддерживаемых суффиксов пакетов. Пути исключений отсчитываются от файла политики с секцией breaking: здесь proto/experimental задан относительно корневой политики. Вложенные секции заменяют секции целиком; extends явно подключает базу секции из локального файла или существующего закреплённого модуля. ## Выбор проектов генерации diff --git a/content/docs/cli/breaking-changes/index.mdx b/content/docs/cli/breaking-changes/index.mdx index 781b333..ca84503 100644 --- a/content/docs/cli/breaking-changes/index.mdx +++ b/content/docs/cli/breaking-changes/index.mdx @@ -45,4 +45,4 @@ Existing compatibility checks remain enabled. The only supported additional cate breaking.ignore_unstable defaults to false. When true, it excludes packages on both sides whose final component matches vNtest..., vNalpha, vNbeta, vNpMalpha, or vNpMbeta. N and M are positive numbers without leading zeros; alpha/beta may have a similarly positive sequence number, and test may have any suffix. For example, acme.v1beta1 is skipped, while acme.v1beta1.service and acme.v0alpha1 are not. Stable packages and their references to unstable types remain checked; source reading and import resolution precede filtering. -breaking.extends is reserved: omit it or leave it empty. Nonempty shared-policy references are unsupported. The old breaking_check.against_git_ref key is not accepted by the v1 CLI. See the [policy reference](/docs/reference/easyp-yaml) for all fields. +breaking.extends loads a local or locked-module policy. Its baseline and ignore paths apply in the consuming repository; local fields override inherited values. The old breaking_check.against_git_ref key is not accepted by the v1 CLI. See the [policy reference](/docs/reference/easyp-yaml) for all fields. diff --git a/content/docs/cli/breaking-changes/index.ru.mdx b/content/docs/cli/breaking-changes/index.ru.mdx index 3b776ab..801e0a4 100644 --- a/content/docs/cli/breaking-changes/index.ru.mdx +++ b/content/docs/cli/breaking-changes/index.ru.mdx @@ -45,4 +45,4 @@ easyp --format json breaking --path proto breaking.ignore_unstable по умолчанию равен false. При true на обеих сторонах сравнения исключаются пакеты, последний компонент имени которых соответствует vNtest..., vNalpha, vNbeta, vNpMalpha или vNpMbeta. N и M — положительные числа без ведущего нуля; после alpha/beta допустим такой же положительный номер, после test — любой суффикс. Например, acme.v1beta1 пропускается, а acme.v1beta1.service и acme.v0alpha1 — нет. Стабильные пакеты и их ссылки на нестабильные типы всё ещё проверяются; чтение исходников и разрешение импортов происходят до фильтрации. -breaking.extends зарезервировано: поле нужно опустить или оставить пустым. Непустые ссылки на общие политики не поддерживаются. Старый ключ breaking_check.against_git_ref CLI v1 не принимает. Все поля описаны в [справочнике политики](/ru/docs/reference/easyp-yaml). +breaking.extends загружает локальную политику или базу из закреплённого модуля. Baseline и ignore применяются в репозитории потребителя; локальные поля приоритетнее базы. Старый ключ breaking_check.against_git_ref CLI v1 не принимает. Все поля описаны в [справочнике политики](/ru/docs/reference/easyp-yaml). diff --git a/content/docs/cli/configuration.mdx b/content/docs/cli/configuration.mdx index 4ac8a1c..ecfdff3 100644 --- a/content/docs/cli/configuration.mdx +++ b/content/docs/cli/configuration.mdx @@ -74,7 +74,7 @@ EasyP expands environment variables in easyp.yaml and easyp.g For breaking, explicit --against overrides breaking.baseline, followed by the default master. Each revision uses its own roots, manifests, and locks; the baseline comes from an isolated Git snapshot. Policies come from current configuration and sections are inherited as a whole. The additional category FILE is supported; package-related and other categories are reserved and rejected. breaking.ignore_unstable defaults to false; its exact unstable suffix forms are in the [reference](/docs/reference/easyp-yaml#unstable-packages). -issues.exclude-rules.path is relative to the file supplying the issues section and supports *, ?, [], and complete ** segments. Literal directories cover their subtree. An empty rule {} explicitly ignores all files. linters.allow_comment_ignores defaults to true per policy. linters.extends and breaking.extends are reserved: omit them or leave them empty. +issues.exclude-rules.path is relative to the file supplying the issues section and supports *, ?, [], and complete ** segments. Literal directories cover their subtree. An empty rule {} explicitly ignores all files. linters.allow_comment_ignores defaults to true per policy. linters.extends and breaking.extends load section-scoped bases from bounded local paths or existing locked modules; see [shared policies](/docs/guides/organization-lint-style). validate-config recursively checks every easyp.yaml, easyp.gen.yaml, protobuf.mod, and protobuf.lock below the current directory. Pass --cfg <file> to check one file or --cfg <directory> to scan another directory. JSON errors identify the file; YAML structure errors also include line and column. Invalid lock versions, incomplete entries, and malformed hashes are reported as validation errors. diff --git a/content/docs/cli/configuration.ru.mdx b/content/docs/cli/configuration.ru.mdx index d8c076a..44b25f6 100644 --- a/content/docs/cli/configuration.ru.mdx +++ b/content/docs/cli/configuration.ru.mdx @@ -74,7 +74,7 @@ Frozen отклоняет все корневые replace, даже В breaking явный --against перекрывает breaking.baseline, затем применяется значение по умолчанию master. Каждая ревизия использует собственные корни, манифесты и lock; база читается из изолированного Git-снимка. Политики берутся из текущей конфигурации, секции наследуются целиком. Поддерживается дополнительная категория FILE; пакетные и другие категории зарезервированы и не принимаются. breaking.ignore_unstable по умолчанию равен false; точные формы нестабильных суффиксов описаны в [справочнике](/ru/docs/reference/easyp-yaml#нестабильные-пакеты). -Пути issues.exclude-rules.path считаются от файла, предоставляющего секцию issues, и поддерживают *, ?, [] и полные сегменты **. Буквальный каталог охватывает поддерево. Пустое правило {} явно исключает все файлы. linters.allow_comment_ignores по умолчанию равен true для каждой политики. linters.extends и breaking.extends зарезервированы: их нужно опустить или оставить пустыми. +Пути issues.exclude-rules.path считаются от файла, предоставляющего секцию issues, и поддерживают *, ?, [] и полные сегменты **. Буквальный каталог охватывает поддерево. Пустое правило {} явно исключает все файлы. linters.allow_comment_ignores по умолчанию равен true для каждой политики. linters.extends и breaking.extends подключают базы отдельных секций из локальных путей или существующих закреплённых модулей; см. [общие политики](/ru/docs/guides/organization-lint-style). validate-config рекурсивно проверяет все easyp.yaml, easyp.gen.yaml, protobuf.mod и protobuf.lock внутри текущего каталога. Передайте --cfg <файл>, чтобы проверить один файл, или --cfg <каталог>, чтобы проверить другой каталог. В JSON-ошибках указан файл, а для ошибок структуры YAML — строка и столбец. Некорректная версия lock-файла, неполные записи и неверные хеши выдаются как ошибки проверки. diff --git a/content/docs/cli/linter/index.mdx b/content/docs/cli/linter/index.mdx index 1ab8c9b..9879f2c 100644 --- a/content/docs/cli/linter/index.mdx +++ b/content/docs/cli/linter/index.mdx @@ -22,7 +22,7 @@ issues: - path: generated ~~~ -Presets are MINIMAL, BASIC, STANDARD, and COMMENTS. Enable/disable and exclusion lists accept implemented rules and groups. Repetition is idempotent; disabling wins. Unknown names are errors, including when repeated in the opposite list. PACKAGE_NO_IMPORT_CYCLE is reserved and cannot be selected. Supported settings are ENUM_ZERO_VALUE_SUFFIX.suffix and SERVICE_SUFFIX.suffix. linters.extends is reserved and must be omitted or empty. +Presets are MINIMAL, BASIC, STANDARD, and COMMENTS. Enable/disable and exclusion lists accept implemented rules and groups. Repetition is idempotent; disabling wins. Unknown names are errors, including when repeated in the opposite list. PACKAGE_NO_IMPORT_CYCLE is reserved and cannot be selected. Supported settings are ENUM_ZERO_VALUE_SUFFIX.suffix and SERVICE_SUFFIX.suffix. linters.extends loads a local or locked-module base before local adjustments; see [shared policies](/docs/guides/organization-lint-style). ~~~bash easyp lint --path proto diff --git a/content/docs/cli/linter/index.ru.mdx b/content/docs/cli/linter/index.ru.mdx index 7c8064e..1be2feb 100644 --- a/content/docs/cli/linter/index.ru.mdx +++ b/content/docs/cli/linter/index.ru.mdx @@ -22,7 +22,7 @@ issues: - path: generated ~~~ -Пресеты: MINIMAL, BASIC, STANDARD и COMMENTS. Списки enable/disable и исключений принимают реализованные правила и группы. Повторы не добавляют проверок; отключение приоритетнее включения. Неизвестные имена — ошибки, даже если повторены в противоположном списке. PACKAGE_NO_IMPORT_CYCLE зарезервировано и выбирать его нельзя. Поддерживаются настройки ENUM_ZERO_VALUE_SUFFIX.suffix и SERVICE_SUFFIX.suffix. Поле linters.extends зарезервировано: его нужно опустить или оставить пустым. +Пресеты: MINIMAL, BASIC, STANDARD и COMMENTS. Списки enable/disable и исключений принимают реализованные правила и группы. Повторы не добавляют проверок; отключение приоритетнее включения. Неизвестные имена — ошибки, даже если повторены в противоположном списке. PACKAGE_NO_IMPORT_CYCLE зарезервировано и выбирать его нельзя. Поддерживаются настройки ENUM_ZERO_VALUE_SUFFIX.suffix и SERVICE_SUFFIX.suffix. linters.extends подключает локальную или закреплённую базу перед локальными изменениями; см. [общие политики](/ru/docs/guides/organization-lint-style). ~~~bash easyp lint --path proto diff --git a/content/docs/guides/buf-migration.mdx b/content/docs/guides/buf-migration.mdx index dcb0102..19cfb7c 100644 --- a/content/docs/guides/buf-migration.mdx +++ b/content/docs/guides/buf-migration.mdx @@ -12,7 +12,7 @@ This guide maps Buf configuration to the EasyP v1 files and commands. Review eac | Buf Construct | EasyP Equivalent | Key Distinction | | --- | --- | --- | | buf.yaml (deps section) | protobuf.mod | Tool-neutral dependency DSL; uses Git URLs instead of proprietary BSR names. | -| buf.yaml (lint section) | easyp.yaml (linters) | Uses presets and rule lists; each policy section comes whole from its nearest definition. Nonempty extends is unsupported. | +| buf.yaml (lint section) | easyp.yaml (linters) | Uses presets and rule lists; each policy section comes whole from its nearest definition. extends explicitly loads a section base from a local file or an existing locked module. | | buf.yaml (breaking section) | easyp.yaml (breaking) | Explicit git baseline comparison (e.g. git:main). | | buf.gen.yaml | easyp.gen.yaml | Resides at consumer project level and selects complete modules. | | buf.gen.yaml (managed) | easyp.gen.yaml (generate.managed) | Explicit managed mode; options.go.package_prefix is a separate Go-only convenience. | diff --git a/content/docs/guides/buf-migration.ru.mdx b/content/docs/guides/buf-migration.ru.mdx index d4a4696..73637db 100644 --- a/content/docs/guides/buf-migration.ru.mdx +++ b/content/docs/guides/buf-migration.ru.mdx @@ -12,7 +12,7 @@ description: "Пошаговое руководство по миграции к | Конструкция Buf | Эквивалент в EasyP | Ключевое отличие | | --- | --- | --- | | buf.yaml (секция deps) | protobuf.mod | Независимый от инструментов DSL; использует Git URL вместо BSR. | -| buf.yaml (секция lint) | easyp.yaml (linters) | Использует пресеты и списки правил; каждая секция политики берётся целиком из ближайшего определения. Непустое extends не поддерживается. | +| buf.yaml (секция lint) | easyp.yaml (linters) | Использует пресеты и списки правил; каждая секция политики берётся целиком из ближайшего определения. extends явно подключает базу секции из локального файла или существующего закреплённого модуля. | | buf.yaml (секция breaking) | easyp.yaml (breaking) | Явное сравнение с git-baseline (например, git:main). | | buf.gen.yaml | easyp.gen.yaml | Находится у потребителя и выбирает целые модули. | | buf.gen.yaml (managed) | easyp.gen.yaml (generate.managed) | Явный managed mode; options.go.package_prefix — отдельная настройка только для Go. | diff --git a/content/docs/guides/organization-lint-style.mdx b/content/docs/guides/organization-lint-style.mdx index 0c608dc..fa20896 100644 --- a/content/docs/guides/organization-lint-style.mdx +++ b/content/docs/guides/organization-lint-style.mdx @@ -1,79 +1,82 @@ --- title: "Organizational Lint Policies" -description: "Keep explicit repository policies consistent and use whole-section cascading for local exceptions." +description: "Share producer policies through local files or verified, pinned Git modules." --- -Teams can keep a reviewed lint policy in each repository and use directory policies for exceptions. EasyP v1 does not fetch shared policies: linters.extends and breaking.extends are reserved, and nonempty values are rejected. There is no built-in shared-policy delivery mechanism. +Each section of easyp.yaml first comes from its nearest definition in the directory tree. That section may explicitly extend a base. Lint and breaking inheritance are independent; a lint base does not import its breaking or issues section. -## 1. Defining a Repository Policy +## Local base -Store the complete policy in proto/easyp.yaml: +Create .policies/lint.yaml inside the workspace: ~~~yaml version: v1 linters: default: STANDARD - enable: - - ENUM_VALUE_PREFIX - - RPC_REQUEST_RESPONSE_UNIQUE - disable: - - PACKAGE_VERSION_SUFFIX + disable: [PACKAGE_VERSION_SUFFIX] linters-settings: - ENUM_ZERO_VALUE_SUFFIX: - suffix: UNSPECIFIED -breaking: - baseline: git:main - categories: [FILE] + SERVICE_SUFFIX: + suffix: Service ~~~ -Review policy changes alongside schema changes. FILE adds declaration-move checks to the existing compatibility checks; categories such as WIRE are not supported. +Then use it from the repository's easyp.yaml: -## 2. Understanding Section Cascading +~~~yaml +version: v1 +linters: + extends: ./.policies/lint.yaml + enable: [PACKAGE_VERSION_SUFFIX] + disable: [RPC_REQUEST_RESPONSE_UNIQUE] +~~~ -Each of linters, linters-settings, issues, and breaking comes as a whole from the nearest file defining that section. Fields within a section are not partially merged. +A local reference begins with ./ or ../ and resolves from the file containing it. A directory means its easyp.yaml. References cannot escape the workspace, including through symlinks. Recursive bases are supported, with cycle detection and a limit of 16 base policies. -For example, a child linters section containing only disable does not retain the parent's enable list. Write the complete intended linter selection in the child. Sections omitted by the child still come from the nearest ancestor that defines them. +## Pinned shared module -## 3. Handling Legacy Subtrees +Declare the policy module as an ordinary dependency. The following organization identity is illustrative; substitute a published module you control. ~~~text -proto/ -├── easyp.yaml -├── user/v1/user.proto -└── legacy/ - ├── easyp.yaml - └── old.proto +module github.com/acme/service +require github.com/acme/proto-policy v1.2.3 ~~~ -To apply a reduced lint policy only to proto/legacy, put this in proto/legacy/easyp.yaml: +Resolve and review its lock with easyp mod tidy. Reference the policy without duplicating the version: ~~~yaml version: v1 linters: - default: MINIMAL - disable: - - FIELD_LOWER_SNAKE_CASE - - ENUM_VALUE_PREFIX + extends: github.com/acme/proto-policy#lint/base.yaml +breaking: + extends: github.com/acme/proto-policy#breaking/easyp.yaml + ignore: [] ~~~ -The child replaces the complete linters section. The ancestor's linters-settings and breaking sections still apply because the child does not define them. +The explicit form is declared-module#policy-path. An exact module identity selects its easyp.yaml. The form declared-module/path uses the longest matching identity already present in the consumer graph; it does not discover a new repository. A nested or major-version module resolves paths from its actual manifest directory, not its proto import roots. -If only one rule needs an exception, keep the parent linter selection and add an issues section to the parent policy instead: +Execution may download an exact missing locked commit, but does not re-resolve a tag, choose HEAD, add dependencies or write the lock. A moved tag cannot silently change an existing base. Relative references made by a dependency policy stay inside that module. The main module's local replacement can supply a policy in normal mode; all remote edges still require existing pins. --frozen rejects replacements and verifies the complete locked graph. -~~~yaml -# Add to proto/easyp.yaml -issues: - exclude-rules: - - path: legacy/**/*.proto - linters: [FIELD_LOWER_SNAKE_CASE] -~~~ +## Precedence + +The resolved base is applied before explicit local values. A local preset replaces the base preset without discarding inherited explicit rule adjustments. A local enable can undo a base disable, including one supplied by a group. Disable wins over enable in the same layer; repeated rules do not duplicate diagnostics. + +Linter settings merge by rule and key. An explicit empty linters-settings map clears inherited settings; an empty rule map clears that rule. Explicit false and empty breaking lists remain overrides. YAML aliases and merge keys preserve these distinctions. + +Nearest-directory cascading is unchanged: a child section without extends replaces its ancestor section, rather than partially merging with it. Only explicit inheritance merges base and local adjustments. -This path is relative to proto/easyp.yaml, including when the section is inherited by a deeper directory. A child issues: {} clears inherited exclusions. +## Consumer-relative breaking behavior -Run the policy explicitly from the repository root: +The inherited baseline is a Git reference in the consuming repository. Inherited ignore paths are relative to the consuming policy file, never to the Git cache. Local ignore lists replace the inherited list, including an explicitly empty list. An explicit --against still overrides the effective baseline. + +A common ancestor policy is resolved independently for each checked module, using that module's dependency graph. Different modules can therefore use different pinned versions or local replacements of the same policy. Deleted modules are checked against historical snapshots. For a wholly deleted module whose base exists only in its old dependency graph, pass --against to identify the historical revision. + +## Validation ~~~bash -easyp --cfg proto/easyp.yaml lint --path . +easyp validate-config --cfg easyp.yaml +easyp lint +easyp breaking --against main ~~~ -See the [policy reference](/docs/reference/easyp-yaml) for supported rules, path patterns, and comment suppressions. +The parser validates reference syntax without network access. The CLI additionally follows local references and verifies already cached dependency content. Missing cached policies produce an actionable error: run easyp mod download, then validate again. Validation itself does not download dependencies. Invalid bases, cycles and boundary violations include the consuming field and the reference chain. + +Loading policies never runs generation plugins or imports a base's issues.exclude-rules. Environment variables are expanded once in each original file, not again after merging. See the [policy reference](/docs/reference/easyp-yaml). diff --git a/content/docs/guides/organization-lint-style.ru.mdx b/content/docs/guides/organization-lint-style.ru.mdx index 50cdb89..d70089e 100644 --- a/content/docs/guides/organization-lint-style.ru.mdx +++ b/content/docs/guides/organization-lint-style.ru.mdx @@ -1,79 +1,82 @@ --- -title: "Организационные политики линтинга" -description: "Согласованные политики репозиториев и каскадирование целых секций для локальных исключений." +title: "Общие политики линтинга" +description: "Наследование политик из локальных файлов и закреплённых Git-модулей." --- -Команды могут хранить согласованную политику линтинга в каждом репозитории и задавать исключения для отдельных каталогов. EasyP v1 не загружает общие политики: linters.extends и breaking.extends зарезервированы, непустые значения отклоняются. Встроенного механизма доставки общих политик нет. +Каждая секция easyp.yaml сначала выбирается из ближайшего определения в дереве каталогов. Затем она может явно подключить базовую политику. Наследование lint и breaking независимо: база линтинга не переносит свои секции breaking и issues. -## 1. Политика репозитория +## Локальная база -Сохраните полную политику в proto/easyp.yaml: +Создайте .policies/lint.yaml внутри рабочего пространства: ~~~yaml version: v1 linters: default: STANDARD - enable: - - ENUM_VALUE_PREFIX - - RPC_REQUEST_RESPONSE_UNIQUE - disable: - - PACKAGE_VERSION_SUFFIX + disable: [PACKAGE_VERSION_SUFFIX] linters-settings: - ENUM_ZERO_VALUE_SUFFIX: - suffix: UNSPECIFIED -breaking: - baseline: git:main - categories: [FILE] + SERVICE_SUFFIX: + suffix: Service ~~~ -Проверяйте изменения политики вместе с изменениями схем. FILE добавляет проверки перемещения объявлений к существующим проверкам совместимости; категории вроде WIRE не поддерживаются. +Подключите её в корневом easyp.yaml: -## 2. Каскадирование секций +~~~yaml +version: v1 +linters: + extends: ./.policies/lint.yaml + enable: [PACKAGE_VERSION_SUFFIX] + disable: [RPC_REQUEST_RESPONSE_UNIQUE] +~~~ -Каждая секция linters, linters-settings, issues и breaking берётся целиком из ближайшего файла, где она определена. Поля внутри секции не сливаются частично. +Локальная ссылка начинается с ./ или ../ и считается от содержащего её файла. Для каталога выбирается его easyp.yaml. Выход за границы рабочего пространства, в том числе через симлинк, запрещён. Базы могут наследовать другие базы; циклы отклоняются, максимальная цепочка — 16 базовых политик. -Например, дочерняя секция linters только с disable не сохраняет родительский список enable. Укажите в дочернем файле весь нужный набор правил. Отсутствующие секции по-прежнему берутся из ближайшего предка, который их определяет. +## Закреплённый модуль политик -## 3. Исключения для устаревших поддеревьев +Объявите модуль политик обычной зависимостью. Ниже использован пример идентификатора организации: замените его реально опубликованным модулем. ~~~text -proto/ -├── easyp.yaml -├── user/v1/user.proto -└── legacy/ - ├── easyp.yaml - └── old.proto +module github.com/acme/service +require github.com/acme/proto-policy v1.2.3 ~~~ -Чтобы ослабить линтинг только в proto/legacy, создайте proto/legacy/easyp.yaml: +Выполните easyp mod tidy и проверьте созданный lock. В ссылке на политику версия не дублируется: ~~~yaml version: v1 linters: - default: MINIMAL - disable: - - FIELD_LOWER_SNAKE_CASE - - ENUM_VALUE_PREFIX + extends: github.com/acme/proto-policy#lint/base.yaml +breaking: + extends: github.com/acme/proto-policy#breaking/easyp.yaml + ignore: [] ~~~ -Дочерний файл заменяет всю секцию linters. Родительские linters-settings и breaking продолжают действовать: дочерний файл их не определяет. +Явная форма — объявленный-модуль#путь-политики. Точный идентификатор модуля выбирает его easyp.yaml. В форме объявленный-модуль/путь используется самый длинный известный идентификатор из графа потребителя; поиска нового репозитория нет. Пути вложенных и major-модулей считаются от их фактического manifest, а не от корней proto-импортов. -Если исключение нужно только для одного правила, сохраните родительский набор линтеров и вместо этого добавьте в родительскую политику секцию issues: +Команда может скачать отсутствующий закреплённый commit, но не пересчитывает теги, не выбирает HEAD, не добавляет зависимости и не переписывает lock. Перенос тега не подменяет базовую политику. Относительные ссылки внутри зависимости остаются в пределах того же модуля. В обычном режиме политику может предоставить локальный replace главного модуля; удалённые зависимости всё равно требуют существующих закреплений. --frozen запрещает replace и проверяет полный закреплённый граф. -~~~yaml -# Добавьте в proto/easyp.yaml -issues: - exclude-rules: - - path: legacy/**/*.proto - linters: [FIELD_LOWER_SNAKE_CASE] -~~~ +## Приоритеты + +Сначала применяется разрешённая база, затем явно заданные локальные значения. Локальный пресет заменяет базовый, сохраняя унаследованные явные изменения правил. Локальный enable может отменить базовый disable, включая отключение через группу. В одной секции disable имеет приоритет над enable; повторные правила не дублируют сообщения. + +Настройки линтеров объединяются по правилу и ключу. Явная пустая секция linters-settings очищает настройки базы, пустая карта отдельного правила очищает это правило. Явные false и пустые списки breaking сохраняют смысл переопределения. YAML-алиасы и merge-ключи учитываются. + +Каскад каталогов не изменён: дочерняя секция без extends заменяет секцию предка целиком, а не частично объединяет её. Слияние базовых и локальных значений происходит только при явном наследовании. -Путь отсчитывается от proto/easyp.yaml, даже когда секция наследуется более глубоким каталогом. Дочерняя issues: {} очищает унаследованные исключения. +## Breaking в контексте потребителя -Из корня репозитория запустите проверку с явной политикой: +Унаследованный baseline — Git-ссылка в репозитории потребителя. Пути ignore считаются от подключающего политику файла, не от кэша Git. Локальный список ignore заменяет базовый, в том числе когда он пуст. Явный --against сохраняет приоритет над итоговым baseline. + +Общая корневая политика разрешается отдельно для каждого проверяемого модуля по его графу зависимостей. Поэтому модули могут использовать разные закреплённые версии или локальные замены одной политики. Удалённые модули сравниваются с историческими снимками. Для полностью удалённого модуля, чья база доступна только через старый граф зависимостей, укажите --against для определения исторической ревизии. + +## Проверка ~~~bash -easyp --cfg proto/easyp.yaml lint --path . +easyp validate-config --cfg easyp.yaml +easyp lint +easyp breaking --against main ~~~ -Поддерживаемые правила, шаблоны путей и подавление замечаний комментариями описаны в [справочнике политики](/ru/docs/reference/easyp-yaml). +Парсер проверяет синтаксис ссылки без сетевых запросов. CLI дополнительно разрешает локальные ссылки и проверяет целостность уже закэшированных зависимостей. Если базы нет в кэше, выполните easyp mod download и повторите проверку. Сама validate-config зависимости не скачивает. Ошибки базы, циклы и выходы за границы содержат поле потребителя и цепочку ссылок. + +Загрузка политик не запускает плагины генерации и не наследует issues.exclude-rules базы. Переменные среды раскрываются один раз в каждом исходном файле и не раскрываются повторно после слияния. Подробнее — в [справочнике политики](/ru/docs/reference/easyp-yaml). diff --git a/content/docs/reference/easyp-yaml.mdx b/content/docs/reference/easyp-yaml.mdx index 46dd204..66ec1c7 100644 --- a/content/docs/reference/easyp-yaml.mdx +++ b/content/docs/reference/easyp-yaml.mdx @@ -3,7 +3,7 @@ title: "easyp.yaml Reference" description: "Complete specification for easyp.yaml, configuring producer-side linting rules, breaking change detection, path exclusions, and policy inheritance." --- -easyp.yaml defines lint and compatibility policies for protobuf schemas. Each section uses its nearest definition in the directory tree. Explicit policy loading through linters.extends and breaking.extends is reserved and unimplemented: omit these fields or leave them empty. +easyp.yaml defines lint and compatibility policies for protobuf schemas. Each section uses its nearest definition in the directory tree. Explicit linters.extends and breaking.extends inherit section-scoped bases from bounded local files or declared, locked modules. See [shared policies](/docs/guides/organization-lint-style). --- @@ -39,7 +39,7 @@ description: "Complete specification for easyp.yaml, configuring producer-side l default: "true" }, "linters.extends": { - description: "Reserved and unimplemented. Omit or leave empty; nonempty values are rejected.", + description: "Base policy from a local ./ or ../ reference, or a declared locked module with optional #policy-path. Local values override the base.", type: "string" }, "linters-settings": { @@ -81,7 +81,7 @@ description: "Complete specification for easyp.yaml, configuring producer-side l type: "string[]" }, "breaking.extends": { - description: "Reserved and unimplemented. Omit or leave empty; nonempty values are rejected.", + description: "Base policy from a local ./ or ../ reference, or a declared locked module with optional #policy-path. Local values override the base.", type: "string" } }} @@ -154,7 +154,7 @@ The baseline can name a local branch, a lightweight or annotated tag, a full com Each selected module uses revision-local roots, manifests, and locks for its current and baseline revisions. The baseline is read from an isolated Git snapshot; the caller's checkout, manifest, and lock are unchanged. Policies come from current configuration and may each select a different baseline. See the [breaking guide](/docs/cli/breaking-changes) for local replacement limits. -The only supported additional category is FILE, which checks declarations moved between files. Existing checks remain enabled. PACKAGE, WIRE, WIRE_JSON, and other categories are unimplemented and cannot be selected. linters.extends and breaking.extends likewise do not load local or remote shared policies: nonempty values are rejected. +The only supported additional category is FILE, which checks declarations moved between files. Existing checks remain enabled. PACKAGE, WIRE, WIRE_JSON, and other categories are unimplemented and cannot be selected. Shared policies use local relative paths or declared-module#policy-path; versions belong only in the module manifest and lock. ## Unstable packages diff --git a/content/docs/reference/easyp-yaml.ru.mdx b/content/docs/reference/easyp-yaml.ru.mdx index d6a8b21..fa56040 100644 --- a/content/docs/reference/easyp-yaml.ru.mdx +++ b/content/docs/reference/easyp-yaml.ru.mdx @@ -3,7 +3,7 @@ title: "Справочник easyp.yaml" description: "Полная спецификация файла easyp.yaml, управляющего правилами линтинга продюсера, проверками ломающих изменений, исключениями путей и наследованием политик." --- -Файл easyp.yaml задаёт политики линтинга и совместимости для protobuf-схем. Для каждой секции применяется ближайшее определение в дереве каталогов. Явная загрузка политик через linters.extends и breaking.extends зарезервирована и не реализована: эти поля нужно опустить или оставить пустыми. +Файл easyp.yaml задаёт политики линтинга и совместимости для protobuf-схем. Для каждой секции применяется ближайшее определение в дереве каталогов. Секции linters.extends и breaking.extends наследуют базы из локальных файлов или объявленных закреплённых модулей. Подробнее — в [руководстве по общим политикам](/ru/docs/guides/organization-lint-style). --- @@ -39,7 +39,7 @@ description: "Полная спецификация файла easyp.yaml, уп default: "true" }, "linters.extends": { - description: "Зарезервировано и не реализовано. Опустите поле или оставьте пустым; непустые значения отклоняются.", + description: "База из локальной ссылки ./ или ../ либо объявленного закреплённого модуля с необязательным #путь-политики. Локальные значения приоритетнее базы.", type: "string" }, "linters-settings": { @@ -81,7 +81,7 @@ description: "Полная спецификация файла easyp.yaml, уп type: "string[]" }, "breaking.extends": { - description: "Зарезервировано и не реализовано. Опустите поле или оставьте пустым; непустые значения отклоняются.", + description: "База из локальной ссылки ./ или ../ либо объявленного закреплённого модуля с необязательным #путь-политики. Локальные значения приоритетнее базы.", type: "string" } }} @@ -154,7 +154,7 @@ breaking: Для каждого выбранного модуля текущая и базовая ревизии используют собственные корни, манифесты и lock. База читается из изолированного Git-снимка; рабочее дерево, манифест и lock пользователя не изменяются. Политики берутся из текущей конфигурации; каждая может задавать свою базу. Подробности и ограничения локальных замен — в [руководстве breaking](/ru/docs/cli/breaking-changes). -Единственная поддерживаемая дополнительная категория — FILE, проверяющая перемещения объявлений между файлами. Она не выключает существующие проверки. Категории PACKAGE, WIRE, WIRE_JSON и другие пока не реализованы; включать их нельзя. linters.extends и breaking.extends также не загружают локальные или удалённые общие политики: непустые значения отклоняются. +Единственная поддерживаемая дополнительная категория — FILE, проверяющая перемещения объявлений между файлами. Она не выключает существующие проверки. Категории PACKAGE, WIRE, WIRE_JSON и другие пока не реализованы; включать их нельзя. Общая политика задаётся локальным относительным путём или ссылкой объявленный-модуль#путь-политики. Версии указываются только в manifest и lock. ## Нестабильные пакеты From 3c92c46840c7a4d61e9cd4c5b4c334ff86d3e1b2 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 30 Sep 2026 22:04:42 +0300 Subject: [PATCH 23/26] docs(generate): explain exact package selection and import closure --- content/docs/cli/configuration.mdx | 2 +- content/docs/cli/configuration.ru.mdx | 2 +- content/docs/cli/generator/index.mdx | 2 +- content/docs/cli/generator/index.ru.mdx | 2 +- content/docs/guides/buf-migration.mdx | 2 +- content/docs/guides/buf-migration.ru.mdx | 2 +- .../docs/guides/multi-target-generation.mdx | 2 +- .../guides/multi-target-generation.ru.mdx | 2 +- content/docs/reference/easyp-gen-yaml.mdx | 22 +++++++++++++++++-- content/docs/reference/easyp-gen-yaml.ru.mdx | 22 +++++++++++++++++-- 10 files changed, 48 insertions(+), 12 deletions(-) diff --git a/content/docs/cli/configuration.mdx b/content/docs/cli/configuration.mdx index ecfdff3..c778e92 100644 --- a/content/docs/cli/configuration.mdx +++ b/content/docs/cli/configuration.mdx @@ -62,7 +62,7 @@ Frozen rejects every root replace, even unused entries, before acce The global flags are --cfg (alias --config, default easyp.yaml), --debug (-d), --format (-f, text or json), and --frozen. EASYP_CFG, EASYP_DEBUG, and EASYP_FORMAT set their respective defaults. The module cache uses EASYPPATH or $HOME/.easyp. -By default, generate selects the closest easyp.gen.yaml in the current directory or a workspace ancestor. Repeat --project for multiple explicit consumers. --all separately opts into recursive selection below the invocation directory and is mutually exclusive with --project. --workspace sets the boundary for module paths and inheritance; by default this is the nearest Git repository or enclosing EasyP files. Modules and roots come from protobuf.mod; generate.packages is reserved and rejects nonempty values. The generate --path and generate --root flags are unavailable. +By default, generate selects the closest easyp.gen.yaml in the current directory or a workspace ancestor. Repeat --project for multiple explicit consumers. --all separately opts into recursive selection below the invocation directory and is mutually exclusive with --project. --workspace sets the boundary for module paths and inheritance; by default this is the nearest Git repository or enclosing EasyP files. Modules and roots come from protobuf.mod; generate.packages selects exact protobuf package names across the selected modules. The generate --path and generate --root flags are unavailable. --descriptor_set_out merges compatible graphs into one file; --descriptor_set_out_dir produces an independent file per project/module pair. The flags are mutually exclusive and destinations are invocation-relative. --include_imports defaults to false and affects exports only. plugins[].with_imports also defaults to false but separately enables imported code generation for an individual plugin. options.go.package_prefix changes Go only; full managed mode requires explicit generate.managed.enabled: true. diff --git a/content/docs/cli/configuration.ru.mdx b/content/docs/cli/configuration.ru.mdx index 44b25f6..575af70 100644 --- a/content/docs/cli/configuration.ru.mdx +++ b/content/docs/cli/configuration.ru.mdx @@ -62,7 +62,7 @@ Frozen отклоняет все корневые replace, даже Общие флаги: --cfg (псевдоним --config, по умолчанию easyp.yaml), --debug (-d), --format (-f, text или json) и --frozen. Переменные EASYP_CFG, EASYP_DEBUG и EASYP_FORMAT задают значения по умолчанию. Кеш модулей находится в EASYPPATH или $HOME/.easyp. -По умолчанию generate выбирает ближайший easyp.gen.yaml в текущем или родительском каталоге workspace. --project можно повторять для нескольких явных потребителей. --all отдельно включает рекурсивный выбор внутри каталога запуска и несовместим с --project. --workspace задаёт границу для путей модулей и наследования; по умолчанию используется ближайший Git-репозиторий или охватывающие файлы EasyP. Модули и корни исходников берутся из protobuf.mod; generate.packages зарезервировано и отклоняется при непустом значении. Флагов generate --path и generate --root нет. +По умолчанию generate выбирает ближайший easyp.gen.yaml в текущем или родительском каталоге workspace. --project можно повторять для нескольких явных потребителей. --all отдельно включает рекурсивный выбор внутри каталога запуска и несовместим с --project. --workspace задаёт границу для путей модулей и наследования; по умолчанию используется ближайший Git-репозиторий или охватывающие файлы EasyP. Модули и корни исходников берутся из protobuf.mod; generate.packages выбирает точные имена protobuf-пакетов среди выбранных модулей. Флагов generate --path и generate --root нет. --descriptor_set_out объединяет совместимые графы в один файл; --descriptor_set_out_dir создаёт независимый файл для каждой пары проект/модуль. Флаги взаимоисключающие, пути считаются от каталога запуска. --include_imports по умолчанию равен false и влияет только на экспорт. plugins[].with_imports также по умолчанию равен false, но отдельно включает генерацию импортов для конкретного плагина. options.go.package_prefix меняет только Go; полный managed mode требует явного generate.managed.enabled: true. diff --git a/content/docs/cli/generator/index.mdx b/content/docs/cli/generator/index.mdx index f3d8d14..dbe7f33 100644 --- a/content/docs/cli/generator/index.mdx +++ b/content/docs/cli/generator/index.mdx @@ -36,7 +36,7 @@ easyp mod tidy easyp generate ~~~ -If generate.modules is omitted, EasyP selects the nearest protobuf.mod beside or above the generator file within the workspace; without a manifest, the project directory is the source root. Explicit entries select local module identities, workspace-relative module paths, or dependencies resolved through the consumer manifest and lock. generate.packages is reserved and must be omitted or empty. +If generate.modules is omitted, EasyP selects the nearest protobuf.mod beside or above the generator file within the workspace; without a manifest, the project directory is the source root. Explicit entries select local module identities, workspace-relative module paths, or dependencies resolved through the consumer manifest and lock. generate.packages optionally selects exact protobuf package names; empty selects all module sources. ## Select projects diff --git a/content/docs/cli/generator/index.ru.mdx b/content/docs/cli/generator/index.ru.mdx index 3bbf08a..87e3a53 100644 --- a/content/docs/cli/generator/index.ru.mdx +++ b/content/docs/cli/generator/index.ru.mdx @@ -36,7 +36,7 @@ easyp mod tidy easyp generate ~~~ -Если generate.modules не указан, EasyP выбирает ближайший protobuf.mod рядом с файлом генератора или выше в пределах workspace; без манифеста корнем исходников становится каталог проекта. Явные элементы выбирают локальный модуль по имени, путь относительно workspace или зависимость из манифеста и lock потребителя. Поле generate.packages зарезервировано: его нужно опустить или оставить пустым. +Если generate.modules не указан, EasyP выбирает ближайший protobuf.mod рядом с файлом генератора или выше в пределах workspace; без манифеста корнем исходников становится каталог проекта. Явные элементы выбирают локальный модуль по имени, путь относительно workspace или зависимость из манифеста и lock потребителя. generate.packages выбирает точные имена protobuf-пакетов; пустой список означает все исходники модуля. ## Выбор проектов diff --git a/content/docs/guides/buf-migration.mdx b/content/docs/guides/buf-migration.mdx index 19cfb7c..58c7016 100644 --- a/content/docs/guides/buf-migration.mdx +++ b/content/docs/guides/buf-migration.mdx @@ -83,7 +83,7 @@ plugins: paths: source_relative ~~~ -The local go plugin requires protoc-gen-go in the build environment. Fix its version there; local plugins reject a YAML version. Remote plugins require a separate pinned semantic version. generate.packages is reserved and cannot filter packages. +The local go plugin requires protoc-gen-go in the build environment. Fix its version there; local plugins reject a YAML version. Remote plugins require a separate pinned semantic version. generate.packages selects exact protobuf package names within the selected modules. ### Step 5: Tidy and Verify diff --git a/content/docs/guides/buf-migration.ru.mdx b/content/docs/guides/buf-migration.ru.mdx index 73637db..b5d99cc 100644 --- a/content/docs/guides/buf-migration.ru.mdx +++ b/content/docs/guides/buf-migration.ru.mdx @@ -83,7 +83,7 @@ plugins: paths: source_relative ~~~ -Локальному плагину go нужен protoc-gen-go в окружении сборки. Фиксируйте версию там: локальные плагины отклоняют version в YAML. Удалённым плагинам нужна отдельная фиксированная семантическая версия. generate.packages зарезервировано и не фильтрует пакеты. +Локальному плагину go нужен protoc-gen-go в окружении сборки. Фиксируйте версию там: локальные плагины отклоняют version в YAML. Удалённым плагинам нужна отдельная фиксированная семантическая версия. generate.packages выбирает точные имена protobuf-пакетов внутри выбранных модулей. ### Шаг 5: Наведение порядка и проверка diff --git a/content/docs/guides/multi-target-generation.mdx b/content/docs/guides/multi-target-generation.mdx index 29d1903..4b5a89e 100644 --- a/content/docs/guides/multi-target-generation.mdx +++ b/content/docs/guides/multi-target-generation.mdx @@ -69,7 +69,7 @@ The nearest explicit options.go.package_prefix wins. The backend ab ## Key Configuration Elements - generate.modules selects complete local modules or canonical module identities available in the selected dependency context. With no list, generation uses the nearest enclosing module, or the project directory when no manifest exists. -- generate.packages is reserved. Omit it or leave it empty; package filtering is not implemented. +- generate.packages selects exact protobuf package names, not prefixes or globs. Empty selects all source files. - Each plugin selects exactly one source: name, path, command, or remote, and requires out. - opts accepts a map or a list of option strings. with_imports: true also generates transitive imports for that plugin. diff --git a/content/docs/guides/multi-target-generation.ru.mdx b/content/docs/guides/multi-target-generation.ru.mdx index 5afbd62..1f79ade 100644 --- a/content/docs/guides/multi-target-generation.ru.mdx +++ b/content/docs/guides/multi-target-generation.ru.mdx @@ -69,7 +69,7 @@ options: ## Ключевые элементы конфигурации - generate.modules выбирает целые локальные модули или канонические идентификаторы модулей, доступные в выбранном контексте зависимостей. Без списка используется ближайший вышестоящий модуль, а при отсутствии манифеста — каталог проекта. -- generate.packages зарезервировано. Опустите поле или оставьте пустой список: фильтрация пакетов не реализована. +- generate.packages выбирает точные имена protobuf-пакетов, не префиксы или glob-шаблоны. Пустой список выбирает все исходники. - Каждый плагин выбирает ровно один источник: name, path, command или remote, и обязательно задаёт out. - opts принимает словарь или список строк опций. with_imports: true дополнительно генерирует транзитивные импорты для этого плагина. diff --git a/content/docs/reference/easyp-gen-yaml.mdx b/content/docs/reference/easyp-gen-yaml.mdx index c2455ba..4c335f5 100644 --- a/content/docs/reference/easyp-gen-yaml.mdx +++ b/content/docs/reference/easyp-gen-yaml.mdx @@ -27,7 +27,7 @@ The easyp.gen.yaml file specifies **consumer-side code generation r type: "string[]" }, "generate.packages": { - description: "Reserved for future package filtering. v1 currently reports an error when this field is nonempty.", + description: "Exact protobuf package names among selected modules. Empty selects all sources.", type: "string[]" }, plugins: { @@ -159,7 +159,7 @@ plugins: A repository-root easyp.gen.yaml may provide options.go.package_prefix as a default for nested generator files. Nested generate.managed rules take precedence over that inherited default. A prefix declared in the same generator file has the highest priority. Plugin lists stay local to each generator file. -The v1 generator selects complete modules. generate.packages is reserved and unimplemented: omit it or leave it empty; nonempty values cause an error. +The generator selects module sources by default. Nonempty generate.packages filters them by exact protobuf package name. Unknown names fail before plugins; required imports remain in the compilation graph. Remote plugins require a version such as v2.0.0. EasyP sends that exact version to the remote generator. For local protoc-gen-* executables and bundled WASM plugins, the executable selected at runtime determines the version; the separate version field is rejected because EasyP cannot verify it. @@ -187,3 +187,21 @@ By default, easyp generate selects the closest config in the curren Both configuration validation and generation reject unknown managed file or field options and values of the wrong type. Boolean options such as java_multiple_files require a YAML boolean, not a quoted string. String options require strings. optimize_for accepts SPEED, CODE_SIZE or LITE_RUNTIME; jstype accepts JS_NORMAL, JS_STRING or JS_NUMBER. Invalid rules cannot silently fall back to managed defaults. Place a remote version in the separate version field, not after a colon in the final plugin path. A server port in the host is allowed. For example, use remote: localhost:8080/go with version: v1.2.3. + +## Package selection and imports + +~~~yaml +version: v1 +generate: + packages: [api.v1] +plugins: + - name: go + out: gen/go + with_imports: true + - name: python + out: gen/python +~~~ + +Select an existing package in your module. All its files become generation targets, while required imports remain available for compilation. Only the Go plugin above generates those dependencies; the Python plugin generates selected files only. Unrelated packages, including invalid unused declarations, are not compiled. Malformed selected sources and required imports still fail. + +Matching is exact and evaluated across all modules of the project. An unknown package fails before any plugin runs; duplicate names do not duplicate execution. Descriptor exports respect the same selection. The separate --include_imports switch adds the selected import closure to the descriptor output without changing plugin targets. diff --git a/content/docs/reference/easyp-gen-yaml.ru.mdx b/content/docs/reference/easyp-gen-yaml.ru.mdx index daa3bd2..28ed047 100644 --- a/content/docs/reference/easyp-gen-yaml.ru.mdx +++ b/content/docs/reference/easyp-gen-yaml.ru.mdx @@ -27,7 +27,7 @@ description: "Полная спецификация файла easyp.gen.yaml, type: "string[]" }, "generate.packages": { - description: "Резерв для будущей фильтрации пакетов. Сейчас непустое поле вызывает ошибку.", + description: "Точные имена protobuf-пакетов выбранных модулей. Пустой список выбирает все исходники.", type: "string[]" }, plugins: { @@ -159,7 +159,7 @@ plugins: Корневой easyp.gen.yaml может задавать options.go.package_prefix по умолчанию для вложенных генераторов. Локальные правила generate.managed имеют приоритет над унаследованным префиксом. Префикс, заданный в том же файле генератора, имеет наивысший приоритет. Списки плагинов не наследуются. -Сейчас v1 генерирует модули целиком. Поле generate.packages зарезервировано и не реализовано: его нужно опустить или оставить пустым; непустое значение вызывает ошибку. +По умолчанию генерируются все исходники выбранных модулей. Непустой generate.packages фильтрует их по точному имени protobuf-пакета. Неизвестные имена отклоняются до запуска плагинов, нужные импорты остаются в графе компиляции. Удалённому плагину нужен version, например v2.0.0. EasyP передаёт именно эту версию удалённому генератору. Для локального protoc-gen-* и встроенного WASM версию определяет выбранный исполняемый файл; отдельное поле version отклоняется, поскольку EasyP не может его проверить. @@ -187,3 +187,21 @@ plugins: Валидация конфигурации и генерация отклоняют неизвестные file/field options и значения неподходящего типа. Булевым опциям вроде java_multiple_files нужен YAML boolean, а не строка в кавычках. Строковым опциям нужны строки. optimize_for принимает SPEED, CODE_SIZE или LITE_RUNTIME; jstype — JS_NORMAL, JS_STRING или JS_NUMBER. Неверное правило не должно незаметно заменяться стандартными managed-настройками. Версию remote-плагина указывайте отдельным полем version, а не после двоеточия в последнем сегменте пути. Порт сервера в имени хоста допустим. Например, remote: localhost:8080/go вместе с version: v1.2.3. + +## Выбор пакетов и импорты + +~~~yaml +version: v1 +generate: + packages: [api.v1] +plugins: + - name: go + out: gen/go + with_imports: true + - name: python + out: gen/python +~~~ + +Укажите существующий пакет модуля. Все его файлы становятся целями генерации, а необходимые импорты сохраняются для компиляции. В примере зависимости генерирует только Go-плагин; Python-плагин генерирует только выбранные файлы. Несвязанные пакеты, включая невалидные неиспользуемые объявления, не компилируются. Ошибки выбранных исходников и нужных импортов по-прежнему останавливают команду. + +Сопоставление точное и выполняется среди всех модулей проекта. Неизвестный пакет отклоняется до запуска любого плагина, повтор имени не дублирует запуск. Экспорт дескрипторов учитывает тот же отбор. Отдельный --include_imports включает достижимые импорты в descriptor set, не меняя цели плагинов. From b80ec5065c7a167d8bd51da27267cd65f95c7098 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 30 Sep 2026 22:54:42 +0300 Subject: [PATCH 24/26] docs: feat(breaking): implement descriptor-based compatibility profiles --- content/docs/cli/breaking-changes/index.mdx | 21 ++++++++++++++++++- .../docs/cli/breaking-changes/index.ru.mdx | 21 ++++++++++++++++++- content/docs/reference/easyp-yaml.mdx | 4 ++-- content/docs/reference/easyp-yaml.ru.mdx | 4 ++-- 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/content/docs/cli/breaking-changes/index.mdx b/content/docs/cli/breaking-changes/index.mdx index ca84503..80ed21a 100644 --- a/content/docs/cli/breaking-changes/index.mdx +++ b/content/docs/cli/breaking-changes/index.mdx @@ -41,7 +41,26 @@ Local replacements inside the repository use the contents of the corresponding r ## Categories and unstable packages -Existing compatibility checks remain enabled. The only supported additional category is FILE, which adds declaration-move checks between files. PACKAGE, WIRE, WIRE_JSON, and other categories are reserved and unimplemented; they cannot be selected. +Nonempty breaking.categories selects real descriptor-based profiles: FILE, PACKAGE, WIRE_JSON, or WIRE. Omitted or empty categories retain the legacy checker; this is not an alias for WIRE. Multiple profiles apply their union without duplicate diagnostics. + +| Change | FILE | PACKAGE | WIRE_JSON | WIRE | +|---|---|---|---|---| +| Move a declaration within its package, preserving options | Reject | Allow | Allow | Allow | +| Rename a field, even with its old JSON name retained | Reject | Reject | Reject | Allow | +| Change int32 to int64 | Reject | Reject | Reject | Allow | +| Change int32 to uint32 | Reject | Reject | Allow | Allow | +| Change string to bytes | Reject | Reject | Reject | Allow | +| Change bytes to string or int32 to sint32 | Reject | Reject | Reject | Reject | +| Delete a non-required field | Reject | Reject | Reserve number and name | Reserve number | +| Add/remove a required field or change a real oneof | Reject | Reject | Reject | Reject | +| Add explicit optional presence | Reject | Reject | Allow | Allow | +| Convert repeated entry messages to a compatible map | Reject | Reject | Reject | Allow | + +A map is encoded as repeated entry messages; repeated scalar values are not compatible merely because their type equals the map value type. Existing reserved names and number ranges cannot be released in any profile. Enum aliases are checked by name/number pairs for source/JSON and by retained numbers for WIRE. RPC/service removal, request/response identity, streaming, idempotency, and actual default-value changes remain checked. Source profiles additionally check supported file/field code-generation options, enum openness, declaration and extension ranges. WIRE_JSON also checks JSON format capability. + +Current and baseline sources are compiled separately using their own imports and pinned revisions. Diagnostics retain source coordinates and repository-relative paths; consumer managed options are not applied. Profiles work with section-scoped extends, ignores, local overlays and frozen verification. No source, manifest, lock or plugin output is written by breaking. + +The precise implemented rule catalog is internal/config/breaking_profiles.go. This feature does not claim full rule-for-rule Buf equivalence. It checks standard descriptor properties and supported effective Edition features, not arbitrary application-defined option semantics or external generated-code behavior. Unsupported syntax/editions are rejected by the pinned compiler instead of being declared compatible. breaking.ignore_unstable defaults to false. When true, it excludes packages on both sides whose final component matches vNtest..., vNalpha, vNbeta, vNpMalpha, or vNpMbeta. N and M are positive numbers without leading zeros; alpha/beta may have a similarly positive sequence number, and test may have any suffix. For example, acme.v1beta1 is skipped, while acme.v1beta1.service and acme.v0alpha1 are not. Stable packages and their references to unstable types remain checked; source reading and import resolution precede filtering. diff --git a/content/docs/cli/breaking-changes/index.ru.mdx b/content/docs/cli/breaking-changes/index.ru.mdx index 801e0a4..656d770 100644 --- a/content/docs/cli/breaking-changes/index.ru.mdx +++ b/content/docs/cli/breaking-changes/index.ru.mdx @@ -41,7 +41,26 @@ easyp --format json breaking --path proto ## Категории и нестабильные пакеты -Существующие проверки совместимости всегда остаются включёнными. Единственная поддерживаемая дополнительная категория — FILE: она добавляет проверки перемещений объявлений между файлами. Категории PACKAGE, WIRE, WIRE_JSON и другие зарезервированы и не реализованы; выбирать их нельзя. +Непустой breaking.categories выбирает профили сравнения скомпилированных дескрипторов: FILE, PACKAGE, WIRE_JSON или WIRE. Отсутствующая секция categories или пустой список сохраняют прежний checker; это не синоним WIRE. Несколько профилей применяются совместно без повторения одинаковых диагностик. + +| Изменение | FILE | PACKAGE | WIRE_JSON | WIRE | +|---|---|---|---|---| +| Перенос объявления внутри пакета с сохранением options | Ошибка | Допустимо | Допустимо | Допустимо | +| Переименование поля, даже при сохранённом JSON-имени | Ошибка | Ошибка | Ошибка | Допустимо | +| int32 → int64 | Ошибка | Ошибка | Ошибка | Допустимо | +| int32 → uint32 | Ошибка | Ошибка | Допустимо | Допустимо | +| string → bytes | Ошибка | Ошибка | Ошибка | Допустимо | +| bytes → string или int32 → sint32 | Ошибка | Ошибка | Ошибка | Ошибка | +| Удаление необязательного поля | Ошибка | Ошибка | Зарезервировать номер и имя | Зарезервировать номер | +| Добавление/удаление required или изменение настоящего oneof | Ошибка | Ошибка | Ошибка | Ошибка | +| Добавление явной optional-presence | Ошибка | Ошибка | Допустимо | Допустимо | +| Повторяемые entry-сообщения → совместимый map | Ошибка | Ошибка | Ошибка | Допустимо | + +Map кодируется повторяемыми entry-сообщениями: повторяемый scalar не становится совместимым с map только из-за совпадения типа значения. Существующие резервные имена и диапазоны номеров нельзя освобождать ни в одном профиле. Alias-значения enum проверяются по парам имя/номер для source/JSON и сохранённым номерам для WIRE. Проверяются удаления RPC/сервисов, типы запросов/ответов, streaming, idempotency и фактические значения по умолчанию. Source-профили дополнительно проверяют поддержанные file/field options генераторов, открытость enum, объявления и диапазоны extension. WIRE_JSON также проверяет возможность JSON-представления. + +Текущие исходники и baseline компилируются отдельно, со своими импортами и закреплёнными ревизиями. Диагностика сохраняет координаты исходника и путь относительно репозитория; consumer managed-options не применяются. Профили работают с extends, исключениями, локальными заменами и frozen-проверкой. Команда breaking не записывает исходники, manifest, lock или результат плагинов. + +Точный реализованный каталог правил находится в internal/config/breaking_profiles.go. Полная эквивалентность всем правилам Buf не заявляется. Проверяются стандартные свойства дескрипторов и поддержанные эффективные Edition features, а не произвольный смысл пользовательских options или поведение внешнего сгенерированного кода. Неподдерживаемый синтаксис/Edition отклоняется закреплённым компилятором, а не признаётся совместимым. breaking.ignore_unstable по умолчанию равен false. При true на обеих сторонах сравнения исключаются пакеты, последний компонент имени которых соответствует vNtest..., vNalpha, vNbeta, vNpMalpha или vNpMbeta. N и M — положительные числа без ведущего нуля; после alpha/beta допустим такой же положительный номер, после test — любой суффикс. Например, acme.v1beta1 пропускается, а acme.v1beta1.service и acme.v0alpha1 — нет. Стабильные пакеты и их ссылки на нестабильные типы всё ещё проверяются; чтение исходников и разрешение импортов происходят до фильтрации. diff --git a/content/docs/reference/easyp-yaml.mdx b/content/docs/reference/easyp-yaml.mdx index 66ec1c7..17e9b16 100644 --- a/content/docs/reference/easyp-yaml.mdx +++ b/content/docs/reference/easyp-yaml.mdx @@ -68,7 +68,7 @@ description: "Complete specification for easyp.yaml, configuring producer-side l default: "master" }, "breaking.categories": { - description: "Only FILE is supported: adds declaration-move checks while existing checks remain enabled. Other categories, including package-related categories, are reserved and rejected.", + description: "FILE, PACKAGE, WIRE_JSON, WIRE: distinct compatibility profiles. Omitted/empty preserves legacy checks; multiple profiles apply their union.", type: "string[]" }, "breaking.ignore_unstable": { @@ -154,7 +154,7 @@ The baseline can name a local branch, a lightweight or annotated tag, a full com Each selected module uses revision-local roots, manifests, and locks for its current and baseline revisions. The baseline is read from an isolated Git snapshot; the caller's checkout, manifest, and lock are unchanged. Policies come from current configuration and may each select a different baseline. See the [breaking guide](/docs/cli/breaking-changes) for local replacement limits. -The only supported additional category is FILE, which checks declarations moved between files. Existing checks remain enabled. PACKAGE, WIRE, WIRE_JSON, and other categories are unimplemented and cannot be selected. Shared policies use local relative paths or declared-module#policy-path; versions belong only in the module manifest and lock. +Select FILE for file/source compatibility, PACKAGE to allow moves within a package, WIRE_JSON for binary plus JSON, or WIRE for binary. See the [profile matrix](/docs/cli/breaking-changes). Omitted/empty categories preserve legacy checks. Shared policies remain pinned through the consuming manifest/lock. ## Unstable packages diff --git a/content/docs/reference/easyp-yaml.ru.mdx b/content/docs/reference/easyp-yaml.ru.mdx index fa56040..317afee 100644 --- a/content/docs/reference/easyp-yaml.ru.mdx +++ b/content/docs/reference/easyp-yaml.ru.mdx @@ -68,7 +68,7 @@ description: "Полная спецификация файла easyp.yaml, уп default: "master" }, "breaking.categories": { - description: "Поддерживается только FILE: добавляет проверки перемещения объявлений, сохраняя существующие проверки. Остальные категории, включая пакетные, зарезервированы и отклоняются.", + description: "FILE, PACKAGE, WIRE_JSON, WIRE: разные профили совместимости. Отсутствие/пустой список сохраняет прежние проверки; несколько профилей применяются совместно.", type: "string[]" }, "breaking.ignore_unstable": { @@ -154,7 +154,7 @@ breaking: Для каждого выбранного модуля текущая и базовая ревизии используют собственные корни, манифесты и lock. База читается из изолированного Git-снимка; рабочее дерево, манифест и lock пользователя не изменяются. Политики берутся из текущей конфигурации; каждая может задавать свою базу. Подробности и ограничения локальных замен — в [руководстве breaking](/ru/docs/cli/breaking-changes). -Единственная поддерживаемая дополнительная категория — FILE, проверяющая перемещения объявлений между файлами. Она не выключает существующие проверки. Категории PACKAGE, WIRE, WIRE_JSON и другие пока не реализованы; включать их нельзя. Общая политика задаётся локальным относительным путём или ссылкой объявленный-модуль#путь-политики. Версии указываются только в manifest и lock. +FILE проверяет совместимость файлов и исходного кода, PACKAGE разрешает переносы внутри пакета, WIRE_JSON защищает бинарное и JSON-представление, WIRE — бинарное. См. [матрицу профилей](/ru/docs/cli/breaking-changes). Отсутствие/пустой список categories сохраняет прежний checker. Общие политики закрепляются через manifest/lock потребителя. ## Нестабильные пакеты From d8779698ecabc2cc2f03f95bae50ace74ffb7d4b Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Wed, 30 Sep 2026 23:12:22 +0300 Subject: [PATCH 25/26] docs: feat(mcp): describe module grammar and locked dependencies --- content/docs/cli/configuration.mdx | 12 +++++++++++- content/docs/cli/configuration.ru.mdx | 12 +++++++++++- content/docs/reference/protobuf-lock.mdx | 4 ++++ content/docs/reference/protobuf-lock.ru.mdx | 4 ++++ content/docs/reference/protobuf-mod.mdx | 4 ++++ content/docs/reference/protobuf-mod.ru.mdx | 4 ++++ 6 files changed, 38 insertions(+), 2 deletions(-) diff --git a/content/docs/cli/configuration.mdx b/content/docs/cli/configuration.mdx index c778e92..f1baf08 100644 --- a/content/docs/cli/configuration.mdx +++ b/content/docs/cli/configuration.mdx @@ -90,7 +90,17 @@ easyp validate-config --cfg ./services/api/easyp.gen.yaml schema-gen --out-dir schemas writes separate JSON Schemas for easyp.yaml, easyp.gen.yaml, and protobuf.lock, each with a -v1.schema.json filename and an unversioned alias. protobuf.mod is a text manifest, so validate it with validate-config instead. CLI validation also checks semantic rules beyond the JSON Schemas. -The exported github.com/easyp-tech/easyp/mcp/easypconfig package registers easyp_config_describe with an MCP server through easypconfig.RegisterTool(server). The tool describes the two editable YAML files and reads the same JSON Schemas as schema-gen. It does not describe protobuf.mod or protobuf.lock. +The exported github.com/easyp-tech/easyp/mcp/easypconfig package registers easyp_config_describe through easypconfig.RegisterTool(server). The tool describes easyp.yaml, easyp.gen.yaml, protobuf.lock and protobuf.mod. YAML references use the same JSON Schemas as schema-gen; the text manifest returns grammar instead of a fabricated YAML/JSON Schema. + +~~~json +{"file":"protobuf.mod","path":"require[].version"} +~~~ + +~~~json +{"file":"protobuf.lock","path":"modules[0].commit"} +~~~ + +file is an exact format selector, not a path to read. Output includes format; YAML examples retain yaml, while manifest examples contain format: text and text. The grammar object describes text directives and block rules. All detail flags default to true; include_schema=false suppresses either the YAML schema or text grammar. examples_limit defaults to 10 and must be 1–50; invalid bounds are errors. The reference does not read project files, access the network, execute plugins or expand variables. Sample commit/hash values are synthetic, not verified repository contents. ## Minimal files diff --git a/content/docs/cli/configuration.ru.mdx b/content/docs/cli/configuration.ru.mdx index 575af70..9020cca 100644 --- a/content/docs/cli/configuration.ru.mdx +++ b/content/docs/cli/configuration.ru.mdx @@ -90,7 +90,17 @@ easyp validate-config --cfg ./services/api/easyp.gen.yaml schema-gen --out-dir schemas создаёт отдельные JSON Schema для easyp.yaml, easyp.gen.yaml и protobuf.lock: файлы с суффиксом -v1.schema.json и псевдонимы без версии. protobuf.mod — текстовый манифест; проверяйте его командой validate-config. CLI также проверяет семантические правила, не выраженные в JSON Schema. -Экспортируемый пакет github.com/easyp-tech/easyp/mcp/easypconfig регистрирует инструмент easyp_config_describe в MCP-сервере через easypconfig.RegisterTool(server). Инструмент описывает два редактируемых YAML-файла и использует те же JSON Schema, что и schema-gen. Он не описывает protobuf.mod и protobuf.lock. +Экспортируемый пакет github.com/easyp-tech/easyp/mcp/easypconfig регистрирует easyp_config_describe через easypconfig.RegisterTool(server). Инструмент описывает easyp.yaml, easyp.gen.yaml, protobuf.lock и protobuf.mod. YAML-справка использует те же JSON Schema, что и schema-gen; для текстового manifest возвращается грамматика, а не вымышленная YAML/JSON Schema. + +~~~json +{"file":"protobuf.mod","path":"require[].version"} +~~~ + +~~~json +{"file":"protobuf.lock","path":"modules[0].commit"} +~~~ + +file выбирает известный формат, а не путь для чтения. В ответе есть format; YAML-примеры сохраняют поле yaml, а примеры manifest содержат format: text и text. Объект grammar описывает директивы и правила блоков. Все флаги детализации по умолчанию включены; include_schema=false убирает YAML-схему или текстовую грамматику. examples_limit по умолчанию равен 10 и должен быть от 1 до 50; неверные границы вызывают ошибку. Справочник не читает файлы проекта, не обращается к сети, не запускает плагины и не раскрывает переменные. Commit и hash в примерах синтетические, а не проверенные данные репозитория. ## Минимальный пример diff --git a/content/docs/reference/protobuf-lock.mdx b/content/docs/reference/protobuf-lock.mdx index 9c38af4..f0e0681 100644 --- a/content/docs/reference/protobuf-lock.mdx +++ b/content/docs/reference/protobuf-lock.mdx @@ -73,3 +73,7 @@ The hash uses Go's dirhash.Hash1 over all regular file The v1 cache reuses an object store per Git remote. A known exact commit can be fetched without contacting the remote. A cold request first tries a depth-one fetch of the exact commit; if the server rejects that request, EasyP falls back to advertised reachable history. The original commit is still required: HEAD is never substituted. Tag lookups are refreshed separately so cache reuse cannot hide a retag. A commit absent from cache can still require access to its source. The source identity and SemVer version must satisfy the [major-version rules](/docs/reference/protobuf-mod): unsuffixed v0/v1, matching /vN for v2+. Invalid suffixes fail before installation. An unsuffixed v2+ +incompatible entry additionally requires the exact revision to have no native manifest, including when installed content is already cached. Commit pins still verify the exact native module identity, including in frozen mode. + +## MCP reference + +easyp_config_describe describes this format without reading local files. Use file: protobuf.lock and path: modules[].commit. See [configuration reference via MCP](/docs/cli/configuration). diff --git a/content/docs/reference/protobuf-lock.ru.mdx b/content/docs/reference/protobuf-lock.ru.mdx index 4163ee8..30cae53 100644 --- a/content/docs/reference/protobuf-lock.ru.mdx +++ b/content/docs/reference/protobuf-lock.ru.mdx @@ -73,3 +73,7 @@ modules: Для каждого Git remote кеш v1 повторно использует хранилище объектов. Известный точный коммит можно получить без обращения к remote. При холодном запросе сначала выполняется shallow-загрузка точного коммита с глубиной один; если сервер её отклоняет, используется доступная история объявленных ссылок. Всё равно требуется исходный коммит: HEAD вместо него не подставляется. Проверки тегов обновляются отдельно, поэтому кеш не скрывает перенос тега. Отсутствующий в кеше коммит всё ещё может потребовать доступа к источнику. Идентификатор source и SemVer в version должны соответствовать [правилам major-версий](/ru/docs/reference/protobuf-mod): v0/v1 без суффикса, v2+ с соответствующим /vN. Некорректные суффиксы отклоняются до установки. Для v2+ без суффикса пути запись +incompatible дополнительно требует отсутствия нативного manifest в точной ревизии, в том числе при уже заполненном кеше. Коммит проверяется по точному нативному имени модуля, включая frozen-режим. + +## Справка MCP + +easyp_config_describe описывает формат, не читая локальные файлы. Укажите file: protobuf.lock и path: modules[].commit. См. [справку по конфигурации через MCP](/ru/docs/cli/configuration). diff --git a/content/docs/reference/protobuf-mod.mdx b/content/docs/reference/protobuf-mod.mdx index 408eeb4..bce19a0 100644 --- a/content/docs/reference/protobuf-mod.mdx +++ b/content/docs/reference/protobuf-mod.mdx @@ -96,3 +96,7 @@ The pre-module +incompatible exception is supported only for unsuff See [Go major version suffixes](https://go.dev/ref/mod#major-version-suffixes) and [mapping versions to commits](https://go.dev/ref/mod#vcs-version). As in Go, an unversioned local replacement may contain a native manifest with the same unsuffixed identity while replacing an explicit legacy +incompatible requirement. This does not certify the published revision: the overlay preserves the shared lock, and frozen mode rejects replacements. Published fetches and both cold and warm locked installations still enforce the pre-native metadata check. + +## MCP reference + +easyp_config_describe describes this format without reading local files. Use file: protobuf.mod and path: require[].version. See [configuration reference via MCP](/docs/cli/configuration). diff --git a/content/docs/reference/protobuf-mod.ru.mdx b/content/docs/reference/protobuf-mod.ru.mdx index fdfdba4..9418b3e 100644 --- a/content/docs/reference/protobuf-mod.ru.mdx +++ b/content/docs/reference/protobuf-mod.ru.mdx @@ -96,3 +96,7 @@ v0 и v1 используют один путь без суффикса. Для См. [мажорные суффиксы Go](https://go.dev/ref/mod#major-version-suffixes) и [соответствие версий коммитам](https://go.dev/ref/mod#vcs-version). Как и в Go, локальная замена без опубликованной версии может содержать нативный манифест с тем же именем без суффикса для явного требования +incompatible. Это не подтверждает опубликованную ревизию: локальный граф сохраняет общий lock, а frozen-режим запрещает замены. Загрузка опубликованных версий и установка lock в холодном и прогретом кеше по-прежнему проверяют домодульные метаданные. + +## Справка MCP + +easyp_config_describe описывает формат, не читая локальные файлы. Укажите file: protobuf.mod и path: require[].version. См. [справку по конфигурации через MCP](/ru/docs/cli/configuration). From c0578ff50fef884fef4eeabd8cddb8469973a8b5 Mon Sep 17 00:00:00 2001 From: Khasbulat Abdullin Date: Mon, 5 Oct 2026 21:33:23 +0300 Subject: [PATCH 26/26] docs: prepare opt-in v1 nightly and update v1 contracts --- components/home/hero.tsx | 2 +- content/docs/cli/breaking-changes/index.mdx | 6 +- .../docs/cli/breaking-changes/index.ru.mdx | 6 +- content/docs/cli/generator/examples/go.mdx | 6 +- content/docs/cli/generator/examples/go.ru.mdx | 6 +- content/docs/cli/generator/index.mdx | 6 +- content/docs/cli/generator/index.ru.mdx | 6 +- content/docs/cli/package-manager/index.mdx | 12 ++- content/docs/cli/package-manager/index.ru.mdx | 12 ++- content/docs/guides/debugging-replace.mdx | 2 + content/docs/guides/debugging-replace.ru.mdx | 2 + content/docs/introduction/install.mdx | 95 ++++++++++++++----- content/docs/introduction/install.ru.mdx | 95 ++++++++++++++----- content/docs/introduction/quickstart.mdx | 8 +- content/docs/introduction/quickstart.ru.mdx | 8 +- content/docs/reference/easyp-gen-yaml.mdx | 16 +++- content/docs/reference/easyp-gen-yaml.ru.mdx | 16 +++- lib/github-release.test.mjs | 87 +++++++++++++++++ lib/github-release.ts | 81 ++++++++-------- package.json | 1 + 20 files changed, 371 insertions(+), 102 deletions(-) create mode 100644 lib/github-release.test.mjs diff --git a/components/home/hero.tsx b/components/home/hero.tsx index 4600822..aa620e3 100644 --- a/components/home/hero.tsx +++ b/components/home/hero.tsx @@ -22,7 +22,7 @@ export function Hero({ version = 'vX.X.X' }: { version?: string }) { const installOptions: InstallOption[] = [ { id: 'brew', label: 'brew', fullLabel: 'macOS (homebrew)', cmd: 'brew install easyp-tech/tap/easyp' }, { id: 'go', label: 'go', fullLabel: 'go Install (any OS)', cmd: 'go install github.com/easyp-tech/easyp/cmd/easyp@latest' }, - { id: 'docker', label: 'docker', fullLabel: 'docker', cmd: 'docker pull easyp/easyp:latest' }, + { id: 'docker', label: 'docker', fullLabel: 'docker', cmd: 'docker pull ghcr.io/easyp-tech/easyp:latest' }, ] const activeOption = installOptions.find((o) => o.id === installMethod) || installOptions[0] diff --git a/content/docs/cli/breaking-changes/index.mdx b/content/docs/cli/breaking-changes/index.mdx index 80ed21a..07aabdf 100644 --- a/content/docs/cli/breaking-changes/index.mdx +++ b/content/docs/cli/breaking-changes/index.mdx @@ -27,6 +27,8 @@ The baseline can name a local branch, a lightweight or annotated tag, a full com --path selects a file or directory relative to the scan root; --root changes that root from the policy directory. Checked file identities remain repository-relative. breaking.ignore excludes directories; vendored sources are excluded from targets. +Directory and file symlinks select their canonical repository paths, including a deleted suffix beneath an existing directory. Selecting an alias does not skip changes visible through the original path. Targets outside the repository are rejected. + breaking.ignore paths are relative to the file supplying the effective breaking section, not the Git root or --root. For example, ignore: [generated] in api/easyp.yaml excludes api/generated, including when that section is inherited. Entries must be nonempty local relative paths; absolute paths and paths escaping the policy directory or repository are rejected. Policies come from current configuration. Each nearest defined breaking section applies as a whole; nested policies may select different baselines. Repeated identical findings are emitted once. @@ -35,13 +37,15 @@ Policies come from current configuration. Each nearest defined breakingprotobuf.mod, protobuf.lock, and dependencies. Baseline sources, manifests, and locks are read from an isolated Git snapshot. The caller's checkout, manifest, and lock are unchanged; the verified dependency cache may be populated. Temporary snapshots are removed after use. +Buf source filters and replacement metadata also belong to their respective revisions. Current files or filters never substitute for missing historical metadata. During consumer checks, reached replacement sources supply imports; they become policy targets only when explicitly selected. Unused replacements cannot exclude consumer targets. + Baseline-only files and deleted modules remain checkable, including through --path. Dependency findings use the policy of the selected files. A policy can also run without a module manifest. Local replacements inside the repository use the contents of the corresponding revision; absolute paths inside the repository are mapped into the baseline snapshot. External local replacements are rejected because they have no recoverable historical identity. Use a locked dependency for a reproducible baseline. ## Categories and unstable packages -Nonempty breaking.categories selects real descriptor-based profiles: FILE, PACKAGE, WIRE_JSON, or WIRE. Omitted or empty categories retain the legacy checker; this is not an alias for WIRE. Multiple profiles apply their union without duplicate diagnostics. +breaking.categories selects descriptor-based profiles: FILE, PACKAGE, WIRE_JSON, or WIRE. Omitted or empty categories select FILE. Multiple profiles apply their union without duplicate diagnostics. | Change | FILE | PACKAGE | WIRE_JSON | WIRE | |---|---|---|---|---| diff --git a/content/docs/cli/breaking-changes/index.ru.mdx b/content/docs/cli/breaking-changes/index.ru.mdx index 656d770..0765706 100644 --- a/content/docs/cli/breaking-changes/index.ru.mdx +++ b/content/docs/cli/breaking-changes/index.ru.mdx @@ -27,6 +27,8 @@ easyp --format json breaking --path proto --path выбирает файл или каталог относительно корня проверки; --root меняет этот корень с каталога политики. Идентичность проверяемых файлов остаётся относительно Git-репозитория. breaking.ignore исключает каталоги; вендорные исходники не становятся целями проверки. +Symlink на каталог или файл выбирает канонический путь внутри репозитория, в том числе удалённый суффикс под существующим каталогом. Выбор ссылки не пропускает изменения, видимые по исходному пути. Цели за пределами репозитория отклоняются. + Пути breaking.ignore отсчитываются от файла, задающего эффективную секцию breaking, а не от корня Git или --root. Например, ignore: [generated] в api/easyp.yaml исключает api/generated, в том числе при наследовании этой секции. Допустимы непустые локальные относительные пути; абсолютные пути и выход за каталог политики или репозиторий отклоняются. Политики берутся из текущей конфигурации. Ближайшая определённая секция breaking применяется целиком; вложенные политики могут выбирать разные базы. Повторяющиеся одинаковые замечания выводятся один раз. @@ -35,13 +37,15 @@ easyp --format json breaking --path proto Каждый выбранный модуль сравнивается отдельно. Текущая ревизия и база используют собственные корни модулей, protobuf.mod, protobuf.lock и зависимости. Исходники, манифесты и lock базы читаются из изолированного Git-снимка. Рабочее дерево, манифест и lock пользователя не меняются; проверенный кеш зависимостей может пополняться. Временные снимки удаляются после проверки. +Фильтры Buf и метаданные замен также берутся из соответствующей ревизии. Текущие файлы и фильтры не подставляются вместо отсутствующих исторических метаданных. При проверке потребителя достижимые исходники замен предоставляют импорты; собственная политика проверяется при явном выборе замены. Неиспользуемые замены не исключают цели потребителя. + Файлы, существующие только в базе, и удалённые модули остаются доступными для проверки, в том числе через --path. Политика выбранных файлов определяет и политику замечаний о зависимостях. Проверка возможна и без манифеста модуля. Локальная замена внутри репозитория использует содержимое соответствующей ревизии; абсолютный путь внутри репозитория отображается в снимок базы. Внешняя локальная замена отклоняется: у неё нет восстановимой исторической идентичности. Для воспроизводимой базы используйте зафиксированную зависимость. ## Категории и нестабильные пакеты -Непустой breaking.categories выбирает профили сравнения скомпилированных дескрипторов: FILE, PACKAGE, WIRE_JSON или WIRE. Отсутствующая секция categories или пустой список сохраняют прежний checker; это не синоним WIRE. Несколько профилей применяются совместно без повторения одинаковых диагностик. +breaking.categories выбирает профили сравнения скомпилированных дескрипторов: FILE, PACKAGE, WIRE_JSON или WIRE. Отсутствующий или пустой список выбирает FILE. Несколько профилей применяются совместно без повторения одинаковых диагностик. | Изменение | FILE | PACKAGE | WIRE_JSON | WIRE | |---|---|---|---|---| diff --git a/content/docs/cli/generator/examples/go.mdx b/content/docs/cli/generator/examples/go.mdx index 1a57d5f..bdd9336 100644 --- a/content/docs/cli/generator/examples/go.mdx +++ b/content/docs/cli/generator/examples/go.mdx @@ -1,6 +1,6 @@ --- title: "Generate Go code" -description: "A minimal EasyP v1 generator using local Go plugins." +description: "A minimal EasyP v1 generator using Go plugins." --- Declare the source root in `protobuf.mod`: @@ -27,6 +27,8 @@ plugins: paths: source_relative ``` -Place `protoc-gen-go` and `protoc-gen-go-grpc` on `PATH`, then run `easyp generate`. A `go_package` option in each source file, or a managed `options.go.package_prefix`, supplies the Go import path. See the [managed options reference](/docs/reference/easyp-gen-yaml). +Run `easyp generate`. If `protoc-gen-go` or `protoc-gen-go-grpc` is on `PATH`, EasyP uses that executable; otherwise it uses the corresponding bundled WASM plugin. A `go_package` option in each source file, or a managed `options.go.package_prefix`, supplies the Go import path. See the [managed options reference](/docs/reference/easyp-gen-yaml). + +For example, adding `options.go.package_prefix: github.com/acme/contracts/gen/go` maps the protobuf package `common.v1` to `github.com/acme/contracts/gen/go/common/v1`. With `paths: source_relative`, the generated files go to `gen/go/common/v1`, keeping directories aligned with the Go imports. The `go` and `go-grpc` names identify plugins; the v1 generator has no `generate.inputs` or `--path` option. Its inputs come from the selected module's roots. diff --git a/content/docs/cli/generator/examples/go.ru.mdx b/content/docs/cli/generator/examples/go.ru.mdx index b9a73bc..d2d51e5 100644 --- a/content/docs/cli/generator/examples/go.ru.mdx +++ b/content/docs/cli/generator/examples/go.ru.mdx @@ -1,6 +1,6 @@ --- title: "Генерация Go-кода" -description: "Минимальная конфигурация EasyP v1 с локальными Go-плагинами." +description: "Минимальная конфигурация EasyP v1 с Go-плагинами." --- Объявите корень исходников в `protobuf.mod`: @@ -27,6 +27,8 @@ plugins: paths: source_relative ``` -Добавьте `protoc-gen-go` и `protoc-gen-go-grpc` в `PATH`, затем выполните `easyp generate`. Go import path задаётся опцией `go_package` в `.proto` или managed-опцией `options.go.package_prefix`. Подробности — в [справочнике managed mode](/ru/docs/reference/easyp-gen-yaml). +Выполните `easyp generate`. Если `protoc-gen-go` или `protoc-gen-go-grpc` доступен в `PATH`, EasyP использует этот бинарник; иначе запускает соответствующий встроенный WASM-плагин. Go import path задаётся опцией `go_package` в `.proto` или managed-опцией `options.go.package_prefix`. Подробности — в [справочнике managed mode](/ru/docs/reference/easyp-gen-yaml). + +Например, `options.go.package_prefix: github.com/acme/contracts/gen/go` отображает protobuf-пакет `common.v1` в `github.com/acme/contracts/gen/go/common/v1`. С `paths: source_relative` файлы попадают в `gen/go/common/v1`, согласуя каталоги с Go-импортами. Имена `go` и `go-grpc` обозначают плагины. У генератора v1 нет `generate.inputs` или флага `--path`: исходники берутся из корней выбранного модуля. diff --git a/content/docs/cli/generator/index.mdx b/content/docs/cli/generator/index.mdx index dbe7f33..f1358ba 100644 --- a/content/docs/cli/generator/index.mdx +++ b/content/docs/cli/generator/index.mdx @@ -87,8 +87,12 @@ All requested graphs and export destinations pass preflight before any plugin ru Each plugin sets exactly one source: name, path, command, or remote. Local binaries and commands run from the invocation directory. Remote plugins require a pinned semantic version; local and bundled plugins reject a separate version field. +Bundled names such as go and go-grpc use a matching protoc-gen-* on PATH when available, otherwise their bundled WASM plugin. + plugins[].with_imports defaults to false. Set it to true for a particular plugin to generate code for transitive imports as well as the selected files. Other plugins still receive dependency descriptors for linking. This setting is independent of descriptor export's --include_imports. Keep Go import paths and output directories aligned: different Go packages must not share one generated directory. Identical shared outputs are deduplicated; conflicting file contents or Go package declarations fail before generated files are written. options.go.package_prefix changes Go options only. Defaults for other languages and field-option transformations require explicit generate.managed.enabled: true. An inherited Go prefix precedes explicit managed Go overrides; a prefix in the current file has the highest priority. Go disable selectors still apply. See the full [configuration reference](/docs/reference/easyp-gen-yaml). -Dependency repositories may use v1 EasyP, older EasyP, Buf v1, or Buf v2 metadata. EasyP reads dependency metadata without executing dependency plugins. +A plain prefix maps a multi-component protobuf package such as common.v1 to <prefix>/common/v1. With explicit paths: source_relative, Go output directories follow the plugin's effective import path under that prefix, including its Mfile.proto mappings. Insertion-point outputs follow the producer's output file. See [Go output paths and plugin mappings](/docs/reference/easyp-gen-yaml#go-output-paths-and-plugin-mappings) for marker templates and precedence. + +Dependency repositories may use v1 EasyP, older EasyP, Buf v1, or Buf v2 metadata. EasyP reads dependency metadata without executing dependency plugins. Buf source includes/excludes also apply when selecting a dependency or its packages for generation; excluded files cannot be reintroduced as imports. See [dependency metadata and filters](/docs/cli/package-manager#dependencies-using-buf-or-older-easyp). diff --git a/content/docs/cli/generator/index.ru.mdx b/content/docs/cli/generator/index.ru.mdx index 87e3a53..02ed54e 100644 --- a/content/docs/cli/generator/index.ru.mdx +++ b/content/docs/cli/generator/index.ru.mdx @@ -87,8 +87,12 @@ easyp generate --all --descriptor_set_out_dir build/descriptors --include_import Каждый плагин задаёт ровно один источник: name, path, command или remote. Локальные бинарные файлы и команды запускаются из каталога вызова EasyP. Удалённому плагину нужен зафиксированный SemVer в version; локальные и встроенные плагины отдельную версию не принимают. +Встроенные имена вроде go и go-grpc используют соответствующий protoc-gen-* из PATH, если он доступен; иначе запускается встроенный WASM-плагин. + plugins[].with_imports по умолчанию равен false. Значение true включает генерацию транзитивных импортов только для этого плагина. Остальные плагины по-прежнему получают дескрипторы зависимостей для связывания. Настройка независима от --include_imports при экспорте дескрипторов. Согласуйте Go import path и выходные каталоги: разные Go-пакеты не должны попадать в один каталог. Одинаковые общие результаты объединяются; конфликт содержимого файлов или объявлений Go-пакетов обнаруживается до записи сгенерированных файлов. options.go.package_prefix меняет только Go-опции. Значения по умолчанию для других языков и преобразования опций полей требуют явного generate.managed.enabled: true. Унаследованный Go-префикс применяется до явных managed-переопределений Go; префикс текущего файла имеет наивысший приоритет. Go-селекторы disable продолжают действовать. Подробнее — в [справочнике конфигурации](/ru/docs/reference/easyp-gen-yaml). -Зависимости могут использовать метаданные EasyP v1, старого EasyP, Buf v1 или Buf v2. EasyP читает метаданные зависимостей, не запуская их плагины. +Обычный префикс отображает protobuf-пакет из нескольких компонентов, например common.v1, в <prefix>/common/v1. С явным paths: source_relative выходные каталоги Go следуют эффективному import path плагина под этим префиксом, включая его параметры Mfile.proto. Результаты с insertion point следуют выходному файлу создавшего его плагина. Шаблоны и приоритеты описаны в [справочнике выходных путей Go](/ru/docs/reference/easyp-gen-yaml#выходные-пути-go-и-параметры-m). + +Зависимости могут использовать метаданные EasyP v1, старого EasyP, Buf v1 или Buf v2. EasyP читает метаданные зависимостей, не запуская их плагины. Buf includes/excludes действуют и при выборе зависимости или её пакетов для генерации; исключённые файлы нельзя вернуть через импорты. См. [метаданные и фильтры зависимостей](/ru/docs/cli/package-manager#зависимости-на-buf-или-старом-easyp). diff --git a/content/docs/cli/package-manager/index.mdx b/content/docs/cli/package-manager/index.mdx index 6cbaa7a..08c2381 100644 --- a/content/docs/cli/package-manager/index.mdx +++ b/content/docs/cli/package-manager/index.mdx @@ -23,8 +23,12 @@ A versionless requirement adds no constraint when the graph supplies a SemVer or replace module => ../local-copy applies only from the main protobuf.mod, including to transitive requirements. All relative replacement paths use the main manifest directory; absolute paths are used directly. With replace, commands use a local effective graph and preserve protobuf.lock byte-for-byte; a missing lock is not created. mod tidy also leaves the manifest unchanged. get and mod update may edit explicit requirements without adding fork-only transitives. mod download installs only needed unreplaced snapshots. Remove replacements and run mod tidy to produce a publishable lock. See [local replacements](/docs/guides/debugging-replace). +A replacement applies only when its module is reached through direct or transitive requirements. An unused replacement is not read or fetched and cannot hide the consumer's sources from lint or breaking checks. Reached replacement trees supply imports during consumer checks; select one explicitly with --path to check its own policy. Frozen still rejects every replacement, including unused ones. + For a Git repository with several manifests, require each nested module separately by its identity. For example, require repo/foo and require repo/bar need no module-specific tags if HEAD is suitable. A v1.2.3 release of the module in foo/ uses tag foo/v1.2.3. Each module's roots are resolved independently. +For a selected tag or commit, module identity, roots, and requirements come from that revision. A nested module remains usable even if its directory was deleted or replaced by a regular file at current HEAD. Native manifests must match the requested identity at the selected revision; invalid native metadata does not fall back to Buf or legacy EasyP, and a pinned revision is never replaced with HEAD. + Module commands and get find the nearest ancestor protobuf.mod within the workspace. easyp get <module> adds a direct requirement; @v1.2.3 or @<full-commit> selects a version. Without a suffix, the unconstrained-requirement rules above apply. Transitive requirements are added with // indirect, and repeated calls do not duplicate entries. Resolution errors leave the manifest and lock unchanged. Major versions use Go-style identities: v0/v1 are unsuffixed; v2+ requires matching /vN. The +incompatible exception requires verified pre-native metadata; it never bypasses a native manifest. See [exact grammar and Git mapping](/docs/reference/protobuf-mod). @@ -59,7 +63,13 @@ A Git dependency may declare its proto roots in buf.work.yaml, Buf When adapting an older easyp.yaml, both deps and generation Git inputs contribute requirements. Exact source/version duplicates are removed; different minimums remain visible to MVS, and malformed deps fail explicitly. A matching native protobuf.mod takes precedence. Only metadata is read; dependency plugins are never executed. -EasyP reads Buf v1, v1beta1, and v2 deps as BSR references, including dependencies declared by modules selected through a v1 buf.work.yaml. A nonempty list is rejected explicitly with the declaring config and references instead of being silently discarded. Automatic BSR-to-Git mapping is intentionally not implemented yet; a Git dependency that uses BSR dependencies needs equivalent native protobuf.mod metadata before EasyP can resolve it. Buf include/exclude filters are also not supported as Git import roots and produce an explicit error. +EasyP reads Buf v1, v1beta1, and v2 deps, including declarations in modules selected through buf.work.yaml. The current compatibility resolver maps known BSR modules to fixed Git snapshots: Googleapis, grpc-gateway, grpc-federation, protoc-gen-validate, and protovalidate. Unknown BSR modules fail explicitly; EasyP does not guess a Git repository from their name. A native protobuf.mod takes precedence, and direct BSR requirements in the consumer's manifest are not supported. + +The lock preserves the original BSR reference and pin alongside the Git binding. Resolution reports compatibility_snapshot: the fixed Git source is hash-verified, but this is not proof of equivalence to an arbitrary BSR revision or verification of its BSR digest. Frozen builds reuse the recorded bindings. Regenerate older locks with mod tidy outside frozen when a dependency declares BSR inputs. + +Buf v1/v1beta1 build.excludes and v2 modules[].includes/excludes select files without changing their import paths. Paths are relative to the declaring buf.yaml; nested workspace configs retain that base. Overlapping roots in one Buf module configuration select the union of their allowed files. + +The same selection applies to imports, dependency generation and package selection, file listing, lint and breaking contexts, collision checks, and vendoring. Excluded files stay unavailable through symlink aliases or a broad consumer root, whether the excluded path is the alias or its physical target. An excluded dependency file does not conflict with an allowed consumer file at the same import path. See [protobuf.mod](/docs/reference/protobuf-mod) and [protobuf.lock](/docs/reference/protobuf-lock) for their field-level formats. diff --git a/content/docs/cli/package-manager/index.ru.mdx b/content/docs/cli/package-manager/index.ru.mdx index fac1f20..de14f1a 100644 --- a/content/docs/cli/package-manager/index.ru.mdx +++ b/content/docs/cli/package-manager/index.ru.mdx @@ -23,8 +23,12 @@ require ( replace module => ../local-copy применяется только из главного protobuf.mod, в том числе к транзитивным требованиям. Все относительные пути замены считаются от главного манифеста; абсолютные используются напрямую. При наличии replace команды работают с локальным эффективным графом и сохраняют protobuf.lock побайтно; отсутствующий lock не создаётся. mod tidy также не меняет манифест. get и mod update могут менять явные требования, но не добавляют транзитивные зависимости только из форка. mod download устанавливает только нужные незаменённые снимки. Для публикуемого lock удалите замены и выполните mod tidy. Подробнее: [локальные замены](/ru/docs/guides/debugging-replace). +Замена применяется, только если модуль достижим через прямые или транзитивные требования. Неиспользуемая замена не читается и не скачивается и не может скрыть исходники потребителя от lint или breaking. При проверке потребителя достижимые деревья замен предоставляют импорты; явно выберите замену через --path, чтобы проверить её собственную политику. Frozen по-прежнему отклоняет все замены, включая неиспользуемые. + Если в Git-репозитории несколько манифестов, объявляйте каждый вложенный модуль отдельно по его имени. Например, require repo/foo и require repo/bar не требуют отдельных тегов, если HEAD подходит. Для релиза v1.2.3 модуля в foo/ используется тег foo/v1.2.3. Корни каждого модуля разрешаются независимо. +Для выбранного тега или коммита идентичность модуля, корни и требования читаются из этой ревизии. Вложенный модуль остаётся доступным, даже если на текущем HEAD его каталог удалён или заменён обычным файлом. Нативный манифест в выбранной ревизии должен соответствовать запрошенному модулю; некорректные native-метаданные не заменяются Buf или старым EasyP, а вместо закреплённой ревизии никогда не используется HEAD. + Команды mod и get находят ближайший protobuf.mod в предках в пределах workspace. easyp get <модуль> добавляет прямое требование; @v1.2.3 или @<полный-коммит> задаёт версию. Без суффикса применяется описанное выше неограниченное требование. Транзитивные требования дописываются с // indirect, повторный вызов не создаёт дубликаты. При ошибке разрешения манифест и lock не меняются. Мажорные версии используют идентичность как в Go: v0/v1 — без суффикса, v2+ — с соответствующим /vN. Исключение +incompatible требует проверки домодульных метаданных и не обходит нативный manifest. См. [точную грамматику и Git mapping](/ru/docs/reference/protobuf-mod). @@ -59,7 +63,13 @@ Git-зависимость может объявлять корни .proto При адаптации старого easyp.yaml требования берутся и из deps, и из Git-входов генерации. Точные дубликаты источник/версия удаляются, разные минимумы сохраняются для MVS; некорректные deps вызывают ошибку. Совпадающий нативный protobuf.mod имеет приоритет. Читаются только метаданные, плагины зависимости не запускаются. -EasyP читает deps Buf v1, v1beta1 и v2 как ссылки BSR, в том числе зависимости модулей, выбранных через v1 buf.work.yaml. Непустой список теперь явно отклоняется с указанием исходного конфига и ссылок, а не молча теряется. Автоматическое сопоставление BSR→Git пока намеренно не реализовано: Git-зависимости с BSR-зависимостями нужны эквивалентные native-метаданные protobuf.mod, прежде чем EasyP сможет разрешить такой граф. Фильтры Buf include/exclude для корней Git-зависимостей также пока не поддерживаются и вызывают явную ошибку. +EasyP читает deps Buf v1, v1beta1 и v2, включая объявления в модулях, выбранных через buf.work.yaml. Текущий resolver совместимости сопоставляет известные BSR-модули с фиксированными Git-снимками: Googleapis, grpc-gateway, grpc-federation, protoc-gen-validate и protovalidate. Неизвестный BSR-модуль вызывает явную ошибку; EasyP не угадывает Git-репозиторий по имени. Нативный protobuf.mod имеет приоритет; прямые BSR-требования в манифесте потребителя не поддерживаются. + +Lock сохраняет исходную BSR-ссылку и pin вместе с Git-привязкой. Разрешение сообщает compatibility_snapshot: хеш Git-исходников проверяется, но это не доказательство эквивалентности произвольной BSR-ревизии и не проверка её BSR digest. Frozen использует сохранённые привязки. Старые lock-файлы для зависимостей с BSR-объявлениями пересоздайте через mod tidy вне frozen. + +Buf v1/v1beta1 build.excludes и v2 modules[].includes/excludes выбирают файлы без изменения import path. Пути считаются от объявляющего buf.yaml; вложенные конфиги workspace сохраняют эту базу. Пересекающиеся корни одного Buf-конфига выбирают объединение разрешённых файлов. + +Тот же отбор действует для импортов, генерации зависимостей и выбора пакетов, списка файлов, контекстов lint и breaking, проверки коллизий и vendoring. Исключённый файл нельзя вернуть через symlink или широкий корень потребителя: учитывается как путь ссылки, так и её физическая цель. Исключённый файл зависимости не конфликтует с разрешённым файлом потребителя по тому же import path. Форматы полей описаны в справочниках [protobuf.mod](/ru/docs/reference/protobuf-mod) и [protobuf.lock](/ru/docs/reference/protobuf-lock). diff --git a/content/docs/guides/debugging-replace.mdx b/content/docs/guides/debugging-replace.mdx index fbb3f77..75077b9 100644 --- a/content/docs/guides/debugging-replace.mdx +++ b/content/docs/guides/debugging-replace.mdx @@ -34,6 +34,8 @@ Only the main consumer's replacements apply, at every depth of the required grap Generate, selected dependency generation, both descriptor export modes, lint, ls-files and breaking import resolution use this same effective graph. Replaced modules need no remote fetch and may be unpublished. A fully local graph works offline without a lock. +Reached replacement trees are imports during consumer lint and breaking checks; their policies do not become consumer policies. Use --path to check a replacement explicitly. Unused replacement paths cannot exclude the consumer's own sources. Buf includes/excludes remain effective for replacement sources; see [dependency filters](/docs/cli/package-manager#dependencies-using-buf-or-older-easyp). + ## Local Mode and the Published Lock While the main manifest contains replacements, EasyP leaves an existing protobuf.lock **byte-for-byte unchanged** and does not create one if absent. Local paths, local versions/hashes and fork-only transitive dependencies never enter the shared lock. This is an explicit EasyP invariant: protobuf.lock is not go.sum, and this does not mean Go never updates go.sum with replacements. The main-module replacement semantics follow [Go's replacement model](https://go.dev/ref/mod#go-mod-file-replace). diff --git a/content/docs/guides/debugging-replace.ru.mdx b/content/docs/guides/debugging-replace.ru.mdx index e2b3244..a5dabee 100644 --- a/content/docs/guides/debugging-replace.ru.mdx +++ b/content/docs/guides/debugging-replace.ru.mdx @@ -34,6 +34,8 @@ easyp generate --project ./proto/user Генерация, выбор зависимостей для генерации, оба режима экспорта дескрипторов, lint, ls-files и разрешение импортов breaking используют один эффективный граф. Заменённые модули не требуют удалённой загрузки и могут быть неопубликованными. Полностью локальный граф работает офлайн без lock-файла. +При lint и breaking потребителя достижимые деревья замен служат импортами; их политики не становятся политиками потребителя. Используйте --path для явной проверки замены. Пути неиспользуемых замен не исключают собственные исходники потребителя. Buf includes/excludes действуют и для замен; см. [фильтры зависимостей](/ru/docs/cli/package-manager#зависимости-на-buf-или-старом-easyp). + ## Локальный режим и публикуемый lock Пока в главном манифесте есть замены, EasyP оставляет существующий protobuf.lock **побайтно неизменным**, а отсутствующий не создаёт. Локальные пути, версии/хеши и транзитивные зависимости только из форка не попадают в общий lock. Это явный инвариант EasyP: protobuf.lock не является go.sum, и это не утверждение, что Go никогда не меняет go.sum при заменах. Правила применения замен главного модуля следуют [модели Go](https://go.dev/ref/mod#go-mod-file-replace). diff --git a/content/docs/introduction/install.mdx b/content/docs/introduction/install.mdx index f22add4..6478ab8 100644 --- a/content/docs/introduction/install.mdx +++ b/content/docs/introduction/install.mdx @@ -1,10 +1,12 @@ --- -title: "Install the EasyP cli" +title: "Install EasyP" --- -### Install from system's package manager + +Install EasyP v1 only by an explicitly selected, published nightly tag. The default stable installation remains v0.17.0 while v1 has only prerelease tags. To use the v1 configuration and commands in these docs, follow [the nightly instructions](#opt-into-v1-nightly). + -##### Recommended installation method +## Install the stable CLI @@ -19,35 +21,84 @@ title: "Install the EasyP cli" `Work in progress`: support for apt, yum, pacman, etc. is under development. - #### Requires Go 1.24 or later + #### Go toolchain - Installs the latest stable version of EasyP using the Go toolchain: + Install the latest published stable version using the Go toolchain required by that release: ```bash go install github.com/easyp-tech/easyp/cmd/easyp@latest ``` - #### Build from source + Download the archive for your OS and architecture from the [latest stable release](https://github.com/easyp-tech/easyp/releases/latest). Extract it and place the `easyp` binary on `PATH`. + + - 1. Clone the official repository: +The stable Docker channel is `ghcr.io/easyp-tech/easyp:latest`; it currently +points to the same image as `ghcr.io/easyp-tech/easyp:v0.17.0`. - ```bash - git clone https://github.com/easyp-tech/easyp.git - ``` +## Opt into v1 nightly - 2. Build binary with Go: +Nightly tags use `v1.0.0-nightly.YYYYMMDD.sequence`. Choose an exact published tag from [GitHub Releases](https://github.com/easyp-tech/easyp/releases). The tag `v1.0.0-nightly.20261005.1` below is an example, not a promise that this release exists; replace it with a published tag before running any command. Nightly releases do not update the stable Homebrew formula or Docker `latest` image. - ```bash - go build ./cmd/easyp - ``` - - +### Go: CLI and MCP + +Building v1 requires **Go 1.26.6 or later**. Install both binaries at the same exact version in a separate directory to keep your stable CLI on `PATH`: + +```bash +# Example only: replace with an actual published nightly tag. +NIGHTLY_TAG='v1.0.0-nightly.20261005.1' +NIGHTLY_BIN="$HOME/.local/share/easyp-nightly/bin" +mkdir -p "$NIGHTLY_BIN" +GOBIN="$NIGHTLY_BIN" go install "github.com/easyp-tech/easyp/cmd/easyp@${NIGHTLY_TAG}" +GOBIN="$NIGHTLY_BIN" go install "github.com/easyp-tech/easyp/cmd/easyp-mcp@${NIGHTLY_TAG}" +"$NIGHTLY_BIN/easyp" --version +``` + +Invoke the nightly CLI by its full path. Configure your MCP client to run the `easyp-mcp` binary from this directory as a stdio server; it exposes the v1 configuration reference through `easyp_config_describe`. To run the v1 examples with bare `easyp` commands, select the nightly for that terminal session with `export PATH="$NIGHTLY_BIN:$PATH"`. Keep it off your permanent `PATH` to retain stable defaults. + +### Release archive: CLI and MCP + +The v1 archive contains both `easyp` and `easyp-mcp`. Download the asset matching your platform and verify it with the release checksums. For Linux amd64: + +```bash +# Example only: replace with an actual published nightly tag. +NIGHTLY_TAG='v1.0.0-nightly.20261005.1' +NIGHTLY_VERSION="${NIGHTLY_TAG#v}" +NIGHTLY_ASSET="easyp-${NIGHTLY_VERSION}-linux-amd64.tar.gz" +NIGHTLY_BIN="$HOME/.local/share/easyp-nightly/bin" +curl -fLO "https://github.com/easyp-tech/easyp/releases/download/${NIGHTLY_TAG}/${NIGHTLY_ASSET}" +curl -fLO "https://github.com/easyp-tech/easyp/releases/download/${NIGHTLY_TAG}/easyp-${NIGHTLY_VERSION}-checksums.txt" +sha256sum --check --ignore-missing "easyp-${NIGHTLY_VERSION}-checksums.txt" +mkdir -p "$NIGHTLY_BIN" +tar -xzf "$NIGHTLY_ASSET" --strip-components=1 -C "$NIGHTLY_BIN" +"$NIGHTLY_BIN/easyp" --version +``` + +Invoke the CLI and MCP binaries by their full paths in this separate directory. macOS archives use `darwin`; Windows archives use `.zip` and contain `.exe` binaries. No Go toolchain is needed to run these binaries. + +### Docker: CLI + +The nightly CLI image uses its exact tag in GHCR: + +```bash +# Example only: replace with an actual published nightly tag. +NIGHTLY_TAG='v1.0.0-nightly.20261005.1' +docker run --rm -v "$PWD:/workspace" -w /workspace \ + "ghcr.io/easyp-tech/easyp:${NIGHTLY_TAG}" --version +``` + +Replace `--version` with the EasyP command you need. This image contains the CLI; use the Go install or archive for the MCP stdio server. + +## Go modules: moving from v0 to v1 + +EasyP v0 and v1 share the module path `github.com/easyp-tech/easyp`; there is no `/v1` suffix. Go requires a new `/v2` path starting at major version 2 so incompatible major versions can coexist. A v0→v1 upgrade can still require changes to your code and configuration. See [Go's version numbering](https://go.dev/doc/modules/version-numbers). + +Merging v1 development into `main` leaves the published `v0.17.0` tag and pinned v0 installations unchanged. When starting from v0, `@latest` and ordinary `go get -u` prefer a published stable version over v1 prereleases; explicitly requesting a nightly opts into v1 and its API/configuration changes. An existing requirement on a higher prerelease is not automatically downgraded. See [Go version queries](https://go.dev/ref/mod#version-queries). -## Local Installation Considerations +A stable `v1.0.0` Git tag would become eligible for Go's default selection even without a GitHub Release, or if that Release were marked prerelease. For this nightly-only phase, publish only the exact nightly tag format above. `@main` explicitly requests development code; it is not the stable installation channel. -Package managers are recommended over manual binary compilation because package managers provide: -- Automatic updates and security patches -- Better integration with system package management -- Simplified installation and uninstallation -- Verified binary distribution +Go selects one version per module path for a build. A different dependency +requiring a v1 nightly can also raise the selected EasyP version through +[minimal version selection](https://go.dev/ref/mod#minimal-version-selection). +Library consumers keeping v0 need a dependency graph compatible with that version. diff --git a/content/docs/introduction/install.ru.mdx b/content/docs/introduction/install.ru.mdx index 8378e5e..ff6118e 100644 --- a/content/docs/introduction/install.ru.mdx +++ b/content/docs/introduction/install.ru.mdx @@ -1,10 +1,12 @@ --- -title: "Установка EasyP CLI" +title: "Установка EasyP" --- -### Установка через менеджер пакетов системы + +Для установки EasyP v1 явно выберите опубликованный nightly-тег. Стабильная установка по умолчанию остаётся на v0.17.0, пока для v1 существуют только prerelease-теги. Для конфигурации и команд v1 из этой документации используйте [инструкцию nightly](#явная-установка-v1-nightly). + -##### Рекомендуемый способ установки +## Установка стабильного CLI @@ -19,35 +21,84 @@ title: "Установка EasyP CLI" `Work in progress` — поддержка других системных менеджеров (apt, yum, pacman и т.д.) в процессе. - #### Требуется Go 1.24 или новее + #### Go toolchain - Установка последней стабильной версии EasyP через Go toolchain: + Установите последнюю опубликованную стабильную версию через Go toolchain, требуемый выбранным релизом: ```bash go install github.com/easyp-tech/easyp/cmd/easyp@latest ``` - #### Сборка из исходников + Скачайте архив для своей ОС и архитектуры из [последнего стабильного релиза](https://github.com/easyp-tech/easyp/releases/latest). Распакуйте его и добавьте бинарник `easyp` в `PATH`. + + - 1. Клонирование репозитория: +Стабильный Docker-канал — `ghcr.io/easyp-tech/easyp:latest`; сейчас он указывает +на тот же образ, что и `ghcr.io/easyp-tech/easyp:v0.17.0`. - ```bash - git clone https://github.com/easyp-tech/easyp.git - ``` +## Явная установка v1 nightly - 2. Сборка с помощью Go: +Nightly-теги имеют формат `v1.0.0-nightly.YYYYMMDD.sequence`. Выберите точный опубликованный тег в [GitHub Releases](https://github.com/easyp-tech/easyp/releases). Тег `v1.0.0-nightly.20261005.1` ниже — пример, а не утверждение, что такой релиз существует; замените его опубликованным тегом перед запуском команд. Nightly не обновляет стабильную формулу Homebrew или Docker-образ `latest`. - ```bash - go build ./cmd/easyp - ``` - - +### Go: CLI и MCP + +Для сборки v1 требуется **Go 1.26.6 или новее**. Установите оба бинарника в одной точной версии в отдельный каталог, чтобы сохранить стабильный CLI в `PATH`: + +```bash +# Только пример: замените тег реально опубликованным nightly. +NIGHTLY_TAG='v1.0.0-nightly.20261005.1' +NIGHTLY_BIN="$HOME/.local/share/easyp-nightly/bin" +mkdir -p "$NIGHTLY_BIN" +GOBIN="$NIGHTLY_BIN" go install "github.com/easyp-tech/easyp/cmd/easyp@${NIGHTLY_TAG}" +GOBIN="$NIGHTLY_BIN" go install "github.com/easyp-tech/easyp/cmd/easyp-mcp@${NIGHTLY_TAG}" +"$NIGHTLY_BIN/easyp" --version +``` + +Вызывайте nightly CLI по полному пути. Настройте MCP-клиент на запуск `easyp-mcp` из этого каталога как stdio-сервера: он предоставляет справочник конфигурации v1 через `easyp_config_describe`. Для примеров с командой `easyp` выберите nightly в текущем терминале: `export PATH="$NIGHTLY_BIN:$PATH"`. Не добавляйте этот каталог в постоянный `PATH`, чтобы сохранить стабильную версию по умолчанию. + +### Архив релиза: CLI и MCP + +Архив v1 содержит `easyp` и `easyp-mcp`. Скачайте файл для своей платформы и проверьте его по контрольным суммам релиза. Пример для Linux amd64: + +```bash +# Только пример: замените тег реально опубликованным nightly. +NIGHTLY_TAG='v1.0.0-nightly.20261005.1' +NIGHTLY_VERSION="${NIGHTLY_TAG#v}" +NIGHTLY_ASSET="easyp-${NIGHTLY_VERSION}-linux-amd64.tar.gz" +NIGHTLY_BIN="$HOME/.local/share/easyp-nightly/bin" +curl -fLO "https://github.com/easyp-tech/easyp/releases/download/${NIGHTLY_TAG}/${NIGHTLY_ASSET}" +curl -fLO "https://github.com/easyp-tech/easyp/releases/download/${NIGHTLY_TAG}/easyp-${NIGHTLY_VERSION}-checksums.txt" +sha256sum --check --ignore-missing "easyp-${NIGHTLY_VERSION}-checksums.txt" +mkdir -p "$NIGHTLY_BIN" +tar -xzf "$NIGHTLY_ASSET" --strip-components=1 -C "$NIGHTLY_BIN" +"$NIGHTLY_BIN/easyp" --version +``` + +Вызывайте CLI и MCP по полным путям в этом отдельном каталоге. Архивы macOS используют `darwin`; архивы Windows имеют расширение `.zip` и содержат `.exe`. Для запуска готовых бинарников Go toolchain не нужен. + +### Docker: CLI + +Nightly-образ CLI в GHCR выбирается по точному тегу: + +```bash +# Только пример: замените тег реально опубликованным nightly. +NIGHTLY_TAG='v1.0.0-nightly.20261005.1' +docker run --rm -v "$PWD:/workspace" -w /workspace \ + "ghcr.io/easyp-tech/easyp:${NIGHTLY_TAG}" --version +``` + +Замените `--version` нужной командой EasyP. Образ содержит CLI; MCP stdio-сервер устанавливается через Go или архив. + +## Go modules: переход с v0 на v1 + +EasyP v0 и v1 используют один путь модуля: `github.com/easyp-tech/easyp`, без суффикса `/v1`. Начиная с major 2 Go требует новый путь `/v2`, чтобы несовместимые мажорные версии могли сосуществовать. Переход v0→v1 всё же может требовать изменений кода и конфигурации. См. [нумерацию версий Go](https://go.dev/doc/modules/version-numbers). + +Слияние разработки v1 в `main` не меняет опубликованный тег `v0.17.0` и установки, закреплённые на v0. При переходе со стабильного v0 команды `@latest` и обычный `go get -u` предпочитают опубликованную стабильную версию prerelease-версиям v1. Явный nightly-тег включает v1 и требует учёта изменений API и конфигурации. Уже выбранная более высокая prerelease-версия автоматически не понижается. См. [запросы версий Go](https://go.dev/ref/mod#version-queries). -## Особые указания по локальной сборке +Стабильный Git-тег `v1.0.0` попадёт в выбор Go по умолчанию даже без GitHub Release или при флаге prerelease у этого Release. На этапе nightly публикуются только точные nightly-теги указанного выше формата. `@main` явно запрашивает код разработки и не является каналом стабильной установки. -Установка через пакетные менеджеры предпочтительнее локальной сборки вручную, так как пакетные менеджеры обеспечивают: -- Автоматические обновления и патчи безопасности -- Улучшенную интеграцию с операционной системой -- Упрощённый процесс установки и удаления -- Проверенные бинарные сборки +Для одной сборки Go выбирает одну версию каждого module path. Другая зависимость, +требующая v1 nightly, также может повысить выбранную версию EasyP через +[minimal version selection](https://go.dev/ref/mod#minimal-version-selection). +Если вы используете v0 как библиотеку, её граф зависимостей тоже должен быть совместим с v0. diff --git a/content/docs/introduction/quickstart.mdx b/content/docs/introduction/quickstart.mdx index b91b73b..dc28e1d 100644 --- a/content/docs/introduction/quickstart.mdx +++ b/content/docs/introduction/quickstart.mdx @@ -1,13 +1,17 @@ --- title: "Quickstart" -description: "Create a protobuf module and generate code with the EasyP v1 pilot." +description: "Create a protobuf module and generate code with EasyP v1 nightly." --- -Install a v1 pilot build of EasyP and make sure Git is available. This example uses a local Go generator, so put `protoc-gen-go` on `PATH` before the generation step. +Install an [explicit v1 nightly](/docs/introduction/install#opt-into-v1-nightly) and make sure Git is available. The `go` plugin uses `protoc-gen-go` from `PATH` when installed, otherwise EasyP uses its bundled WASM generator. ## 1. Initialize a module ```bash +# Use the nightly installed in the installation guide for this terminal session. +export PATH="$HOME/.local/share/easyp-nightly/bin:$PATH" +easyp --version + mkdir contracts && cd contracts git init easyp init --module github.com/acme/contracts diff --git a/content/docs/introduction/quickstart.ru.mdx b/content/docs/introduction/quickstart.ru.mdx index 2c4293a..c96600d 100644 --- a/content/docs/introduction/quickstart.ru.mdx +++ b/content/docs/introduction/quickstart.ru.mdx @@ -1,13 +1,17 @@ --- title: "Быстрый старт" -description: "Создание protobuf-модуля и генерация кода в пилотной версии EasyP v1." +description: "Создание protobuf-модуля и генерация кода в EasyP v1 nightly." --- -Установите пилотную сборку EasyP v1 и убедитесь, что доступен Git. В примере используется локальный Go-плагин: перед генерацией добавьте `protoc-gen-go` в `PATH`. +Установите [явно выбранный v1 nightly](/ru/docs/introduction/install#явная-установка-v1-nightly) и убедитесь, что доступен Git. Плагин `go` использует `protoc-gen-go` из `PATH`, если он установлен; иначе EasyP запускает встроенный WASM-генератор. ## 1. Создайте модуль ```bash +# Выберите nightly из инструкции по установке для текущего терминала. +export PATH="$HOME/.local/share/easyp-nightly/bin:$PATH" +easyp --version + mkdir contracts && cd contracts git init easyp init --module github.com/acme/contracts diff --git a/content/docs/reference/easyp-gen-yaml.mdx b/content/docs/reference/easyp-gen-yaml.mdx index 4c335f5..119a1f0 100644 --- a/content/docs/reference/easyp-gen-yaml.mdx +++ b/content/docs/reference/easyp-gen-yaml.mdx @@ -19,7 +19,7 @@ The easyp.gen.yaml file specifies **consumer-side code generation r default: "v1" }, generate: { - description: "Complete-module selection; package filtering is reserved.", + description: "Module and exact protobuf-package selection, with managed descriptor options.", type: "object" }, "generate.modules": { @@ -139,7 +139,9 @@ plugins: Instead of requiring explicit file-level options (like option go_package = "...") inside every individual .proto schema file, EasyP's managed options block groups settings logically by target language. -options.go.package_prefix computes go_package from the proto file path without changing the source. The prefix alone changes Go options only: it does not enable Java, C#, PHP, Ruby, Objective-C, or C++ defaults. Full managed mode and field-option transformations require explicit generate.managed.enabled: true. Go disable selectors, including go_package, suppress the prefix. +options.go.package_prefix computes go_package without changing the source. A plain prefix uses the hierarchy of a multi-component protobuf package: common.v1 with prefix github.com/acme/sdk becomes github.com/acme/sdk/common/v1;commonv1. A single-component package keeps the proto file directory. Templates such as `{{file_path}}` and `{{file_dir}}` use the proto path instead. + +The prefix changes Go options even when full managed mode is omitted or disabled. It does not enable Java, C#, PHP, Ruby, Objective-C, or C++ defaults. Full managed mode and field-option transformations require explicit generate.managed.enabled: true. Go disable selectors, including go_package, suppress the prefix. The existing managed-mode rules remain available under generate.managed. For example, a package-specific override can be written as: @@ -159,10 +161,20 @@ plugins: A repository-root easyp.gen.yaml may provide options.go.package_prefix as a default for nested generator files. Nested generate.managed rules take precedence over that inherited default. A prefix declared in the same generator file has the highest priority. Plugin lists stay local to each generator file. +### Go output paths and plugin mappings + +With a Go prefix and explicit paths: source_relative, generated Go directories follow the effective import path relative to that prefix. In the common.v1 example, out: gen/go writes gen/go/common/v1/*.go, regardless of the proto file's directory. Marker templates use the complete parent path before the first marker as their output base. Imports outside that base keep the plugin's output path. Default paths, paths: import, and the plugin's module option retain plugin-controlled layouts. + +A plugin's Mfile.proto=import/path option overrides the effective import path for that plugin. The last nonempty import mapping wins; alias-only or empty mappings do not erase the descriptor import or a preceding import mapping. These plugin parameters do not change exported descriptors or other plugins' options. + +Insertion-point responses follow the output file created by their producer, even when the inserting plugin has different path or mapping options. An ambiguous producer is an error. Comments copied from a proto source do not change which Go or gRPC file receives the generated output. + The generator selects module sources by default. Nonempty generate.packages filters them by exact protobuf package name. Unknown names fail before plugins; required imports remain in the compilation graph. Remote plugins require a version such as v2.0.0. EasyP sends that exact version to the remote generator. For local protoc-gen-* executables and bundled WASM plugins, the executable selected at runtime determines the version; the separate version field is rejected because EasyP cannot verify it. +For bundled names such as go and go-grpc, a matching protoc-gen-* executable on PATH takes precedence. Otherwise EasyP uses the bundled WASM plugin. Use path or command to select an explicit executable. + Each plugin declares exactly one source: name, path, command, or remote. Use path for a specific binary and command for an executable plus arguments. Both run from the directory where easyp generate starts and, like any Protobuf plugin, must read a CodeGeneratorRequest from stdin and write a CodeGeneratorResponse to stdout. ~~~yaml diff --git a/content/docs/reference/easyp-gen-yaml.ru.mdx b/content/docs/reference/easyp-gen-yaml.ru.mdx index 28ed047..6ab79af 100644 --- a/content/docs/reference/easyp-gen-yaml.ru.mdx +++ b/content/docs/reference/easyp-gen-yaml.ru.mdx @@ -19,7 +19,7 @@ description: "Полная спецификация файла easyp.gen.yaml, default: "v1" }, generate: { - description: "Выбор целых модулей; фильтрация пакетов зарезервирована.", + description: "Выбор модулей и точных protobuf-пакетов с managed-опциями дескрипторов.", type: "object" }, "generate.modules": { @@ -139,7 +139,9 @@ plugins: Вместо явного прописывания опций вроде option go_package = "..." внутри каждого .proto файла, блок options в EasyP группирует настройки по целевым языкам программирования. -Например, options.go.package_prefix вычисляет go_package по пути proto-файла без изменения исходника. Сам префикс меняет только Go-опции: он не включает значения по умолчанию для Java, C#, PHP, Ruby, Objective-C или C++. Для полного managed mode и преобразований опций полей явно задайте generate.managed.enabled: true. Go-селекторы disable, включая go_package, подавляют префикс. +options.go.package_prefix вычисляет go_package без изменения исходника. Обычный префикс использует иерархию protobuf-пакета из нескольких компонентов: common.v1 с префиксом github.com/acme/sdk становится github.com/acme/sdk/common/v1;commonv1. Для пакета из одного компонента сохраняется каталог proto-файла. Шаблоны вроде `{{file_path}}` и `{{file_dir}}` используют путь proto-файла. + +Префикс меняет Go-опции, даже когда полный managed mode не задан или выключен. Он не включает значения по умолчанию для Java, C#, PHP, Ruby, Objective-C или C++. Для полного managed mode и преобразований опций полей явно задайте generate.managed.enabled: true. Go-селекторы disable, включая go_package, подавляют префикс. Существующие правила managed mode доступны в generate.managed. Например, переопределение для конкретного Protobuf-пакета: @@ -159,10 +161,20 @@ plugins: Корневой easyp.gen.yaml может задавать options.go.package_prefix по умолчанию для вложенных генераторов. Локальные правила generate.managed имеют приоритет над унаследованным префиксом. Префикс, заданный в том же файле генератора, имеет наивысший приоритет. Списки плагинов не наследуются. +### Выходные пути Go и параметры M + +С Go-префиксом и явным paths: source_relative каталоги Go-кода соответствуют эффективному import path относительно префикса. В примере common.v1 настройка out: gen/go записывает gen/go/common/v1/*.go независимо от каталога proto-файла. Для шаблонов с маркером базой служит полный родительский путь до первого маркера. Импорты за пределами этой базы сохраняют выходной путь плагина. Значение paths по умолчанию, paths: import и параметр плагина module сохраняют расположение, выбранное плагином. + +Параметр плагина Mfile.proto=import/path переопределяет эффективный import path только для этого плагина. Последнее непустое значение импорта имеет приоритет; пустое значение или только alias не стирают импорт дескриптора либо предыдущее значение импорта. Эти параметры не меняют экспортируемые дескрипторы или настройки других плагинов. + +Ответы с insertion point используют выходной файл создавшего его плагина, даже если у вставляющего плагина другие параметры пути или M. Неоднозначный выбор создателя — ошибка. Скопированные из proto комментарии не меняют выбор выходного Go- или gRPC-файла. + По умолчанию генерируются все исходники выбранных модулей. Непустой generate.packages фильтрует их по точному имени protobuf-пакета. Неизвестные имена отклоняются до запуска плагинов, нужные импорты остаются в графе компиляции. Удалённому плагину нужен version, например v2.0.0. EasyP передаёт именно эту версию удалённому генератору. Для локального protoc-gen-* и встроенного WASM версию определяет выбранный исполняемый файл; отдельное поле version отклоняется, поскольку EasyP не может его проверить. +Для встроенных имён вроде go и go-grpc приоритет имеет соответствующий protoc-gen-* в PATH. Если его нет, EasyP использует встроенный WASM-плагин. Для явного выбора исполняемого файла задайте path или command. + Для каждого плагина указывают ровно один источник: name, path, command или remote. path запускает конкретный бинарный файл, а command принимает список из программы и её аргументов. Оба варианта работают из каталога запуска easyp generate и, как любой плагин Protobuf, должны принимать CodeGeneratorRequest из stdin и возвращать CodeGeneratorResponse в stdout. ~~~yaml diff --git a/lib/github-release.test.mjs b/lib/github-release.test.mjs new file mode 100644 index 0000000..9eab3ac --- /dev/null +++ b/lib/github-release.test.mjs @@ -0,0 +1,87 @@ +import assert from 'node:assert/strict' +import test from 'node:test' +import { getLatestRelease } from './github-release.ts' + +const latestURL = 'https://api.github.com/repos/easyp-tech/easyp/releases/latest' +const releasesURL = 'https://api.github.com/repos/easyp-tech/easyp/releases?per_page=100' +const release = (tag, flags = {}) => ({ + tag_name: tag, + name: tag, + draft: false, + prerelease: false, + ...flags, +}) + +function mockGitHub(t, latest, releases) { + t.mock.method(console, 'error', () => {}) + return t.mock.method(globalThis, 'fetch', async (url) => { + const value = url === latestURL ? latest : releases + if (value instanceof Error) throw value + return value instanceof Response ? value : Response.json(value) + }) +} + +test('uses the validated published stable latest release and keeps Next cache options', async (t) => { + const fetch = mockGitHub(t, release('v0.17.1'), []) + assert.equal(await getLatestRelease(), 'v0.17.1') + assert.equal(fetch.mock.callCount(), 1) + const [url, options] = fetch.mock.calls[0].arguments + assert.equal(url, latestURL) + assert.equal(options.next.revalidate, 3600) + assert.equal(options.headers.Accept, 'application/vnd.github+json') +}) + +test('allows a future published stable v1 release without a major-version ceiling', async (t) => { + mockGitHub(t, release('v1.0.0'), []) + assert.equal(await getLatestRelease(), 'v1.0.0') +}) + +for (const [name, latest] of [ + ['HTTP error', new Response('', { status: 404 })], + ['network error', new Error('network unavailable')], + ['invalid JSON', new Response('{invalid', { headers: { 'Content-Type': 'application/json' } })], + ['malformed JSON shape', { tag_name: 42, draft: false, prerelease: false }], + ['nightly tag with false prerelease flag', release('v1.0.0-nightly.20261005.1')], + ['stable-shaped prerelease', release('v1.0.0', { prerelease: true })], + ['stable-shaped draft', release('v1.0.0', { draft: true })], + ['missing publication flags', { tag_name: 'v1.0.0' }], + ['non-boolean publication flags', { tag_name: 'v1.0.0', draft: 0, prerelease: 'false' }], +]) { + test(`falls back to published stable releases after latest ${name}`, async (t) => { + const fetch = mockGitHub(t, latest, [ + release('v1.0.0-nightly.20261005.1', { prerelease: true }), + release('v0.17.1'), + ]) + assert.equal(await getLatestRelease(), 'v0.17.1') + assert.equal(fetch.mock.calls[1].arguments[0], releasesURL) + }) +} + +test('fallback chooses the highest stable version numerically, independently of list order', async (t) => { + mockGitHub(t, new Response('', { status: 503 }), [ + release('v0.9.9'), + release('v2.0.0-nightly.20261005.1'), + release('v1.0.0', { draft: true }), + release('v1.0.0', { prerelease: true }), + release('v0.10.2'), + release('v0.10.1'), + release('v0.10.3-rc.1'), + ]) + assert.equal(await getLatestRelease(), 'v0.10.2') +}) + +for (const [name, releases] of [ + ['nightlies and prereleases only', [release('v1.0.0-nightly.20261005.1'), release('v1.0.0-rc.1'), release('v1.0.0-beta.2')]], + ['drafts and stable-shaped prereleases only', [release('v1.0.0', { draft: true }), release('v0.17.1', { prerelease: true })]], + ['unknown and malformed tags only', [release('nightly'), release('v1.0'), release('v01.2.3'), { name: 'v0.17.1' }, null]], + ['empty list', []], + ['invalid list shape', { tag_name: 'v0.17.1' }], + ['fallback HTTP failure', new Response('', { status: 500 })], + ['fallback network failure', new Error('network unavailable')], + ['fallback invalid JSON', new Response('{invalid')], +]) { + test(`fails closed when fallback contains ${name}`, async (t) => { + mockGitHub(t, new Response('', { status: 404 }), releases) + assert.equal(await getLatestRelease(), 'unknown version') + }) +} diff --git a/lib/github-release.ts b/lib/github-release.ts index ec109dd..21a103a 100644 --- a/lib/github-release.ts +++ b/lib/github-release.ts @@ -1,32 +1,26 @@ interface GithubRelease { tag_name: string -} - -interface GithubTag { - name: string + draft: boolean + prerelease: boolean } const REPO = 'easyp-tech/easyp' -function isStable(name: string): boolean { - const v = name.toLowerCase() +function isPublishedStable(value: unknown): value is GithubRelease { + if (typeof value !== 'object' || value === null) return false + const release = value as Partial return ( - !v.includes('-rc') && - !v.includes('-alpha') && - !v.includes('-beta') && - !v.includes('-pre') && - !v.includes('-dev') + release.draft === false && + release.prerelease === false && + typeof release.tag_name === 'string' && + /^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.test(release.tag_name) ) } -/** - * Server-friendly latest stable version (Next fetch cache). - * Prefer /releases/latest; fall back to tags list. - */ -export async function getLatestRelease(): Promise { +async function readReleases(path: string): Promise { try { - const releaseRes = await fetch( - `https://api.github.com/repos/${REPO}/releases/latest`, + const response = await fetch( + `https://api.github.com/repos/${REPO}/${path}`, { headers: { Accept: 'application/vnd.github+json', @@ -36,30 +30,39 @@ export async function getLatestRelease(): Promise { }, ) - if (releaseRes.ok) { - const data = (await releaseRes.json()) as GithubRelease - if (data.tag_name) return data.tag_name - } + if (!response.ok) return null + return await response.json() + } catch (error) { + console.error(error) + return null + } +} - const tagsRes = await fetch(`https://api.github.com/repos/${REPO}/tags`, { - headers: { - Accept: 'application/vnd.github+json', - 'User-Agent': 'easyp-docs', - }, - next: { revalidate: 3600 }, - }) +function compareVersions(left: string, right: string): number { + const a = left.slice(1).split('.').map(BigInt) + const b = right.slice(1).split('.').map(BigInt) + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i]) return a[i] > b[i] ? 1 : -1 + } + return 0 +} - if (!tagsRes.ok) { - throw new Error(`GitHub tags status ${tagsRes.status}`) - } +/** Server-friendly published stable version, cached with Next fetch. */ +export async function getLatestRelease(): Promise { + const latest = await readReleases('releases/latest') + if (isPublishedStable(latest)) return latest.tag_name - const tags = (await tagsRes.json()) as GithubTag[] - if (tags.length === 0) throw new Error('No tags') + const releases = await readReleases('releases?per_page=100') + if (!Array.isArray(releases)) return 'unknown version' - const stable = tags.find((t) => isStable(t.name)) - return stable?.name ?? tags[0].name - } catch (error) { - console.error(error) - return 'unknown version' + let stable: string | undefined + for (const release of releases) { + if ( + isPublishedStable(release) && + (stable === undefined || compareVersions(release.tag_name, stable) > 0) + ) { + stable = release.tag_name + } } + return stable ?? 'unknown version' } diff --git a/package.json b/package.json index 8832f65..9a78d7e 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "build": "fumadocs-mdx && next build", "start": "next start", "types:check": "fumadocs-mdx && tsc --noEmit", + "test:release": "node --experimental-strip-types --test lib/github-release.test.mjs", "migrate:content": "node scripts/migrate-content.mjs" }, "dependencies": {