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',