Начало работы
Раздел показывает путь от установки до первого сгенерированного пайплайна.
Установка
opm install pipelinerБиблиотека зависит от autumn, autumn-cli и oscript-yaml — они установятся автоматически.
Как устроена библиотека
Pipeliner построен на DI-фреймворке autumn. Вы описываете джобы в .os-файлах, библиотека собирает их в YAML.
Три главных желудя:
| Желудь | Назначение |
|---|---|
ФабрикаЗадач | Реестр задач: Новая() создаёт описание задачи и накапливает список |
ГенераторПайплайнаГитлаб | Превращает накопленные задачи в YAML и пишет файл |
ОписаниеПайплайна | Топ-левел настройки: глобальные переменные, coverage, before/after script |
Первый пайплайн
Создайте скрипт build.os:
#Использовать pipeliner
#Использовать autumn
#Использовать oscript-yaml
Поделка = Новый Поделка();
Поделка.ЗапуститьПриложение();
Фабрика = Поделка.НайтиЖелудь("ФабрикаЗадач");
Генератор = Поделка.НайтиЖелудь("ГенераторПайплайнаГитлаб");
Сборка = Фабрика.Новая();
Сборка.Наименование = "build";
Сборка.Стадия = "build";
Сборка.Образ.Имя = "alpine:3.19";
Сборка.Скрипты.Добавить("make build");
Тесты = Фабрика.Новая();
Тесты.Наименование = "test";
Тесты.Стадия = "test";
Тесты.Нуждается.Добавить("build");
Тесты.Скрипты.Добавить("make test");
Генератор.СформироватьПайплайн(".gitlab-ci.yml");Запустите:
oscript build.osПолучите .gitlab-ci.yml — закоммитьте его в репозиторий.
Важные правила
- Задачи создавайте только через
Фабрика.Новая()— прямойНовый ОписаниеЗадачи()уходит мимо DI и реестра задач. - Пустые поля не выводятся — если поле/список не заполнены, ключ не попадёт в YAML. Чистый вывод без мусора.
- Валидация на генерации — ошибка в
needs, недопустимое условиеretry, отсутствие тега у релиза и т.п. роняют генерацию с понятным текстом до записи файла.
Повторное использование конфигурации
Общая настройка джоб выносится в обычную процедуру OneScript:
Процедура НастроитьDeployДжобу(Задача)
Задача.Стадия = "deploy";
Задача.Образ.Имя = "alpine:3.19";
Задача.Окружение.Имя = "production";
Задача.Кэш.ДобавитьПуть("vendor/");
КонецПроцедуры
ДеплойПрод = Фабрика.Новая();
ДеплойПрод.Наименование = "deploy-prod";
НастроитьDeployДжобу(ДеплойПрод);
ДеплойПрод.Скрипты.Добавить("make deploy-PROD");
ДеплойСтейдж = Фабрика.Новая();
ДеплойСтейдж.Наименование = "deploy-stage";
НастроитьDeployДжобу(ДеплойСтейдж);
ДеплойСтейдж.Окружение.Имя = "staging";
ДеплойСтейдж.Скрипты.Добавить("make deploy-STAGE");Это ключевая идея pipeliner: вместо YAML-шаблонов (extends) — обычные BSL-процедуры, с параметрами, условиями и автоподсказками.
Локальный запуск вне GitLab
Ссылки на переменные GitLab ($CI_COMMIT_TAG и т.п.) при локальной генерации работают: недостающие переменные возвращают своё имя ("$CI_COMMIT_TAG"), поэтому пайплайн генерируется без окружения CI.
Дальше
- Описание задачи — все поля и методы джобы
- Стадии и .pre/.post
- CLI
Описание задачи
ОписаниеЗадачи — центральная модель библиотеки. Создаётся только через фабрику:
Задача = Фабрика.Новая();Под-объекты (образ, кэш, артефакты, сервисы и т.д.) создаются лениво при первом обращении — отдельной инициализации не требуется.
Базовые поля
| Поле | Тип | Ключ YAML | Описание |
|---|---|---|---|
Наименование | Строка | имя джобы | Имя джобы в пайплайне |
Стадия | Строка | stage | Стадия выполнения |
Скрипты | Массив | script | Команды — добавляйте через Скрипты.Добавить("...") |
Когда | Строка | when | Условие запуска. Сахар: СобытияПайплайна.ПриУспехе(), .РучнойЗапуск(), .ПриНеудаче(), .Всегда() |
ТегиРаннера | Массив | tags | Теги раннера |
Таймаут | Строка | timeout | Например "2h", "30m" |
Прерываемый | Булево | interruptible | Отмена при новом пуше |
РазрешитьПадение | Булево | allow_failure | Не валить пайплайн при падении |
СтартоватьСразу | Булево | needs: [] | Немедленный старт, игнорируя стадии. Взаимоисключающее с Нуждается |
ГруппаРесурсов | Строка | resource_group | Сериализация запусков (deploy-джобы не должны бежать параллельно) |
Пример
Задача.Наименование = "deploy-prod";
Задача.Стадия = "deploy";
Задача.Таймаут = "2h";
Задача.Прерываемый = Истина;
Задача.ГруппаРесурсов = "production";
Задача.Скрипты.Добавить("make deploy");Нуждается (needs)
Массив имён джоб, от которых зависит запуск (DAG). Валидируется при генерации: ссылка на несуществующую джобу роняет генерацию с перечнем доступных.
Задача.Нуждается.Добавить("build");
Задача.Нуждается.Добавить("test");Зависимости (dependencies)
Какие артефакты тащить из предыдущих стадий. Валидации нет (это отдельный механизм GitLab).
Задача.Зависимости.Добавить("build");Образ (image)
Задача.Образ.Имя = "docker:latest";
Задача.Образ.УказатьПолитику("always"); // с валидацией
// или сахар:
Задача.Образ.Всегда();
Задача.Образ.Никогда();
Задача.Образ.ЕслиОтсутствует();
Задача.Образ.Принудительно(); // pull, GitLab/раннер >= 15.1
Задача.Образ.ДобавитьКомандуЭнтрипоинт("/bin/sh");Сервисы (services)
Массив сервис-контейнеров, фабрика НовыйСервис():
База = Задача.НовыйСервис();
База.Имя = "postgres:14";
База.Алиас = "db";
База.ДобавитьПеременную("POSTGRES_PASSWORD", "secret");Кэш (cache)
Задача.Кэш.ДобавитьПуть("vendor/");
Задача.Кэш.КлючПоФайлам.Добавить("packagedef");Артефакты (artifacts)
Задача.Артефакты.ДобавитьПуть("dist/");
Задача.Артефакты.ДобавитьИсключение("dist/*.tmp");
Задача.Артефакты.ВремяХранения = "1 week";Отчёты (reports)
Виды отчётов — через модуль ВидыОтчетов с валидацией:
Задача.Артефакты.ДобавитьОтчет(ВидыОтчетов.Юнит(), "junit.xml");
Задача.Артефакты.ДобавитьОтчет(ВидыОтчетов.САСТ(), "gl-sast-report.json");
Задача.Артефакты.ДобавитьОтчетПокрытия(ВидыОтчетов.Кобертура(), "coverage.xml");Допустимые виды: Юнит, САСТ, ДАСТ, Дотенв, СканированиеЗависимостей, ПоискСекретов, КачествоКода, СканированиеКонтейнеров, САРИФ, ЦиклонДХ, Терраформ и другие — полный список в модуле ВидыОтчетов.os.
Повтор (retry)
Задача.Повтор.Повторы = 2;
Задача.Повтор.ДобавитьУсловие(УсловияПовтора.СбойСкрипта());
Задача.Повтор.ДобавитьУсловие(УсловияПовтора.СбойРаннера());
Задача.Повтор.ДобавитьКодВыхода(42);Условия валидируются против набора GitLab (22 значения, см. УсловияПовтора.os). При нескольких условиях выводится массив, при одном — строка. Дубли сворачиваются.
Параллельность (parallel)
// Число копий
Задача.Параллельность.Количество = 5;
// Матрица: декартово произведение в одном ряду
Ряд = Новый Соответствие();
Ряд.Вставить("OS", ОС);
Ряд.Вставить("VERSION", Версии);
Задача.Параллельность.ДобавитьРяд(Ряд);
// Или независимые ряды
Задача.Параллельность.ДобавитьРядМатрицы("OS", ОС);Число и матрица взаимоисключающие — одновременное задание роняет генерацию.
Окружение (environment)
Деплой.Окружение.Имя = "production";
Деплой.Окружение.УРЛ = "https://prod.example.com";
Деплой.Окружение.ПриОстановке = "stop-prod";
Деплой.Окружение.АвтоОстановка = "1 week";
// Стоп-джоба:
СтопДжоба.Окружение.Действие = ДействияОкружения.Остановка();Валидации: недопустимое действие, пустое имя при заполненных остальных, ПриОстановке на несуществующую джобу.
Релиз (release)
Задача.Релиз.Тег = "$CI_COMMIT_TAG";
Задача.Релиз.Описание = "Что нового";
Задача.Релиз.Имя = "Версия 1.2.3";
Задача.Релиз.ДобавитьВеху("Milestone 1");
Задача.Релиз.ДобавитьСсылку("Установщик", "https://example.com/setup.exe");Тег и описание обязательны — без них генерация падает с именем задачи.
GitLab Pages
// Джоба с именем "pages", стадия deploy
Страницы.Наименование = "pages";
Страницы.Стадия = "deploy";
Страницы.Страницы.Публиковать("dist");publish автоматически добавляется в artifacts:paths (GitLab 17.10+). Валидации: pages без артефактов и не в стадии deploy роняют генерацию.
Переменные джобы
Задача.ДобавитьПеременную("BUILD_TYPE", "release");Описание пайплайна
ОписаниеПайплайна — топ-левел настройки всего пайплайна. Доступ через желудь:
ОписаниеПайплайна = Поделка.НайтиЖелудь("ОписаниеПайплайна");Глобальные переменные
ОписаниеПайплайна.ДобавитьПеременную("REGISTRY", "registry.example.com");
ОписаниеПайплайна.ДобавитьПеременную("DEPLOY_ENV", "staging");Выводится в корень YAML:
variables:
REGISTRY: registry.example.com
DEPLOY_ENV: stagingCoverage
Регекс извлечения процента покрытия из лога джобы:
ОписаниеПайплайна.ШаблонПокрытия = "/^Total.*?(\d+\s*)$/";Экранирование бэкслешей выполняется автоматически при сериализации.
Before/After script по умолчанию
ОписаниеПайплайна.ДобавитьПередСкрипт("echo start");
ОписаниеПайплайна.ДобавитьПослеСкрипт("echo done");Выводится в блок default: и применяется ко всем джобам без собственного before/after.
Порядок топ-левел ключей
Генератор выводит секции в фиксированном порядке:
default -> stages -> variables -> coverage -> (джобы)Стадии
Массив stages генератор собирает автоматически из стадий задач (порядок появления). Зарезервированные стадии .pre/.post в список не попадают — подробнее в разделе Стадии.
Стадии
Массив stages генератор собирает автоматически: берёт все стадии из задач в порядке появления, без дублей. Явно объявлять стадии не нужно.
Сборка = Фабрика.Новая();
Сборка.Стадия = "build";
Тесты = Фабрика.Новая();
Тесты.Стадия = "test";
// stages будет [build, test]Зарезервированные стадии .pre и .post
GitLab имеет две особые стадии, которые выполняются до всех пользовательских (.pre) и после всех (.post). Их не объявляют в stages — GitLab знает их сам.
Pipeliner это учитывает: стадии .pre/.post не попадают в сгенерированный stages, но джобы с ними выводятся как обычные.
Сахар
Вместо строковых литералов используйте методы задачи:
Линт = Фабрика.Новая();
Линт.Наименование = "lint";
Линт.ДоВсех(); // stage: .pre
Линт.Скрипты.Добавить("lint.sh");
Уведомление = Фабрика.Новая();
Уведомление.Наименование = "notify";
Уведомление.ПослеВсех(); // stage: .post
Уведомление.Скрипты.Добавить("notify.sh");Прямое присваивание тоже работает и фильтруется так же:
Задача.Стадия = ".pre";Реестр зарезервированных стадий
Источник имён — Гитлаб.ЗарезервированныеСтадии(), соответствие ключ → значение:
Реестр = Гитлаб.ЗарезервированныеСтадии();
// ДоВсех -> ".pre"
// ПослеВсех -> ".post"Если GitLab добавит новую зарезервированную стадию — она дописывается в реестр, фильтр генератора подхватит её автоматически.
Ограничение GitLab
Пайплайн, состоящий только из .pre/.post джоб, не запускается — нужна минимум одна джоба в обычной стадии.
Связка с needs
Джобы в .pre и джобы с needs: [] стартуют немедленно при создании пайплайна — используйте это для быстрых проверок (линт, smoke-тесты), которые не должны ждать сборки.
CLI
Pipeliner устанавливается как консольная утилита pipeliner (см. packagedef → ИсполняемыйФайл).
Команда gitlab
Генерация пайплайна для GitLab:
pipeliner gitlab <путь_к_файлу>Пример:
pipeliner gitlab .gitlab-ci.ymlКоманда загружает стадии из каталога ./pipeline (все *.os файлы, включая вложенные), выполняет их и пишет накопленный пайплайн в указанный файл.
Структура каталога pipeline
Каждый *.os-файл в каталоге pipeline — это стадия пайплайна. Файлы загружаются автоматически:
проект/
├── pipeline/
│ ├── build.os
│ ├── test.os
│ └── deploy.osПример содержимого pipeline/build.os:
#Использовать pipeliner
#Использовать autumn
#Использовать oscript-yaml
Поделка = Новый Поделка();
Поделка.ЗапуститьПриложение();
Фабрика = Поделка.НайтиЖелудь("ФабрикаЗадач");
Сборка = Фабрика.Новая();
Сборка.Наименование = "build";
Сборка.Стадия = "build";
Сборка.Скрипты.Добавить("make build");Фабрика накапливает задачи из всех загруженных файлов, генератор собирает их в один YAML.
Docker
Библиотеку можно запускать в контейнере — Dockerfile.local собирает образ из исходников:
docker build -f Dockerfile.local -t pipeliner:local .
docker run --rm -v $(pwd):/app pipeliner:local gitlab /app/.gitlab-ci.ymlОбраз базируется на sleemp/oscript:2.1.0, пакет собирается и устанавливается при сборке образа.
Каталог .dockerignore
В репозитории есть .dockerignore, исключающий .git и *.ospx из контекста сборки — без него собранный пакет из рабочего каталога ломает повторную сборку образа.
