← MergifyCONTENT HISTORYWHAT CHANGED · RULE-BASED ANALYSIS
Update to Mergify
Snapshot Sep 30, 2026 · 23:16 UTC · version 1.0.0
Collection source: not recorded for this historical snapshot.
First saved snapshot
No earlier snapshot is available to establish a change.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"name": "mergify-ci",
"description": "Use Mergify CI commands to upload JUnit test results, detect git references, manage CI scopes, and retrieve merge queue metadata. ALWAYS use this skill when working with CI pipelines, test result uploads, quarantine, scopes detection, or merge queue CI context. Triggers on CI, JUnit, test results, quarantine, scopes, git refs, CI insights.",
"included_files": [],
"skill_md_contents": "---\nname: mergify-ci\ndescription: Use Mergify CI commands to upload JUnit test results, detect git references, manage CI scopes, and retrieve merge queue metadata. ALWAYS use this skill when working with CI pipelines, test result uploads, quarantine, scopes detection, or merge queue CI context. Triggers on CI, JUnit, test results, quarantine, scopes, git refs, CI insights.\n---\n\n# Mergify CI Commands\n\n## Overview\n\nThe `mergify ci` command group provides tools for CI pipelines: uploading JUnit test results to Mergify CI Insights, detecting git references for diff-based operations, managing CI scopes for selective testing, and retrieving merge queue batch metadata.\n\n## Commands\n\n```bash\nmergify ci junit-process FILES... # Upload JUnit XML + evaluate quarantine (primary command)\nmergify ci junit-upload FILES... # (Deprecated) Use junit-process instead\nmergify ci git-refs # Detect base/head git references for the current PR\nmergify ci scopes --config PATH # Detect scopes impacted by changed files\nmergify ci scopes-send -s SCOPE # Report scopes against the pull request's head commit\nmergify ci queue-info # Output the current build's merge queue batch metadata (from the git note)\nmergify tests show NAME... # Look up tests by name and print health, ratios, last failure\nmergify tests quarantines add NAME # Add a test to the CI Insights quarantine\nmergify tests quarantines remove NAME # Remove a test from the CI Insights quarantine\nmergify tests quarantines get NAME # Print a single quarantine by test name or id\nmergify tests quarantines list # List the tests currently in the CI Insights quarantine\n```\n\n## Authentication\n\nTwo classes of Mergify application key, both minted in the dashboard:\n\n| Key | Reaches |\n| --- | --- |\n| `ci` | What a CI job does: trace upload, `scopes-send`, quarantine *evaluation* (`junit-process`) and the quarantine *list*. |\n| `admin` | Everything a `ci` key reaches, plus reading test health and mutating the quarantine. |\n\nEvery endpoint below that refuses a `ci` key accepts a GitHub PAT instead.\n`GITHUB_TOKEN` inside GitHub Actions is *not* a PAT — it is the ephemeral\ninstallation token — so do not reach for it to clear one of these `403`s.\n\nThe split follows the endpoint each command calls: reads of test health and\nwrites to the quarantine are a person inspecting or overriding a repository,\nnot something a pipeline does, so they are outside what a `ci` key carries.\nPer command:\n\n| Command | `ci` key |\n| --- | --- |\n| `ci junit-process`, `ci junit-upload`, `ci scopes-send` | yes |\n| `tests quarantines list`, `tests quarantines get` | yes — both read the quarantine list |\n| `tests show` | **no** — `403` |\n| `tests quarantines add`, `tests quarantines remove` | **no** — `403` |\n\n`ci git-refs`, `ci scopes` and `ci queue-info` are evaluated locally and need\nno token at all.\n\n## JUnit Processing (`junit-process`)\n\nThe primary CI command. Parses JUnit XML reports, checks quarantine status for failing tests, uploads results to Mergify CI Insights, and determines the final CI exit code.\n\n```bash\nmergify ci junit-process \\\n --token \"$MERGIFY_TOKEN\" \\\n --repository owner/repo \\\n --tests-target-branch main \\\n path/to/junit-results.xml\n```\n\n`FILES` can be individual paths or quoted glob patterns (e.g. `'reports/**/*.xml'`). Always quote the pattern so Mergify expands it rather than the shell — this is the recommended approach for large, sharded test suites.\n\n**Key options:**\n- `--token` / `-t` (env: `MERGIFY_TOKEN`) -- CI Insights application key\n- `--repository` / `-r` -- Repository full name (auto-detected in GitHub Actions)\n- `--tests-target-branch` / `-ttb` -- Branch used for quarantine evaluation. Auto-detected per CI provider: GitHub Actions (`GITHUB_BASE_REF` → `GITHUB_HEAD_REF` → `GITHUB_REF_NAME` → `GITHUB_REF`), Buildkite (`BUILDKITE_PULL_REQUEST_BASE_BRANCH` → `BUILDKITE_BRANCH`), CircleCI (`CIRCLE_BRANCH`), Jenkins (`CHANGE_TARGET` → `GIT_BRANCH`).\n- `--api-url` / `-u` (env: `MERGIFY_API_URL`) -- Mergify API URL (default: `https://api.mergify.com`)\n- `--test-framework` -- Test framework name (optional metadata)\n- `--test-language` -- Test language (optional metadata)\n- `--test-exit-code` / `-e` (env: `MERGIFY_TEST_EXIT_CODE`) -- Exit code of the test runner, used to detect silent failures where the runner crashed but the JUnit report appears clean\n\n**Behavior:**\n1. Parses JUnit XML files into test spans\n2. Checks quarantine status for failing tests against the Mergify API\n3. Uploads all test spans to Mergify CI Insights\n4. Prints a summary: tests run, failures, quarantined vs blocking\n5. Exits with code 0 if all failures are quarantined, code 1 if any are blocking\n6. If `--test-exit-code` is non-zero but no test failures are found, exits with code 1 (silent failure detection)\n7. Upload failures never affect the exit code (Mergify-side trouble must not break CI), but they are surfaced: on GitHub Actions the command emits an `::error::` annotation when the upload is rejected (HTTP 4xx except 408/429, e.g. a token without CI Insights access) or a `::warning::` annotation for transient errors (5xx, 408, 429, network), and appends `test_results_upload=success|rejected|failed` to `$GITHUB_OUTPUT` so workflows can detect dead ingest programmatically\n\n**GitHub Actions example:**\n```yaml\n- name: Run tests\n id: tests\n run: pytest --junitxml=results.xml || echo \"exit_code=$?\" >> \"$GITHUB_OUTPUT\"\n\n- name: Process test results\n if: always()\n run: |\n mergify ci junit-process \\\n --test-exit-code ${{ steps.tests.outputs.exit_code || 0 }} \\\n results.xml\n env:\n MERGIFY_TOKEN: ${{ secrets.MERGIFY_TOKEN }}\n```\n\n## Git References (`git-refs`)\n\nDetects the base and head git references for the current pull request context. Writes results to `GITHUB_OUTPUT` when running in GitHub Actions, and to Buildkite meta-data (`mergify-ci.base`, `mergify-ci.head`, `mergify-ci.source`) when running in Buildkite.\n\n```bash\nmergify ci git-refs\n# Output:\n# Base: abc1234\n# Head: def5678\n```\n\n**Output formats (`--format`):**\n- `text` (default) — human-readable `Base:` / `Head:` lines\n- `shell` — `MERGIFY_GIT_REFS_{BASE,HEAD,SOURCE}=...` lines suitable for `eval`, with POSIX-safe shell quoting. When base can't be detected, `MERGIFY_GIT_REFS_BASE=''`.\n- `json` — single-line JSON object with `base`, `head`, `source` keys. `base` may be `null` when it can't be detected (e.g., `workflow_dispatch` events); use `jq -r '.base // \"\"'` to coalesce to empty string.\n\n```bash\n# Consume values in a shell script without parsing:\neval \"$(mergify ci git-refs --format=shell)\"\nnx show projects --affected \\\n --base=\"$MERGIFY_GIT_REFS_BASE\" \\\n --head=\"$MERGIFY_GIT_REFS_HEAD\"\n\n# Or with jq:\nBASE=$(mergify ci git-refs --format=json | jq -r '.base // \"\"')\n```\n\nSources detected (in priority order): merge queue context, GitHub pull request event, GitHub push event, fallback to last commit.\n\n## Scopes (`scopes`)\n\nDetects which CI scopes are impacted by changed files, based on a Mergify configuration file. Used for selective/targeted CI -- only run tests for scopes that have changed files.\n\n```bash\n# Detect scopes from changed files\nmergify ci scopes --config .mergify.yml\n\n# Detect scopes with explicit base/head\nmergify ci scopes --config .mergify.yml --base origin/main --head HEAD\n\n# Write detected scopes to a file\nmergify ci scopes --config .mergify.yml --write scopes.json\n```\n\n**Key options:**\n- `--config` (env: `MERGIFY_CONFIG_PATH`) -- Path to the Mergify YAML config file (auto-detected)\n- `--base` -- Base git reference (auto-detected)\n- `--head` -- Head git reference (default: HEAD)\n- `--write` / `-w` -- Write detected scopes to a JSON file\n\nThe config file defines scopes with file patterns. When files change between base and head, matching scopes are identified and written to `GITHUB_OUTPUT` (on GitHub Actions) or to Buildkite meta-data under `mergify-ci.scopes` (on Buildkite), as a JSON map of scope names to `\"true\"`/`\"false\"`.\n\nA renamed file counts against **both** of its paths, same as the engine: `git mv critical/guard.txt ignored/guard.txt` touches `critical` and `ignored`.\n\n## Scopes Send (`scopes-send`)\n\nSends scopes tied to a pull request to the Mergify API. Used when scopes are determined manually or from a file rather than auto-detected.\n\nThe report is addressed by the pull request's **head SHA**, so it says which revision it was computed for and a result computed for an older head cannot be taken for the current one. The head is detected from the CI environment (GitHub Actions event payload, or `BUILDKITE_COMMIT`); pass `--head-sha` to name it explicitly. When no head SHA can be resolved -- or the Mergify deployment predates the commit endpoint -- the command falls back to reporting against the pull request number alone, which is what it always did.\n\n```bash\n# Send specific scopes\nmergify ci scopes-send -s frontend -s backend -p 123\n\n# Send scopes from a JSON file (produced by `mergify ci scopes --write`)\nmergify ci scopes-send --scopes-json scopes.json -p 123\n\n# Send scopes from a plain-text file (one scope per line)\nmergify ci scopes-send --scopes-file scopes.txt -p 123\n\n# Declare the PR impacts every scope (merge-queue barrier),\n# e.g. a build-system or CI-workflow change\nmergify ci scopes-send -s build-system --all -p 123\n\n# Name the revision explicitly (the pull request head, not the\n# revision a `pull_request` job checked out)\nmergify ci scopes-send -s frontend -p 123 --head-sha \"$PR_HEAD_SHA\"\n```\n\n**Key options:**\n- `--token` / `-t` (env: `MERGIFY_TOKEN`) -- Mergify key\n- `--repository` / `-r` -- Repository full name (auto-detected)\n- `--pull-request` / `-p` -- Pull request number (auto-detected in GitHub Actions)\n- `--scope` / `-s` -- Scope name (repeatable)\n- `--scopes-json` -- JSON file containing scopes (output of `mergify ci scopes --write`)\n- `--scopes-file` -- Plain-text file with one scope per line\n- `--head-sha` -- Head SHA the scopes were computed for, 40 hexadecimal characters (auto-detected from the CI environment)\n- `--all` -- Declare the pull request impacts every scope. The merge queue treats it as a barrier: never batched or run in parallel with other pull requests. The concrete scopes are still sent alongside the flag.\n\n## Tests Show (`tests show`)\n\nLooks up tests by name on the repository's default branch and prints their\nhealth, success/failure ratios, and last failure context. The search is a\nbatch API: pass one or more names (globs supported) and one block per match\nis rendered. It is read-only: it exits `0` once it has rendered the matches,\nwhatever their health. Gate on health by consuming `--json`, not the exit code.\n\nNeeds an `admin` key or a GitHub PAT — a `ci` key gets a `403`. See\n[Authentication](#authentication).\n\n```bash\n# Single test.\nmergify tests show -r owner/repo \\\n 'ApplicationKeys.spec.ts.Permissions › Should not see keys table if not admin'\n\n# Batch with glob, narrowed to one pipeline, JSON for jq.\nmergify tests show -r owner/repo \\\n --pipeline-name e2e --json \\\n '*test_login*' '*test_logout*' \\\n | jq '.tests[] | {test_name, health_status}'\n```\n\n**Key options:**\n- `--repository` / `-r` -- Repository full name (`owner/repo`); auto-detected from the CI environment or the local git remote when omitted.\n- `--token` / `-t` (env: `MERGIFY_TOKEN`) -- Mergify credential. Falls back to the credential `mergify auth login` stored, then to `GITHUB_TOKEN` / `gh auth token`, both deprecated for the Mergify API.\n- `--api-url` / `-u` (env: `MERGIFY_API_URL`) -- API base URL.\n- `--pipeline-name`, `--pipeline-name-exclude` -- Restrict / exclude by pipeline.\n- `--job-name`, `--job-name-exclude` -- Restrict / exclude by job.\n- `--per-page` -- Cap the search result count (1–100, server default 10).\n- `--json` -- Emit a single JSON document `{\"tests\": [...]}` to stdout.\n\n**Exit codes:**\n- `0` -- Tests rendered, or no match at all. Health does **not** affect it.\n- `6` -- Mergify API error, including the `403` a `ci` key gets here.\n\n## Tests Quarantines Add (`tests quarantines add`)\n\nAdds a test to the repository's CI Insights quarantine, so its failures stop\nblocking the CI verdict. Takes a single fully qualified test name; a `--reason`\nis required.\n\nNeeds an `admin` key or a GitHub PAT — a `ci` key gets a `403`. See\n[Authentication](#authentication).\n\n```bash\n# Quarantine on all branches.\nmergify tests quarantines add -r owner/repo \\\n --reason 'flaky — tracked in MRGFY-1234' \\\n 'test_login'\n\n# Scope the quarantine to one branch (or branch pattern), JSON output.\nmergify tests quarantines add -r owner/repo \\\n --reason 'broken on release branch' --branch 'release/*' --json \\\n 'test_logout'\n```\n\n**Key options:**\n- `--repository` / `-r` -- Repository full name (`owner/repo`); auto-detected from the CI environment or the local git remote when omitted.\n- `--reason` -- Reason recorded for the quarantine; required.\n- `--branch` / `-b` -- Branch name or pattern to scope to. Omit for all branches.\n- `--token` / `-t` (env: `MERGIFY_TOKEN`) -- Mergify credential. Falls back to the credential `mergify auth login` stored, then to `GITHUB_TOKEN` / `gh auth token`, both deprecated for the Mergify API.\n- `--api-url` / `-u` (env: `MERGIFY_API_URL`) -- API base URL.\n- `--json` -- Emit `{\"id\", \"test_name\", \"reason\", \"branch\"}` to stdout.\n\n**Exit codes:**\n- `0` -- Test quarantined.\n- `6` -- Mergify API error (e.g. the test is already quarantined).\n\n## Tests Quarantines Remove (`tests quarantines remove`)\n\nRemoves a test from the quarantine. Accepts either the fully qualified test\nname (resolved to its quarantine id via the list endpoint) or the quarantine\nid directly (as printed by `tests quarantines add`). A UUID-shaped argument\nis treated as the id and deleted without a lookup.\n\nNeeds an `admin` key or a GitHub PAT — a `ci` key gets a `403`. See\n[Authentication](#authentication).\n\n```bash\n# By test name.\nmergify tests quarantines remove -r owner/repo 'test_login'\n\n# By quarantine id (the value `tests quarantines add` printed).\nmergify tests quarantines remove -r owner/repo 12345678-1234-5678-1234-567812345678\n```\n\n**Key options:**\n- `--repository` / `-r` -- Repository full name (`owner/repo`); auto-detected from the CI environment or the local git remote when omitted.\n- `--token` / `-t` (env: `MERGIFY_TOKEN`) -- Mergify credential. Falls back to the credential `mergify auth login` stored, then to `GITHUB_TOKEN` / `gh auth token`, both deprecated for the Mergify API.\n- `--api-url` / `-u` (env: `MERGIFY_API_URL`) -- API base URL.\n- `--json` -- Emit `{\"id\", \"test_name\"}` to stdout (`test_name` is null when\n addressed by id).\n\n**Exit codes:**\n- `0` -- Test unquarantined.\n- `6` -- Mergify API error (e.g. the test is not quarantined).\n\n## Tests Quarantines Get (`tests quarantines get`)\n\nPrints a single quarantine, addressed by the fully qualified test name or the\nquarantine id (a UUID-shaped argument is matched against the id). The output\nmirrors one record of `tests quarantines list`.\n\n```bash\n# By test name.\nmergify tests quarantines get -r owner/repo 'test_login'\n\n# By quarantine id, JSON output.\nmergify tests quarantines get -r owner/repo --json \\\n 12345678-1234-5678-1234-567812345678\n```\n\n**Key options:**\n- `--repository` / `-r` -- Repository full name (`owner/repo`); auto-detected from the CI environment or the local git remote when omitted.\n- `--token` / `-t` (env: `MERGIFY_TOKEN`) -- Mergify credential. Falls back to the credential `mergify auth login` stored, then to `GITHUB_TOKEN` / `gh auth token`, both deprecated for the Mergify API.\n- `--api-url` / `-u` (env: `MERGIFY_API_URL`) -- API base URL.\n- `--json` -- Emit the record (`id`, `test_name`, `reason`, `branch`, `created_at`,\n `source`, `is_recovered`) to stdout.\n\n**Exit codes:**\n- `0` -- Quarantine found and printed.\n- `6` -- Mergify API error (e.g. no matching quarantine).\n\n## Tests Quarantines List (`tests quarantines list`)\n\nLists every test currently in the repository's CI Insights quarantine. Takes no\ntest argument -- it prints the whole quarantine. Human output is one indented\nblock per record -- the test name on its own line (never wrapped mid-name),\nthen its id (the value `delete` accepts), branch, source, recovered, and\nreason. `--json` emits the full records.\n\n```bash\n# Human output (one block per record).\nmergify tests quarantines list -r owner/repo\n\n# JSON for jq -- e.g. names of quarantines an auto-recover run flagged.\nmergify tests quarantines list -r owner/repo --json \\\n | jq -r '.quarantined_tests[] | select(.is_recovered) | .test_name'\n```\n\nA null `branch` renders as `*` (the quarantine applies to all branches).\n`source` is `manual` (added by a user) or `auto` (added by flaky detection).\n`is_recovered` flags quarantines whose recent runs suggest they can be removed.\n\n**Key options:**\n- `--repository` / `-r` -- Repository full name (`owner/repo`); auto-detected from the CI environment or the local git remote when omitted.\n- `--token` / `-t` (env: `MERGIFY_TOKEN`) -- Mergify credential. Falls back to the credential `mergify auth login` stored, then to `GITHUB_TOKEN` / `gh auth token`, both deprecated for the Mergify API.\n- `--api-url` / `-u` (env: `MERGIFY_API_URL`) -- API base URL.\n- `--json` -- Emit `{\"quarantined_tests\": [...]}` to stdout, each record carrying\n `id`, `test_name`, `reason`, `branch`, `created_at`, `source`, `is_recovered`.\n\n**Exit codes:**\n- `0` -- Always, including an empty quarantine (\"No quarantined tests found.\").\n\n## Queue Info (`queue-info`)\n\nOutputs the current build's merge queue batch metadata as JSON. Reads the `refs/notes/mergify/<branch>` git note Mergify writes on the merge queue branch head for the current `HEAD`; exits `INVALID_STATE` (7) when no note is found (i.e. not a merge queue batch build). Takes no arguments and needs no GitHub token.\n\nThe note's full payload is emitted verbatim (every field Mergify wrote, e.g. `checking_base_sha`, `pull_requests` with per-PR `scopes`, `previous_failed_batches`, top-level `scopes`). New fields appear automatically without a CLI update, so don't assume a fixed schema.\n\n```bash\n# In CI, on a merge queue batch build. Works in any CI (GitHub Actions,\n# GitLab, CircleCI, Jenkins, ...) with plain git. When GITHUB_OUTPUT is\n# set (GitHub Actions runner) it also writes the metadata there.\nmergify ci queue-info\n```\n\nMergify attaches the batch metadata as a git note to the MQ branch head commit, so reading it needs only git, no PR body and no GitHub token. The command runs `git fetch origin \"refs/notes/mergify/*\"` itself (notes aren't fetched by default), then returns the note attached to `HEAD`. Requirements: the `origin` remote is reachable and the checkout is at the MQ branch head commit, which is the normal state inside a merge-queue CI run. A detached HEAD is fine.\n\nThis command is useful in CI workflows that need to know whether the current run is part of a merge queue batch and what other PRs are in the batch.\n\n## Common Patterns\n\n### Full CI pipeline with quarantine\n```yaml\njobs:\n test:\n steps:\n - uses: actions/checkout@v4\n - name: Run tests\n run: pytest --junitxml=results.xml\n - name: Upload and evaluate\n if: always()\n run: mergify ci junit-process results.xml\n env:\n MERGIFY_TOKEN: ${{ secrets.MERGIFY_TOKEN }}\n```\n\n### Selective testing with scopes\n```yaml\njobs:\n detect:\n outputs:\n scopes: ${{ steps.scopes.outputs.scopes }}\n steps:\n - uses: actions/checkout@v4\n with:\n fetch-depth: 0\n - id: scopes\n run: mergify ci scopes --config .mergify.yml\n\n backend:\n needs: detect\n if: fromJSON(needs.detect.outputs.scopes).backend == 'true'\n steps:\n - run: pytest backend/\n```\n"
}SHA-256: 3abb45ee8d253e7112322b7e5fb9cf7633bec98e02e559e072423727f9964cc4