feat: универсальный GitLab webhook endpoint с фильтрами, шаблонами и роутингом по чатам#19
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- config: register server.gitlab in knownKeys so config validate no longer emits a spurious unknown-key warning and validates keys inside the block - server: reject empty X-Gitlab-Token outright (defense-in-depth for direct WithGitlab construction with an empty SecretToken) - server: collapse duplicated open/merge branches in classifyGitlab - serve: drop redundant gitlab endpoint-enabled log (server.New already logs it) - docs/commands.md: document /gitlab endpoint, X-Gitlab-Token auth exception, and gitlab cross-reference validation - tests: cover 502 send failure, MR comment without nested merge_request, author username fallback, global-default/single-chat/query chat resolution; render the default template in buildGitlabConfig test instead of asserting on an internal field; assert no spurious unknown-key warning for server.gitlab Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Task 1: заменён типизированный GitlabWebhook на generic map[string]any decode;
новый gitlabView{Kind,Action,EventKey,Project,User,Title,URL,Raw}; deriveEventKey
по правилам object_kind, normalizeGitlab best-effort, template-helper get/.Get;
generic default-шаблон; хендлер и тесты переписаны под новую модель.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Обновлён /gitlab под generic-модель: любой object_kind, event-ключ kind/kind.subtype, фильтры only/exclude, реестр шаблонов, error_events. - openapi.yaml: описание /gitlab, generic GitlabWebhook, GitlabIgnoredResponse, 200 sent/ignored oneOf - docs/integrations.md: деривация субтипов, фильтры, шаблоны+переменные+хелперы, error_events - docs/configuration.md: таблица полей server.gitlab (events/templates/ template_files/error_events) - README: краткое упоминание универсального приёмника - examples/gitlab: конфиг с фильтрами/шаблонами + payload pipeline/push/issue Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…я gitlab-хендлера Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- selectTemplate: match kind.* wildcard template keys at runtime, so validated/documented wildcard keys actually take effect (previously dead) - untrack express-botx.yaml (default auto-loaded config that leaked a live BotX token) and gitignore it; token must be rotated separately - remove committed docs/.DS_Store; gitignore .DS_Store - docs/commands.md: /gitlab is universal (any event), not MR-only - tests: kind.* wildcard selection, runtime template-execution 400 path, gitlabIsEmpty non-string branch, secret-resolve-error startup guard; drop weak duplicate of the endpoint-not-registered test Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Guard against posting a blank message: a payload without object_kind renders the generic default to an empty string; treat it as ignored instead of delivering an empty notification. - deriveEventKey: fall back to a flat top-level status (e.g. deployment hooks have no object_attributes), so deployment.success/failed can be targeted by only/exclude/error_events like build_status. - examples/gitlab/config.yaml: add build.failed to only so the build.failed error_events entry is actually reachable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- openapi.yaml: GitlabFanoutResponse schema, routes in /gitlab description, oneOf results/errors on 200/502, updated chat-resolution priority - docs/integrations.md: "Роутинг событий по чатам" section (all-match+stop, selectors, branch normalization, glob vs /regex/, fan-out codes) - docs/configuration.md: routes in example + fields table + chat priority - examples/gitlab/config-routing.yaml: multi-rule fan-out + stop example (passes `config validate`); README entry Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- gitlab routing: match reserved 'project' selector against project.path_with_namespace (fallback project.name) per the design spec, so namespaced globs like 'group/backend/*' route correctly against real GitLab payloads; keep template .Project as the short name for display - add gitlabProject helper decoupling routing (namespace) from display (name) - tests: cover config->Routes wiring in buildGitlabConfig, namespaced-project routing end-to-end through normalizeGitlab, and error_events status on the fan-out path; update unit-test views to carry project in Raw - docs/examples: correct project-selector precedence, add path_with_namespace to sample payloads, align config-routing example, document kind/kind.* template catch-all ambiguity, broaden GitlabIgnoredResponse description Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a "build" (job hook) case to gitlabBranch so branch selectors match failed jobs on protected branches. GitLab job hooks carry the branch in a top-level ref field, which was previously ignored, causing build.failed events to resolve to an empty branch and silently miss the branch-filtered route in the shipped example (routing failures to default_chat_id instead of oncall). Align the doc comment and integrations.md normalization table, and add gitlabBranch test coverage for build. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- gitlab routing: preserve namespace of bare slashed branch on build/job events (was reduced to basename, breaking feature/* rules) - design spec: correct non-working object_attributes.labels example
Keep spec files locally as working artifacts; they should not ship in the repo. docs/superpowers/ now gitignored alongside docs/plans/. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
lavr
added a commit
that referenced
this pull request
Jul 8, 2026
Универсальный приём событий (only/exclude, шаблоны, error_events) и роутинг по чатам с фан-аутом.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Новый эндпоинт
POST /api/v1/gitlab, принимающий group/project webhooks GitLab ирассылающий сообщения в чаты eXpress. Две связанные части:
1. Универсальный приёмник событий
kind/kind.subtype) инормализация полей (project, user, title, url, branch).
events.only/events.excludeс wildcard(
kind,kind.subtype,kind.*).event → templateсо встроенными дефолтами и генерик-fallback;любой ключ переопределяется в конфиге (inline или
template_files).error_events→ сообщения уходят сstatus=error(BotX notification.status).X-Gitlab-Token(subtle.ConstantTimeCompare), т.к. GitLabне умеет
Authorization/X-API-Key.2. Роутинг событий по чатам (
server.gitlab.routes)объединяются + дедуплицируются), флаг
stopобрывает перебор.reserved-ключи
kind/event/action/project/branch/user/title/url+ произвольныепути в Raw.
/regex/для регэкспа (RE2, компиляция на старте);event— через тот же матчер, чтоonly/exclude.?chat_id→ routes →default_chat_id→ global default →единственный чат → 200 ignored.
200с по-чатовымиresults/errorsесли доставлено ≥1;502если упали все (GitLab ретрайнет без дублей в успешных чатах).Секции
server.gitlab.*полностью опциональны; без них поведение не меняется.Docs & examples
docs/integrations.md,docs/configuration.md,README.md, OpenAPI (/gitlab).examples/gitlab/— конфиги (базовый + с роутингом) и примеры payload (MR, note,push, pipeline, issue).
Tests
go build ./...— OKgo test ./...— все пакеты зелёныеmain— преэкзистинг репозитория)🤖 Generated with Claude Code