Skip to content

0047. Продвижение артефактов: стадии и перенос между репозиториями ​

Статус: accepted. Дата: 2026-09-30.

Контекст ​

Сборка проходит путь от CI до production: её проверяют, одобряют и выкатывают. Агенту развёртывания нужен вопрос «какая версия сейчас в prod», а не идентификатор файла. Свободные метки (labels) для этого не подходят: их меняет любой с правом annotation.write, у них нет истории и автора, а удаление не фиксируется. Владелец продукта выбрал две совместимые модели: артефакт может переходить между репозиториями, выделенными под этапы (например dev → staging → prod), или получать promote-метки (стадии); у одного артефакта может быть несколько стадий.

Решение ​

  • Стадия — управляемая метка артефакта: ^[a-z0-9][a-z0-9_.-]{0,31}$, не больше 16 на артефакт. Стадии хранятся отдельно от свободных меток (arkvory_artifact_stages) и меняются только через promotion API с правом artifact.promote (для file keys и групп — read+write). Каждое добавление и снятие пишется в журнал arkvory_promotion_events с автором, временем и комментарием. Операции идемпотентны: повторное добавление существующей стадии не меняет время и не пишет событие.
  • Перенос в репозиторий — POST R/artifacts/{id}/promote с {target, mode, stages, comment}. Режим copy оставляет исходный артефакт, move логически удаляет его в той же транзакции, что и публикация копии. Байты не передаются заново: локальное хранилище создаёт жёсткую ссылку, опубликованный blob неизменяем. Копия получает метки, metadata и коллекции источника, идентичность UPack и указанные стадии. Нужны artifact.read и content.read в источнике, artifact.promote в цели и, для move, artifact.promote в источнике.
  • Повторный promote того же источника в тот же репозиторий возвращает уже опубликованную копию. Если в цели уже есть пакет с той же group/name/version и другим SHA-256 — 409; с тем же SHA-256 возвращается существующий артефакт. Прерванный promote оставляет pending-резерв, который обычная очистка удаляет после истечения.
  • move отклоняется, если у источника есть блокеры удаления (внешние ссылки, история файлов, вложения). Стадии источника переходят в копию.
  • Артефакт со стадией защищён от retention: блокер promotion_stage.
  • Разрешение версии — GET R/packages/resolve и GET|HEAD R/packages/content принимают name, group, ровно одно из version (точная) или range (SemVer-диапазон: 1.2.3, ^1.2, ~1.2.3, 1.x, >=1.0.0 <2.0.0, ||), необязательную stage и prerelease=true. Без version prerelease-версии исключаются, пока их не разрешили явно. При stage и order=promoted выбирается последняя продвинутая версия (откат = повторный promote старой версии), иначе — старшая SemVer.
  • GET R/promotions — постраничный журнал продвижений репозитория для CI/CD; GET R/artifacts/{id}/promotions — история артефакта.

Альтернативы ​

  • Только репозитории-этапы: требует копии на каждый этап и не позволяет отметить одну сборку сразу как qa и beta.
  • Только стадии: не подходит для раздельных прав и квот по окружениям.
  • Свободные метки с аудитом: смешивает управляемое состояние с произвольными тегами и ломает существующую семантику annotation.write.
  • Физическое копирование байтов: удваивает место и время; жёсткая ссылка сохраняет неизменяемость и независимость жизненного цикла каждой копии.

Последствия ​

  • Логическая квота целевого репозитория учитывает копию; физически байты делят один inode до удаления последней ссылки. Глобальная ARKVORY_CAPACITY_BYTES считает каждую копию, это консервативная оценка.
  • Промежуточное состояние после сбоя — pending-строка и, возможно, жёсткая ссылка; их удаляет обычная очистка.
  • Новое действие artifact.promote добавлено в managed-ключи и в отображение coarse-прав (read+write).

Проверка ​

  • Unit: имена стадий, запросы promote, разбор и сопоставление SemVer-диапазонов, отбор prerelease.
  • PostgreSQL/HTTP: стадии с историей и идемпотентностью; copy и move между репозиториями с правами, конфликтом идентичности, повтором и блокерами; resolve по version/range/stage/order; retention-блокер; байты копии совпадают, удаление источника не затрагивает копию.
  • SDK/CLI/браузер: те же сценарии через публичные клиенты.

Arkvory · ProAnimaStudio