Skip to content
Apothem
Руководства по эксплуатации

Руководство по циклу релиза

Полный рабочий процесс релиза от локальных шлюзов через подписанный GitHub Release до публикации в npm.

Это руководство проводит релиз vX.Y.Z проекта apothem от чистого рабочего дерева до проверенных поверхностей распространения. Процедура написана для сопровождающего, владеющего gh, git и оболочкой релизного уровня; она завершается проверенной страницей Release, заполненным CHANGELOG и дымовой проверкой пути установки, подтверждающей, что каждая пользовательская поверхность отвечает на каноническую команду установки.

Модель релизов — аддитивная. Каждый релиз добавляет один коммит в main и один подписанный аннотированный тег vX.Y.Z; ничего не отправляется через force-push, и ни один более ранний тег, GitHub Release или версия npm не удаляется. Каждый релиз сохраняет свой тег, свой GitHub Release и свою версию npm, и все остаются опубликованными: версии npm неизменяемы (опубликованный name@version никогда не может быть заменён), а закреплённые установки зависят от тегов.

Push тега запускает три рабочих процесса. .github/workflows/release.yml собирает, подписывает, аттестует и публикует GitHub Release с полным набором артефактов: sdist, wheel, CycloneDX SBOM, бандлы Sigstore cosign, происхождение SLSA-3 и архивы платформенной среды выполнения. publish-npm.yml публикует @ahmed-g-gad/apothem на npmjs.com через доверенную публикацию npm, а publish-vscode.yml упаковывает расширение VS Code и публикует его в Visual Studio Marketplace. Версионный раздел CHANGELOG попадает в коммит релиза; оператор запускает дымовую проверку пути установки после завершения обоих рабочих процессов.

1. Предварительные условия

Сопровождающий подтверждает следующее перед тегированием:

  • Рабочее дерево. Чистое (git status не показывает ничего ожидающего). Вся работа над функциями для релиза находится в main.

  • CI зелёный. Для последнего main gh run list --branch=main --limit=1 --json conclusion --jq '.[0].conclusion' возвращает success.

  • Инструментарий. gh (GitHub CLI) версии 2.40 или новее, авторизованный в ahmed-g-gad; git 2.40 или новее с загруженным подключом подписи GPG; привязка доверенного издателя npm для @ahmed-g-gad/apothem действует (проверено согласно руководству по настройке учётной записи издателя).

  • Якоря версий выровнены. Строка версии, объявленная в pyproject.toml, совпадает с планируемым тегом без префикса v (§2.1 устанавливает её вместе со всеми остальными якорями). Проверьте:

    grep '^version' pyproject.toml

    Ожидаемый вывод (для релиза vX.Y.Z; заполнители обозначают тег текущего выпускаемого релиза):

    version = "X.Y.Z"
  • Записи CHANGELOG подготовлены. Пункты релиза находятся под ## [Unreleased] в заголовках Keep-a-Changelog; §2.1 превращает их в датированный раздел версии в коммите, на который ставится тег.

2. Тегирование и запуск

2.1 Создание коммита релиза

Версия хранится более чем в десятке файлов, поэтому не редактируйте их вручную. Одна команда обновляет их все:

git checkout main
git pull --ff-only origin main
python scripts/release/bump_version.py X.Y.Z

bump_version.py обновляет все якоря версий вместе:

  • Каждый манифест упаковки, расширения, плагина и маркетплейса, а также файл цитирования (версия и дата релиза). Полный список:

    pyproject.toml
    package.json
    site/package.json
    site/package-lock.json            (the project entries only)
    vscode-extension/package.json
    gemini-extension.json
    qwen-extension.json
    .claude-plugin/marketplace.json   (top level and metadata)
    plugins/apothem/plugin.json
    plugins/apothem/.codex-plugin/plugin.json
    CITATION.cff
  • CHANGELOG.md: записи [Unreleased] становятся датированным разделом ## [X.Y.Z], [Unreleased] сравнивается начиная с vX.Y.Z, и добавляется ссылка [X.Y.Z].

  • SECURITY.md: новая минорная версия получает строку поддерживаемой версии X.Y.x. Оставлять ли в списке более старые минорные версии — решать вам; скрипт выводит напоминание.

