Files
homelab/apps/harness/src/lib/event-matching.ts
Julia McGhee eeb87018d7
Some checks failed
Deploy Production / deploy (push) Failing after 35s
CI / lint-and-test (push) Successful in 33s
CI / build (push) Has been cancelled
Add event-driven tasks via Gitea webhooks
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).
2026-03-21 21:15:15 +00:00

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));
}