Webhook icon
Schedule icon
Script icon
Loop icon
Commands icon
Docker icon
If icon
SlackIncomingWebhook icon
Fail icon
Log icon

Run Only the Monorepo Tests Your Changed Paths Touch

Map changed monorepo paths to package test targets, run only the selected suites in a loop, and escalate changed paths no package covers.

Categories
Infrastructure

How it works

  1. on_push_changed_paths (io.kestra.plugin.core.trigger.Webhook, keyed with the MONOREPO_PUSH_WEBHOOK_KEY secret) receives the changed file list from the push hook or CI router. On manual runs the changed_files input stands in. nightly_path_rescan (io.kestra.plugin.core.trigger.Schedule, cron 0 3 * * *) is the safety net and ships disabled: true until an operator turns it on.
  2. select_test_targets (io.kestra.plugin.scripts.python.Script on python:3.12-slim) accepts either a JSON array body or a comma separated list, matches every path against an in-file PACKAGE_MAP using longest prefix rules so services/api/ never shadows a sibling package, deduplicates the matched packages, and keeps the leftovers as unmapped paths. The selected targets with their suite commands, the counts and the unmapped list are printed as a single ::{"outputs": ...}:: line.
  3. run_selected_suites (io.kestra.plugin.core.flow.Loop, runIf the target list is non empty, concurrencyLimit 2) walks the selected targets and run_suite (io.kestra.plugin.scripts.shell.Commands on the io.kestra.plugin.scripts.runner.docker.Docker runner, image alpine:3.20) attempts each package suite command, absorbing the expected miss on a bare fixture container so the log records what would run in a checkout that has the repo.
  4. path_coverage_gate (io.kestra.plugin.core.flow.If) branches when the selection failed or changed paths matched no package. Unmapped paths reach alert_unmapped_paths (io.kestra.plugin.slack.notifications.SlackIncomingWebhook) with the leftovers and the selected targets, then enforce_unmapped_policy (io.kestra.plugin.core.flow.If) applies the fail_on_unmapped policy with fail_execution (io.kestra.plugin.core.execution.Fail) or the advisory log_policy_softened. A payload that could not be parsed routes through check_selection_health and alert_selection_failed, and a fully covered change lands on log_all_paths_mapped.
  5. The flow level errors handler (io.kestra.plugin.slack.notifications.SlackIncomingWebhook) reports any failure with the execution id, because a selector that dies silently would look like an empty diff.

What you get

  • Path based test selection from an in-file package map with longest prefix matching, no full matrix on every push.
  • One loop iteration per selected package, each attempt visible in the execution history with its suite command.
  • A coverage gate that names changed paths no package claims, so documentation drift and orphan directories never pass as tested.
  • targets_selected, files_changed, selected_targets and unmapped_paths as typed outputs for build dashboards and merge checks.
  • A disabled nightly rescan as a second net once the webhook path is trusted.

Who it's for

  • Platform teams owning a monorepo who want push feedback in proportion to the change instead of the whole matrix.
  • CI engineers tired of paying the full package matrix for a README edit.
  • Maintainers extending the package map who need unmapped paths surfaced the moment a new directory ships without a suite entry.

Why orchestrate this with Kestra

A repo side script can diff paths but it cannot carry the package map, the coverage gate, the escalation policy and the history in one reviewable place. Kestra puts the push webhook, the selection rules, the suite loop, the fail on unmapped policy and the outputs a merge check can consume into a single version controlled file, and the execution log proves which suites ran for which change on every push.

Prerequisites

  • A worker with Docker access, the selector runs in python:3.12-slim and each suite attempt in alpine:3.20.
  • A push hook that POSTs the changed file list as a JSON array of paths or a comma separated string, or rely on the changed_files input for trial runs.
  • A Slack incoming webhook for the unmapped path alert, the selection failure alert and failure alerts.

Secrets

  • MONOREPO_PUSH_WEBHOOK_KEY: key segment guarding the push webhook URL, anyone holding it can trigger a selection run.
  • SLACK_WEBHOOK_URL: Slack incoming webhook for the unmapped path alert, the selection failure alert and failure alerts.

Quick start

  1. Add the two secrets to your Kestra namespace.
  2. Run the flow once with the default inputs and confirm targets_selected reads 2, files_changed reads 4, selected_targets holds services/api and libs/auth, unmapped_paths holds docs/setup.md and README.md, and the unmapped alert arrived in Slack.
  3. Set fail_on_unmapped to false and re-run to watch log_policy_softened keep the execution green while the alert still fires.
  4. Point your push hook at /api/v1/{tenant}/executions/webhook/{namespace}/monorepo-selective-ci/{MONOREPO_PUSH_WEBHOOK_KEY} and enable nightly_path_rescan once the path is trusted.

How to extend

  • Grow PACKAGE_MAP into a JSON input so each repository can ship its own map without editing the flow.
  • Replace the fixture suite attempts with an io.kestra.plugin.git.Clone of the pushed revision inside the loop, so the real commands run against real sources.
  • Fan the selected targets out as parallel subflows with io.kestra.plugin.core.flow.ForEachItem when one package suite takes longer than the whole selection should.
  • Record each selection run with io.kestra.plugin.jdbc.postgresql.Queries to chart how often unmapped paths block a push.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.