Webhook endpoint at /api/webhooks/gitea receives Gitea status events,
matches them against configurable event triggers with conditions
(event type, repo glob, state, context), renders task templates with
{{variable}} substitution, and creates harness tasks automatically.
Includes circuit breaker: after N consecutive task failures from the
same trigger (default 3), the trigger auto-disables. Re-enable
manually via PATCH /api/event-triggers/:id.
New tables: harness_event_triggers (rules + circuit breaker state),
harness_event_log (audit trail + dedup via X-Gitea-Delivery).
35 lines
1.1 KiB
TypeScript
35 lines
1.1 KiB
TypeScript
// Match webhook events against event trigger conditions.
|
|
|
|
import { getEnabledEventTriggers, type EventTrigger } from "./event-store";
|
|
import { type ParsedEvent } from "./template";
|
|
|
|
function escapeRegex(s: string): string {
|
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
}
|
|
|
|
function globMatch(pattern: string, value: string): boolean {
|
|
const regex = new RegExp(
|
|
"^" + pattern.split("*").map(escapeRegex).join(".*") + "$",
|
|
);
|
|
return regex.test(value);
|
|
}
|
|
|
|
export function matchesTrigger(trigger: EventTrigger, event: ParsedEvent): boolean {
|
|
if (!trigger.enabled) return false;
|
|
|
|
if (trigger.eventType !== "*" && trigger.eventType !== event.eventType) return false;
|
|
|
|
if (trigger.repoFilter && !globMatch(trigger.repoFilter, event.repo)) return false;
|
|
|
|
if (trigger.stateFilter && trigger.stateFilter !== event.state) return false;
|
|
|
|
if (trigger.contextFilter && !event.context.includes(trigger.contextFilter)) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
export async function findMatchingTriggers(event: ParsedEvent): Promise<EventTrigger[]> {
|
|
const triggers = await getEnabledEventTriggers();
|
|
return triggers.filter(t => matchesTrigger(t, event));
|
|
}
|