From a7cc10e67814425b0fa22a66d19c93d8d78eecb5 Mon Sep 17 00:00:00 2001 From: Mehdi ABAAKOUK Date: Thu, 30 Jul 2026 12:14:03 +0200 Subject: [PATCH] docs: fold Monorepo CI into the GitHub Actions and Buildkite integrations Monorepo CI is not a product, it is an advanced way to consume scopes on a specific CI. Sitting at the top level next to Merge Queue and CI Insights, it read as a third product: customers who wanted scope-aware batching or parallel mode clicked "Monorepo CI" and landed on a GitHub Actions job-skipping guide instead of /merge-queue/scopes. Delete the overview and the two per-CI setup guides, inlining their setup content as a "Monorepo CI" section on /integrations/gha and /integrations/buildkite. /merge-queue/scopes stays the single canonical explanation of what scopes are; each new section opens by saying plainly that it covers CI job skipping and points at scopes for batching and parallel mode. The old URLs 301 to the integration pages. Change-Id: I2f4584a8da4c7733a1ab05930a339745c926125a --- .../references/placement-guide.md | 1 - public/_redirects | 10 + src/content/docs/integrations/buildkite.mdx | 226 +++++++++++++++++- src/content/docs/integrations/gha.mdx | 174 +++++++++++++- .../migrate-partitions-to-scopes.mdx | 2 +- src/content/docs/merge-queue/monorepo.mdx | 13 +- src/content/docs/merge-queue/scopes.mdx | 5 +- .../docs/merge-queue/scopes/file-patterns.mdx | 10 +- src/content/docs/monorepo-ci.mdx | 116 --------- src/content/docs/monorepo-ci/buildkite.mdx | 191 --------------- .../docs/monorepo-ci/github-actions.mdx | 156 ------------ .../gha/monorepo-ci-summary.png} | Bin src/content/navItems.tsx | 18 -- 13 files changed, 424 insertions(+), 498 deletions(-) delete mode 100644 src/content/docs/monorepo-ci.mdx delete mode 100644 src/content/docs/monorepo-ci/buildkite.mdx delete mode 100644 src/content/docs/monorepo-ci/github-actions.mdx rename src/content/images/{monorepo-ci/github-actions/summary.png => integrations/gha/monorepo-ci-summary.png} (100%) diff --git a/.claude/skills/document-a-feature/references/placement-guide.md b/.claude/skills/document-a-feature/references/placement-guide.md index 4fb4d4f47d..732b653247 100644 --- a/.claude/skills/document-a-feature/references/placement-guide.md +++ b/.claude/skills/document-a-feature/references/placement-guide.md @@ -24,7 +24,6 @@ Top-level sections under `src/content/docs/`: | `commands/` | GitHub comment commands (queue, dequeue, rebase, squash, backport, copy, update, refresh) | | `ci-insights/` | CI analytics setup (GitHub Actions, Buildkite, Jenkins) | | `test-insights/` | Test framework integrations (pytest, Jest, Go, Rust, RSpec, Cypress, …) | -| `monorepo-ci/` | Monorepo CI guides | | `stacks/` | Stacked PRs: concepts, setup, workflow, adoption | | `integrations/` | Third-party integrations (GitHub, Datadog, Slack, Dependabot, Terraform, …) | | `api/`, `cli/` | API and CLI usage + reference | diff --git a/public/_redirects b/public/_redirects index 7c97acf047..603c19027f 100644 --- a/public/_redirects +++ b/public/_redirects @@ -83,3 +83,13 @@ /test-insights/cli /cli/tests 301 /test-insights/cli/ /cli/tests 301 + +/monorepo-ci /integrations/gha#monorepo-ci 301 +/monorepo-ci/ /integrations/gha#monorepo-ci 301 +/monorepo-ci.md /integrations/gha.md 301 +/monorepo-ci/github-actions /integrations/gha#monorepo-ci 301 +/monorepo-ci/github-actions/ /integrations/gha#monorepo-ci 301 +/monorepo-ci/github-actions.md /integrations/gha.md 301 +/monorepo-ci/buildkite /integrations/buildkite#monorepo-ci 301 +/monorepo-ci/buildkite/ /integrations/buildkite#monorepo-ci 301 +/monorepo-ci/buildkite.md /integrations/buildkite.md 301 diff --git a/src/content/docs/integrations/buildkite.mdx b/src/content/docs/integrations/buildkite.mdx index ec4feddf52..299c325ce9 100644 --- a/src/content/docs/integrations/buildkite.mdx +++ b/src/content/docs/integrations/buildkite.mdx @@ -31,11 +31,233 @@ reported to GitHub can also be referenced from your Mergify - **[CI Insights](/ci-insights/setup/buildkite)**: collect Buildkite job metrics, detect flaky tests, and get Slack notifications for CI failures. -- **[Monorepo CI](/monorepo-ci/buildkite)**: skip unaffected pipelines on - pull requests to cut CI spend in monorepos. +- **[Monorepo CI](#monorepo-ci)**: skip unaffected steps on pull requests to cut + CI spend in monorepos. - **[Merge Queue Scopes](/merge-queue/scopes/others)**: run only the jobs affected by a batch when processing the merge queue. Examples for [Bazel](/merge-queue/scopes/bazel), [Nx](/merge-queue/scopes/nx), and [Turborepo](/merge-queue/scopes/turborepo) are available. + +## Monorepo CI + +Monorepo CI is [scopes](/merge-queue/scopes) applied to your pipelines. The same +`scopes` block that lets the merge queue batch by scope also tells your pipeline +which steps have work to do, so a pull request that only touches the frontend +does not pay for the API and docs test suites. + +This section covers step skipping on pull requests. For smarter batching or +[parallel mode](/merge-queue/queue-modes#parallel-mode) in the merge queue, +scopes already do that on their own. See +[Merge Queue Scopes](/merge-queue/scopes). + +Running GitHub Actions instead? The +[GitHub Actions integration](/integrations/gha#monorepo-ci) covers the same +ground. Scopes themselves are CI-agnostic, so for any other provider +[let us know](mailto:support@mergify.com) and see +[Merge Queue Scopes](/merge-queue/scopes/others). + +### Declare your scopes + +The plugin reads the `scopes` block of your `.mergify.yml` to know which areas +of the repository map to each scope name: + +```yaml +scopes: + source: + files: + frontend: + include: + - apps/web/**/* + api: + include: + - services/api/**/* + docs: + include: + - docs/**/* +``` + +### Pipeline outline + +A Buildkite pipeline driven by scopes has two parts: + +1. **Detect scopes** using the + [`mergifyio/mergify-ci`](https://github.com/Mergifyio/mergify-ci-buildkite-plugin) plugin. + +2. **Use a dynamic pipeline** to conditionally upload only the steps that match + the affected scopes. + +```dot class="graph" +strict digraph { + fontname="sans-serif"; + rankdir="LR"; + nodesep=0.9; + ranksep=1.1; + splines=polyline; + + node [shape=box, style="rounded,filled", fontname="sans-serif", margin="0.35,0.2", color="#165B33", fillcolor="#347D39", fontcolor="white"]; + edge [fontname="sans-serif", color="#374151", penwidth=1.2, arrowhead=normal]; + + PR [label="Pull request\nchanges"]; + Config [fillcolor="#1CB893", color="#0B7A5C", fontcolor="#063C2C", label="Scopes config\n(.mergify.yml)"]; + Detect [fillcolor="#2563EB", color="#1E40AF", label="detect-scopes step\n(mergify-ci plugin)"]; + + Frontend [label="frontend-tests\n(run)"]; + API [fillcolor="#6B7280", color="#4B5563", label="api-tests\n(skipped)"]; + Docs [label="docs-tests\n(run)"]; + + PR -> Detect; + Config -> Detect; + Detect -> Frontend [label="scope: frontend"]; + Detect -> Docs [label="scope: docs"]; + Detect -> API [style=dashed, color="#9CA3AF", fontcolor="#9CA3AF", label="scope: api (false)"]; +} +``` + +### Static pipeline entry point + +```yaml +# .buildkite/pipeline.yml +steps: + - label: ":mag: Detect scopes" + key: detect-scopes + plugins: + - mergifyio/mergify-ci#@@BUILDKITE_PLUGIN_VERSION@@: + action: scopes + token: "${MERGIFY_TOKEN}" + + - label: ":pipeline: Upload conditional steps" + depends_on: detect-scopes + command: .buildkite/dynamic-pipeline.sh | buildkite-agent pipeline upload +``` + +### Dynamic pipeline script + +The script below parses the scope results with +[`jq`](https://jqlang.github.io/jq/), so install it on your Buildkite agents +first. + +```bash +#!/bin/bash +# .buildkite/dynamic-pipeline.sh +set -euo pipefail + +SCOPES=$(buildkite-agent meta-data get "mergify-ci.scopes" --default '{}') + +echo "steps:" + +if echo "$SCOPES" | jq -e '.frontend == "true"' > /dev/null 2>&1; then + cat <<'YAML' + - label: ":react: Frontend tests" + command: npm test + plugins: + - mergifyio/mergify-ci#@@BUILDKITE_PLUGIN_VERSION@@: + action: junit-process + report_path: "junit.xml" + token: "${MERGIFY_TOKEN}" +YAML +fi + +if echo "$SCOPES" | jq -e '.api == "true"' > /dev/null 2>&1; then + cat <<'YAML' + - label: ":gear: API tests" + command: pytest tests/api/ + plugins: + - mergifyio/mergify-ci#@@BUILDKITE_PLUGIN_VERSION@@: + action: junit-process + report_path: "reports/*.xml" + token: "${MERGIFY_TOKEN}" +YAML +fi + +if echo "$SCOPES" | jq -e '.docs == "true"' > /dev/null 2>&1; then + cat <<'YAML' + - label: ":books: Docs build" + command: make docs +YAML +fi + +# Buildkite rejects a pipeline with no steps, so emit a no-op when a pull +# request touches nothing in any scope. +if [ "$(echo "$SCOPES" | jq '[.[] | select(. == "true")] | length')" = "0" ]; then + cat <<'YAML' + - label: ":fast_forward: No affected scopes" + command: "true" +YAML +fi +``` + +Make the script executable: + +```bash +chmod +x .buildkite/dynamic-pipeline.sh +``` + +In this pipeline: + +- The `detect-scopes` step calls the `mergifyio/mergify-ci` plugin with the + `scopes` action, which inspects the pull request diff and stores a JSON map of + scopes (`"true"` or `"false"`) as Buildkite meta-data under the key + `mergify-ci.scopes`. + +- The dynamic pipeline script reads the scopes meta-data and only emits the + steps for scopes that are `"true"`, so unaffected steps are skipped entirely. + +- Each test step can optionally use the `junit-process` action to upload test + results to CI Insights. + +### Triggering separate pipelines + +If your monorepo builds live in separate Buildkite pipelines, use trigger steps +instead: + +```bash +#!/bin/bash +# .buildkite/dynamic-pipeline.sh +set -euo pipefail + +SCOPES=$(buildkite-agent meta-data get "mergify-ci.scopes" --default '{}') + +echo "steps:" + +if echo "$SCOPES" | jq -e '.frontend == "true"' > /dev/null 2>&1; then + cat <<'YAML' + - trigger: "frontend-pipeline" + label: ":react: Trigger frontend pipeline" + build: + branch: "${BUILDKITE_BRANCH}" + commit: "${BUILDKITE_COMMIT}" +YAML +fi + +if echo "$SCOPES" | jq -e '.api == "true"' > /dev/null 2>&1; then + cat <<'YAML' + - trigger: "api-pipeline" + label: ":gear: Trigger API pipeline" + build: + branch: "${BUILDKITE_BRANCH}" + commit: "${BUILDKITE_COMMIT}" +YAML +fi + +if echo "$SCOPES" | jq -e '.docs == "true"' > /dev/null 2>&1; then + cat <<'YAML' + - trigger: "docs-pipeline" + label: ":books: Trigger docs pipeline" + build: + branch: "${BUILDKITE_BRANCH}" + commit: "${BUILDKITE_COMMIT}" +YAML +fi + +if [ "$(echo "$SCOPES" | jq '[.[] | select(. == "true")] | length')" = "0" ]; then + cat <<'YAML' + - label: ":fast_forward: No affected scopes" + command: "true" +YAML +fi +``` + +Declare a trigger branch for every scope you define. A scope with no matching +branch produces a pull request that silently runs no checks at all. diff --git a/src/content/docs/integrations/gha.mdx b/src/content/docs/integrations/gha.mdx index 19d089ca1f..a754816d90 100644 --- a/src/content/docs/integrations/gha.mdx +++ b/src/content/docs/integrations/gha.mdx @@ -2,7 +2,9 @@ title: Integrating GitHub Actions with Mergify description: Run CI Insights, Monorepo CI, and Merge Queue Scopes on GitHub Actions. --- +import { Image } from "astro:assets" import ghaLogo from "../../images/integrations/gha/logo.png" +import ghaSummaryScreenshot from "../../images/integrations/gha/monorepo-ci-summary.png" import IntegrationLogo from "../../../components/IntegrationLogo.astro" @@ -29,8 +31,8 @@ can also be referenced from your Mergify - **[CI Insights](/ci-insights/setup/github-actions)**: collect job metrics, detect flaky tests, and get Slack notifications for CI failures. -- **[Monorepo CI](/monorepo-ci/github-actions)**: skip unaffected jobs on pull - requests to cut CI spend in monorepos. +- **[Monorepo CI](#monorepo-ci)**: skip unaffected jobs on pull requests to cut + CI spend in monorepos. - **[Merge Queue Scopes](/merge-queue/scopes/others)**: run only the jobs affected by a batch when processing the merge queue. Examples for @@ -45,3 +47,171 @@ can also be referenced from your Mergify To match a GitHub Actions status check with `check-success`, use the job name only, not the workflow name. ::: + +## Monorepo CI + +Monorepo CI is [scopes](/merge-queue/scopes) applied to your workflows. The same +`scopes` block that lets the merge queue batch by scope also tells each job +whether it has work to do, so a pull request that only touches the frontend +does not pay for the API and docs test suites. + +This section covers job skipping on pull requests. For smarter batching or +[parallel mode](/merge-queue/queue-modes#parallel-mode) in the merge queue, +scopes already do that on their own. See +[Merge Queue Scopes](/merge-queue/scopes). + +Running Buildkite instead? The +[Buildkite integration](/integrations/buildkite#monorepo-ci) covers the same +ground. Scopes themselves are CI-agnostic, so for any other provider +[let us know](mailto:support@mergify.com) and see +[Merge Queue Scopes](/merge-queue/scopes/others). + +### Declare your scopes + +The action reads the `scopes` block of your `.mergify.yml` to know which areas +of the repository map to each scope name: + +```yaml +scopes: + source: + files: + frontend: + include: + - apps/web/**/* + api: + include: + - services/api/**/* + docs: + include: + - docs/**/* +``` + +### Workflow outline + +A GitHub Actions workflow driven by scopes has three parts: + +1. **Detect scopes** using the + [`gha-mergify-ci`](https://github.com/Mergifyio/gha-mergify-ci) action. + +2. **Reuse the scope outputs** to conditionally run jobs. + +3. **Publish a final status** (for example with a `ci-gate` job) if you want one + check that reflects all the jobs that ran. + +```dot class="graph" +strict digraph { + fontname="sans-serif"; + rankdir="LR"; + nodesep=0.9; + ranksep=1.1; + splines=polyline; + + node [shape=box, style="rounded,filled", fontname="sans-serif", margin="0.35,0.2", color="#165B33", fillcolor="#347D39", fontcolor="white"]; + edge [fontname="sans-serif", color="#374151", penwidth=1.2, arrowhead=normal]; + + PR [label="Pull request\nchanges"]; + Config [fillcolor="#1CB893", color="#0B7A5C", fontcolor="#063C2C", label="Scopes config\n(.mergify.yml)"]; + Detect [fillcolor="#2563EB", color="#1E40AF", label="detect-scopes job\n(gha-mergify-ci)"]; + + Frontend [label="frontend-tests\n(run)"]; + API [fillcolor="#6B7280", color="#4B5563", label="api-tests\n(skipped)"]; + Docs [label="docs-tests\n(run)"]; + Gate [fillcolor="#111827", color="#0B1120", label="ci-gate\n(optional)"]; + + PR -> Detect; + Config -> Detect; + Detect -> Frontend [label="scope: frontend"]; + Detect -> Docs [label="scope: docs"]; + Detect -> API [style=dashed, color="#9CA3AF", fontcolor="#9CA3AF", label="scope: api (false)"]; + Frontend -> Gate; + Docs -> Gate; +} +``` + +### Example workflow + +:::caution + The `scopes` action requires a pull request context. If your workflow also + triggers on `push` events, guard the scopes job with + `if: ${{ github.event_name == 'pull_request' }}` to avoid failures. +::: + +```yaml +name: Monorepo CI +on: + pull_request: + +jobs: + detect-scopes: + runs-on: ubuntu-24.04 + outputs: + frontend: ${{ fromJSON(steps.scopes.outputs.scopes).frontend }} + api: ${{ fromJSON(steps.scopes.outputs.scopes).api }} + docs: ${{ fromJSON(steps.scopes.outputs.scopes).docs }} + steps: + - uses: actions/checkout@v5 + + - name: Detect scopes + id: scopes + uses: Mergifyio/gha-mergify-ci@@@GHA_MERGIFY_CI_VERSION@@ + with: + action: scopes + + frontend-tests: + needs: detect-scopes + if: ${{ needs.detect-scopes.outputs.frontend == 'true' }} + uses: ./.github/workflows/frontend-tests.yaml + secrets: inherit + + api-tests: + needs: detect-scopes + if: ${{ needs.detect-scopes.outputs.api == 'true' }} + uses: ./.github/workflows/api-tests.yaml + secrets: inherit + + docs-tests: + needs: detect-scopes + if: ${{ needs.detect-scopes.outputs.docs == 'true' }} + uses: ./.github/workflows/docs-tests.yaml + secrets: inherit + + ci-gate: + if: ${{ !cancelled() }} + needs: + - detect-scopes + - frontend-tests + - api-tests + - docs-tests + runs-on: ubuntu-24.04 + steps: + - name: Report status + uses: Mergifyio/gha-mergify-ci@@@GHA_MERGIFY_CI_VERSION@@ + with: + action: wait-jobs + jobs: ${{ toJSON(needs) }} +``` + +In this workflow: + +- `detect-scopes` calls `gha-mergify-ci` with the `scopes` action, which + inspects the pull request diff and returns a JSON map of scopes set to `true` + or `false`. + +- Each job checks the scope it cares about before running, reducing redundant + builds. + +- The final `ci-gate` job ensures that the aggregated status reflects the actual + CI coverage, even if some jobs were skipped. Keep `detect-scopes` in its + `needs`: without it, a failed scope detection skips every test job and + `ci-gate` still reports success. + +Mergify also publishes annotations that can be seen in your GitHub Actions jobs +summary. + +GitHub Actions job summary listing the scopes detected for a pull request + +### Protecting the branch with `ci-gate` + +Once `ci-gate` publishes a single status, add it as a required check in your +GitHub branch ruleset so that only pull requests with the relevant jobs executed +can merge. diff --git a/src/content/docs/merge-queue/migrate-partitions-to-scopes.mdx b/src/content/docs/merge-queue/migrate-partitions-to-scopes.mdx index 319751b80f..7f83ada856 100644 --- a/src/content/docs/merge-queue/migrate-partitions-to-scopes.mdx +++ b/src/content/docs/merge-queue/migrate-partitions-to-scopes.mdx @@ -170,7 +170,7 @@ jobs: :::tip Did you know? Scopes also work outside of the merge queue to optimize your - CI pipelines. See the [GitHub Actions integration guide](/monorepo-ci/github-actions) + CI pipelines. See the [GitHub Actions integration](/integrations/gha#monorepo-ci) for a complete setup walkthrough. ::: diff --git a/src/content/docs/merge-queue/monorepo.mdx b/src/content/docs/merge-queue/monorepo.mdx index 5237ee74aa..18d25d7708 100644 --- a/src/content/docs/merge-queue/monorepo.mdx +++ b/src/content/docs/merge-queue/monorepo.mdx @@ -47,15 +47,16 @@ With scopes, Mergify can: build system (Nx, Bazel, Turborepo) or want to gate expensive tests on the scopes a pull request touches. -Need scope-aware CI without the merge queue? Explore [Monorepo CI](/monorepo-ci) for workflows that -target GitHub Actions today. +Need scope-aware CI without the merge queue? The [GitHub +Actions](/integrations/gha#monorepo-ci) and [Buildkite](/integrations/buildkite#monorepo-ci) +integrations show how to skip unaffected CI jobs with the same scopes. ### No monorepo tooling yet? Just declare file-pattern scopes in `.mergify.yml`. Mergify evaluates them and the merge queue batches by scope with no workflow to add, so you get scope-aware batching without introducing Nx, -Bazel, or Turborepo first. When you also want scope-aware CI, the -[Monorepo CI](/monorepo-ci) GitHub Actions guide ships a ready-made +Bazel, or Turborepo first. When you also want scope-aware CI, the [GitHub Actions +integration](/integrations/gha#monorepo-ci) ships a ready-made [`gha-mergify-ci`](https://github.com/Mergifyio/gha-mergify-ci) workflow. As your repository grows you can swap in more advanced tooling, and your scopes stay the same. @@ -78,4 +79,6 @@ of how you compute them. test and merge pull requests that touch different scopes simultaneously, reducing merge times in monorepos. -- [Monorepo CI](/monorepo-ci): opinionated GitHub Actions workflows if you need turnkey automation. +- [GitHub Actions](/integrations/gha#monorepo-ci) and + [Buildkite](/integrations/buildkite#monorepo-ci) integrations: reuse the same scopes to skip + unaffected CI jobs on pull requests. diff --git a/src/content/docs/merge-queue/scopes.mdx b/src/content/docs/merge-queue/scopes.mdx index 897940bd81..3bc9707bc3 100644 --- a/src/content/docs/merge-queue/scopes.mdx +++ b/src/content/docs/merge-queue/scopes.mdx @@ -9,8 +9,9 @@ Mergify scopes describe the areas of your codebase that a pull request touches. to pull requests, the merge queue can build smarter batches, reuse the same CI work, and avoid mixing unrelated changes. -Looking to use scopes outside of the merge queue? Check out [Monorepo CI](/monorepo-ci) for -scope-driven CI workflows. +Looking to use scopes outside of the merge queue? The same scopes can skip unaffected CI jobs on +pull requests. See the [GitHub Actions](/integrations/gha#monorepo-ci) and +[Buildkite](/integrations/buildkite#monorepo-ci) integrations. Here's a quick walkthrough of how we use scopes on Mergify's own monorepo: diff --git a/src/content/docs/merge-queue/scopes/file-patterns.mdx b/src/content/docs/merge-queue/scopes/file-patterns.mdx index f440b61bfd..c7526b0915 100644 --- a/src/content/docs/merge-queue/scopes/file-patterns.mdx +++ b/src/content/docs/merge-queue/scopes/file-patterns.mdx @@ -56,8 +56,8 @@ up: declare the patterns above and the queue batches by scope. ## Conditioning CI Jobs on Scopes (Optional) The same scopes can also drive your CI, letting you skip jobs whose scope a pull request doesn't -touch. This is optional and independent of merge queue batching. To wire it up, follow the -[Monorepo CI GitHub Actions guide](/monorepo-ci/github-actions). It walks through: +touch. This is optional and independent of merge queue batching. To wire it up, follow the Monorepo +CI section of the [GitHub Actions integration](/integrations/gha#monorepo-ci). It walks through: - Adding the [`gha-mergify-ci`](https://github.com/Mergifyio/gha-mergify-ci) workflow step that reads your file-pattern scopes and exposes them as outputs. @@ -66,8 +66,10 @@ touch. This is optional and independent of merge queue batching. To wire it up, - Waiting on the right set of jobs so required checks always report, even when work is skipped. -That guide already includes complete workflow samples, so you do not need to duplicate the config -here. Just reuse the same scopes you declared above. +That section already includes complete workflow samples, so you do not need to duplicate the config +here. Just reuse the same scopes you declared above. The +[Buildkite integration](/integrations/buildkite#monorepo-ci) walks through the first two steps for +Buildkite pipelines, using a dynamic pipeline instead of job conditions. ## The Merge Queue Scope diff --git a/src/content/docs/monorepo-ci.mdx b/src/content/docs/monorepo-ci.mdx deleted file mode 100644 index 6e4e7fdb6e..0000000000 --- a/src/content/docs/monorepo-ci.mdx +++ /dev/null @@ -1,116 +0,0 @@ ---- -title: Monorepo CI -description: Run the right tests for the right pull requests by combining scopes with your CI system. ---- - -Monorepos make continuous integration expensive. Every change potentially -touches hundreds of packages or services, and running the full test matrix for -all of them at every pull request update quickly becomes unsustainable. - -Mergify Monorepo CI brings precision testing to your existing CI pipelines by -tagging each pull request with **scopes**. Scopes are named slices of your -repository that describe a service, package, or set of files (see -[Merge Queue Scopes](/merge-queue/scopes) for the full specification). A scope acts as -the contract between your codebase and your CI: if a pull request touches files -that belong to the `frontend` scope, every workflow that cares about that scope -knows it has work to do. - -With scopes in place you can: - -- Detect which projects or services are really impacted by a change. -- Run only the CI jobs that matter for those scopes. -- Reuse those scopes later in the merge queue to build smarter batches. - -Native support is available for GitHub Actions through our -[`gha-mergify-ci`](https://github.com/Mergifyio/gha-mergify-ci) action and for -Buildkite through the -[`mergify-ci` plugin](https://github.com/Mergifyio/mergify-ci-buildkite-plugin). - -## How it works - -```dot class="graph" -strict digraph { - fontname="sans-serif"; - rankdir="LR"; - nodesep=0.9; - ranksep=1.1; - splines=polyline; - - node [shape=box, style="rounded,filled", fontname="sans-serif", margin="0.35,0.2", color="#165B33", fillcolor="#347D39", fontcolor="white"]; - edge [fontname="sans-serif", color="#374151", penwidth=1.2, arrowhead=normal]; - - subgraph cluster_repo { - label="Repository"; - style="rounded"; - color="#1CB893"; - fontcolor="#063C2C"; - - PR [label="Pull request\nchanges"]; - ScopesConfig [fillcolor="#1CB893", fontcolor="#063C2C", color="#0B7A5C", margin="0.4,0.2", label="Scopes config\n(.mergify.yml)"]; - } - - Detect [fillcolor="#2563EB", color="#1E40AF", label="gha-mergify-ci\n(scopes)"]; - - subgraph cluster_ci { - label="GitHub Actions jobs"; - style="rounded"; - color="#1CB893"; - fontcolor="#063C2C"; - - Frontend [label="Frontend tests"]; - API [fillcolor="#6B7280", color="#4B5563", label="API tests\n(skipped)"]; - Docs [fillcolor="#347D39", color="#165B33", label="Docs checks"]; - } - - Queue [fillcolor="#111827", color="#0B1120", label="Merge Queue\n(optional reuse)"]; - - PR -> Detect; - ScopesConfig -> Detect; - Detect -> Frontend [label="scope: frontend"]; - Detect -> Docs [label="scope: docs"]; - Detect -> Queue [style=dashed, color="#9CA3AF", fontcolor="#9CA3AF"]; -} -``` - -1. **Define scopes** in your `.mergify.yml` file by mapping the areas of your repository (via file - patterns) to scope names that matter for your CI. - -2. **Collect scopes in CI.** A helper such as - [`gha-mergify-ci`](https://github.com/Mergifyio/gha-mergify-ci) inspects the - pull request diff and dispatches only the jobs whose scopes are touched. - -3. **Drive your jobs conditionally.** Use the reported scopes to decide which - workflows, test suites, or deployment steps should run for the current pull - request. - -4. **(Optional) Share scopes with Merge Queue.** The very same scopes help the merge queue build - batches that group related pull requests, reuse your CI runs, and unlock advanced strategies like - [batch merging](/merge-queue/batches) or [two-step CI](/merge-queue/two-step). - -## What you can do with Monorepo CI - -- Gate language-specific test suites with fine-grained scope checks. -- Trigger targeted build pipelines for individual services or packages. -- Run nightly or specialized workflows only when relevant scopes change. - -## Get started - -Define your scopes first so every workflow speaks the same language: - -1. List the services, packages, or domains that deserve their own scope. - -2. Map each scope to file patterns inside the - [`scopes`](/merge-queue/scopes#configuration) block of your `.mergify.yml` - file. - -3. Commit the configuration and open a pull request to verify that the reported - scopes match your expectations. - -Once those scopes exist, pick the workflow that matches your setup: - -- [Scope configuration reference](/merge-queue/scopes) -- [GitHub Actions setup](/monorepo-ci/github-actions) -- [Buildkite setup](/monorepo-ci/buildkite) -- [Merge queue monorepo overview](/merge-queue/monorepo) - -Looking for a different CI provider? [Let us know](mailto:support@mergify.com); more platforms are on our roadmap. diff --git a/src/content/docs/monorepo-ci/buildkite.mdx b/src/content/docs/monorepo-ci/buildkite.mdx deleted file mode 100644 index b58eb251ae..0000000000 --- a/src/content/docs/monorepo-ci/buildkite.mdx +++ /dev/null @@ -1,191 +0,0 @@ ---- -title: Monorepo CI with Buildkite -description: Use the Mergify CI Buildkite plugin to run only the pipelines impacted by a pull request. ---- - -Mergify's Buildkite integration makes scopes actionable in your CI. This -guide shows how to wire scopes into your pipelines so that each pull request -runs only the jobs it truly needs. - -## Prerequisites - -Before you start, make sure you have: - -- [`jq`](https://jqlang.github.io/jq/) installed on your Buildkite agents (used - by the dynamic pipeline script to parse scope results) - -- Scopes declared in your `.mergify.yml` so the plugin knows which areas of the - repo map to each scope name: - -```yaml -scopes: - source: - files: - frontend: - include: - - apps/web/**/* - api: - include: - - services/api/**/* - docs: - include: - - docs/**/* -``` - -## Pipeline outline - -A typical Buildkite pipeline with scopes consists of two parts: - -1. **Detect scopes** using the - [`mergifyio/mergify-ci`](https://github.com/Mergifyio/mergify-ci-buildkite-plugin) plugin. - -2. **Use a dynamic pipeline** to conditionally upload only the steps that match - the affected scopes. - -```dot class="graph" -strict digraph { - fontname="sans-serif"; - rankdir="LR"; - nodesep=0.9; - ranksep=1.1; - splines=polyline; - - node [shape=box, style="rounded,filled", fontname="sans-serif", margin="0.35,0.2", color="#165B33", fillcolor="#347D39", fontcolor="white"]; - edge [fontname="sans-serif", color="#374151", penwidth=1.2, arrowhead=normal]; - - PR [label="Pull request\nchanges"]; - Config [fillcolor="#1CB893", color="#0B7A5C", fontcolor="#063C2C", label="Scopes config\n(.mergify.yml)"]; - Detect [fillcolor="#2563EB", color="#1E40AF", label="detect-scopes step\n(mergify-ci plugin)"]; - - Frontend [label="frontend-tests\n(run)"]; - API [fillcolor="#6B7280", color="#4B5563", label="api-tests\n(skipped)"]; - Docs [label="docs-tests\n(run)"]; - - PR -> Detect; - Config -> Detect; - Detect -> Frontend [label="scope: frontend"]; - Detect -> Docs [label="scope: docs"]; - Detect -> API [style=dashed, color="#9CA3AF", fontcolor="#9CA3AF", label="scope: api (false)"]; -} -``` - -## Example pipeline - -### Static pipeline entry point - -```yaml -# .buildkite/pipeline.yml -steps: - - label: ":mag: Detect scopes" - key: detect-scopes - plugins: - - mergifyio/mergify-ci#@@BUILDKITE_PLUGIN_VERSION@@: - action: scopes - token: "${MERGIFY_TOKEN}" - - - label: ":pipeline: Upload conditional steps" - depends_on: detect-scopes - command: .buildkite/dynamic-pipeline.sh | buildkite-agent pipeline upload -``` - -### Dynamic pipeline script - -```bash -#!/bin/bash -# .buildkite/dynamic-pipeline.sh -set -euo pipefail - -SCOPES=$(buildkite-agent meta-data get "mergify-ci.scopes") - -echo "steps:" - -if echo "$SCOPES" | jq -e '.frontend == "true"' > /dev/null 2>&1; then - cat <<'YAML' - - label: ":react: Frontend tests" - command: npm test - plugins: - - mergifyio/mergify-ci#@@BUILDKITE_PLUGIN_VERSION@@: - action: junit-process - report_path: "junit.xml" - token: "${MERGIFY_TOKEN}" -YAML -fi - -if echo "$SCOPES" | jq -e '.api == "true"' > /dev/null 2>&1; then - cat <<'YAML' - - label: ":gear: API tests" - command: pytest tests/api/ - plugins: - - mergifyio/mergify-ci#@@BUILDKITE_PLUGIN_VERSION@@: - action: junit-process - report_path: "reports/*.xml" - token: "${MERGIFY_TOKEN}" -YAML -fi - -if echo "$SCOPES" | jq -e '.docs == "true"' > /dev/null 2>&1; then - cat <<'YAML' - - label: ":books: Docs build" - command: make docs -YAML -fi -``` - -Make the script executable: - -```bash -chmod +x .buildkite/dynamic-pipeline.sh -``` - -### How it works - -- The `detect-scopes` step calls the Mergify CI plugin with the `scopes` - action, which inspects the pull request diff and stores a JSON map of scopes - (`"true"` or `"false"`) as Buildkite meta-data under the key - `mergify-ci.scopes`. - -- The dynamic pipeline script reads the scopes meta-data and only emits the - steps for scopes that are `"true"`, so unaffected jobs are skipped entirely. - -- Each test step can optionally use the `junit-process` action to upload test - results to CI Insights. - -## Alternative: trigger pipelines - -If your monorepo jobs live in separate Buildkite pipelines, you can use -`buildkite-agent pipeline upload` with trigger steps instead: - -```bash -#!/bin/bash -# .buildkite/dynamic-pipeline.sh -set -euo pipefail - -SCOPES=$(buildkite-agent meta-data get "mergify-ci.scopes") - -echo "steps:" - -if echo "$SCOPES" | jq -e '.frontend == "true"' > /dev/null 2>&1; then - cat <<'YAML' - - trigger: "frontend-pipeline" - label: ":react: Trigger frontend pipeline" - build: - branch: "${BUILDKITE_BRANCH}" - commit: "${BUILDKITE_COMMIT}" -YAML -fi - -if echo "$SCOPES" | jq -e '.api == "true"' > /dev/null 2>&1; then - cat <<'YAML' - - trigger: "api-pipeline" - label: ":gear: Trigger API pipeline" - build: - branch: "${BUILDKITE_BRANCH}" - commit: "${BUILDKITE_COMMIT}" -YAML -fi -``` - -## Merge Queue integration - -To reuse the same scopes for merge queue batching, see [Merge Queue -Scopes](/merge-queue/scopes). diff --git a/src/content/docs/monorepo-ci/github-actions.mdx b/src/content/docs/monorepo-ci/github-actions.mdx deleted file mode 100644 index 6f5b673a37..0000000000 --- a/src/content/docs/monorepo-ci/github-actions.mdx +++ /dev/null @@ -1,156 +0,0 @@ ---- -title: Monorepo CI with GitHub Actions -description: Use `gha-mergify-ci` to run only the workflows impacted by a pull request. ---- - -import { Image } from "astro:assets" -import ghaSummaryScreenshot from "../../images/monorepo-ci/github-actions/summary.png" - -Mergify's GitHub Actions integration makes scopes actionable in your CI. This -guide shows how to wire scopes into your workflows so that each pull request -runs only the jobs it truly needs. - -## Prerequisites - -Before you start, declare scopes in your `.mergify.yml` so the action knows -which areas of the repo map to each scope name: - -```yaml -scopes: - source: - files: - frontend: - include: - - apps/web/**/* - api: - include: - - services/api/**/* - docs: - include: - - docs/**/* -``` - -## Workflow outline - -A typical GitHub Actions pipeline with scopes consists of three parts: - -1. **Detect scopes** using the - [`gha-mergify-ci`](https://github.com/Mergifyio/gha-mergify-ci) action. - -2. **Reuse the scope outputs** to conditionally run jobs. - -3. **Publish a final status** (for example with a `ci-gate` job) if you want one - check that reflects all the jobs that ran. - -```dot class="graph" -strict digraph { - fontname="sans-serif"; - rankdir="LR"; - nodesep=0.9; - ranksep=1.1; - splines=polyline; - - node [shape=box, style="rounded,filled", fontname="sans-serif", margin="0.35,0.2", color="#165B33", fillcolor="#347D39", fontcolor="white"]; - edge [fontname="sans-serif", color="#374151", penwidth=1.2, arrowhead=normal]; - - PR [label="Pull request\nchanges"]; - Config [fillcolor="#1CB893", color="#0B7A5C", fontcolor="#063C2C", label="Scopes config\n(.mergify.yml)"]; - Detect [fillcolor="#2563EB", color="#1E40AF", label="detect-scopes job\n(gha-mergify-ci)"]; - - Frontend [label="frontend-tests\n(run)"]; - API [fillcolor="#6B7280", color="#4B5563", label="api-tests\n(skipped)"]; - Docs [label="docs-tests\n(run)"]; - Gate [fillcolor="#111827", color="#0B1120", label="ci-gate\n(optional)"]; - - PR -> Detect; - Config -> Detect; - Detect -> Frontend [label="scope: frontend"]; - Detect -> Docs [label="scope: docs"]; - Detect -> API [style=dashed, color="#9CA3AF", fontcolor="#9CA3AF", label="scope: api (false)"]; - Frontend -> Gate; - Docs -> Gate; -} -``` - -## Example workflow -```yaml -name: Monorepo CI -on: - pull_request: - -jobs: - detect-scopes: - runs-on: ubuntu-24.04 - outputs: - frontend: ${{ fromJSON(steps.scopes.outputs.scopes).frontend }} - api: ${{ fromJSON(steps.scopes.outputs.scopes).api }} - docs: ${{ fromJSON(steps.scopes.outputs.scopes).docs }} - steps: - - uses: actions/checkout@v5 - - - name: Detect scopes - id: scopes - uses: Mergifyio/gha-mergify-ci@@@GHA_MERGIFY_CI_VERSION@@ - with: - action: scopes - - frontend-tests: - needs: detect-scopes - if: ${{ needs.detect-scopes.outputs.frontend == 'true' }} - uses: ./.github/workflows/frontend-tests.yaml - secrets: inherit - - api-tests: - needs: detect-scopes - if: ${{ needs.detect-scopes.outputs.api == 'true' }} - uses: ./.github/workflows/api-tests.yaml - secrets: inherit - - docs-tests: - needs: detect-scopes - if: ${{ needs.detect-scopes.outputs.docs == 'true' }} - uses: ./.github/workflows/docs-tests.yaml - secrets: inherit - - ci-gate: - if: ${{ !cancelled() }} - needs: - - frontend-tests - - api-tests - - docs-tests - runs-on: ubuntu-24.04 - steps: - - name: Report status - uses: Mergifyio/gha-mergify-ci@@@GHA_MERGIFY_CI_VERSION@@ - with: - action: wait-jobs - jobs: ${{ toJSON(needs) }} -``` - -### How it works - -- `detect-scopes` calls `gha-mergify-ci` with the `scopes` action, which - inspects the pull request diff and returns a JSON map of scopes set to `true` - or `false`. - -- Each job checks the scope it cares about before running, reducing - redundant builds. - -- The final `ci-gate` job ensures that the aggregated status reflects the actual - CI coverage, even if some jobs were skipped. - -Mergify also publishes annotations that can be seen in your GitHub Actions jobs -summary. - -GitHub Actions summary showing detected scopes and ci-gate result - -## Protecting the branch with `ci-gate` - -Once `ci-gate` publishes a single status, add it as a required check in your -GitHub branch ruleset so that only pull requests with the relevant jobs executed -can merge. - -## Merge Queue integration - -Ready to reuse the same scopes for batching? Head over to [Merge Queue -Scopes](/merge-queue/scopes) to see how they power smarter batches. diff --git a/src/content/images/monorepo-ci/github-actions/summary.png b/src/content/images/integrations/gha/monorepo-ci-summary.png similarity index 100% rename from src/content/images/monorepo-ci/github-actions/summary.png rename to src/content/images/integrations/gha/monorepo-ci-summary.png diff --git a/src/content/navItems.tsx b/src/content/navItems.tsx index e2eaba2c0a..9d787ffb3b 100644 --- a/src/content/navItems.tsx +++ b/src/content/navItems.tsx @@ -286,24 +286,6 @@ const navItems: NavItem[] = [ }, ], }, - { - title: 'Monorepo CI', - path: '/monorepo-ci', - icon: 'lucide:network', - children: [ - { title: 'Overview', path: '/monorepo-ci', icon: 'lucide:network' }, - { - title: 'GitHub Actions', - path: '/monorepo-ci/github-actions', - icon: 'simple-icons:githubactions', - }, - { - title: 'Buildkite', - path: '/monorepo-ci/buildkite', - icon: 'simple-icons:buildkite', - }, - ], - }, { title: 'Rule Engine', icon: 'lucide:book',