Deploy smoke
A custom DSL run that hits critical URLs after a successful deploy. The GitHub App webhook fires it directly — zero GHA minutes, no workflow file; an Action-mode `ci.yml` is included as the GHA-native alternative.
Source
This recipe ships both triggers — a typed Effect-TS run
(*.run.ts) and a GitHub Actions workflow
(ci.yml). Use whichever fits;
Webhook mode is the recommended default.
// Recipe: post-deploy smoke test
//
// Use case: after a deploy succeeds, hit the live URL and a few critical
// endpoints; fail a check-run on the deployed SHA if anything is down.
//
// The probe-and-classify loop is the `probeHttp` primitive, so this recipe
// is just trigger config + a one-line health check. See specs/03-dsl.md
// § Primitives.
//
// Mode: Webhook mode — fires on `deployment_status.success`, no GHA workflow
// file. Drop this file into your repo's `runs/` directory; the
// FlareDispatch GitHub App webhook does the rest. An Action-mode
// alternative (./ci.yml) dispatches the same run from a GitHub Actions
// workflow, for repos that cannot install the App.
// DSL: see specs/03-dsl.md.
import { Effect, Schema } from "effect";
import { defineRun, step, io } from "@flare-dispatch/core";
import { probeHttp } from "@flare-dispatch/core/primitives";
export const deploySmoke = defineRun({
name: "deploy-smoke",
version: "1.0.0",
// Webhook-mode trigger config — the receiver-side equivalent of a GHA
// `on:` filter. See specs/04-gha-integration.md#webhook-mode.
triggers: [
{
event: "deployment_status",
// only the success transition, only production, and only when GitHub
// actually gave us a URL to probe — `environment_url` is optional in
// the payload, and without it `baseURL` would be empty.
gate: ({ payload }) =>
payload.deployment_status.state === "success" &&
payload.deployment.environment === "production" &&
!!payload.deployment_status.environment_url,
// key on the deployment id, not the commit: the same SHA can be
// deployed many times (rollback-forward, redeploy) and each deploy
// must get its own smoke test rather than collapsing onto the first.
idempotencyKey: ({ payload }) =>
`deploy-smoke:${payload.repository.full_name}:${payload.deployment.id}`,
inputs: ({ payload }) => ({
repo: payload.repository.full_name,
sha: payload.deployment.sha,
baseURL: payload.deployment_status.environment_url,
paths: ["/", "/health", "/api/status"],
}),
},
],
inputs: Schema.Struct({
repo: Schema.String,
sha: Schema.String,
baseURL: Schema.String,
paths: Schema.Array(Schema.String),
}),
outputs: Schema.Struct({
checked: Schema.Number,
failed: Schema.Number,
}),
limits: { maxDurationSec: 300 },
run: (input) =>
Effect.gen(function* () {
// `probeHttp` hits every path in parallel and classifies each as
// healthy or failed (non-2xx/3xx, or a request that never completed —
// see the primitive's note on curl exit codes).
const probe = yield* step("probe", () =>
probeHttp({ baseURL: input.baseURL, paths: input.paths }),
);
yield* io.log(
probe.failed === 0 ? "info" : "error",
`deploy-smoke: ${probe.checked - probe.failed}/${probe.checked} endpoints healthy`,
);
// A non-zero `failed` count fails the check-run on the deployed SHA.
return { checked: probe.checked, failed: probe.failed };
}),
}); # Recipe: post-deploy smoke test — Action-mode alternative
#
# Use case: same `deploy-smoke` run as ./smoke.run.ts, but dispatched from a
# GitHub Actions workflow instead of the FlareDispatch GitHub App webhook.
#
# Webhook mode (the `triggers` block in ./smoke.run.ts) is preferred — it
# burns zero GHA minutes and needs no workflow file. Use this Action-mode
# file when you cannot install the App, or want the smoke test to interleave
# with other jobs on the deployment.
#
# Mode: Action mode, fire-and-forget. See specs/04-gha-integration.md.
# Run: deploy-smoke — defined in ./smoke.run.ts.
name: deploy-smoke
on:
deployment_status:
jobs:
deploy-smoke:
# GHA cannot filter `deployment_status` by state in `on:`, so gate the job
# here. This `if:` mirrors the webhook `gate` in ./smoke.run.ts — success
# transition, production only, environment_url present.
if: >-
github.event.deployment_status.state == 'success' &&
github.event.deployment.environment == 'production' &&
github.event.deployment_status.environment_url != ''
runs-on: ubuntu-latest
steps:
- uses: openhackersclub/flare-dispatch-action@v1
with:
run: deploy-smoke
endpoint: ${{ vars.FLAREDISPATCH_ENDPOINT }}
hmac-secret: ${{ secrets.FLAREDISPATCH_HMAC }}
inputs: |
{
"repo": "${{ github.repository }}",
"sha": "${{ github.event.deployment.sha }}",
"baseURL": "${{ github.event.deployment_status.environment_url }}",
"paths": ["/", "/health", "/api/status"]
}
# A non-zero `failed` count fails the check-run `flare-dispatch/deploy-smoke`
# on the deployed SHA — require it in branch protection, not this GHA job.