Documentation
¶
Overview ¶
Package treeposture отвечает на ОДИН вопрос: лежит ли модуль в дереве платформы — и приводит координаты, записанные от корня платформы, к той посадке, в которой идёт прогон.
ЗДЕСЬ НЕТ `testing` — И ЭТО НЕСУЩЕЕ. Тот же вопрос задаёт не только проба: приборы модуля (отпечаток сетки замера, писатель отчётов) читают свои каталоги по координатам, записанным от корня платформы, и в самостоятельном клоне ошибаются ровно так же. Пакет с `testing` в импорте прод-код звать не вправе — он утащил бы испытательную оснастку в поставляемый двоичный. Поэтому чистая часть живёт здесь, а третий исход для пробы (`Require*`) — в обёртке `internal/testsupport/platformtree`, которая эту часть и зовёт.
───────────────────────────────────────────────────────────────────────────── ПРЕДМЕТ
Модуль живёт в двух посадках. В монорепо рядом с ним лежат манифесты остальных модулей платформы, каталог контрактов и зонтичный чарт стенда; в самостоятельном клоне у арендатора их нет и не будет — они в поставку модуля не входят BY CONSTRUCTION.
Проба, судящая такое дерево, в клоне не «красная»: у неё не создано условие. Красное у КАЖДОГО, кто склонирует, вердиктом о продукте не является — это «проверка НЕ ИСПОЛНЯЛАСЬ», третий исход (`testing.md` §«Чтение вердикта»), который не вычитается из вердикта и не зачитывается в успех.
───────────────────────────────────────────────────────────────────────────── ПОЧЕМУ ЭТО НЕ МАСКА — И ЧЕМ ЭТО ДЕРЖИТСЯ
Пропуск, который проба назначает себе сама, был бы ровно тем механизмом, который корпус запрещает: его нельзя отличить от «проба сломалась, и её заглушили». Здесь пропуск назначает НЕ проба, а ПРЕДПОСЫЛКА, и предпосылка эта — свойство дерева, проверяемое на месте:
дерево платформы ЕСТЬ → Require возвращает корень, проба идёт целиком; дерева платформы НЕТ → пропуск с НАЗВАННОЙ причиной и координатой.
Отсюда несущее свойство: **в монорепо пропуск невозможен**. Не «его там не бывает», а невозможен — детектор отвечает «есть», и ветвь пропуска не достижима ни для одной пробы. Держит это гейт-сосед (`platformtree_gate_test.go`): он спрашивает детектор о ТОМ дереве, в котором идёт прогон, и падает, если в монорепо тот ответил «нет». Тогда «сколько проб пропущено» перестаёт быть вопросом доверия: их ноль, и это следует из одного утверждения, а не из переписи по каждой пробе.
Пометка ИСТЕКАЕТ САМА в обратную сторону: приедет каталог контрактов в поставку модуля — детектор в клоне ответит «есть», и помеченные пробы начнут исполняться там, где раньше пропускались. Снимать пометки для этого не нужно.
───────────────────────────────────────────────────────────────────────────── ПОЧЕМУ ПРИЗНАК — СОСЕДНИЕ МОДУЛИ, А НЕ ИМЯ КАТАЛОГА
Имя каталога у арендатора выбирает тот, кто клонировал. Признаком служит то, ради чего дерево и нужно: каталог `services/` с манифестами модулей рядом с нашим. Он есть в монорепо и отсутствует в поставке — то есть ровно та величина, которую пробы и спрашивают.
ЧЕГО ЗДЕСЬ НЕТ. Пакет не решает, ЧТО пробе читать, и не заменяет резолв канона модели: тот резолвится в ОБЕИХ посадках (модуль везёт свою побайтовую копию) и пометки не требует. Здесь только «есть ли рядом остальная платформа».
Index ¶
- Variables
- func CorpusRoot(start string) (root, prefix string, err error)
- func ModuleDirIn(root, moduleRoot string) (string, error)
- func ModuleDirInPlatform() string
- func ModuleRootFrom(start string) (string, error)
- func PathOf(start, rel string) (string, error)
- func PathUnder(root, rel string) (string, error)
- func PrefixUnder(root string) string
- func RootFrom(start string) (string, error)
- func Under(prefix, rel string) string
Constants ¶
This section is empty.
Variables ¶
var ErrModuleRootUnknown = errors.New("корень модуля не установлен")
ErrModuleRootUnknown — корень модуля не установлен: судить не о чем.
var ErrNoPlatformTree = errors.New("дерева платформы рядом с модулем нет")
ErrNoPlatformTree — дерева платформы рядом с модулем нет.
Отдельный признак, а не общий отказ: «платформы рядом нет» и «пробу не удалось запустить» — разные исходы, и первый есть свойство поставки, а не поломка.
Functions ¶
func CorpusRoot ¶
CorpusRoot — КОРЕНЬ ДЕРЕВА, которое проба обходит, и ПРИСТАВКА, под которой в нём лежат файлы этого модуля.
───────────────────────────────────────────────────────────────────────────── ЗАЧЕМ ОТДЕЛЬНО ОТ PathOf
`PathOf` отвечает про ОДИН путь. Есть другой род проб: они не читают названный файл, а ОБХОДЯТ состав дерева и судят его целиком — «композиция одна, тонких вызывающих двое», «у каждой записи ведомости есть предмет», «литерал не является источником чтения». Такой пробе нужны две величины сразу: от какого корня брать состав и с какой приставки начинаются её собственные файлы в этом составе.
В монорепо это корень платформы и `services/iam`; в самостоятельном клоне — корень модуля и ПУСТАЯ приставка: модуль там сам себе дерево, и файлы лежат без неё.
───────────────────────────────────────────────────────────────────────────── ПОЧЕМУ ЭТО НЕ ПРОПУСК
Пропускать такие пробы в клоне было бы ЛОЖЬЮ в другую сторону: их предмет — собственная композиция модуля — в поставку ВХОДИТ, и судить его есть чем. Пропуск здесь означал бы «условие не создано» там, где оно создано.
Пропуск остаётся законным ровно для тех проб, чей предмет лежит ВНЕ модуля (манифесты соседей, каталог контрактов, зонтичный чарт) — для них `Require` и `RequirePath`, и они возвращают ErrNoPlatformTree честно.
func ModuleDirIn ¶
ModuleDirIn — каталог модуля В НАЗВАННОМ дереве.
Существует ради вызывающих, которые прежде складывали этот путь литералом `services/iam`: литерал верен ровно для одной посадки, а в другой указывает в несуществующий подкаталог клона. Здесь он ВЫВОДИТСЯ, поэтому верен в обеих.
func ModuleDirInPlatform ¶
func ModuleDirInPlatform() string
ModuleDirInPlatform — та же координата для гейта, который её сверяет.
func ModuleRootFrom ¶
ModuleRootFrom поднимается от start до БЛИЖАЙШЕГО каталога с `go.mod`.
Маркер — `go.mod`, а не число уровней и не имя каталога: имя у арендатора выбирает тот, кто клонировал, а число уровней верно ровно для одной посадки.
func PathOf ¶
PathOf — путь, записанный ОТ КОРНЯ ДЕРЕВА ПЛАТФОРМЫ, приведённый к посадке, в которой идёт прогон.
───────────────────────────────────────────────────────────────────────────── ЗАЧЕМ
Пробы модуля называют свои файлы координатами монорепо: `services/iam/internal/migrations`, `services/iam/docs/…`. В монорепо это верно. В самостоятельном клоне модуль САМ является корнем, поэтому тот же путь указывает в несуществующий подкаталог — и проба отказывает «нет файла» там, где файл ЕСТЬ и лежит на уровень выше по этому же дереву.
Замер, ради которого функция написана: в клоне так отказывали 66 проб, читая то, что с модулем ЕДЕТ (миграции, посев, документы, собственные исходники).
───────────────────────────────────────────────────────────────────────────── ТРИ ИСХОДА, И ТРЕТИЙ НЕСУЩИЙ
дерево платформы есть → путь как написан, от его корня;
клон, путь ВНУТРИ модуля → приставка модуля снимается, путь от корня клона;
клон, путь ВНЕ модуля → ErrNoPlatformTree: названного в поставку не
входит, и это «условие не создано», а не «нет файла».
Третий исход — то, ради чего у функции есть ошибка. Каталог контрактов, манифест соседнего модуля, зонтичный чарт стенда у арендатора отсутствуют BY CONSTRUCTION; вернуть для них «путь, которого нет» значило бы превратить свойство поставки в находку о продукте.
func PathUnder ¶
PathUnder — координата, записанная от корня платформы, приведённая к НАЗВАННОМУ корню.
───────────────────────────────────────────────────────────────────────────── ЧЕМ ОТЛИЧАЕТСЯ ОТ PathOf
`PathOf` сам ищет корень подъёмом от рабочего каталога. Здесь корень УЖЕ ДАН — его спросили у git (`rev-parse --show-toplevel`) либо получили аргументом. Такие вызывающие есть, и это приборы модуля: отпечаток сетки замера, писатель отчётов, сверщик состава. Они читают свои каталоги по координатам вида `services/iam/...` и складывают их с корнем — то есть верны ровно для монорепо.
В самостоятельном клоне корень репозитория И ЕСТЬ корень модуля, поэтому сложенный путь указывает в несуществующий подкаталог `<клон>/services/iam/…`, а прибор отказывает «нет файла» там, где файл есть уровнем выше.
───────────────────────────────────────────────────────────────────────────── ПОСАДКА ОПОЗНАЁТСЯ ПО САМОМУ КОРНЮ, А НЕ ПО РАБОЧЕМУ КАТАЛОГУ
Признак — лежит ли модуль в `services/` этого корня. Спрашивать рабочий каталог здесь нельзя: вызывающий мог получить корень откуда угодно, и два разных ответа об одном дереве разошлись бы молча.
Третий исход сохранён: путь ВНЕ модуля в клоне даёт ErrNoPlatformTree, а не «нет файла». Названного в поставку не входит by construction, и подменять свойство поставки находкой о продукте нельзя.
func PrefixUnder ¶
PrefixUnder — приставка модуля в составе, отсчитываемом от НАЗВАННОГО корня.
`"services/iam"` в дереве платформы и ПУСТАЯ в самостоятельном клоне. Нужна обходчикам состава: они сравнивают записи с координатами, и склеенная не с той приставкой не совпадёт ни с одной — молча.
func RootFrom ¶
RootFrom — корень дерева платформы для модуля, найденного от start.
Возвращает ErrNoPlatformTree, если модуль стоит самостоятельным клоном. Подъём ограничен деревом: за пределы каталога, содержащего модуль, резолв не выходит — иначе нашлось бы ЧУЖОЕ дерево, и вердикт был бы о нём.
func Under ¶
Under — координата файла модуля в составе, приведённая к приставке.
`Under("services/iam", "internal/x")` -> `services/iam/internal/x`; `Under("", "internal/x")` -> `internal/x`.
Существует ради вызывающих, которые иначе склеили бы приставку конкатенацией и получили ведущий слеш в клоне — путь, который не совпадёт ни с одной записью состава, причём МОЛЧА: обход просто не найдёт ничего, и «ноль находок» стало бы неотличимо от «ноль прочитанного».
Types ¶
This section is empty.