Затем он регенерирует производные деревья: пакет плагина Claude Code, эталонные снимки behavior-diff, а также справочные страницы документации и страницы журнала изменений. Передайте --dry-run, чтобы сначала вывести список изменений, --date YYYY-MM-DD, чтобы задать дату релиза (по умолчанию: сегодня по UTC), или --no-regen, чтобы пропустить регенерацию. Скрипт отклоняет некорректную версию или понижение версии, а его повторный запуск с текущей версией только заново выравнивает отбившиеся якоря.

Просмотрите diff, затем сделайте коммит:

git add -A
git commit -S -m "chore(release): cut vX.Y.Z"
git push origin main

Флаг -S подписывает коммит ключом GPG. Push запускает стандартную матрицу CI (lint, test, build); дождитесь зелёного статуса перед тегированием.

Проверка готовности в §2.4 также требует, чтобы CodeQL и Conformity были зелёными на коммите релиза. Оба запускаются только при изменении файлов, указанных в их условиях запуска, а коммит релиза обычно не меняет ни одного такого файла, поэтому запустите их, как только коммит релиза станет последним коммитом в main, и затем убедитесь, что в каждом запуске указан этот коммит:

gh workflow run codeql.yml --ref main
gh workflow run conformity.yml --ref main
gh run list --workflow codeql.yml --commit "$(git rev-parse HEAD)" --limit 1
gh run list --workflow conformity.yml --commit "$(git rev-parse HEAD)" --limit 1

Дождитесь успешного завершения обоих запусков перед тегированием и не отправляйте ничего другого в main, пока релиз не выпущен: более поздний push сдвигает main с коммита релиза, а CI отменяет запуск, который ещё выполняется на той же ветке.

2.2 Подпись и push тега

git tag -a -s vX.Y.Z -m "vX.Y.Z"
git push origin vX.Y.Z

Комбинация -a -s создаёт аннотированный тег с подписью GPG. Push запускает .github/workflows/release.yml, который собирает, подписывает, аттестует и публикует.

2.3 Подтверждение завершения рабочего процесса релиза

gh run watch $(gh run list --workflow=release.yml --limit=1 --json databaseId --jq '.[0].databaseId')

Рабочий процесс выполняет сборку (sdist + wheel, затем CycloneDX SBOM этих дистрибутивов, записываемый рядом с ними), бесключевую подпись cosign, генерацию и проверку происхождения SLSA-3, сборку платформенных архивов (darwin / linux / windows), подпись архивов с агрегированным манифестом SHA256SUMS и финальную публикацию GitHub Release. Сопровождающий просматривает журнал задания publish GitHub Release на предмет подтверждений загрузки ресурсов.

Задание publish GitHub Release выполняется в среде release, для которой требуется одобрение сопровождающего, поэтому запуск ждёт одобрения, как только предыдущие задания завершатся успешно. Одобрите его на странице запуска (Review deployments — проверка развёртываний) или из оболочки:

run_id=$(gh run list --workflow=release.yml --limit=1 --json databaseId --jq '.[0].databaseId')
env_id=$(gh api repos/ahmed-g-gad/apothem/environments/release --jq .id)
gh api -X POST "repos/ahmed-g-gad/apothem/actions/runs/${run_id}/pending_deployments" \
  -F "environment_ids[]=${env_id}" -f state=approved -f comment="vX.Y.Z"

Push тега также запускает рабочие процессы npm и расширения VS Code. Их задания публикации ждут того же одобрения до §2.4.

2.4 Подтверждение публикации в npm

Отправка тега также запускает publish-npm.yml наряду с release.yml. Рабочий процесс npm не ждёт рабочего процесса релиза; шлюзом служит одобрение среды release. Когда рабочий процесс релиза из §2.3 завершится, подтвердите готовность. Проверка читает релизы, запуски рабочих процессов и опубликованный SBOM, поэтому сначала подготовьте два входных параметра:

  • GH_TOKEN. Скрипт отказывается работать без него, даже когда gh уже выполнил вход. Используйте персональный токен доступа с точечными разрешениями (fine-grained), ограниченный репозиторием ahmed-g-gad/apothem, с правами Actions: Read (запуски рабочих процессов) и Contents: Read (релизы). Проверка ничего не записывает, поэтому право на запись не нужно. Токен из gh auth token несёт все разрешения текущего входа, поэтому предпочтительнее токен с точечными разрешениями.
  • Опубликованный SBOM. Проверка читает dist/release-assets/sbom.cdx.json — файл CycloneDX, который прикрепляет релиз. Загрузите копию, опубликованную релизом, а не локальную сборку.
