Релизы
Tuist автоматически публикует новые версии по мере слияния изменений в основную ветку. CLI, сервер и кэш-сервер Kura поставляются через каналы релизов (canary, кандидат в релиз, стабильный), чтобы рекомендуемая установка оставалась стабильной и медленно меняющейся; выпуск кандидата в релиз и его продвижение в стабильный — это осознанные еженедельные шаги. Приложение выпускается непрерывно (iOS-приложение развёртывается только в TestFlight, подробнее здесь).
Обзор#
Мы выпускаем следующие основные компоненты:
- Tuist CLI — инструмент командной строки, поставляемый через каналы canary, кандидата в релиз и стабильный каналы
- Tuist Server — бэкенд-сервисы, поставляемые по той же канальной модели, что и CLI
- Kura — кэш-сервер, поставляемый по той же канальной модели, что и CLI
- Tuist App — приложения для macOS и iOS, выпускаемые непрерывно (iOS-приложение развёртывается только в TestFlight, подробнее здесь)
Каждый пуш в main публикует canary-пререлиз для CLI, сервера и Kura. Стабильный релиз для каждого из этих компонентов выпускается только тогда, когда мейнтейнер продвигает проверенный кандидат в релиз, а еженедельное расписание запускает все три потока синхронно (см. Каналы релизов). Приложение публикует стабильную версию при каждом пуше в main.
Как это работает#
1. Соглашения о коммитах#
Мы используем Conventional Commits для структурирования сообщений коммитов. Это позволяет нашим инструментам понимать характер изменений, определять повышение версий и генерировать соответствующие списки изменений.
Формат: type(scope): description
Типы коммитов и их влияние#
| Тип | Описание | Влияние на версию | Пример |
|---|---|---|---|
feat | Новая функция или возможность | Повышение минорной версии (x.Y.z) | feat(cli): add support for Swift 6 |
fix | Исправление ошибки | Повышение патч-версии (x.y.Z) | fix(app): resolve crash when opening projects |
docs | Изменения в документации | Без релиза | docs: update installation guide |
style | Изменения стиля кода | Без релиза | style: format code with swiftformat |
refactor | Рефакторинг кода | Без релиза | refactor(server): simplify auth logic |
perf | Улучшения производительности | Повышение патч-версии | perf(cli): optimize dependency resolution |
test | Добавление/изменение тестов | Без релиза | test: add unit tests for cache |
chore | Задачи по обслуживанию | Без релиза | chore: update dependencies |
ci | Изменения CI/CD | Без релиза | ci: add workflow for releases |
Для CLI эти повышения определяют версию canary и группировку списка изменений. Стабильные версии CLI — это минорные линии (X.Y.0), выпускаемые вручную, а стабильные патчи (X.Y.Z) поступают только из бэкпортов, поэтому feat или fix достигают пользователей CLI через приведённый ниже поток каналов, а не как немедленный стабильный релиз.
Критические изменения#
Критические изменения вызывают повышение мажорной версии (X.0.0) и должны быть указаны в теле коммита:
feat(cli): change default cache location
BREAKING CHANGE: The cache is now stored in ~/.tuist/cache instead of .tuist-cache.
Users will need to clear their old cache directory.
2. Обнаружение изменений#
Каждый компонент использует git cliff для:
- Анализа коммитов с момента последнего релиза
- Фильтрации коммитов по области (cli, app, server)
- Определения наличия изменений, готовых к релизу
- Автоматической генерации списков изменений
3. Пайплайн релиза#
Когда обнаружены изменения, готовые к релизу:
- Расчёт версии: пайплайн определяет номер следующей версии
- Генерация списка изменений: git cliff создаёт список изменений на основе сообщений коммитов
- Процесс сборки: компонент собирается и тестируется
- Генерация артефактов: создаются специфичные для релиза ресурсы, такие как архивы CLI, контрольные суммы и спецификация CLI
tuist.spec.json, генерируемая изtuist --experimental-dump-help - Создание релиза: в GitHub создаётся релиз с артефактами
- Дистрибуция: обновления публикуются в менеджерах пакетов (например, Homebrew для CLI)
Для приложения это приводит к стабильному релизу при каждом слиянии. Для CLI, сервера и Kura тот же автоматический пайплайн выпускает только предварительный релиз canary; релиз-кандидаты и стабильные релизы выпускаются еженедельно (см. Каналы релизов).
4. Фильтрация по области#
Каждый компонент выпускается только при наличии соответствующих изменений:
- CLI: коммиты с областью
(cli)или без указания области - App: коммиты с областью
(app) - Server: коммиты с областью
(server)
Каналы релизов#
CLI, сервер и Kura не переводятся в стабильный релиз при каждом пуше в main. Каждый из них поставляется через три канала, чтобы рекомендуемая установка оставалась стабильной и медленно меняющейся, в то время как ранние пользователи получают сборки для каждого коммита. Пользовательская документация находится по адресам Каналы релизов CLI и Каналы релизов сервера; этот раздел предназначен для сопровождающих.
Каждый компонент использует одни и те же три канала:
| Канал | Версия | Выпускается |
|---|---|---|
| Canary | X.Y.0-canary.N | Автоматически, при каждом пуше в main, затрагивающем компонент (<component>-release.yml; для Kura вызывается из server-production-deployment.yml при изменении kura/) |
| Релиз-кандидат | X.Y.0-rc.N | Каждый понедельник или вручную, в ветке releases/<component>-<major>.<minor>.x (<component>-rc.yml) |
| Стабильный | X.Y.Z | Каждый понедельник или вручную, путём перевода проверенного RC в стабильный статус (<component>-promote.yml); патчи через <component>-backport.yml |
Сборки Canary и RC публикуются как предварительные релизы GitHub (никогда не помечаются как «Latest», никогда не перемещают тег :latest в GHCR, никогда не отправляются в Homebrew для CLI), поэтому менеджеры пакетов и резолверы образов подбирают их только при явном согласии. Canary всегда нацелен на следующую невыпущенную минорную версию: как только выпущена линия RC, canary в main переходит к следующей минорной версии.
Hosted Tuist не ждёт стабильного релиза: сервер развёртывается для каждого коммита, а hosted canary и production используют новейший canary Kura. Каскад развёртывания публикует этот canary перед его развёртыванием, поэтому у kura-release.yml нет собственного триггера. Изменения только в инструментах релиза Kura (mise/tasks/kura/**, рабочие процессы kura-*.yml) не приводят к выпуску canary.
Вы никогда не выбираете номера версий вручную. Следующая версия каждого канала выводится из существующих git-тегов скриптом mise/tasks/<component>/release/channel-version.sh, который вызывают приведённые ниже рабочие процессы.
Ветки релизов изолированы по компонентам (releases/server-X.Y.x, releases/kura-X.Y.x, releases/X.Y.x для CLI), чтобы линии трёх компонентов никогда не пересекались на одной минорной версии.
Еженедельное расписание#
Каждый понедельник в 06:00 UTC задачи продвижения трёх компонентов выполняются синхронно: CLI Promote to Stable, Server Promote to Stable и Kura Promote to Stable. Каждая задача продвигает новейшую линию RC, которая ещё не стала стабильной, обычно это линия, выпущенная в предыдущий понедельник. Если такой линии нет, задача ничего не публикует.
По завершении продвижения, независимо от результата, запускается соответствующий рабочий процесс Release Candidate (cli-rc.yml, server-rc.yml, kura-rc.yml) через workflow_run и выпускает следующую линию из main.
Если запланированный запуск завершается ошибкой или отменяется, в Slack отправляется сообщение. Продвижение завершается ошибкой, если в ветке релиза есть коммиты после её последнего RC. Чтобы выпустить эту линию, создайте на ней новый RC и переведите его в стабильный статус вручную. В противном случае в следующий понедельник будет продвинута более новая линия.
Выпуск релиз-кандидата#
Чтобы выпустить новую линию вне еженедельного расписания (подставьте ниже имя рабочего процесса компонента):
- Запустите рабочий процесс <Component> Release Candidate (например,
server-rc.yml) с пустым входным параметромbranch. - Он публикует
X.Y.0-rc.1и после успешного завершения создаёт защищённую веткуreleases/<component>-X.Y.xна собранном коммите.
Чтобы добавить критическое исправление или устранить регрессию в линии, проходящей тестирование, сделайте cherry-pick в ветку релиза через PR (тот же поток, что и для бэкпортов; CI никогда не делает cherry-pick самостоятельно), затем обновите RC:
- Создайте ветку от
releases/<component>-X.Y.x, сделайте cherry-pick исправления, откройте PR обратно в ветку релиза, разрешите возможные конфликты и выполните слияние. - Снова запустите рабочий процесс Release Candidate с параметром
branch=releases/<component>-X.Y.x. Он опубликуетX.Y.0-rc.(N+1)из HEAD ветки.
Линия, проходящая тестирование, заморожена по функциональности: в неё попадают только критические исправления и устранение регрессий.
Продвижение в стабильный статус#
Чтобы продвинуть линию вне еженедельного расписания после чистого прохождения тестирования её RC:
- Запустите рабочий процесс <Component> Promote to Stable (например,
server-promote.yml) с параметромbranch=releases/<component>-X.Y.x. - Он публикует образ с семантическим тегом, устанавливая
make_latest=true, что перемещает тег GHCR:latestи указатель «Latest» на GitHub. CLI дополнительно обновляет формулу Homebrew.
Продвижение не запускается, если HEAD ветки не совпадает точно с коммитом, на который указывает последний RC. Поэтому, если после последнего RC в линию было внесено какое-либо исправление, необходимо создать новый RC и дать ему пройти тестирование, прежде чем он сможет быть выпущен как стабильный.
Бэкпорт исправлений в стабильную линию#
Когда линия становится стабильной, выпускайте патчи с помощью рабочего процесса Backport Release, доступного только для CLI (cli-backport.yml): сделайте cherry-pick исправления в releases/X.Y.x через PR, затем запустите рабочий процесс для этой ветки, чтобы выпустить X.Y.(Z+1). Бэкпорты никогда не перемещают указатель «Latest» и не обновляют формулу Homebrew. Одновременно поддерживаются две линии: текущая линия получает исправления регрессий и уязвимостей безопасности, предыдущая — только критические исправления и исправления безопасности. Другие исправления ошибок не бэкпортятся и выходят со следующим минорным релизом.
Для сервера и Kura используйте Server Backport Release (server-backport.yml) или Kura Backport Release (kura-backport.yml). Продвижение публикует только X.Y.0 версии RC; оно не может применять патчи к уже стабильной линии.
- Начните с последнего опубликованного стабильного тега компонента на выбранной линии
X.Yи откройте точечный PR с исправлением в существующую веткуreleases/server-X.Y.xилиreleases/kura-X.Y.x. Более новый минорный или мажорный релиз не препятствует применению патчей к поддерживаемой линии. Не включайте изменения из main, не относящиеся к делу. - Проверьте и слейте исходный PR. Получите удалённую ветку релиза и подтвердите её финальный слитый коммит, включая поддерживаемые платформы компонента и положительные/отрицательные контрольные точки TLS. Успешное прохождение проверок до слияния не означает квалификацию другого squash-коммита или коммита слияния.
- После отдельного утверждения публикации запустите соответствующий рабочий процесс бэкпорта из main, установив
source_shaв тот самый квалифицированный слитый коммит, аbase_tag— в текущий стабильный тег, например[email protected]или[email protected]. Рабочий процесс выводитX.Y.(Z+1); операторы не выбирают повышение минорной версии и не продвигают содержимое canary.
Планирование обновляет точную удалённую ветку и базовый тег, требует, чтобы выбранный источник совпадал с концом ветки, отвергает неизменённый источник или изменения вне компонента, его входные данные политики доверия и валидацию, и фиксирует разрешённый базовый коммит. Контроли, основанные на main, повторяют эти проверки непосредственно перед публикацией версионированного образа и на GitHub. Если исходная ветка, стабильная база или доступная версия изменяются, остановитесь и повторно проведите квалификацию, вместо замены источника.
Бэкпорты используют существующие мультиплатформенные издатели без перемещения указателя «Latest» на GitHub или тега GHCR :latest. Публикация отделена от развёртывания на хостинге: эти рабочие процессы не продвигают размещённый сервер или флот Kura, не обходят приёмку canary и не квалифицируют установленную среду выполнения. Вспомогательные скрипты сборки и Dockerfile по-прежнему берутся из выбранного стабильного источника. Контроли являются шлюзами публикации, а не задачами сборки без учётных данных; сборки могут загружать нетегированные дайджесты образов до финального шлюза. Публикация образа и на GitHub не является атомарной: если позже шлюз завершается ошибкой после публикации тега образа, изучите частичный релиз и сохраните его исходный источник и артефакты. Никогда не заменяйте существующий релиз и не используйте другие байты под его тегом.
Написание хороших сообщений коммитов#
Поскольку сообщения коммитов напрямую влияют на примечания к релизу, важно писать понятные и описательные сообщения:
Рекомендуется:#
- Используйте настоящее время: «add feature», а не «added feature»
- Будьте лаконичны, но описательны
- Указывайте область изменений, если они относятся к конкретному компоненту
- Ссылайтесь на задачи, если применимо:
fix(cli): resolve build cache issue (#1234)
Не рекомендуется:#
- Использовать расплывчатые сообщения, такие как «fix bug» или «update code»
- Объединять несколько несвязанных изменений в одном коммите
- Забывать включать информацию о критических изменениях
Критические изменения#
Для критических изменений включайте BREAKING CHANGE: в тело коммита:
feat(cli): change cache directory structure
BREAKING CHANGE: Cache files are now stored in a new directory structure.
Users need to clear their cache after updating.
Рабочие процессы релизов#
CLI, сервер и Kura имеют собственный набор рабочих процессов каналов, следующих одной структуре:
<component>-release.yml— публикует canary при каждом пуше вmain, затрагивающем компонент (для Kura это переиспользуемый рабочий процесс, который вызываетserver-production-deployment.ymlпри измененииkura/)<component>-rc.yml— выпускает релиз-кандидат каждый понедельник (черезworkflow_runпосле продвижения) или вручную выпускает либо обновляет его<component>-promote.yml— продвигает ожидающий RC в стабильный статус каждый понедельник в 06:00 UTC или вручную продвигает прошедший тестирование RC<component>-build-publish.yml— общий конвейер сборки и публикации, вызываемый тремя вышеуказанными процессами
CLI, сервер и Kura также имеют <component>-backport.yml для выпуска патчей на стабильной линии. Все рабочие процессы компонента сериализуются через одну группу параллелизма <component>-publish, чтобы разрешение версий и тегирование никогда не конкурировали. Исключение составляет Kura: её canary использует kura-canary-publish, а RC, продвижение и бэкпорт используют kura-stable-publish, поэтому длительная стабильная сборка никогда не задерживает каскад развёртывания. Пространства имён тегов не пересекаются, поэтому две группы не могут конфликтовать.
Диаграмма Helm и образы инфраструктуры (оператор CAPI, контроллер раннеров, образ обработчика xcresult, образ linux-раннера и так далее) по-прежнему выпускаются через .github/workflows/server-production-deployment.yml. Процесс запускается при пушах в main и выполняет каскад canary → приёмочные тесты → продакшен для хостингового развёртывания, публикуя эти инфраструктурные компоненты по мере их изменения. Приложение, кэш, плагин Gradle, навыки, Noora и отдельные контроллеры инфраструктуры имеют выделенный рабочий процесс *-release.yml. Все они используют общий механизм обнаружения изменений: mise/tasks/release/components.json объявляет префикс тега и пути включения для каждого компонента, а git cliff превращает соответствующие коммиты в примечания к релизу.
Сборка CLI (cli-build-publish.yml) также создаёт и публикует артефакт tuist.spec.json (генерируемый из tuist --experimental-dump-help), чтобы сторонние инструменты могли использовать интерфейс командной строки.
Мониторинг релизов#
Вы можете отслеживать релизы через:
- Страницу релизов на GitHub
- Вкладку GitHub Actions для запусков рабочих процессов
- Файлы changelog в директории каждого компонента
Преимущества#
Этот подход непрерывных релизов обеспечивает:
- Быструю доставку: Изменения попадают к пользователям сразу после слияния
- Снижение узких мест: Не нужно ждать ручных релизов
- Чёткую коммуникацию: Автоматизированные списки изменений на основе сообщений коммитов
- Единый процесс: Одинаковый поток релиза для всех компонентов
- Гарантию качества: Выпускаются только протестированные изменения
Устранение неполадок#
Если релиз не удался:
- Проверьте логи GitHub Actions для неудачного рабочего процесса
- Убедитесь, что сообщения ваших коммитов соответствуют общепринятому формату
- Проверьте, что все тесты проходят
- Убедитесь, что компонент успешно собирается
Для срочных исправлений, требующих немедленного выпуска:
- Убедитесь, что ваш коммит имеет чёткую область действия
- После слияния отслеживайте рабочий процесс релиза
- Для сервера или приложения исправление выйдет со следующим пушем; при необходимости запустите ручной релиз
- Для CLI исправление автоматически попадает в canary. Чтобы доставить его пользователям стабильной версии, выполните бэкпорт в поддерживаемую стабильную линию (линии) (см. Бэкпорт исправлений в стабильную линию)
Релиз в App Store#
Хотя CLI и сервер следуют описанному выше процессу непрерывных релизов, iOS-приложение является исключением из-за процесса проверки Apple App Store:
- Ручные релизы: Релизы iOS-приложения требуют ручной отправки в App Store
- Задержки проверки: Каждый релиз должен пройти проверку Apple, которая может занять 1–7 дней
- Пакетные изменения: Несколько изменений обычно объединяются в каждый релиз iOS
- TestFlight: Бета-версии могут распространяться через TestFlight перед релизом в App Store
- Примечания к релизу: Должны быть написаны специально в соответствии с требованиями App Store
iOS-приложение всё ещё следует тем же соглашениям о коммитах и использует git cliff для генерации списка изменений, но фактический релиз для пользователей происходит по менее частому, ручному графику.