Руководство по циклу релиза
Полный рабочий процесс релиза от локальных шлюзов через подписанный 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 зелёный. Для последнего
maingh run list --branch=main --limit=1 --json conclusion --jq '.[0].conclusion'возвращаетsuccess. -
Инструментарий.
gh(GitHub CLI) версии 2.40 или новее, авторизованный вahmed-g-gad;git2.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.Zbump_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 остаются альтернативами, которые выбирает оператор.
-
Используйте релиз vsce, который это поддерживает. На этом маршруте задание публикации перед публикацией проверяет релиз vsce, зафиксированный в
tools/vsce, и останавливается с ошибкой, называющей минимальный релиз, когда зафиксированная версия старше. Dependabot предлагает обновления vsce для этого lock-файла; слейте то, которое достигает минимального релиза, до переключения. -
Создайте политику. Войдите как 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. - Policy name: любое имя, например
-
Переключите маршрут. Оставьте
VSCODE_MARKETPLACE_READYравнойtrueи задайте селектор. Задавайте его, когда ни один тег не ожидает, потому что следующий push тега публикует через этот маршрут.gh variable set VSCE_AUTH --body oidc -
Опубликуйте. Следующий push тега или запуск для существующего тега публикует через Trusted Publishing. У этого маршрута нет пробного запуска: первая публикация и есть проверка, а запуск с
dry_runлишь предупреждает, что ничего не было проверено. -
Вернитесь к запасному варианту при сбое. Удалите селектор и снова запустите рабочий процесс для того же тега; при заданном секрете
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
недоступен издателю.
-
Проверьте предварительные условия. Найдите учётную запись, которой принадлежит издатель
ahmed-g-gad(вкладка Members наhttps://marketplace.visualstudio.com/manage/publishers/ahmed-g-gad), и клиент Entra, в котором вы можете регистрировать приложения. Не подтверждено: должен ли клиент владельца издателя совпадать с клиентом приложения и должна ли организация Azure DevOpsAhmed-G-Gadбыть подключена к Entra (dev.azure.com/Ahmed-G-Gad, Organization settings, Microsoft Entra). Ни один источник не утверждает ни того, ни другого. Если шаг 5 или 6 завершится сбоем, сначала проверьте это. -
Зарегистрируйте приложение. В
https://entra.microsoft.comоткройте App registrations, затем New registration. Назовите егоapothem-vscode-publish, выберите один клиент и оставьте URI перенаправления пустым. На странице Overview скопируйте Application (client) ID и Directory (tenant) ID. Не создавайте секрет клиента и не выдавайте никаких разрешений API. Для этого шага нужны права владельца приложения или роль Entra, например Application Administrator. -
Добавьте федеративные учётные данные. В этом приложении откройте 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 сразу после создания означает, что учётные данные ещё не распространились; подождите несколько минут и повторите. -
Задайте переменные репозитория. Пока
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, если тот задан; без секрета он ничего не публикует, а запуск всё равно завершается зелёным, поэтому ищите предупреждение. -
Выполните пробный запуск. Запустите рабочий процесс для существующего тега релиза с заданным
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. -
Добавьте приложение в издателя. На вкладке Members из шага 1 войдите как Owner издателя и добавьте участника по
idпрофиля из шага 5 с ролью Contributor. Не подтверждено: подпись поля в диалоге и принимает ли он id до того, как приложение станет участником организации Azure DevOps. Azure DevOps, как правило, добавляет удостоверения приложений для каждой организации отдельно. Если диалог отклонит id, добавьте субъект-службу в организациюAhmed-G-Gad(Organization settings, Users, используя Object ID корпоративного приложения (Enterprise application)) и повторите. Также не подтверждено: существует ли профиль до первого вызова Azure DevOps от имени этого удостоверения. -
Повторите пробный запуск. Шаг проверки теперь завершается успешно с сообщением «verification succeeded for the publisher»; в его сообщениях по-прежнему упоминается Personal Access Token, потому что токен Entra проходит тот же путь. Проверка доказывает членство в издателе (Creator, Owner, Contributor или Reader), а не права на публикацию. Не подтверждено: что роли Contributor достаточно для публикации обновления. Описание роли от Microsoft говорит, что достаточно, но ни один источник не показывает публикацию с ней, поэтому доказательством будет первая реальная публикация.
-
Опубликуйте релиз. Поставьте тег, как в §2.2, и одобрите запуск. Выполняется шаг
Publish to Visual Studio Marketplace (Entra ID), заголовок его окружения перечисляет толькоAZURE_TENANT_ID, запасной шаг с токеном пропускается, а vsce выводитDONE Published ahmed-g-gad.apothem-vscode. Галерея Marketplace показывает новую версию примерно через четыре минуты. -
Решите судьбу токена. Сохраняйте
VSCE_PATдо первой успешной публикации через Entra, затем удалите секрет, если запасной вариант не нужен. После его удаления удалённая или пустая переменная Entra оставляет запуск зелёным без публикации: с предупреждением, когдаVSCE_AUTHвсё ещё равнаentra, и только с уведомлением о пропуске, когда нет. Читайте аннотации запуска после каждого тега. Чтобы сохранить запасной вариант после вывода из эксплуатации глобальных персональных токенов доступа, создайте токен уровня организации дляAhmed-G-Gadс пользовательской областью Marketplace Manage и самым коротким сроком действия, который вы готовы принять, и сохраните его какVSCE_PAT. Не подтверждено: подписи портала в этом шаге приведены по памяти, а не по первичному источнику; Microsoft называет токены уровня организации временным обходным решением и может перестать их принимать; а страницы Microsoft расходятся в дате вывода из эксплуатации глобальных токенов. -
Вернитесь к токену. Удалите селектор и запустите рабочий процесс снова, затем одобрите запуск. Сбойная публикация через 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. Поверхности распространения
У каждой поверхности есть команда проверки, отвечающая на вопрос «попал ли релиз сюда?»:
| # | Поверхность | Артефакт | Проверка |
|---|---|---|---|
| 1 | GitHub Release (дистрибутивы Python) | apothem-X.Y.Z.tar.gz (sdist) + apothem-X.Y.Z-py3-none-any.whl | gh release view vX.Y.Z --json assets --jq '.assets[].name' включает оба имени файлов |
| 2 | GitHub Release (SBOM) | sbom.cdx.json + sbom.cdx.json.cosign.bundle | список ресурсов включает оба; metadata.component.purl в SBOM равен pkg:pypi/[email protected], а его компоненты включают каждый пакет из src/apothem/_vendor/vendor.txt |
| 3 | GitHub Release (подписи) | по одному <asset>.cosign.bundle на sdist, wheel, SBOM, расширение VS Code, платформенный архив и SHA256SUMS (в более ранних релизах бандлы архивов и SHA256SUMS называются <asset>.sig) | cosign verify-blob с точной идентичностью из §5.5 завершается с кодом 0 |
| 4 | GitHub Release (происхождение) | provenance.intoto.jsonl | bash scripts/release/verify-provenance.sh <download-dir> завершается с кодом 0 (§5.5) |
| 5 | GitHub 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 показывают один дайджест дважды |
| 6 | GitHub Release (расширение VS Code) | apothem.vsix + apothem.vsix.cosign.bundle | список ресурсов включает оба; code --install-extension apothem.vsix устанавливает его. Релизы, вышедшие до того, как рабочий процесс релиза начал упаковывать расширение, не содержат ни того, ни другого |
| 7 | npmjs.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 |
| 8 | Pages (скриптовые установщики) | install.sh / install.ps1 на сайте документации | curl -fsSL https://apothem.ahmedgad.com/install.sh | head -n 1 возвращает заголовок скрипта |
| 9 | Visual Studio Marketplace | ahmed-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 + подписи + устаревания, которую соблюдает это руководство.
Руководства по эксплуатации
Руководства по эксплуатации Apothem — пошаговые операционные процедуры для релизов, настройки издателя, включения Pages, восстановления и создания адаптеров.
Контрольный список развёртывания
Контрольный список предварительной проверки для развёртывания или совместного использования экосистемы Apothem