read -rs GH_TOKEN && export GH_TOKEN
mkdir -p dist/release-assets
gh release download vX.Y.Z --repo ahmed-g-gad/apothem \
  --pattern sbom.cdx.json --dir dist/release-assets --clobber
bash scripts/release/check-release-ready.sh vX.Y.Z

Проверка завершается ошибкой, когда релиз является черновиком или предварительным релизом, когда обязательный рабочий процесс для коммита тега не зелёный, когда SBOM отсутствует, когда он описывает другую версию или когда в нём нет вендорённого пакета. Сообщение об ошибке называет причину.

Когда проверка пройдёт, одобрите ожидающий запуск Publish npm так же, как в §2.3 (его ID запуска берётся из gh run list --workflow=publish-npm.yml). Рабочий процесс публикует @ahmed-g-gad/[email protected] на npmjs.com через доверенную публикацию npm (OIDC); в репозитории не хранится токен реестра. Также одобрите ожидающий запуск Publish VS Code Extension. Он упаковывает apothem.vsix и публикует его в Visual Studio Marketplace как ahmed-g-gad.apothem-vscode. Шаг публикации выполняется только тогда, когда переменная репозитория VSCODE_MARKETPLACE_READY равна true и настроен один набор учётных данных: переменная VSCE_AUTH=oidc (Marketplace Trusted Publishing, без хранимого секрета), переменные VSCE_AUTH=entra, AZURE_CLIENT_ID и AZURE_TENANT_ID (короткоживущий токен Microsoft Entra ID, без хранимого секрета) или секрет VSCE_PAT. Если ничего из этого нет, запуск упаковывает расширение и пропускает публикацию. Учётные данные — это переключатель, а не повторная попытка: сбойная публикация по одному маршруту сама по себе не переходит на другой. Настройка каждого маршрута описана ниже в разделах Публикация в Marketplace через Trusted Publishing (предпочтительно) и Публикация в Marketplace через Microsoft Entra ID.

Чтобы опубликовать снова после сбойного запуска, запустите рабочий процесс для того же тега (gh workflow run publish-npm.yml --field tag=vX.Y.Z). Он пропускает публикацию, когда версия уже есть в реестре, потому что версии npm неизменяемы.

Публикация в Marketplace через Trusted Publishing

