Schedule icon
Webhook icon
Request icon
Script icon
Process icon
If icon
Create icon
SlackIncomingWebhook icon
Log icon

Detect Newly Flaky Buildkite Test Steps and Ratchet Them Open as Issues

Detect Buildkite steps that swing pass to fail, then ratchet newly flaky tests open as a GitHub issue with a Slack quarantine suggestion.

Categories
CoreInfrastructure

Flaky tests are expensive because they hide real regressions behind noise, and most teams only notice them when a release slips. This blueprint turns flake detection into a ratchet: it reads the recent Buildkite run set, compares it with the previous one, and escalates only when a step is newly flaky or when its failed share got worse. Every step it raises lands as a GitHub issue with the numbers attached and a Slack suggestion for what to quarantine, while a clean comparison quietly records itself.

How it works

  1. The daily_ratchet trigger (io.kestra.plugin.core.trigger.Schedule) runs the check every day at 06:00 and ships disabled: true, and on_build_finished (io.kestra.plugin.core.trigger.Webhook) fires the same check the moment Buildkite posts a build finished event.
  2. fetch_builds (io.kestra.plugin.core.http.Request) GETs the last 40 builds of organization and pipeline from the Buildkite REST API with the BUILDKITE_TOKEN secret sent as a Bearer header.
  3. fetch_test_analytics GETs the Test Engine records for the newest build, marked allowFailure so a pipeline without Test Engine still gets the step level check.
  4. analyze_flakes (io.kestra.plugin.scripts.python.Script) reads the two JSON inputs, keeps only builds that ended passed or failed, and splits them into a recent window of 10 builds and the previous window of 10.
  5. It computes a per-step failed share in each window, takes the steps that pass and fail inside the recent window but were clean before them, and emits verdict, newly_flaky, worst_rate, and new_flake_count through the ::json:: outputs protocol.
  6. ratchet_gate (io.kestra.plugin.core.flow.If) branches when the new flake count is over zero or the worst failed share got worse, opening open_ratchet_issue (io.kestra.plugin.github.issues.Create) and posting quarantine_hint (io.kestra.plugin.slack.notifications.SlackIncomingWebhook) on that path, while the clean path only logs with log_stable.
  7. The errors handler alerts Slack when the API call or the analysis fails, so a broken ratchet is never mistaken for a healthy pipeline.

What you get

  • A ratchet instead of a dashboard, meaning the same old flake stops producing noise while anything that changes is escalated.
  • A GitHub issue that lists the newly flaky steps, their failed shares in both windows, and the builds behind them.
  • A quarantine suggestion drawn from Buildkite Test Engine labels and from tests that both passed and failed in the window.
  • Typed flow outputs (verdict, newly_flaky, worst_rate, new_flake_count) that a parent release flow can branch on.
  • Dated execution history in Kestra for every comparison, including the runs that found nothing new.

Who it's for

  • CI owners who want flaky steps quarantined before they consume another release slot.
  • Test engineers who care about which step changed this week rather than which steps are always noisy.
  • Platform teams that already run Buildkite and GitHub and want the comparison in one file they can review.
  • Release managers who need a searchable record of every quarantine decision and the data behind it.

Why orchestrate this with Kestra

Buildkite tells you that a build failed, but it does not remember which steps were clean last week or who should decide what gets quarantined. Kestra holds the comparison window, the branch, the issue creation, and the Slack ping in one declarative file, with an execution record for each decision. A cron script can do the arithmetic, yet it cannot open the issue, notify the right channel, and prove what the verdict was last Tuesday from the same artifact. Putting the ratchet in the orchestrator also means retries, failure alerting, and a place to hang approvals when your team wants a human in the loop.

Prerequisites

  • A Buildkite organization with an API token that can read builds, and pipelines that publish terminal step states for their jobs.
  • Buildkite Test Engine enabled if you want quarantine candidates, otherwise the analytics call degrades to a warning and the step check still runs.
  • A GitHub repository where this flow may open issues, using a classic token with repo scope or a fine-grained token with Issues write access.
  • Python 3 available on the Kestra worker for the analysis task, or switch its task runner to a container image.

Secrets

  • BUILDKITE_TOKEN: Buildkite API token used as the Bearer credential for the builds and test analytics calls.
  • BUILDKITE_WEBHOOK_KEY: key segment guarding the webhook URL, so only Buildkite can start a ratchet run.
  • GITHUB_TOKEN: token passed to jwtToken by the issue task when the ratchet opens.
  • SLACK_WEBHOOK_URL: Slack incoming webhook used for quarantine suggestions and failure alerts.

Quick start

  1. Add the four secrets above to the company.team namespace in Kestra.
  2. Set the organization, pipeline, and github_repository inputs to your real slugs.
  3. Copy the trigger block below and flip disabled to false when you are ready for the daily run:
triggers:
  - id: daily_ratchet
    type: io.kestra.plugin.core.trigger.Schedule
    cron: "0 6 * * *"
    disabled: false
  - id: on_build_finished
    type: io.kestra.plugin.core.trigger.Webhook
    key: "{{ secret('BUILDKITE_WEBHOOK_KEY') }}"
  1. Point the Buildkite build finished hook at /api/v1/{tenant}/executions/webhook/{namespace}/buildkite-flaky-test-ratchet/{BUILDKITE_WEBHOOK_KEY}, or POST to that keyed URL after any build to try it by hand.
  2. Run the flow once manually and read the verdict output, then check GitHub and Slack when a step flips between pass and fail.

How to extend

  • Watch several pipelines by copying the flow and overriding organization and pipeline per copy.
  • Fail the execution with io.kestra.plugin.core.execution.Fail on the ratchet branch when you want the check to block a merge instead of only filing an issue.
  • Record each verdict with io.kestra.plugin.core.kv.Set to chart flake rate trends across months rather than one window at a time.
  • Replace the GitHub issue with a Jira ticket through io.kestra.plugin.jira.issues.Create, keeping the same step list and rates.
  • Raise WINDOW inside the analysis script when your pipeline runs more than ten times a day, so the comparison covers a longer memory.
  • Feed the gate from vars instead of inputs so every copy in a namespace shares one repository target and one threshold.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.