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 активируются при наличии соответствующей секции в extensions:. Удаление секции отключает плагин:

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

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

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

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

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

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

yaml
extensions:
  cost:
    providers:
      aws:
        enabled: true

  policy:
    enabled: true
    sources:
      - type: path
        path: policies

  tfupdate:
    enabled: true
    policy:
      bump: minor

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

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

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

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

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

Плагины реализуют один или несколько интерфейсов-возможностей. Registry lifecycle facades владеют discovery; авторы плагинов только реализуют контракты интерфейсов:

ВозможностьНазначениеПлагины
CommandProviderCLI-субкоманды (terraci cost, terraci local-exec и т.д.)cost, policy, summary, tfupdate, localexec
PipelineContributorДобавление шагов/джобов в pipeline IRcost, policy, summary, tfupdate
InitContributorПоля формы для terraci initgitlab, github, cost, policy, summary, tfupdate
PipelineGeneratorFactoryСоздание provider-specific генератора из immutable pipeline IR (NewGenerator(*pipeline.IR))gitlab, github
CommentServiceFactoryСоздание сервиса MR/PR комментариевgitlab, github
EnvDetectorОпределение CI-окружения по переменным средыgitlab, github
CIInfoProviderИмя провайдера, ID пайплайна, SHA коммитаgitlab, github
ChangeDetectionProviderSDK-возможность, встраивающая plugin-agnostic workflow.ChangeDetector для VCS diffgit
PreflightableДешёвая валидация при стартеgitlab, github, git, cost, policy, tfupdate
VersionProviderИнформация о версии для terraci versionpolicy
KVCacheProviderKV-кэш бэкенд по имениinmemcache
BlobStoreProviderБэкенд blob/object store (NewBlobStore(ctx, appCtx, opts))diskblob

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

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

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

1. Register    -- init() регистрирует плагин через registry.RegisterFactory()
2. Configure   -- фреймворк декодирует секцию extensions.<key> из YAML
3. Preflight   -- дешёвая валидация (определение окружения, проверка конфига)
4. Bind        -- runflow строит immutable Prepared/AppContext state
5. Execute     -- команды лениво создают plugin-local typed рантаймы по необходимости

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

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

Сборка через 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.RegisterFactory():

go
package myplugin

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

func init() {
    registry.RegisterFactory(func() plugin.Plugin {
        return &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"`
}

func (c *Config) Clone() *Config {
    if c == nil {
        return nil
    }
    out := *c
    return &out
}

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

go
// CommandProvider -- добавляет команду `terraci myplugin`
func (p *Plugin) Commands() []*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.goPlugin-local builder для ленивого тяжёлого state
usecases.goОркестрация команд над типизированным рантаймом
pipeline.goPipelineContributor — шаги/джобы
init_wizard.goInitContributor — поля формы
output.goХелперы рендеринга CLI
report.goСборка CI-отчётов

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

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

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

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

Released under the MIT License.