diff --git a/.claude/skills/docs-from-code/SKILL.md b/.claude/skills/docs-from-code/SKILL.md index fb5b0feea1..18a939977c 100644 --- a/.claude/skills/docs-from-code/SKILL.md +++ b/.claude/skills/docs-from-code/SKILL.md @@ -84,6 +84,11 @@ Input: a feature — a PR number, or a code area / config key. docs repo, never add it to `.gitignore` (keep it in the scratch dir). - Document the user-facing contract, not implementation details. Code is the source of truth for *what is true*, not for *how to say it*. +- **The clone is private. Nothing that identifies it may reach the docs** — no + `Mergifyio/monorepo` references, no `mergify_engine/...` paths, no internal + module or function names, no `file:line` citations. Cite the code in your + *report* to the user, never in the page. See `proofread-leaks` and the + "Never Publish Internal Information" section of AGENTS.md. - When code and a doc disagree, the code wins for facts (defaults, enums, behavior) — but if you cannot tell whether a difference is intentional, flag it rather than "fixing" it. diff --git a/.claude/skills/docs-gap-analysis/SKILL.md b/.claude/skills/docs-gap-analysis/SKILL.md index 544c3e8dc7..aff3eb62c6 100644 --- a/.claude/skills/docs-gap-analysis/SKILL.md +++ b/.claude/skills/docs-gap-analysis/SKILL.md @@ -89,6 +89,9 @@ Create a todo for each step. target. - Don't flag internal/refactor PRs as doc gaps. Only user-facing capability changes count. +- The report is internal, the docs are not. Linear IDs, monorepo paths, and + customer names belong in the report and must never survive into a page written + from it — see `proofread-leaks`. - Be honest about uncertainty: if you can't tell whether something is documented, say "needs review" rather than asserting a gap. - The output is a plan, not edits. To actually write a page, hand the item to diff --git a/.claude/skills/document-a-feature/SKILL.md b/.claude/skills/document-a-feature/SKILL.md index 3f6c7f9d7b..23ce6cd820 100644 --- a/.claude/skills/document-a-feature/SKILL.md +++ b/.claude/skills/document-a-feature/SKILL.md @@ -47,6 +47,11 @@ Identify the source of truth for the feature: Establish: what the feature does, who uses it, the exact config/CLI/API surface, and any plan/tier gating. +Every one of these sources is internal. Take the *behavior* from them and leave +the *provenance* behind: no ticket or Linear IDs, no customer or org names, no +monorepo paths, no internal links. Read the "Never Publish Internal Information" +section of AGENTS.md before you write a line. + ## Step 2 — Place the page Read `references/placement-guide.md` for the full section map and decision rules. @@ -106,13 +111,15 @@ exact snippets. Run these before claiming the page is done: -1. **Proofread pipeline** — if total changed/added docs lines ≥ 10, spawn the 4 - proofread subagents in parallel per the repo CLAUDE.md (`proofread-style`, - `proofread-technical`, `proofread-structure`, `proofread-consistency`) on the - diff. -2. **Config examples** — if the page contains any YAML/`.mergify.yml` snippets, +1. **Leak check** — always, whatever the diff size: run + `pnpm check:internal-leaks` and the **proofread-leaks** subagent on the diff. +2. **Proofread pipeline** — if total changed/added docs lines ≥ 10, spawn the + other 4 proofread subagents in parallel per the repo CLAUDE.md + (`proofread-style`, `proofread-technical`, `proofread-structure`, + `proofread-consistency`) on the diff. +3. **Config examples** — if the page contains any YAML/`.mergify.yml` snippets, invoke the **validate-config-examples** skill. -3. **Build check** — run `pnpm check` (astro check + eslint + biome). Fix any +4. **Build check** — run `pnpm check` (astro check + eslint + biome). Fix any errors. For a final SSG sanity check, `pnpm build`. ## Hard rules diff --git a/.claude/skills/proofread-leaks/SKILL.md b/.claude/skills/proofread-leaks/SKILL.md new file mode 100644 index 0000000000..06153be3b1 --- /dev/null +++ b/.claude/skills/proofread-leaks/SKILL.md @@ -0,0 +1,202 @@ +--- +name: proofread-leaks +description: >- + Proofread documentation changes for leaked internal + information. Catches support ticket and thread IDs, + customer and org names, private repo paths, internal + URLs and dashboards, and credentials that came in + from the source material a page was written from. + Designed to run as a subagent on diffs of MDX files. +--- + +# Proofread: Internal Information Leaks + +You are a proofreading subagent. Your job is to make +sure nothing internal ended up in published +documentation. + +Docs are usually written *from* internal material: a +support case, a private PR, an engine source file, a +Linear ticket. That material travels with the draft. +The reader never needs to know where a page came +from, so anything that only describes the *provenance* +of a doc is a leak, not context. + +This check is different from the other proofreaders in +two ways: it runs on **every** docs change regardless +of size, and it covers **code blocks, comments, +frontmatter, alt text, and image contents** — not just +prose. + +## What You Receive + +You will be given a diff or list of changed MDX files +in `src/content/docs/`. Review ONLY the changed/added +lines, including code fences and frontmatter. + +## What You Check + +### Never Publish + +1. **Support ticket and thread IDs.** Plain ticket + refs (`T-1234`), Plain thread IDs + (`th_01JQZK4M8XN2VR7TDY0P3WGA6H`), `app.plain.com` + links, or any equivalent from another helpdesk. + +2. **Customer, org, and account identifiers.** GitHub + org or repo names belonging to a customer, account + IDs, subscription IDs, Stripe customer or invoice + IDs, seat counts of a real account, email + addresses. + +3. **Private repositories and internal code paths.** + `Mergifyio/monorepo`, `mergify_shadow_office/...`, + `mergify_engine/...`, dashboard source paths, + internal module, class, or function names, and + file:line references into private code. + +4. **Internal URLs and tools.** Linear and Notion + links, internal dashboards and admin consoles, + staging or internal Mergify hostnames, cloud + consoles, internal runbooks. + +5. **Credentials.** Real tokens, API keys, private + keys, or webhook secrets. Placeholders like + `ghp_*` or `` are fine; anything that + could be a live secret is not. + +6. **Internal-only framing.** Employee names in an + internal context, quotes from a support + conversation, "as discussed with the customer", + references to unreleased work, or an explanation + that only makes sense if you have read the ticket. + +### Signals a Leak Is Nearby + +Read these lines extra carefully: + +- Anything that explains *why* the page was written, + or that names a specific incident. +- Examples that look copied rather than constructed — + a real-looking org name, a specific date, an odd + number of contributors, a plausible invoice amount. +- "For example, one customer…" openers. +- YAML examples whose `repository`, `owner`, or + `login` values are not obvious placeholders. +- Screenshots and their alt text: a dashboard capture + can show a real org name, a customer's repo list, or + an email address. + +### What Is Fine + +- Public Mergify repos (`Mergifyio/mergify`, + `Mergifyio/gha-mergify-ci`), public product URLs + (`dashboard.mergify.com`, `docs.mergify.com`). +- Public docs of third parties, including their + dashboards (`app.datadoghq.com`, GitHub settings + pages) when the reader is meant to go there. +- Generic placeholders: `my-org`, `your-repo`, + ``, `user@example.com`. +- Product behavior learned from a private source. The + *fact* is publishable; the *source* is not. + +## How to Verify + +1. **Run the deterministic scan first.** It catches + the mechanical patterns in seconds: + + ```bash + pnpm check:internal-leaks + ``` + + It only knows fixed patterns. Customer names, copied + examples, and internal framing are yours to catch — + do not treat a clean run as a pass. + +2. **Re-read every added example.** For each org name, + repo name, number, and URL in the diff, ask: could + this be real? If you cannot tell, replace it with an + obvious placeholder. + +3. **Check the source you wrote from.** If a ticket, a + private PR, or an engine file was in your context, + grep the diff for its identifiers. + +4. **Open added screenshots** and look at the pixels, + not just the filename. + +## How You Fix + +Rewrite so the page states the product behavior and +drops the provenance. Removing the sentence is usually +wrong — the behavior is why the page exists. + +Leak: + +```text +Customer acme-corp (ticket T-1234) cancelled mid-period +and still received an invoice, because prorations are +collected on the next invoice (see +mergify_shadow_office/models/billing.py). +``` + +Fixed: + +```text +If you cancel mid-period, you may still receive an +invoice on the last day of the period. It collects the +prorations recorded during the period, so it is a +true-up rather than a renewal. +``` + +## How You Report + +1. **Always fix, never only flag.** A leak is the one + class of issue you must not leave in the file for + someone else. Redact or rewrite it, then report it. + +2. **Report every removal explicitly**, so a human can + judge whether the value also needs scrubbing from + the branch history or from an already-published + page: + + ```text + LEAK: [file:line] — [what kind] — removed/replaced with [what] + ``` + +3. **Escalate what you cannot judge.** If you cannot + tell whether a name is a real customer, do not + guess. Replace it with a placeholder and say so: + + ```text + CHECK: [file:line] — replaced "acme-corp" with "my-org"; confirm it was not a real customer + ``` + +4. **Follow-up suggestions:** If you spot a probable + leak in surrounding UNCHANGED content, note it + rather than editing: + + ```text + FOLLOW-UP: [file:line] — [description] + ``` + + Say so in your summary even if the diff was clean. + An already-published leak is more urgent than one + you just caught. + +## Scope + +- Review changed/added content in MDX files under + `src/content/docs/`, plus any image added alongside + them. + +- Do NOT edit `src/content/changelog/` — those files + are autogenerated. Report a leak there as a + FOLLOW-UP so a human can fix it upstream. + +- Fix leaks and nothing else. Leave style, structure, + and terminology to the other proofreaders. + +- When you are unsure whether something is internal, + treat it as internal. A placeholder costs the reader + nothing; a leaked identifier cannot be unpublished. diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 68c698688f..4161d55370 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -86,6 +86,23 @@ jobs: pnpm install --frozen-lockfile pnpm check:config-examples + internal-leaks: + timeout-minutes: 5 + runs-on: ubuntu-24.04 + steps: + - name: Checkout 🛎️ + uses: actions/checkout@v7.0.1 + + - name: Setup Node 🔧 + uses: actions/setup-node@v7.0.0 + with: + node-version-file: .node-version + + # No dependencies needed: the scanner is plain Node. Its own unit tests + # run in the `test` job. + - name: Check for leaked internal information + run: node scripts/check-internal-leaks.mjs + build: timeout-minutes: 20 runs-on: ubuntu-24.04 diff --git a/AGENTS.md b/AGENTS.md index 1945a203f4..d482317cc0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -40,6 +40,9 @@ pnpm format:check # Check formatting without modifying # Testing pnpm test # Run Vitest unit tests ./scripts/detect-broken-links.sh # Check for broken links + +# Safety +pnpm check:internal-leaks # Scan docs for leaked internal information ``` ## Key Directories @@ -147,6 +150,55 @@ Do NOT use regular `git push` - always use `mergify stack push`. option's own reference page (matching existing action pages) is acceptable; dated migration notices are not. +8. **Never publish internal information** - Ticket IDs, customer names, private + repo paths, internal links, and credentials must never reach + `src/content/docs/`. See the section below; it applies to every change, with + no size threshold. + +## Never Publish Internal Information + +Docs are usually written *from* internal material: a support case, a private PR, +an engine source file, a Linear ticket. That material travels with the draft. +The reader never needs to know where a page came from, so anything describing +the *provenance* of a doc is a leak, not context. A leaked identifier cannot be +unpublished. + +**Never write any of these into `src/content/docs/`** - prose, code blocks, +comments, frontmatter, alt text, or screenshots: + +- **Support ticket and thread IDs** - Plain refs (`T-1234`), thread IDs + (`th_01JQ...`), `app.plain.com` links, or the equivalent from any helpdesk. +- **Customer, org, and account identifiers** - a customer's GitHub org or repo, + account and subscription IDs, Stripe customer or invoice IDs, email addresses, + real seat or contributor counts. +- **Private repositories and internal code paths** - `Mergifyio/monorepo`, + `mergify_shadow_office/...`, `mergify_engine/...`, dashboard source paths, + internal module or function names, `file:line` references into private code. +- **Internal URLs and tools** - Linear and Notion links, admin consoles, + internal dashboards, staging or internal Mergify hostnames, runbooks. +- **Credentials** - real tokens, API keys, private keys, webhook secrets. + Placeholders (`ghp_*`, ``) are fine. +- **Internal-only framing** - employee names in an internal context, quotes from + a support conversation, "as discussed with the customer", unreleased work, or + an explanation that only makes sense if you read the ticket. + +The fix is almost never deletion. State the product behavior and drop the +provenance: "customer acme-corp on ticket T-1234 was billed after cancelling" +becomes "if you cancel mid-period, a final invoice may still arrive on the last +day of the period." + +**Enforcement**, in order of what catches what: + +1. `pnpm check:internal-leaks` - deterministic scan for the mechanical patterns + (ticket IDs, internal paths, internal trackers and hosts). Run it before + committing any docs change. It also runs in CI. It cannot catch customer + names, copied examples, or internal framing, so a clean run is not a pass. +2. The `proofread-leaks` subagent - judgment-level review of the diff. **Unlike + the other proofreaders, this one runs on every docs change**, including + sub-10-line edits, frontmatter-only edits, and code-block-only edits. +3. If something internal did reach a commit, say so plainly instead of quietly + amending it. A value that was pushed may need scrubbing beyond the branch. + ## Documentation Proofreading After editing MDX files in `src/content/docs/`, if the @@ -160,7 +212,7 @@ pipeline before considering the work done. MDX files in `src/content/docs/` (use `git diff` for staged/unstaged changes). -2. **Spawn 4 proofreading subagents in parallel** +2. **Spawn 5 proofreading subagents in parallel** using the Agent tool, each with the diff and the list of changed files: - Style (`proofread-style`): AI patterns, banned @@ -175,6 +227,9 @@ pipeline before considering the work done. - Consistency (`proofread-consistency`): terminology drift, capitalization, naming + - Leaks (`proofread-leaks`): ticket IDs, customer + names, private paths, internal links, secrets + 3. **Each subagent:** - Reads the skill with the Skill tool for its full guidelines @@ -215,6 +270,14 @@ When spawning each subagent, include: ### When to Skip +**`proofread-leaks` is never skipped.** None of the +conditions below apply to it: a leaked ticket ID is +usually a one-line change, and it hides in code blocks +and frontmatter as readily as in prose. Run it, plus +`pnpm check:internal-leaks`, on every docs change. + +The other four are skipped when: + - Changes are fewer than 10 lines of docs content - Changes are ONLY to frontmatter metadata diff --git a/package.json b/package.json index a1ae7f1d2d..5cdb92e0b6 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "format:check": "biome format src integrations plugins scripts", "check": "astro check && eslint . && biome check .", "check:config-examples": "node scripts/validate-config-examples.mjs", + "check:internal-leaks": "node scripts/check-internal-leaks.mjs", "check:links": "linkinator dist/ --recurse --concurrency 25 --verbosity error --skip 'https?://'" }, "devDependencies": { diff --git a/scripts/check-internal-leaks.mjs b/scripts/check-internal-leaks.mjs new file mode 100644 index 0000000000..11ba7d944a --- /dev/null +++ b/scripts/check-internal-leaks.mjs @@ -0,0 +1,160 @@ +#!/usr/bin/env node +/** + * Scan the docs for internal information that must never be published: support + * ticket and thread IDs, private repository and source paths, and internal + * tracker links. + * + * Docs are frequently written *from* internal material — a support case, a + * private PR, an engine source file — and that material travels with the draft. + * This catches the mechanical half of the problem so a leak fails CI instead of + * shipping to docs.mergify.com. + * + * It only knows fixed patterns. Customer and org names, copied examples, and + * "as discussed with the customer" framing cannot be regexed; those are the + * `proofread-leaks` skill's job. A clean run here is not a clean bill of health. + * + * Usage: + * node scripts/check-internal-leaks.mjs [paths...] # scan (default: src/content/docs) + * node scripts/check-internal-leaks.mjs --json [paths...] + * + * False positives are expected to be rare enough to handle one at a time. To + * allow a specific line, put a comment on the line before it naming the rule: + * + * {/* internal-leaks: allow internal-source-path — documenting the OSS engine layout *\/} + * + * In YAML or shell fences, use `# internal-leaks: allow — why`. + */ + +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const ROOT = path.resolve(fileURLToPath(import.meta.url), '..', '..'); +const DEFAULT_TARGETS = ['src/content/docs']; +const SCANNED_EXTENSIONS = ['.mdx', '.md']; + +/** + * Each rule is deliberately narrow: it must not fire on anything already in the + * docs, or on the placeholders docs legitimately use (`my-org`, `your-repo`). + * Public Mergify repos, `dashboard.mergify.com`, and third-party dashboards the + * reader is meant to visit are all fine and must not match. + */ +export const RULES = [ + { + id: 'support-ticket', + label: 'support ticket or thread ID', + re: /\bT-\d{3,6}\b|\bth_[0-9A-Za-z]{16,}\b|\bapp\.plain\.com\b/g, + }, + { + id: 'internal-source-path', + label: 'private repository or internal source path', + re: /\bmergify_shadow_office\b|\bshadow[-_ ]office\b|\bMergifyio\/monorepo\b|\bmergify_engine\b/gi, + }, + { + id: 'internal-tracker', + label: 'internal tracker or wiki link', + re: /\blinear\.app\/|\.notion\.so\/|\bnotion\.site\//gi, + }, + { + id: 'internal-host', + label: 'internal Mergify hostname', + re: /\b(?:admin|internal|staging|shadow(?:-office)?)\.mergify\.(?:com|io)\b/gi, + }, +]; + +const ALLOW_RE = /internal-leaks:\s*allow\s+([\w-]+)/i; + +/** Rule IDs allowed by a directive on the line above `index` (0-based). */ +function allowedOnLine(lines, index) { + const allowed = new Set(); + for (let p = index - 1; p >= 0; p -= 1) { + if (!lines[p].trim()) continue; + const m = lines[p].match(ALLOW_RE); + if (m) allowed.add(m[1].toLowerCase()); + break; + } + return allowed; +} + +/** Scan text; returns [{line, rule, label, match}, ...]. */ +export function scanText(text, rules = RULES) { + const lines = text.split('\n'); + const findings = []; + lines.forEach((line, i) => { + let allowed = null; + for (const rule of rules) { + rule.re.lastIndex = 0; + const matches = line.match(rule.re); + if (!matches) continue; + allowed ??= allowedOnLine(lines, i); + if (allowed.has(rule.id)) continue; + for (const match of new Set(matches)) { + findings.push({ line: i + 1, rule: rule.id, label: rule.label, match }); + } + } + }); + return findings; +} + +export function scanFile(file, rules = RULES) { + return scanText(fs.readFileSync(file, 'utf8'), rules).map((f) => ({ + ...f, + file: path.relative(ROOT, file), + })); +} + +export function* iterFiles(targets) { + for (const t of targets) { + const abs = path.resolve(ROOT, t); + const stat = fs.statSync(abs); + if (stat.isDirectory()) { + for (const entry of fs.readdirSync(abs, { withFileTypes: true, recursive: true })) { + if (entry.isFile() && SCANNED_EXTENSIONS.some((ext) => entry.name.endsWith(ext))) { + yield path.join(entry.parentPath ?? entry.path, entry.name); + } + } + } else if (SCANNED_EXTENSIONS.some((ext) => abs.endsWith(ext))) { + yield abs; + } + } +} + +function main(argv) { + const jsonMode = argv.includes('--json'); + const targets = argv.filter((a) => a !== '--json'); + if (targets.length === 0) targets.push(...DEFAULT_TARGETS); + + const findings = []; + let scanned = 0; + for (const file of iterFiles(targets)) { + scanned += 1; + findings.push(...scanFile(file)); + } + + if (jsonMode) { + process.stdout.write(`${JSON.stringify(findings, null, 2)}\n`); + return findings.length === 0 ? 0 : 1; + } + + console.log(`Scanned ${scanned} file(s) for internal information.`); + if (findings.length === 0) { + console.log('No internal identifiers found.'); + return 0; + } + console.error(`\n${findings.length} possible leak(s):\n`); + for (const f of findings) { + console.error(` ${f.file}:${f.line} — ${f.label} — ${f.match}`); + } + console.error( + '\nRewrite the line so it states the product behavior without the internal\n' + + 'identifier (see .claude/skills/proofread-leaks). If a match is genuinely\n' + + 'public, allow it on the line above:\n' + + ' {/* internal-leaks: allow — why */}' + ); + return 1; +} + +// Run as a CLI only when invoked directly, so tests can import the helpers. +if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + process.exit(main(process.argv.slice(2))); +} diff --git a/scripts/check-internal-leaks.test.mjs b/scripts/check-internal-leaks.test.mjs new file mode 100644 index 0000000000..7ef01d2552 --- /dev/null +++ b/scripts/check-internal-leaks.test.mjs @@ -0,0 +1,76 @@ +import { describe, expect, it } from 'vitest'; +import { iterFiles, scanFile, scanText } from './check-internal-leaks.mjs'; + +const rulesOf = (text) => scanText(text).map((f) => f.rule); + +describe('scanText', () => { + it('catches support ticket and thread identifiers', () => { + expect(rulesOf('See ticket T-1234 for details.')).toEqual(['support-ticket']); + expect(rulesOf('thread th_01JQZK4M8XN2VR7TDY0P3WGA6H')).toEqual(['support-ticket']); + expect(rulesOf('https://app.plain.com/workspace/x')).toEqual(['support-ticket']); + }); + + it('catches private repositories and internal source paths', () => { + expect(rulesOf('mergify_shadow_office/models/billing.py')).toEqual(['internal-source-path']); + expect(rulesOf('cloned from Mergifyio/monorepo')).toEqual(['internal-source-path']); + expect(rulesOf('engine/mergify_engine/rules/config.py')).toEqual(['internal-source-path']); + }); + + it('catches internal trackers and hostnames', () => { + expect(rulesOf('https://linear.app/mergifyio/issue/MRGFY-1')).toEqual(['internal-tracker']); + expect(rulesOf('https://www.notion.so/mergify/runbook')).toEqual(['internal-tracker']); + expect(rulesOf('https://admin.mergify.com/orgs')).toEqual(['internal-host']); + }); + + it('leaves public Mergify and third-party references alone', () => { + expect(rulesOf('https://github.com/Mergifyio/mergify/discussions')).toEqual([]); + expect(rulesOf('the `mergifyio/gha-mergify-ci` action')).toEqual([]); + expect(rulesOf('https://dashboard.mergify.com/ci-insights')).toEqual([]); + expect(rulesOf('https://app.datadoghq.com/integrations?search=mergify')).toEqual([]); + expect(rulesOf('owner: my-org\nrepository: your-repo')).toEqual([]); + // The docs document token prefixes as placeholders; those must not fire. + expect(rulesOf('Use a classic `ghp_*` or fine-grained `github_pat_*` token.')).toEqual([]); + expect(rulesOf('Authorization: Bearer ')).toEqual([]); + }); + + it('reports the line number and the matched text', () => { + const findings = scanText('intro\n\nsee T-1234 now\n'); + expect(findings).toEqual([ + { line: 3, rule: 'support-ticket', label: 'support ticket or thread ID', match: 'T-1234' }, + ]); + }); + + it('honors an allow directive naming the rule on the previous line', () => { + expect(rulesOf('{/* internal-leaks: allow support-ticket — public */}\nT-1234\n')).toEqual([]); + expect(rulesOf('# internal-leaks: allow internal-tracker — public\nlinear.app/x\n')).toEqual( + [] + ); + // The directive is scoped: it only allows the rule it names. + expect(rulesOf('{/* internal-leaks: allow internal-tracker */}\nT-1234\n')).toEqual([ + 'support-ticket', + ]); + // ...and only the next non-blank line. + expect(rulesOf('{/* internal-leaks: allow support-ticket */}\nfine\nT-1234\n')).toEqual([ + 'support-ticket', + ]); + }); +}); + +describe('published docs', () => { + it('contain no internal information', () => { + const findings = []; + let scanned = 0; + for (const file of iterFiles(['src/content/docs'])) { + scanned += 1; + findings.push(...scanFile(file)); + } + if (findings.length) { + const detail = findings + .map((f) => `${f.file}:${f.line} — ${f.label} — ${f.match}`) + .join('\n'); + throw new Error(`Internal information found in published docs:\n${detail}`); + } + // Sanity: the scan actually walked the docs tree. + expect(scanned).toBeGreaterThan(50); + }); +}); diff --git a/src/content/docs/workflow/actions.mdx b/src/content/docs/workflow/actions.mdx index 90e472f95c..c7da5f1572 100644 --- a/src/content/docs/workflow/actions.mdx +++ b/src/content/docs/workflow/actions.mdx @@ -9,13 +9,11 @@ import DocsetGrid from '../../../components/DocsetGrid/DocsetGrid.astro'; Actions are the engine that powers Mergify. They define what Mergify should do when a set of conditions is met. This can range from merging a pull request, updating it with the latest changes, commenting on the pull request, assigning -it to a user, adding labels, and so much more. +it to a user, adding labels, and more. -In essence, actions are the tasks that Mergify performs on your behalf to -automate your pull request management workflow. By carefully crafting and -combining actions, you can create a highly efficient and automated process -that takes care of most of the routine tasks associated with pull request -management. +Actions are the tasks that Mergify performs on your behalf. By combining +actions, you can automate most of the routine tasks associated with pull +request management. @@ -34,7 +32,7 @@ management. Post a comment on a pull request. - Deprecated — use GitHub's built-in "Automatically delete head branches" setting instead. + Deprecated. Use GitHub's built-in "Automatically delete head branches" setting instead. Dismiss previous reviews on a pull request. @@ -43,7 +41,7 @@ management. Convert a pull request to or from a draft. - Deprecated — start your workflows from GitHub Actions events instead. + Deprecated. Start your workflows from GitHub Actions events instead. Add, remove, or toggle labels on a pull request. @@ -52,7 +50,7 @@ management. Automate the merging of your pull requests. - Deprecated — use Merge Protections instead. + Deprecated. Use Merge Protections instead. Add the pull request to the merge queue. diff --git a/src/content/docs/workflow/actions/assign.mdx b/src/content/docs/workflow/actions/assign.mdx index 9babd0b64c..4c1f1d7af5 100644 --- a/src/content/docs/workflow/actions/assign.mdx +++ b/src/content/docs/workflow/actions/assign.mdx @@ -8,9 +8,7 @@ import ActionOptionsTable from '../../../../components/Tables/ActionOptionsTable The `assign` action allows you to assign one or more users to a pull request when the conditions you specify are met. This can help automate the process of designating the right people to handle specific pull requests, based on your -conditions. This can significantly streamline your pull request management -process and ensure that the right people are always aware of and working on the -pull requests that require their attention. +conditions. ## Parameters diff --git a/src/content/docs/workflow/actions/backport.mdx b/src/content/docs/workflow/actions/backport.mdx index e01c95f240..fe403c6306 100644 --- a/src/content/docs/workflow/actions/backport.mdx +++ b/src/content/docs/workflow/actions/backport.mdx @@ -10,7 +10,7 @@ The `backport` action enables you to automatically create a backport of a merged pull request. When the conditions you specify are met, Mergify will create a new pull request to merge the changes into the specified base branch. -The `backport` action is extremely useful for maintaining older versions of +The `backport` action is useful for maintaining older versions of your project. It helps automate the process of applying bug fixes or other changes from the main branch to other branches. @@ -123,6 +123,6 @@ defaults: ``` :::note - Pull request author will need to log at least once in the Mergify dashboard - for a pull request to be created on their behalf. + The pull request author will need to log in to the Mergify dashboard at + least once for a pull request to be created on their behalf. ::: diff --git a/src/content/docs/workflow/actions/close.mdx b/src/content/docs/workflow/actions/close.mdx index 870c782359..0a7211c361 100644 --- a/src/content/docs/workflow/actions/close.mdx +++ b/src/content/docs/workflow/actions/close.mdx @@ -15,10 +15,10 @@ want to ensure that certain types of pull requests are not merged. ## Examples -### Automatically close pull request touching a file +### Automatically close pull requests touching a file -If you wanted to automatically close pull request that touches a certain file, -let's say `do_not_touch.txt`, you could write a rule such as: +If you want to automatically close any pull request that touches a certain +file, let's say `do_not_touch.txt`, you could write a rule such as: ```yaml pull_request_rules: diff --git a/src/content/docs/workflow/actions/comment.mdx b/src/content/docs/workflow/actions/comment.mdx index ff4d4e29b7..1c95e0ed22 100644 --- a/src/content/docs/workflow/actions/comment.mdx +++ b/src/content/docs/workflow/actions/comment.mdx @@ -8,10 +8,8 @@ import ActionOptionsTable from '../../../../components/Tables/ActionOptionsTable The `comment` action allows Mergify to post a comment on your pull request when certain conditions are met. -The comment action is a powerful tool that can provide automated responses to -various events in your pull request workflow. By customizing the conditions and -the message, you can create a more interactive and responsive experience for -your contributors. +The comment action can provide automated responses to events in your pull +request workflow, based on the conditions and message you customize. ## Parameters @@ -42,7 +40,7 @@ notified automatically by Mergify. You can do this using this rule: ```yaml pull_request_rules: - - name: comment when a pull request is merged + - name: comment when a pull request is in conflict conditions: - conflict actions: diff --git a/src/content/docs/workflow/actions/delete_head_branch.mdx b/src/content/docs/workflow/actions/delete_head_branch.mdx index eece8b29c3..7f8aa9557d 100644 --- a/src/content/docs/workflow/actions/delete_head_branch.mdx +++ b/src/content/docs/workflow/actions/delete_head_branch.mdx @@ -6,8 +6,8 @@ description: Delete pull request head branch. Deprecated in favor of GitHub's bu import ActionOptionsTable from '../../../../components/Tables/ActionOptionsTable'; :::danger - The `delete_head_branch` action is **deprecated** and will be removed on - June 30, 2026. Use GitHub's built-in + The `delete_head_branch` action is **deprecated** and will be removed in a + future release. Use GitHub's built-in [automatically delete head branches][gh-auto-delete] setting instead. ::: @@ -38,7 +38,4 @@ In this example, Mergify will automatically delete the head branch of a pull request once it has been merged, but only if the pull request has been labeled with "cleanup". -The `delete_head_branch` action is a simple yet powerful tool that can help -maintain the cleanliness and organization of your repository. - [gh-auto-delete]: https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-the-automatic-deletion-of-branches diff --git a/src/content/docs/workflow/actions/dismiss_reviews.mdx b/src/content/docs/workflow/actions/dismiss_reviews.mdx index e945b0c2d8..3ecb4bd638 100644 --- a/src/content/docs/workflow/actions/dismiss_reviews.mdx +++ b/src/content/docs/workflow/actions/dismiss_reviews.mdx @@ -7,8 +7,6 @@ import ActionOptionsTable from '../../../../components/Tables/ActionOptionsTable The `dismiss_reviews` action allows Mergify to automatically dismiss approved or changes requested reviews when new commits are pushed to the pull request. -It is a powerful tool that can help maintain the freshness and relevance of -reviews in your pull request workflow. ## Parameters diff --git a/src/content/docs/workflow/actions/github_actions.mdx b/src/content/docs/workflow/actions/github_actions.mdx index 8d50e20fd4..74fed394e2 100644 --- a/src/content/docs/workflow/actions/github_actions.mdx +++ b/src/content/docs/workflow/actions/github_actions.mdx @@ -12,15 +12,13 @@ import OptionsTable from '../../../../components/Tables/OptionsTable'; [migration guide](/workflow/actions/migrate-github-actions). ::: -The `github_actions` action enables Mergify to seamlessly dispatch existing +The `github_actions` action enables Mergify to dispatch existing GitHub workflows within a repository when specified conditions are satisfied. -By integrating this action, users can optimize their CI/CD pipeline, invoking -specific GitHub Actions based on Mergify's conditions. :::note To use the `github_actions` action, ensure your workflow includes the - `workflow_dispatch` trigger. Additionally, Mergify requires write permissions - on Actions. Navigate to Mergify's UI to accept the permissions necessary for + `workflow_dispatch` trigger. Mergify also requires write permissions + on Actions. Go to Mergify's UI to accept the permissions necessary for this action. ::: diff --git a/src/content/docs/workflow/actions/label.mdx b/src/content/docs/workflow/actions/label.mdx index fd28ba0f26..f5af415a77 100644 --- a/src/content/docs/workflow/actions/label.mdx +++ b/src/content/docs/workflow/actions/label.mdx @@ -8,8 +8,7 @@ import { Image } from "astro:assets" import prConflictScreenshot from "../../../images/workflow/actions/label/conflict-pr-list.png" The `label` action allows Mergify to automatically add or remove labels from a -pull request based on the conditions specified in your rules, making your -workflow more organized and efficient. +pull request based on the conditions specified in your rules. :::caution **Avoid rule pairs that flip the same label.** If one rule adds a label and @@ -56,8 +55,8 @@ rule anymore, the label will be removed. ### Warn on Conflicts -When browsing the list of pull request, GitHub does not give any indication on -which pull requests might be in conflict. Mergify allows to do this easily by +When browsing the list of pull requests, GitHub does not give any indication on +which pull requests might be in conflict. Mergify lets you do this by adding a label. ```yaml @@ -79,7 +78,7 @@ Then, your pull request list will look like this on conflict: ### Toggle A Label Based on CI Status -This rule toggle a label based on the failure status of a CI system. +This rule toggles a label based on the failure status of a CI system. ```yaml pull_request_rules: diff --git a/src/content/docs/workflow/actions/merge.mdx b/src/content/docs/workflow/actions/merge.mdx index 45e099f884..5e51039577 100644 --- a/src/content/docs/workflow/actions/merge.mdx +++ b/src/content/docs/workflow/actions/merge.mdx @@ -8,21 +8,20 @@ import { Image } from "astro:assets" import branchProtectionConditionsScreenshot from "../../../images/workflow/actions/merge/branch-protections-injection.png" The `merge` action allows Mergify to automatically merge pull requests when -certain conditions are met. This can significantly streamline your workflow by -reducing the need for manual intervention. +certain conditions are met. This reduces the need for manual intervention. Whatever your conditions are, Mergify might inject extra conditions for the merge action to take place: - Mergify always respects the [branch protection settings](#branch-protection-conditions) -- Mergify always respect [pull request dependencies](#pull-request-dependencies) +- Mergify always respects [pull request dependencies](#pull-request-dependencies) -- Mergify always respect the [merge date](#merge-date) +- Mergify always respects the [merge date](#merge-date) -- Mergify allows merging pull request modifying its configuration file by +- Mergify allows merging pull requests that modify its configuration file by default. But Mergify will always check whether these changes are - valid or not, to avoid merging broken configurations. + valid, to avoid merging broken configurations. ## Branch Protection Conditions diff --git a/src/content/docs/workflow/actions/post_check.mdx b/src/content/docs/workflow/actions/post_check.mdx index afdca0cd38..fde0820612 100644 --- a/src/content/docs/workflow/actions/post_check.mdx +++ b/src/content/docs/workflow/actions/post_check.mdx @@ -5,7 +5,6 @@ description: Create a check-run on a pull request. Deprecated in favor of Merge import { Image } from 'astro:assets'; import ActionOptionsTable from '../../../../components/Tables/ActionOptionsTable'; -import Button from '../../../../components/Button.astro'; import PostCheckScreenshot from '../../../images/workflow/actions/post_check/post-check-actions.png'; :::danger @@ -54,7 +53,7 @@ merge_protections: ``` :::note - The `title` and `summary` options have no equivalent in merge protections + The `title` and `summary` options have no equivalent in Merge Protections and will be dropped during the automatic migration. ::: diff --git a/src/content/docs/workflow/actions/queue.mdx b/src/content/docs/workflow/actions/queue.mdx index e15f34c8b1..c2e45f584d 100644 --- a/src/content/docs/workflow/actions/queue.mdx +++ b/src/content/docs/workflow/actions/queue.mdx @@ -9,7 +9,7 @@ The `queue` action allows you to put a pull request into the [merge queue](/merge-queue). By placing pull requests in the queue, you can make sure they are up-to-date and control their processing based on their priority. -If you have enabled [`auto_merge`](/merge-protections/auto-merge) in +If you have enabled [`auto_merge_conditions`](/merge-protections/auto-merge) in `merge_protections_settings`, matching pull requests are added automatically and you usually do not need this action. Use the action when you want explicit, rule-driven or conditional enqueueing beyond what `queue_conditions` express. diff --git a/src/content/docs/workflow/actions/rebase.mdx b/src/content/docs/workflow/actions/rebase.mdx index 02eaead292..3e4c113998 100644 --- a/src/content/docs/workflow/actions/rebase.mdx +++ b/src/content/docs/workflow/actions/rebase.mdx @@ -17,8 +17,9 @@ up-to-date with the latest changes from the base branch. ::: :::caution - The `rebase` action with `bot_account` will no longer support fork pull - requests after **July 1, 2026**. If you use this configuration on + Support for the `rebase` action with `bot_account` on fork pull requests is + **deprecated** and will be removed in a future release. If you use this + configuration on repositories that receive PRs from forks, switch to the [`update` action](/workflow/actions/update) instead. ::: diff --git a/src/content/docs/workflow/actions/request_reviews.mdx b/src/content/docs/workflow/actions/request_reviews.mdx index de33ccc36f..10bb45d60c 100644 --- a/src/content/docs/workflow/actions/request_reviews.mdx +++ b/src/content/docs/workflow/actions/request_reviews.mdx @@ -10,7 +10,7 @@ or teams. This is useful when you want to ensure specific team members review certain pull requests. :::note - GitHub does not allow to request more than 15 users or teams for a review. + GitHub does not allow requesting more than 15 users or teams for a review. ::: ## Parameters diff --git a/src/content/docs/workflow/actions/review.mdx b/src/content/docs/workflow/actions/review.mdx index d4c3057f50..43cb3adf07 100644 --- a/src/content/docs/workflow/actions/review.mdx +++ b/src/content/docs/workflow/actions/review.mdx @@ -8,9 +8,7 @@ import ActionOptionsTable from '../../../../components/Tables/ActionOptionsTable The `review` action provides you with an automated way to review pull requests. This can be particularly useful in situations where you want to automatically approve pull requests that meet certain criteria, or to request changes on a -pull request when a particular check fails. By automating this process, you can -increase the efficiency of your workflow and ensure consistency in the way pull -requests are reviewed in your repository. +pull request when a particular check fails. ## Parameters @@ -37,15 +35,15 @@ checks have passed successfully. ### Approve Dependabot Pull Requests You can use Mergify to review a pull request on your behalf. This can be handy -if you require a minimum number of review to be present on a pull request +if you require a minimum number of reviews to be present on a pull request (e.g., due to [branch protection](https://docs.github.com/en/github/administering-a-repository/about-protected-branches)) -but want to automate some merge. +but want to automate some merges. -[Dependabot](https://github.com/features/security) is the bot behind GitHub -automatic security update. It sends automatic updates for your project's +[Dependabot](https://github.com/features/security) is the bot behind GitHub's +automatic security updates. It sends automatic updates for your project's dependencies, making sure they are secure. You can automate the approval of -pull request created by `dependabot` with a rule such as: +pull requests created by `dependabot` with a rule such as: ```yaml pull_request_rules: diff --git a/src/content/docs/workflow/actions/update.mdx b/src/content/docs/workflow/actions/update.mdx index 4a518bae5f..ed618f1ed0 100644 --- a/src/content/docs/workflow/actions/update.mdx +++ b/src/content/docs/workflow/actions/update.mdx @@ -48,8 +48,8 @@ pull_request_rules: As GitHub supports linear history in pull request settings, it is very handy to use a rule to keep your pull requests up-to-date. As you do not want to trigger -your CI too often by always re-running it on every pull request — especially -when there is still work in progress — you can limit this action to labeled +your CI too often by always re-running it on every pull request (especially +when there is still work in progress), you can limit this action to labeled pull requests. ```yaml