Для выполнения действия необходимы учётные данные:

  • password — пароль (токен) пользователя, от имени которого будет запускаться выполнение действия.
  • username — имя пользователя, от которого будет запускаться выполнение действия.

CreateRepositoryFromTemplate — создаёт новый репозиторий из шаблона в GitLab. Механизм рендеринга основан на Go template и поддерживает все встроенные методы, а также расширения, добавленные в платформу.

Пример запроса

sourceBranch: main
sourceTag: v1.0.0
templateRepositoryUrl: https://gitlab.example.com/example-1.git
targetRepositoryUrl: https://gitlab.example.com/example-2.git
targetBranch: master
additionalIgnoreFiles:
  - .ignore
  - .example
values:
  key1: value1
  nested:
    enabled: true
    subkey: 123

Спецификация запроса

НазваниеОбязательностьОписаниеЗначение по умолчанию
templateRepositoryUrlДаURL шаблонного репозитория-
targetRepositoryUrlДаURL репозитория, который будет создан в результате выполнения действия-
valuesДаПеременные, используемые при шаблонизации, в формате ключ: значение-
additionalIgnoreFilesНетСписок файлов, содержащих пути для исключения из целевого репозитория. Заполняется по аналогии с .templateignore-
sourceTagНетТег шаблонного репозитория, который будет использоваться при шаблонизации. Если не указан, используется ветка шаблонного репозитория-
sourceBranchНетВетка шаблонного репозитория, которая будет использоваться при шаблонизацииmain
targetBranchНетВетка целевого репозитория, которая будет создана в результате выполнения действияmain

Алгоритм работы

Платформа:

  1. Клонирует шаблонный репозиторий по указанному URL (templateRepositoryUrl), используя в качестве ref либо sourceTag, либо sourceBranch, либо ветку main.
  2. Считывает файл values.yaml, хранящийся в корне репозитория, и определяет переменные по умолчанию для шаблонизации.
  3. Считывает переменные, передаваемые при запуске действия, и объединяет (merge) их с переменными из values.yaml. Приоритет при merge отдаётся переменным, передаваемым при запуске действия.
  4. Считывает файл .templateignore и определяет директории и файлы, исключаемые из шаблонизации.
  5. Рендерит из шаблонов файлы, учитывая values.yaml и переданные в действие переменные.
  6. Изменяет удалённый (remote) репозиторий на целевой (targetRepositoryUrl) и делает git push в целевую ветку (targetBranch), либо в основную ветку main.

Детали работы

Действие поддерживает шаблонизацию имён директорий и файлов. Для этого необходимо в их название добавить выражение в формате Go template. Например, директория src/{{ .module }}/utils при наличии value module со значением example будет отрендерена в директорию src/example/utils в целевом репозитории.

Если после рендеринга из шаблона содержимое файла будет отсутствовать, файл не создаётся. Например, файл с содержимым:

{{- if .createContent }}
- Это контент, который будет отображаться, если переменная createContent == true
{{- end }}

не будет создан, если переменная createContent имеет значение false. Аналогичным образом, не будут созданы файлы, изначально являющиеся пустыми.

При отсутствии переменных для шаблонизации одновременно в файле values.yaml и в переменных, передаваемых при запуске действия, рендеринг завершится с ошибкой и целевой репозиторий создан не будет.

Переменные шаблонного репозитория

Для добавления переменных по умолчанию, используемых при шаблонизации, необходимо создать в корне репозитория файл values.yaml с соответствующим содержимым.

Пример файла values.yaml:

module: example
createContent: false

Файл values.yaml является опциональным.

Исключение файлов

Некоторые файлы могут содержать переменные в формате Go template, которые необходимо сохранять при рендеринге репозитория из шаблона, например, Helm-чарты в директории helm. Директория .git игнорируется всегда.

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