Trusted Publishing позволяет Marketplace напрямую принимать токен GitHub OIDC этого репозитория: vsce publish --oidc обменивает токен задания публикации на короткоживущие учётные данные Marketplace. Здесь нет ни хранимого секрета, ни ресурса Azure, поэтому этот маршрут предпочтителен. Маршрут Entra ниже и секрет VSCE_PAT остаются альтернативами, которые выбирает оператор.

  1. Используйте релиз vsce, который это поддерживает. На этом маршруте задание публикации перед публикацией проверяет релиз vsce, зафиксированный в tools/vsce, и останавливается с ошибкой, называющей минимальный релиз, когда зафиксированная версия старше. Dependabot предлагает обновления vsce для этого lock-файла; слейте то, которое достигает минимального релиза, до переключения.

  2. Создайте политику. Войдите как Owner издателя, откройте https://marketplace.visualstudio.com/manage/publishers/ahmed-g-gad и добавьте политику в разделе Trusted Publishing:

    • Policy name: любое имя, например apothem-release
    • Repository owner: Ahmed-G-Gad
    • Repository: apothem
    • Workflow: publish-vscode.yml
    • Environment: release

    Названия полей — те, что перечислены в руководстве по публикации VS Code, в его разделе о публикации с GitHub Actions и Trusted Publishing (https://code.visualstudio.com/api/working-with-extensions/publishing-extension). Не подтверждено: видит ли уже каждый издатель вкладку Trusted Publishing. Если ваш не видит, используйте маршрут Entra.

  3. Переключите маршрут. Оставьте VSCODE_MARKETPLACE_READY равной true и задайте селектор. Задавайте его, когда ни один тег не ожидает, потому что следующий push тега публикует через этот маршрут.

    gh variable set VSCE_AUTH --body oidc
  4. Опубликуйте. Следующий push тега или запуск для существующего тега публикует через Trusted Publishing. У этого маршрута нет пробного запуска: первая публикация и есть проверка, а запуск с dry_run лишь предупреждает, что ничего не было проверено.

  5. Вернитесь к запасному варианту при сбое. Удалите селектор и снова запустите рабочий процесс для того же тега; при заданном секрете VSCE_PAT публикует маршрут с токеном. Сбойная публикация ничего не опубликовала, поэтому тот же тег можно запустить снова.

    gh variable delete VSCE_AUTH

Публикация в Marketplace через Microsoft Entra ID

Маршрут Entra заменяет хранимый персональный токен доступа короткоживущим токеном. publish-vscode.yml запрашивает у GitHub токен OIDC, действие Azure/login обменивает его на вход в Entra через федеративные учётные данные, а vsce publish --azure-credential публикует с полученным токеном. Секрета клиента не существует. Секрет VSCE_PAT остаётся запасным вариантом, который выбирает оператор; рабочий процесс никогда не переключается на него сам.

Релиз vsce, закреплённый в tools/vsce, поддерживает этот маршрут. Ему нужны клиент (tenant) Entra, регистрация приложения и членство в издателе, которые не нужны для Trusted Publishing выше; используйте его, когда Trusted Publishing недоступен издателю.

  1. Проверьте предварительные условия. Найдите учётную запись, которой принадлежит издатель ahmed-g-gad (вкладка Members на https://marketplace.visualstudio.com/manage/publishers/ahmed-g-gad), и клиент Entra, в котором вы можете регистрировать приложения. Не подтверждено: должен ли клиент владельца издателя совпадать с клиентом приложения и должна ли организация Azure DevOps Ahmed-G-Gad быть подключена к Entra (dev.azure.com/Ahmed-G-Gad, Organization settings, Microsoft Entra). Ни один источник не утверждает ни того, ни другого. Если шаг 5 или 6 завершится сбоем, сначала проверьте это.

  2. Зарегистрируйте приложение. В https://entra.microsoft.com откройте App registrations, затем New registration. Назовите его apothem-vscode-publish, выберите один клиент и оставьте URI перенаправления пустым. На странице Overview скопируйте Application (client) ID и Directory (tenant) ID. Не создавайте секрет клиента и не выдавайте никаких разрешений API. Для этого шага нужны права владельца приложения или роль Entra, например Application Administrator.

  3. Добавьте федеративные учётные данные. В этом приложении откройте Certificates & secrets, Federated credentials, Add credential и выберите сценарий «GitHub Actions deploying Azure resources». Введите организацию Ahmed-G-Gad, репозиторий apothem, тип сущности Environment, имя среды release и имя учётных данных apothem-release. Сгенерированные поля должны выглядеть так:

    issuer:   https://token.actions.githubusercontent.com
    subject:  repo:Ahmed-G-Gad/apothem:environment:release
    audience: api://AzureADTokenExchange

    Сопоставление точное и чувствительно к регистру. Если последующий вход завершится ошибкой AADSTS700213 или AADSTS7002138, сравните учётные данные со строкой subject claim, которую Azure/login пишет в журнал задания. AADSTS70021 сразу после создания означает, что учётные данные ещё не распространились; подождите несколько минут и повторите.

  4. Задайте переменные репозитория. Пока VSCODE_MARKETPLACE_READY равна true, маршрут Entra активен, как только заданы все три, поэтому задавайте их, когда ни один тег релиза не ожидает одобрения. Без VSCODE_MARKETPLACE_READY=true вход не выполняется, и запуск пропускает публикацию.

    gh variable set AZURE_CLIENT_ID --body "<application-client-id>"
    gh variable set AZURE_TENANT_ID --body "<directory-tenant-id>"
    gh variable set VSCE_AUTH --body entra

    Оставьте VSCODE_MARKETPLACE_READY и VSCE_PAT как есть. Когда VSCE_AUTH равна entra, но AZURE_CLIENT_ID или AZURE_TENANT_ID пуста, рабочий процесс записывает в журнал предупреждение — независимо от того, задан ли VSCE_PAT, — и не использует маршрут Entra. Затем он использует секрет VSCE_PAT, если тот задан; без секрета он ничего не публикует, а запуск всё равно завершается зелёным, поэтому ищите предупреждение.

  5. Выполните пробный запуск. Запустите рабочий процесс для существующего тега релиза с заданным dry_run. На маршруте Entra он выполняет вход, выводит профиль Azure DevOps и проверяет доступ к издателю без публикации. У маршрута с токеном нет пробного запуска: если в журнале указано Marketplace credential mode: pat, запуск завершается зелёным с предупреждением и ничего не проверил. Одобрите ожидающий запуск среды release.

    gh workflow run publish-vscode.yml --ref main -f tag=vX.Y.Z -f dry_run=true

    Ожидается: Marketplace credential mode: entra, строка subject claim, совпадающая с subject из шага 3, а также id и displayName профиля, выведенные первым шагом пробного запуска. Ожидается, что шаг проверки завершится ошибкой 403 до шага 6. Не подтверждено: что вход без подписки Azure выдаёт токен для Marketplace через Azure CLI. Этот запуск — первая проверка этого. Если здесь произойдёт сбой, зарегистрируйте вместо этого назначаемое пользователем управляемое удостоверение в подписке — это маршрут, который документирует Microsoft.

  6. Добавьте приложение в издателя. На вкладке Members из шага 1 войдите как Owner издателя и добавьте участника по id профиля из шага 5 с ролью Contributor. Не подтверждено: подпись поля в диалоге и принимает ли он id до того, как приложение станет участником организации Azure DevOps. Azure DevOps, как правило, добавляет удостоверения приложений для каждой организации отдельно. Если диалог отклонит id, добавьте субъект-службу в организацию Ahmed-G-Gad (Organization settings, Users, используя Object ID корпоративного приложения (Enterprise application)) и повторите. Также не подтверждено: существует ли профиль до первого вызова Azure DevOps от имени этого удостоверения.

  7. Повторите пробный запуск. Шаг проверки теперь завершается успешно с сообщением «verification succeeded for the publisher»; в его сообщениях по-прежнему упоминается Personal Access Token, потому что токен Entra проходит тот же путь. Проверка доказывает членство в издателе (Creator, Owner, Contributor или Reader), а не права на публикацию. Не подтверждено: что роли Contributor достаточно для публикации обновления. Описание роли от Microsoft говорит, что достаточно, но ни один источник не показывает публикацию с ней, поэтому доказательством будет первая реальная публикация.

  8. Опубликуйте релиз. Поставьте тег, как в §2.2, и одобрите запуск. Выполняется шаг Publish to Visual Studio Marketplace (Entra ID), заголовок его окружения перечисляет только AZURE_TENANT_ID, запасной шаг с токеном пропускается, а vsce выводит DONE Published ahmed-g-gad.apothem-vscode. Галерея Marketplace показывает новую версию примерно через четыре минуты.

  9. Решите судьбу токена. Сохраняйте VSCE_PAT до первой успешной публикации через Entra, затем удалите секрет, если запасной вариант не нужен. После его удаления удалённая или пустая переменная Entra оставляет запуск зелёным без публикации: с предупреждением, когда VSCE_AUTH всё ещё равна entra, и только с уведомлением о пропуске, когда нет. Читайте аннотации запуска после каждого тега. Чтобы сохранить запасной вариант после вывода из эксплуатации глобальных персональных токенов доступа, создайте токен уровня организации для Ahmed-G-Gad с пользовательской областью Marketplace Manage и самым коротким сроком действия, который вы готовы принять, и сохраните его как VSCE_PAT. Не подтверждено: подписи портала в этом шаге приведены по памяти, а не по первичному источнику; Microsoft называет токены уровня организации временным обходным решением и может перестать их принимать; а страницы Microsoft расходятся в дате вывода из эксплуатации глобальных токенов.

  10. Вернитесь к токену. Удалите селектор и запустите рабочий процесс снова, затем одобрите запуск. Сбойная публикация через Entra ничего не опубликовала, поэтому тот же тег можно запустить снова; сначала проверьте страницу Marketplace, потому что версию, которая уже попала туда, нельзя опубликовать дважды.

    gh variable delete VSCE_AUTH
    gh workflow run publish-vscode.yml --ref main -f tag=vX.Y.Z

Когда публикация через Entra завершается сбоем, прочитайте журнал шага:

  • Сообщение, начинающееся с «Can not acquire a Microsoft Entra ID access token», означает, что не удался вход или цепочка учётных данных. Сначала проверьте шаг Sign in to Microsoft Entra ID и федеративные учётные данные. Если вход зелёный, удалите AZURE_TENANT_ID из env шага vsce в рабочем процессе; собственный рабочий процесс релиза расширения GitHub его не экспортирует.
  • «InvalidAccessException» или «not allowed» означает, что удостоверение токена не является участником издателя. Сравните id профиля из пробного запуска с вкладкой Members.
  • Ошибка 403 от шага проверки пробного запуска означает, что у приложения ещё нет роли.

К этому маршруту применяются три ограничения:

  • id-token: write выдаётся всему заданию публикации, поэтому любой шаг в нём может запросить токен OIDC, в том числе в режиме токена. Subject токена привязан к среде release, которая требует одобрения рецензента.
  • У среды release нет политики веток или тегов развёртывания, поэтому любая ссылка, которую одобрит сопровождающий, может получить токен с subject этой среды. Чтобы ограничить её тегами v*.*.*, сначала нужно проверить, что запускают release.yml и publish-npm.yml.
  • Переименование или передача репозитория меняет формат subject OIDC и незаметно ломает федеративные учётные данные. После любого переименования снова скопируйте subject из журнала Azure/login в учётные данные.

2.5 Обновление закрепления дайджестов шаблонов

После создания тега задайте _LATEST_RELEASE и _LATEST_RELEASE_DIGESTS в tests/unit/test_template_digests.py равными новому релизу и дайджесту SHA-256 каждого текстового шаблона в том виде, в каком его поставил этот релиз (git show vX.Y.Z:<template path> | sha256sum). Сделайте это в следующем изменении main и добавьте предыдущий дайджест в earlier_digests записи манифеста, если шаблон изменился. Задание CI release-preflight извлекает каждый тег, поэтому оно завершается ошибкой с именами тегов, пока закрепление не обновлено.

3. Поверхности распространения

У каждой поверхности есть команда проверки, отвечающая на вопрос «попал ли релиз сюда?»:

#ПоверхностьАртефактПроверка
1GitHub Release (дистрибутивы Python)apothem-X.Y.Z.tar.gz (sdist) + apothem-X.Y.Z-py3-none-any.whlgh release view vX.Y.Z --json assets --jq '.assets[].name' включает оба имени файлов
2GitHub Release (SBOM)sbom.cdx.json + sbom.cdx.json.cosign.bundleсписок ресурсов включает оба; metadata.component.purl в SBOM равен pkg:pypi/[email protected], а его компоненты включают каждый пакет из src/apothem/_vendor/vendor.txt
3GitHub Release (подписи)по одному <asset>.cosign.bundle на sdist, wheel, SBOM, расширение VS Code, платформенный архив и SHA256SUMS (в более ранних релизах бандлы архивов и SHA256SUMS называются <asset>.sig)cosign verify-blob с точной идентичностью из §5.5 завершается с кодом 0
4GitHub Release (происхождение)provenance.intoto.jsonlbash scripts/release/verify-provenance.sh <download-dir> завершается с кодом 0 (§5.5)
5GitHub Release (платформенные архивы)apothem-vX.Y.Z-darwin.tar.gz, apothem-vX.Y.Z-linux.tar.gz, apothem-vX.Y.Z-windows.zipсписок ресурсов включает каждый архив плюс SHA256SUMS. Архивы darwin и linux — это одни и те же байты под двумя именами (среда выполнения не зависит от платформы; --platform выбирает только tar.gz или zip), поэтому их строки в SHA256SUMS показывают один дайджест дважды
6GitHub Release (расширение VS Code)apothem.vsix + apothem.vsix.cosign.bundleсписок ресурсов включает оба; code --install-extension apothem.vsix устанавливает его. Релизы, вышедшие до того, как рабочий процесс релиза начал упаковывать расширение, не содержат ни того, ни другого
7npmjs.com@ahmed-g-gad/[email protected]npm view @ahmed-g-gad/apothem version возвращает X.Y.Z; npx @ahmed-g-gad/[email protected] --version печатает Apothem, version X.Y.Z
8Pages (скриптовые установщики)install.sh / install.ps1 на сайте документацииcurl -fsSL https://apothem.ahmedgad.com/install.sh | head -n 1 возвращает заголовок скрипта
9Visual Studio Marketplaceahmed-g-gad.apothem-vscode, версия X.Y.Zстраница расширения в Visual Studio Marketplace показывает версию X.Y.Z; code --install-extension ahmed-g-gad.apothem-vscode устанавливает его

GitHub Release — это каноническая поверхность артефактов; пакет npm и скриптовые установщики — это пути установки, построенные поверх него. Публикация в npm выполняется наряду с рабочим процессом релиза при том же push тега.

4. Дисциплина CHANGELOG

CHANGELOG.md содержит один раздел на релиз согласно соглашению Keep-a-Changelog. Правка CHANGELOG в коммите релиза:

  • Подтверждает, что раздел версии использует заголовок ## [X.Y.Z] - YYYY-MM-DD (дефис; его пишет bump_version.py, а extract_release_notes.py сопоставляет префикс ## [X.Y.Z]).
  • Подтверждает, что стандартные заголовки — Added, Changed, Deprecated, Removed, Fixed, Security — используются там, где это применимо. Пустые заголовки удаляются из отрендеренного файла.
  • Фиксирует возможности, а не реализацию. Только язык предметной области; никаких ссылок на внутренние планы; никаких хешей коммитов; никаких идентификаторов плана или фазы.

Раздел CHANGELOG, прошедший проверку сопровождающего, служит якорем примечаний к релизу для текста анонса.

5. Дымовая проверка пути установки

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

5.1 Плагин Claude Code

/plugin marketplace add ahmed-g-gad/apothem
/plugin install apothem@apothem

Ожидается: плагин устанавливается, и команды apothem доступны внутри Claude Code.

5.2 Node.js (npx)

npx @ahmed-g-gad/[email protected] --version

Ожидаемый вывод: Apothem, version X.Y.Z.

5.3 Одношаговый скриптовый установщик (POSIX)

Установщик записывает лаунчер apothem в ~/.local/bin или в каталог, указанный в APOTHEM_BIN_DIR, если эта переменная задана. Для проверки ниже этот каталог должен быть в PATH. Если его там нет, установщик выводит строку export PATH, которую нужно добавить. Пока этот каталог не в PATH, оболочка не находит apothem, и проверка завершается ошибкой. Если установщик не может разместить лаунчер, он выводит предупреждение и не выводит строку export PATH. На хосте, где ещё нет ключа подписи сопровождающего, первая строка импортирует его; без этого ключа установщик останавливается.

curl -fsSL https://github.com/ahmed-g-gad.gpg | gpg --import
curl -fsSL https://apothem.ahmedgad.com/install.sh | sh
apothem --version

Ожидаемый вывод: Apothem, version X.Y.Z.

5.4 Одношаговый скриптовый установщик (Windows)

Первая строка импортирует ключ подписи сопровождающего через собственный bash Git, связка ключей gpg которого — та же, что читает git verify-tag.

& "$env:ProgramFiles\Git\bin\bash.exe" -c 'curl -fsSL https://github.com/ahmed-g-gad.gpg | gpg --import'
irm https://apothem.ahmedgad.com/install.ps1 | iex
apothem --version

Ожидаемый вывод: Apothem, version X.Y.Z.

5.5 Проверка артефактов (доказательства цепочки поставок)

Скачайте все ресурсы в пустой каталог, затем выполните проверку. Идентичность сертификата — это рабочий процесс релиза именно на этом теге. Проверки идентичности чувствительны к регистру, а сертификаты содержат владельца в том виде, в каком его сообщает GitHub, — Ahmed-G-Gad, поэтому владелец в нижнем регистре не проходит проверку.

mkdir release-vX.Y.Z && cd release-vX.Y.Z
gh release download vX.Y.Z --repo ahmed-g-gad/apothem
cosign verify-blob \
  --bundle apothem-X.Y.Z-py3-none-any.whl.cosign.bundle \
  --certificate-identity https://github.com/Ahmed-G-Gad/apothem/.github/workflows/release.yml@refs/tags/vX.Y.Z \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  apothem-X.Y.Z-py3-none-any.whl
slsa-verifier verify-artifact \
  --provenance-path provenance.intoto.jsonl \
  --source-uri github.com/Ahmed-G-Gad/apothem \
  --source-tag vX.Y.Z \
  apothem-X.Y.Z-py3-none-any.whl apothem-X.Y.Z.tar.gz
bash ../scripts/release/verify-provenance.sh .

Ожидается: Verified OK, PASSED: SLSA verification passed и verify-provenance: chain OK (3 of 3 layers verified). Скрипт проверяет SHA256SUMS, каждый бандл подписи и происхождение за один запуск; он выводит тег из имени wheel (--tag vX.Y.Z переопределяет его).

Дымовая проверка выдаёт по одной строке PASS / FAIL на поверхность; запишите эти строки в журнал релизов сопровождающего.

6. Восстановление после сбоев

У рабочего процесса релиза есть задокументированные режимы сбоя для релизного движка и публикатора npm:

СбойДиагностикаВосстановление
Push тега отклонён (сбой подписи)git push origin vX.Y.Z возвращает error: failed to push some refs с сообщением, связанным с GPGПроверьте, что подключ GPG загружен (gpg --list-secret-keys --keyid-format=long); заново поставьте тег локально с -s после исправления связки ключей; повторите push
Сборка релиза останавливается на Check the plugin version changed with the pluginЖурнал задания сборки называет плагин и предыдущий тег; ни один ресурс не был собран или опубликованПакет плагина изменился с предыдущего релиза, а его версия — нет. Удалите тег (git push --delete origin vX.Y.Z, git tag -d vX.Y.Z), выполните python scripts/release/bump_version.py X.Y.Z, сделайте коммит, затем снова подпишите и отправьте тег (§2.2). Та же проверка выполняется на каждом pull request как аннотация-предупреждение, поэтому обычно это проявляется до тегирования
Задание release.yml даёт сбой на одном этапеgh run view <run-id> --log называет сбойное задание (build, которое также записывает SBOM / sign / provenance / archive / publish)Перезапустите только сбойное задание через gh run rerun <run-id> --failed; если сбой повторяется, исправьте входные данные задания в их источнике перед повторным тегированием
Проверка происхождения SLSA не проходитЗадание verify SLSA provenance artifact завершается с ненулевым кодомПроверьте артефакт происхождения на несоответствие дайджеста субъекта; пересоберите из того же тега — происхождение привязано к точным дайджестам артефактов, поэтому любая регенерация артефакта требует полного перезапуска рабочего процесса
Публикация на npmjs.com отклоненаЗадание npm завершается с ненулевым кодом во время npm publish; ошибка реестра 404 во время PUT — это несоответствие авторизации / доверенного издателя, а не доказательство отсутствия кода пакетаПроверьте, что npm Trusted Publishing для @ahmed-g-gad/apothem называет владельца ahmed-g-gad, репозиторий apothem, рабочий процесс publish-npm.yml и разрешённое действие npm publish; убедитесь, что задание выполняется с версией Node и минимальной версией npm CLI для OIDC, закреплёнными в рабочем процессе
Тег виден, но ресурсы отсутствуютgh release view vX.Y.Z возвращает релиз-заглушкуПерезапустите задание публикации рабочего процесса релиза; оно редактирует существующий релиз и повторно загружает каждый ресурс. Удаляйте тег и ставьте его заново только тогда, когда ничего из этого тега не дошло до пользователей (нет ресурсов, нет версии npm); в противном случае исправьте вперёд следующим патч-релизом (руководство по восстановлению релиза, §2)

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

7. Перекрёстные ссылки

  • Настройка издателя. Руководство по настройке учётной записи издателя устанавливает привязку доверенного издателя npm и предварительные условия на стороне GitHub, которые предполагает это руководство.
  • Поток восстановления. Руководство по восстановлению релиза следует той же аддитивной модели: оно поэтапно восстанавливает сбойный тег или этап публикатора и выполняет откат выпуском исправления как новой патч-версии, никогда не удаляя и не перенаправляя опубликованный тег, релиз или версию npm.
  • Включение Pages. Рабочий процесс publish-static-site.yml проверяет и развёртывает сайт проекта на пользовательском домене; руководство по включению Pages (site/content/docs/runbooks/pages-enablement.mdx) — это вышестоящая процедура, которая изначально установила пользовательский домен.
  • Политика версионирования. site/content/docs/governance/release-engineering-policy.mdx содержит политику SemVer + подписи + устаревания, которую соблюдает это руководство.

On this page