Skip to content

Система плагинов

TerraCi использует систему плагинов на этапе компиляции по аналогии с database/sql в Go. Плагины регистрируются через init() и blank-импорты при сборке.

Встроенные плагины

ПлагинНазначениеНужна конфигурация
gitОпределение изменённых модулей через git diffНет
gitlabГенерация GitLab CI пайплайнов и MR-комментарииДа (наличие секции активирует)
githubГенерация GitHub Actions воркфлоу и PR-комментарииДа (наличие секции активирует)
summaryПубликация сводных комментариев в MR/PRНет (включён по умолчанию)
costОценка стоимости облачных ресурсов (AWS)Да (providers.aws.enabled: true)
policyПроверка политик через встроенный OPAДа (enabled: true)
tfupdateРазрешение зависимостей Terraform и синхронизация lock-файловДа (enabled: true)

Политики активации

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

Всегда активен

Плагин git не требует конфигурации. Он обеспечивает определение изменённых модулей для режима --changed-only и доступен всегда.

Активируется при наличии конфига

Плагины gitlab и github активируются при наличии соответствующей секции в plugins:. Удаление секции отключает плагин:

yaml
plugins:
  gitlab:      # наличие этой секции включает плагин
    image: { name: hashicorp/terraform:1.6 }

Активен по умолчанию

Плагин summary включён по умолчанию. Он публикует сводку планов в MR/PR. Можно отключить явно:

yaml
plugins:
  summary:
    enabled: false   # отключить

Требует явного включения

Плагины cost, policy и tfupdate требуют явной активации:

yaml
plugins:
  cost:
    providers:
      aws:
        enabled: true

  policy:
    enabled: true
    sources:
      - path: policies

  tfupdate:
    enabled: true
    policy:
      bump: minor

Определение CI-провайдера

TerraCi автоматически определяет активный CI-провайдер:

  1. Переменные окружения -- GITLAB_CI=true выбирает GitLab, GITHUB_ACTIONS=true выбирает GitHub
  2. TERRACI_PROVIDER -- явное указание:
    bash
    TERRACI_PROVIDER=gitlab terraci generate -o pipeline.yml
  3. Единственный сконфигурированный провайдер -- если настроен только один CI-провайдер, он используется автоматически

Если настроено несколько провайдеров и окружение не определено, TerraCi возвращает ошибку с рекомендацией задать TERRACI_PROVIDER.

Возможности плагинов

Плагины реализуют один или несколько интерфейсов-возможностей. Фреймворк обнаруживает их через type assertion:

ВозможностьНазначениеПлагины
CommandProviderCLI-субкоманды (terraci cost и т.д.)cost, policy, summary, tfupdate
PipelineContributorДобавление шагов/джобов в pipeline IRcost, policy, summary
InitContributorПоля формы для terraci initgitlab, github, cost, policy, summary, tfupdate
GeneratorFactoryСоздание генератора пайплайна для CI-провайдераgitlab, github
CommentFactoryСоздание сервиса MR/PR комментариевgitlab, github
EnvDetectorОпределение CI-окружения по переменным средыgitlab, github
ChangeDetectionProviderОпределение изменённых модулей через VCSgit
RuntimeProviderЛенивая инициализация тяжёлых зависимостейcost, policy, tfupdate
PreflightableДешёвая валидация при стартеgitlab, github, git, cost, policy, tfupdate
VersionProviderИнформация о версии для terraci versionpolicy

Один плагин может реализовывать несколько возможностей. Например, cost реализует CommandProvider (команда terraci cost), PipelineContributor (шаг оценки стоимости в пайплайне), InitContributor (переключатель в мастере init), RuntimeProvider (ленивая инициализация estimator) и Preflightable (валидация конфига).

Жизненный цикл плагина

Каждый плагин проходит одинаковый жизненный цикл:

1. Register    -- init() регистрирует плагин через registry.Register()
2. Configure   -- фреймворк декодирует секцию plugins.<key> из YAML
3. Preflight   -- дешёвая валидация (определение окружения, проверка конфига)
4. Freeze      -- AppContext замораживается, мутации запрещены
5. Execute     -- команды лениво создают RuntimeProvider рантаймы по необходимости

