/** * WGL019: Missing Retry on Deploy Jobs * * Deploy-stage jobs should have a `retry:` strategy to handle transient * infrastructure failures. This is informational, not a hard requirement. */ import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth"; import { isPropertyDeclarable } from "@intentius/chant/declarable"; const DEPLOY_STAGES = new Set(["deploy", "deployment", "release", "production", "staging"]); export const wgl019: PostSynthCheck = { id: "WGL019", description: "Missing retry — deploy jobs without retry strategy", check(ctx: PostSynthContext): PostSynthDiagnostic[] { const diagnostics: PostSynthDiagnostic[] = []; for (const [entityName, entity] of ctx.entities) { if (isPropertyDeclarable(entity)) continue; const entityType = (entity as unknown as Record).entityType as string; if (entityType !== "GitLab::CI::Job") continue; const props = (entity as unknown as Record).props as Record | undefined; if (!props) continue; const stage = props.stage as string | undefined; if (!stage || !DEPLOY_STAGES.has(stage.toLowerCase())) continue; // chant #1544 — `!props.retry` treated an explicit `retry: 0` the same // as no `retry` at all, warning on a job that stated its policy // ("retrying a deploy without a human is deliberate") as if it hadn't. // `retry: 0` is falsy but present — only an actually-absent key means // "no retry strategy". if (props.retry === undefined) { diagnostics.push({ checkId: "WGL019", severity: "info", message: `Deploy job "${entityName}" (stage: ${stage}) has no retry strategy — consider adding retry for transient failures`, entity: entityName, lexicon: "gitlab", }); } } return diagnostics; }, };