В каждой строке .templateignore задаётся одно правило — путь или маска. Если в строке есть {{, вся строка выполняется как один шаблон Go с теми же переменными и функциями, что при подстановке в имена файлов и каталогов (подробнее — «Как обрабатывается строка правила»). Если {{ в строке нет, подстановка переменных из values.yaml и из запроса действия не делается: строка читается как есть и сравнивается с относительным путём на диске, допускаются литералы и символы маски * и **.

Пример файла .templateignore только с масками пути, без шаблонов подстановки, для игнорирования содержимого директорий helm, docs:

helm/**
docs/**

Добавление путей в игнорирование

  1. В корне шаблонного репозитория создайте или отредактируйте файл .templateignore (по одному правилу на строку).
  2. Каждая строка — это одно правило: путь от корня репозитория. В нём допускаются обычные символы пути и маски: звёздочка * в имени сегмента, последовательность ** — для произвольной глубины вложенных каталогов. Платформа сопоставляет относительный путь с маской по встроенным правилам (аналогично распространённым соглашениям для масок в файлах игнорирования в системах контроля версий).
  3. Чтобы подставить фрагмент пути из values.yaml или из поля values запроса действия, используйте в строке конструкции Go template ({{ ... }}). Если в строке есть {{, платформа обрабатывает всю строку от начала до конца как один шаблон Go: нельзя оставить часть строки «простым текстом» и шаблонизировать только середину пути. Примеры — в разделе «Примеры Go template в .templateignore».
  4. Пустые строки и строки, начинающиеся с #, при разборе файла пропускаются — их можно использовать для комментариев.

Примеры без подстановки (только маски пути)

Отдельные файлы в корне:

package-lock.json
yarn.lock
LICENSE
.env.local

Каталоги целиком и типичные артефакты сборки:

vendor/**
node_modules/**
dist/**
build/tmp/**

Вложенность по маске:

docs/**/*.pdf
charts/*/values.schema.json
.github/workflows/**

Секреты по расширению во всём дереве:

**/*.pem
**/*.key

Обработка строки правила

Переменные для раскрытия правил те же, что объединены из values.yaml в корне шаблонного репозитория и из поля values в запросе действия (приоритет у values в запросе).

Для каждой непустой строки из .templateignore или из файла из additionalIgnoreFiles платформа делает следующее.

  1. В список правил всегда попадает строка как в файле, без изменений. Именно её потом сравнивают с путём к файлу в первую очередь — это нужно, когда в именах на диске ещё есть фрагменты вроде {{ .module }} до переименования.
  2. Если в строке есть {{, платформа один раз прогоняет всю строку через шаблонизатор Go template с теми же возможностями, что при подстановке в имена файлов и каталогов (встроенные функции платформы и набор Sprig). Если {{ в строке нет, этот шаг пропускают.
  3. Если шаг подстановки был и полученный текст отличается от строки в файле (включая случай «на выходе пусто»), в список правил добавляют вторую запись — уже с этим полученным текстом. Итого из одной строки файла может получиться две записи в списке. При проверке пути к файлу смотрят обе: достаточно совпадения с любой из них — файл попадает под правило.

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

Так одна строка в файле может задать два правила: например, исходное charts/{{ .name }}/** (чтобы не трогать путь до переименования каталогов), и раскрытое charts/billing/** (чтобы совпадало с путём после подстановки переменных в имена на диске). Поэтому правила работают и «до», и «после» этапа переименования каталогов по шаблону.

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

Поле additionalIgnoreFiles в действии задаёт имена дополнительных файлов в корне репозитория; в каждом из них — такие же строки-правила, как в .templateignore, с тем же раскрытием шаблонов. Но смысл другой: совпавшие пути убирают из рабочей копии (каталог или файл удаляют), и делают это дважды — в начале и в конце цепочки обработки, чтобы эти объекты не участвовали в дальнейших шагах и не попали в итоговый репозиторий.

Файл .templateignore, наоборот, означает «не шаблонизировать»: для совпавших путей платформа не подставляет переменные в содержимое файлов и не применяет к соответствующим каталогам переименование по шаблону в пути. Сами файлы и каталоги при этом не удаляются только из‑за записи в .templateignore — они остаются в копии, но обрабатываются как обычный текст и обычные имена, без шага шаблонизации.

Примеры Go template в .templateignore

Ниже в каждом примере показаны фрагменты values.yaml (или эквивалентные поля в values запроса) и строки .templateignore. Несколько независимых правил задают несколькими строками файла: результат одной строки-шаблона — одна строка с маской; перевод строк внутри результата шаблона не делит правило на несколько.

Имя каталога в правиле берётся из values.yaml или из values действия:

values.yaml:

project: payment-gateway

.templateignore:

{{ .project }}/legacy/**

В набор правил попадут строки {{ .project }}/legacy/** и payment-gateway/legacy/**.

Сегмент пути из переменной и фиксированная часть, которая сохраняется после подстановки значения переменной:

values.yaml:

lang: ru

.templateignore:

apps/{{ .lang }}/messages.yaml

Условное правило в одной строке работает следующим образом: при skipGenerated: false подстановка даёт пустую строку, которая всё равно добавляется вторым правилом. Исходная строка с {{ используется как маска пути и обычно не совпадает с реальными путями. При skipGenerated: true вторым правилом становится generated/**):

values.yaml:

skipGenerated: false

.templateignore:

{{- if .skipGenerated }}generated/**{{- end }}

Вариант «игнорировать только не production»:

values.yaml:

tier: staging

.templateignore:

{{- if ne .tier "prod" }}mock/**{{- end }}

Использование printf для сборки строки маски (удобно, если имя чарта в переменной):

values.yaml:

chartName: wordpress

.templateignore:

{{ printf "charts/%s/**" .chartName }}

Значение по умолчанию для «пустого» значения — функция default из набора Sprig. Поле в данных должно существовать (иначе при раскрытии сработает missingkey=error); для «не задано в YAML» заведите ключ с пустой строкой или используйте условие if / index:

values.yaml:

envName: ""

.templateignore:

{{ default "dev" .envName }}/secrets/**

При пустом envName в правило попадёт и {{ default "dev" .envName }}/secrets/**, и dev/secrets/**.

Опциональный сегмент пути (with):

values.yaml:

analyticsModule: tracking

.templateignore:

{{ with .analyticsModule }}{{ . }}/vendor/**{{ end }}

Если analyticsModule пусто, шаблон даёт пустую строку (правила раскрытия приведены выше).

Доступ к полю вложенной структуры по строковому ключу index:

values.yaml:

regions:
  primary: eu-west

.templateignore:

configs/{{ index .regions "primary" }}/bootstrap.yaml

Удаление пробелов в сегменте имени — функция trim из набора Sprig:

values.yaml:

serviceName: " billing-api "

.templateignore:

{{ trim .serviceName " " }}/logs/**

Несколько фрагментов в одной маске:

values.yaml:

base: services
variant: canary

.templateignore:

{{ .base }}/{{ .variant }}/**/*.tmp

Примеры для additionalIgnoreFiles

В спецификации действия перечисляются имена файлов в корне репозитория (например, .ship-ignore, .ci-remove). Формат строк внутри таких файлов тот же: комментарии #, пустые строки, маски пути, при необходимости — шаблоны Go в строках.

Файл .ship-ignore в шаблоне:

# не попадает в целевой репозиторий
local/fixtures/**
scratchpad.md

Фрагмент запроса действия:

additionalIgnoreFiles:
  - .ship-ignore

Шаблон в файле для additionalIgnoreFiles (удаление каталога, имя из переменных):

Файл .env-drop в корне шаблона:

{{ .obsoleteDir }}/**

При obsoleteDir: legacy-ui из values после раскрытия в списке удаления окажутся и {{ .obsoleteDir }}/**, и legacy-ui/** — совпавшие пути будут удалены из копии перед финальными шагами.

Учитывайте различия:

  • .templateignore оставляет файлы на диске, но отключает для них переименование пути и рендер содержимого;
  • списки из additionalIgnoreFiles удаляют совпавшие пути из рабочей копии.

Пример структуры директорий шаблонного репозитория

├── example-folder-01
│   ├── example-file-01
│   └── {{ .example }}-file-02
├── {{ .example }}-folder-02
│   └── ...
├── values.yaml
└── .templateignore

Если переменная example при рендере репозитория примет значение new, то итоговая структура после рендера будет выглядеть следующим образом:

├── example-folder-01
│   ├── example-file-01
│   └── new-file-02
├── new-folder-02
│   └── ...
├── values.yaml
└── .templateignore

Локальная отладка

Для локальной отладки шаблонов доступна утилита ddp-render-dir.

Утилита:

  1. Создаёт копию исходной директории.
  2. Выполняет рендеринг файлов в этой директории по тем же правилам, что и действие создания репозиториев из шаблонов.

Ключи командной строки для запуска:

  • --source-dir — исходная директория, которую необходимо отрендерить.
  • --target-dir — директория, в которую будет помещен результат рендеринга.
  • --values (опционально) — путь к файлу values.yaml с переменными, которые будут использоваться при рендеринге.
  • --ignore-files (опционально) — список файлов, содержащих пути для исключения из целевого репозитория.