Preflight выполняется для всех включённых плагинов до любой команды. Он должен быть быстрым и без побочных эффектов — никаких сетевых вызовов и тяжёлого state. Тяжёлая работа (API-клиенты, кеши, estimators) принадлежит RuntimeProvider, который создаёт рантайм лениво, когда команда реально его требует.

Кастомные плагины

Сборка через xterraci

xterraci создаёт кастомный бинарник TerraCi с дополнительными или исключёнными плагинами:

bash
# Добавить внешний плагин
xterraci build --with github.com/your-org/terraci-plugin-slack

# Закрепить конкретную версию
xterraci build --with github.com/your-org/terraci-plugin-slack@v1.2.0

# Использовать локальный плагин во время разработки
xterraci build --with github.com/your-org/plugin=../my-plugin

# Убрать ненужные встроенные плагины
xterraci build --without cost --without policy

# Комбинировать
xterraci build \
  --with github.com/your-org/terraci-plugin-slack \
  --without cost \
  --output ./build/terraci-custom

Как это работает

xterraci build:

  1. Создаёт временный Go-модуль
  2. Генерирует main.go с blank-импортами выбранных плагинов
  3. Выполняет go get для каждого внешнего плагина
  4. Собирает бинарник через go build

Результат идентичен стандартному terraci, но с другим набором скомпилированных плагинов.

Список встроенных плагинов

bash
xterraci list-plugins

Написание плагина

Минимальный внешний плагин:

1. Регистрация -- функция init(), вызывающая registry.Register():

go
package myplugin

import (
    "github.com/edelwud/terraci/pkg/plugin"
    "github.com/edelwud/terraci/pkg/plugin/registry"
)

func init() {
    registry.Register(&Plugin{
        BasePlugin: plugin.BasePlugin[*Config]{
            PluginName: "myplugin",
            PluginDesc: "My custom plugin",
            EnableMode: plugin.EnabledExplicitly,
            DefaultCfg: func() *Config { return &Config{} },
            IsEnabledFn: func(cfg *Config) bool {
                return cfg != nil && cfg.Enabled
            },
        },
    })
}

type Plugin struct {
    plugin.BasePlugin[*Config]
}

type Config struct {
    Enabled bool   `yaml:"enabled"`
    APIKey  string `yaml:"api_key"`
}

2. Возможности -- реализуйте нужные интерфейсы:

go
// CommandProvider -- добавляет команду `terraci myplugin`
func (p *Plugin) Commands(ctx *plugin.AppContext) []*cobra.Command {
    return []*cobra.Command{{
        Use:   "myplugin",
        Short: "Run my custom plugin",
        RunE: func(cmd *cobra.Command, _ []string) error {
            // логика плагина
            return nil
        },
    }}
}

3. Go-модуль -- опубликуйте как Go-модуль с go.mod, зависящим от github.com/edelwud/terraci.

Конвенция файлов плагина

Для крупных плагинов используйте конвенцию «один файл на возможность»:

ФайлСодержимое
plugin.goinit(), struct плагина, BasePlugin embedding
lifecycle.goРеализация Preflightable
commands.goCommandProvider с cobra-командами
runtime.goRuntimeProvider для ленивого тяжёлого state
usecases.goОркестрация команд над типизированным рантаймом
pipeline.goPipelineContributor — шаги/джобы
init_wizard.goInitContributor — поля формы
output.goХелперы рендеринга CLI
report.goСборка CI-отчётов

Рабочий пример

Смотрите examples/external-plugin для полного рабочего примера плагина, добавляющего команду terraci hello.

Справочник конфигурации

ПлагинСтраница конфигурации
GitLab CIconfig/gitlab
GitLab MRconfig/gitlab-mr
GitHub Actionsconfig/github
Оценка стоимостиconfig/cost
Проверка политикconfig/policy
Обновление зависимостейconfig/tfupdate

Released under the MIT License.