Ручная подготовка staging
Курс «Лаборатория GitLab CI/CD»
После успешного build и verify лаборатория course-card имеет проверенный статический каталог. Добавим ручное действие prepare-staging: оно получает тот же dist/, повторно сверяет целостность и создаёт папку staging/ внутри собственного job. Человек сможет явно разрешить эту подготовку после обсуждения результата.
Здесь staging означает учебный пакет готовых файлов. Мы не подключаем сервер, S3, Netlify или почтовую рассылку. Система GitLab может показывать логическую запись environment, но наличие такой записи не создаёт внешний сайт. Эта граница позволяет изучить ручную стадию и передачу выпуска без реальных внешних изменений.
Условие появления
Добавьте стадию prepare после verify и следующее полное определение job. Имена производителей остаются из предыдущих уроков. Правила включают действие только после push в default branch; MR pipeline проверяет изменения, но не содержит эту ручную подготовку.
prepare-staging:
stage: prepare
needs:
- job: build-site
artifacts: true
- job: verify-site
artifacts: false
rules:
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
when: manual
- when: never
allow_failure: false
script:
- node scripts/promote.mjs
environment:
name: laboratory/staging
artifacts:
paths:
- staging/
expire_in: 7 days
Needs на build-site передаёт dist/, а needs на verify-site создаёт обязательное условие успешной проверки. У отчёта verify нет причины становиться входом самой подготовки, поэтому artifacts false. Если оставить только verify needs, можно получить отчёт без файла сайта. Зависимость качества и зависимость данных здесь выражены отдельно.
when: manual требует явного запуска. allow_failure: false делает этот ручной шаг блокирующим для завершения соответствующего pipeline: без него основная ветка может показывать ожидание ручного действия. Это ожидаемая политика лаборатории, а не ошибка runner. Если процесс требует необязательное действие, политику можно изменить осознанно, сохраняя различие состояний.
Что делает программа
promote.mjs читает dist/release.json и проверяет файлы по тем же хэшам, затем очищает собственную staging/ и копирует туда dist/. Рядом записывает promotion.json с исходным commit и pipeline. Сборки из courses.json внутри этого job нет. Поэтому подготовленный пакет относится к тому артефакту, который прошёл предыдущий этап.
Имя promotion не означает переход в production. Оно описывает смену учебного состояния: из проверенного артефакта в отдельно подготовленную папку. Содержимое файла и место его записи должны отражать это назначение. В архиве нет команд SSH, загрузки в облако или отправки уведомлений, а программа ограничена папками своего проекта.
Если хэш изменился после проверки или dist/ отсутствует, программа завершится ошибкой и не должна сохранять новый staging как готовый. Ручное нажатие выражает намерение выполнить действие, но не отменяет обязательные условия входа. По этой причине полезно повторить дешёвую сверку целостности непосредственно перед копированием.
Логическое окружение
environment:name позволяет GitLab связать job с именем окружения. В нашем примере laboratory/staging является записью процесса. URL не задан, потому что внешнего адреса нет. Не добавляйте фиктивный https://staging.example.com ради красивой ссылки: интерфейс начнёт обещать ресурс, который не создавался.
Подробнее устройство окружений и ручных работ описано в документации environments и управления manual jobs. В реальном процессе за environment должны стоять необходимые полномочия, состояние и способ проверки. Наша программа показывает лишь ограниченную передачу файла.

Изображение GitLab Docs демонстрирует ручной job с production-именем. Это пример документации; course-card использует только job-local laboratory/staging и не публикуется наружу.
Не переносите production-права из чужого проекта ради повторения формы кнопки. Если внешняя публикация когда-нибудь войдёт в задачу, её нужно будет отдельно спроектировать: получатель, доступ, защита от устаревших выпусков, проверка и возврат. Эти темы разобраны в курсе сопровождения сайта, поэтому здесь не повторяем эксплуатацию серверов.
Возраст артефакта
Ручной job может быть запущен позже автоматических стадий. Если артефакт build уже недоступен по правилам хранения, операция не сможет использовать тот же файл. Не следует в такой ситуации тихо перестроить каталог и подписать прежним pipeline ID. Это создало бы недостоверное происхождение пакета.
Для лаборатории срок семь дней достаточен как учебное условие, но не является универсальным решением. При самостоятельном процессе сравните срок хранения с временем обсуждения. Если нужна более длительная передача, сохраните выпуск в соответствующем хранилище с понятной идентичностью и правами. Кэш не заменяет такое хранилище.
Отличайте retry job от нового pipeline. Повторная работа может читать те же входы и создать новый диагностический результат, а новая сборка получит другой контекст. В журнале и метаданных должен быть виден конкретный источник. Даже когда bytes совпадают, процесс не должен скрывать, какое действие было выполнено и кем разрешено.
Ручной job у старого pipeline остаётся связан с его исходным артефактом. Если после обсуждения появился новый commit, нажатие прежней кнопки не означает подготовку самой новой версии. В нашем job-local сценарии это создаст отдельный пакет с явно старым commit, который можно распознать по release metadata. При внешнем получателе такой случай потребовал бы политики допустимой версии и дополнительных ограничений. Поэтому уже в лаборатории смотрите на идентификатор pipeline рядом с действием. Название кнопки без контекста не сообщает возраст данных, хотя человеку может казаться, что он выбирает текущий результат.
Ручное действие сохраняет связь с тем pipeline, в котором оно показано. Если после него появился новый commit, старый job не превращается автоматически в подготовку свежей версии. Перед выбором действия сопоставьте источник pipeline и release metadata; название основной ветки само по себе не указывает возраст артефакта. Для лаборатории это означает получение ожидаемого учебного пакета из выбранной сборки. Для настоящего окружения потребовались бы дополнительные правила актуальности и доступа, которые нельзя заменить одной кнопкой manual. Мы сохраняем эти вопросы как границу следующего самостоятельного проекта.
Граница параллельных подготовок
Папка staging находится внутри отдельного job и не является общей постоянной директорией сервера. Поэтому две работы не переключают единый рабочий сайт и не конкурируют за production-состояние. Механизмы сериализации внешнего деплоя для этой модели не требуются. Не копируйте resource_group только ради наличия ключа, если общего изменяемого получателя здесь нет.
Сравните staging/release.json с исходным dist/release.json: commit, pipeline и файловые хэши должны сохраняться. promotion.json описывает подготовку, а не переписывает происхождение сборки. Это критерий результата для самостоятельной работы; при подготовке курса копирование и jobs не выполнялись.
После урока ожидаем ручной шаг, который имеет явное условие появления, обязательную проверку и локальный output. Он не превращает зелёный pipeline в утверждение о опубликованном сайте. Последний урок соберёт конфигурацию в поддерживаемую структуру и покажет, как читать ошибки без изменения её смысла.