diff --git a/docs.json b/docs.json index 20d59dc..2698941 100644 --- a/docs.json +++ b/docs.json @@ -96,7 +96,8 @@ "merge-queue/using-the-queue/monitor-queue-status", "merge-queue/using-the-queue/handle-failed-pull-requests", "merge-queue/using-the-queue/stacked-pull-requests", - "merge-queue/using-the-queue/emergency-pull-requests" + "merge-queue/using-the-queue/emergency-pull-requests", + "merge-queue/using-the-queue/force-merge" ] }, { @@ -111,7 +112,8 @@ "pages": [ "merge-queue/administration", "merge-queue/administration/advanced-settings", - "merge-queue/administration/metrics" + "merge-queue/administration/metrics", + "merge-queue/administration/terraform" ] }, { @@ -198,13 +200,16 @@ "pages": [ "flaky-tests/detection", "flaky-tests/detection/pass-on-retry-monitor", - "flaky-tests/detection/threshold-monitor", + "flaky-tests/detection/failure-rate-monitor", "flaky-tests/detection/flag-as-flaky", "flaky-tests/infrastructure-failure-protection", "flaky-tests/the-importance-of-pr-test-results", "flaky-tests/quarantining", "flaky-tests/quarantine-service-availability", - "flaky-tests/github-pull-request-comments" + "flaky-tests/github-pull-request-comments", + "flaky-tests/test-labels", + "flaky-tests/autofix-flaky-tests", + "flaky-tests/autofix-ci-failures" ] }, { @@ -239,8 +244,11 @@ "flaky-tests/use-mcp-server/configuration/github-copilot-ide", "flaky-tests/use-mcp-server/configuration/claude-code-cli", "flaky-tests/use-mcp-server/configuration/gemini-cli", + "flaky-tests/use-mcp-server/configuration/bearer-auth", "flaky-tests/use-mcp-server/mcp-tool-reference", - "flaky-tests/use-mcp-server/mcp-tool-reference/get-root-cause-analysis", + "flaky-tests/use-mcp-server/mcp-tool-reference/fix-flaky-test", + "flaky-tests/use-mcp-server/mcp-tool-reference/search-test", + "flaky-tests/use-mcp-server/mcp-tool-reference/investigate-ci-failure", "flaky-tests/use-mcp-server/mcp-tool-reference/set-up-test-uploads" ] } @@ -258,6 +266,7 @@ "pages": [ "setup-and-administration/managing-your-organization", "setup-and-administration/github-app-permissions", + "setup-and-administration/trunk-sudo-app", "setup-and-administration/support", "setup-and-administration/billing", "setup-and-administration/security" diff --git a/flaky-tests/autofix-ci-failures.mdx b/flaky-tests/autofix-ci-failures.mdx new file mode 100644 index 0000000..069a509 --- /dev/null +++ b/flaky-tests/autofix-ci-failures.mdx @@ -0,0 +1,77 @@ +--- +title: "Autofix CI Failures" +description: "Automatically analyze and fix CI failures using AI agents and Trunk's MCP server" +--- +Trunk can return targeted information about CI failures, enabling AI agents and automation tools to analyze and fix issues automatically. + +### Prerequisites + +To use the Autofix CI Failures feature, you'll need to have: + +* Your repository set up to [upload test results to Trunk](/flaky-tests/get-started) + +### Cursor CI Autofix + +You can set up a [Cursor Automation](https://cursor.com/automations) to automatically fix CI failures by connecting to Trunk's CI failure investigation data via MCP. This is an extension of the Cursor `CI Autofix` template. + +Set up the Trunk MCP using [Bearer Authentication](/flaky-tests/use-mcp-server/configuration/bearer-auth). + + + +```json +{ + "name": "CI Autofix v1", + "description": "Detect CI failures on main and automatically open PRs", + "triggers": [ + { + "git": { + "ciCompleted": { + "repos": [ + "https://github.com/" + ], + "condition": 1, + "ignoreBaseFailures": true + } + } + } + ], + "actions": [ + { + "gitPr": {} + }, + { + "mcp": { + "server": { + "name": "trunk" + } + } + } + ], + "prompts": [ + { + "prompt": "Your task is to fix CI failures on PRs.\n\n# Deduplication\n\nTo avoid racing against other agents, before any investigation:\n1. Collect the names of ALL failing CI jobs/checks from the CI Status Report above.\n2. Calculate your memory filename: sort the failing jobs alphabetically, join with \"_\", then remove any characters that are not letters, digits, hyphens, underscores, or dots. Prepend \"ci-fail-\" and truncate to 64 characters total. This is the filename.\n3. Read the memory file with this filename.\n - If it exists and the timestamp inside is less than 30 minutes old, stop immediately — no branch, no Slack, no output.\n4. Else, write the memory file with the current unix timestamp.\n - If the write SUCCEEDS: you claimed this failure. Proceed with the investigation below.\n - If the write FAILS (version conflict): another agent claimed it first. Stop immediately — no branch, no Slack, no output.\n\n# Investigation\n\nRoot cause the CI failure. Call investigate-ci-failure on the trunk MCP in order to get information about the failing test by passing in the workflow URL. Use that to identify which tests to fix. Look at the error output returned by this tool. ONLY IF you need additional information, look at the CI run's logs.\n\n- If the CI failure is due to a bug introduced on that commit, create a new PR that fixes the bug. The PR should be stacked on the PR with the failure. Modify/ensure the base branch of the PR you create is the branch of the PR you are fixing.\n- If the CI failure is due to a flaky test, create a new PR that skips that test.\n- If you are not confident in either of these outcomes, then do nothing.\n\n# Output\n\nOutput your results in the following format:\n**CI Autofix Automation**\n\n**Failure logs**: \n**Broken by**: (cc @prAuthor)\n**Reason**: <1-2 sentence explanation of why CI broke>\n**Fixed by**: <1-2 sentence explanation of what fixed it>\n\nMake sure to push the PR but don't include a PR link in your output — the system will generate that for you." + } + ], + "memoryEnabled": true, + "scope": "team_editable_user", + "templateId": "ci-autofix" +} +``` + + + +We recommend the following conventions: + +* Version your Automation names for more clarity (e.g., "CI Autofix v1") +* Refine the prompt to avoid scanning GitHub logs in order to save time and tokens +* Be specific about your repository's conventions and common failure patterns + + +Currently Cursor will create a pull request with a base of `main`. You will need to adjust the pull request base if you want to merge the fix into your PR. + + +### Claude Code Routines + + +**Coming soon.** Set up Claude Routines to autofix CI failures + diff --git a/flaky-tests/autofix-flaky-tests.mdx b/flaky-tests/autofix-flaky-tests.mdx new file mode 100644 index 0000000..853278c --- /dev/null +++ b/flaky-tests/autofix-flaky-tests.mdx @@ -0,0 +1,72 @@ +--- +title: "Autofix Flaky Tests" +description: "Automatically investigate flaky tests and raise fix pull requests with suggested solutions" +--- +Trunk can automatically investigate flaky tests in your codebase and raise fix pull requests with suggested solutions. + +### Prerequisites + +To use the Autofix Flaky Tests feature, you'll need: + +1. Beta access via waitlist (reach out to us on [Slack](https://slack.trunk.io)) +2. The "Investigate Flaky Tests" setting enabled in your workspace +3. Active installation of the [Trunk GitHub App](/setup-and-administration/github-app-permissions) + +### Auto-Investigate Flaky Tests + +Once enabled, any time that Trunk [detects a flaky test](/flaky-tests/detection), Trunk analyzes the failure patterns, failure output, and git history of the test to provide a number of insights. + +Flaky tests can also be analyzed manually via the UI and via the [MCP server](/flaky-tests/use-mcp-server/mcp-tool-reference/fix-flaky-test). + +### Autofix with Cursor Automations + +Whenever an investigation is completed, Trunk will emit a [webhook](/flaky-tests/webhooks) for `test_case.investigation_completed`. Enable webhooks via [Svix](/flaky-tests/webhooks). + +You can then set up a [Cursor Automation](https://cursor.com/automations) to trigger when webhooks are received. + + + +```json +{ + "name": "Autofix Flaky Tests v1", + "triggers": [ + { + "webhook": {} + } + ], + "actions": [], + "prompts": [ + { + "prompt": "Your task is to fix flaky tests in this repo using provided insights.\n\n# Filter\n\nIf the test does not include the repository html_url \"https://github.com/\", exit early and do nothing.\n\n# Root Cause\n\nThe payload will include metadata about the failing test as well as some insights about the flakiness.\n\n1. The markdown_summary field includes the most important insights and the first steps you should take to root cause the flaky tests.\n2. The facts field includes more findings from historical data about running the test.\n3. Remember that the test is flaky. Sometimes it passes and sometimes it fails. Use the investigation payload to target your analysis.\n4. Use the memory tool to capture any important findings as you analyze the codebase to root cause the flakiness, such as codebase structure or test patterns.\n\n## Antipatterns\n\n1. Identify the root cause of the flakiness of the test. Do not simply increase the test's timeout or change the assertion to be more generic.\n2. Do not attempt to fix flakiness in other tests, limit your analysis to this single test.\n3. Do not add new tests, fix the flaky test in the payload.\n4. If the test is not present on your stable branch, exit early.\n5. When modifying end to end tests, do not wait on internal API calls to resolve. Focus on the page state and what the end user sees.\n6. There may be additional reasons for test flakiness, such as nondeterministic seed data, noisy neighbors, or test order issues. Conduct a deep analysis for necessary evidence, do not terminate your analysis early.\n\n## Output\n\n1. Once you have identified the root cause of the test's flakiness, open a pull request to fix the PR.\n2. Title the Pull Request: \"[Cursor Fix Flaky Test]: \".\n3. Include 1 short paragraph about the fix and the supporting evidence in the pull request body. Include links to relevant files/pages that were relevant from the webhook payload and its facts.\n4. In a collapsible summary of the PR description, include the entire webhook payload you received." + } + ], + "memoryEnabled": true, + "scope": "private", + "gitConfig": { + "repo": "https://github.com/", + "repos": [ + "https://github.com/" + ], + "branch": "main" + } +} +``` + + + +We recommend the following conventions: + +* Version your Automation names for more clarity. +* Configure the Svix endpoint with the Cursor Bearer token. +* Webhooks are configured for your entire organization, so you will need to use [Svix transformations](https://docs.svix.com/transformations) or filter out events that are not for your intended repository. +* Be specific about conventions and antipatterns for your repository. You will need to refine the Automation prompt to suit your needs. +* If your CI setup allows it, prompt Cursor to run the tests to verify them. + +### What's next? + +* Continue to monitor your tests to confirm the flaky test fixes are effective +* Investigations can be triggered and applied via [MCP](/flaky-tests/use-mcp-server/mcp-tool-reference/fix-flaky-test) + + +**Coming soon.** Set up Claude Routines to autofix flaky tests + diff --git a/flaky-tests/detection.mdx b/flaky-tests/detection.mdx index 27839e1..5676319 100644 --- a/flaky-tests/detection.mdx +++ b/flaky-tests/detection.mdx @@ -10,8 +10,8 @@ Each monitor independently observes your test runs and tracks two states per tes | Priority | Status | Condition | | -------- | ----------- | --------------------------------------------------------------------- | -| Highest | **Broken** | Any enabled broken-type threshold monitor is active for this test | -| Middle | **Flaky** | Any enabled flaky-type monitor (threshold or pass-on-retry) is active | +| Highest | **Broken** | Any enabled broken-type failure rate monitor is active for this test | +| Middle | **Flaky** | Any enabled flaky-type monitor (failure rate or pass-on-retry) is active | | Lowest | **Healthy** | No active monitors | If a test triggers both a broken monitor and a flaky monitor simultaneously, it shows as **Broken**. When the broken monitor resolves (e.g., you fix the regression and the failure rate drops), the test transitions to **Flaky** if a flaky monitor is still active, or to **Healthy** if no monitors remain active. @@ -22,16 +22,16 @@ A test stays in its detected state until every relevant monitor that flagged it When you disable or delete a monitor, it is immediately set to **resolved** for every test case in the repo. This triggers a status re-evaluation for all affected tests. If the disabled monitor was the only active monitor for a test, that test transitions to healthy. If other monitors are still active, the test remains in the most severe active state. -For example, if you have a broken threshold monitor and a flaky pass-on-retry monitor, and you disable the broken monitor, any test that was only flagged by the broken monitor will become healthy. A test flagged by both will transition from broken to flaky (because pass-on-retry is still active). +For example, if you have a broken failure rate monitor and a flaky pass-on-retry monitor, and you disable the broken monitor, any test that was only flagged by the broken monitor will become healthy. A test flagged by both will transition from broken to flaky (because pass-on-retry is still active). ## Monitor Types | Monitor | What it detects | Detection type | Plan availability | Default state | | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | --------------- | ----------------- | ------------- | | [**Pass-on-Retry**](/flaky-tests/detection/pass-on-retry-monitor) | A test fails then passes on the same commit (retry after failure) | Flaky | Team and above | Enabled | -| [**Threshold**](/flaky-tests/detection/threshold-monitor) | Failure rate exceeds a configured percentage over a time window | Flaky or Broken | Paid plans | Disabled | +| [**Failure Rate**](/flaky-tests/detection/failure-rate-monitor) | Failure rate exceeds a configured percentage over a time window | Flaky or Broken | Paid plans | Disabled | -You can run multiple monitors simultaneously. For example, you might use pass-on-retry to catch classic retry-based flakiness while also running threshold monitors scoped to different branches. A common pattern is to pair a broken-type threshold monitor (catching consistently failing tests) with a flaky-type threshold monitor (catching intermittently failing tests). See [Threshold Monitor: Recommended Configurations](/flaky-tests/detection/threshold-monitor#recommended-configurations) for details. +You can run multiple monitors simultaneously. For example, you might use pass-on-retry to catch classic retry-based flakiness while also running failure rate monitors scoped to different branches. A common pattern is to pair a broken-type failure rate monitor (catching consistently failing tests) with a flaky-type failure rate monitor (catching intermittently failing tests). See [Failure Rate Monitor: Recommended Configurations](/flaky-tests/detection/failure-rate-monitor#recommended-configurations) for details. If you need to manually flag a test that automated monitors haven't caught, use [Flag as Flaky](/flaky-tests/detection/flag-as-flaky) from the test detail page. @@ -39,7 +39,7 @@ If you need to manually flag a test that automated monitors haven't caught, use Tests often behave differently depending on where they run. Failures on `main` are usually unexpected and signal flakiness. Failures on PR branches may be expected during active development. Merge queue failures are suspicious because the code has already passed PR checks. -Rather than applying a single set of branch rules automatically, Trunk gives you control over how detection treats different branches through **branch scoping** on threshold monitors. You can create separate monitors with different thresholds and windows for your stable branch, PR branches, and merge queue branches. See [Threshold Monitor: Recommended configurations](/flaky-tests/detection/threshold-monitor#recommended-configurations) for specific guidance. +Rather than applying a single set of branch rules automatically, Trunk gives you control over how detection treats different branches through **branch scoping** on failure rate monitors. You can create separate monitors with different thresholds and windows for your stable branch, PR branches, and merge queue branches. See [Failure Rate Monitor: Recommended configurations](/flaky-tests/detection/failure-rate-monitor#recommended-configurations) for specific guidance. Pass-on-retry detection is branch-agnostic. It flags any test that fails and passes on the same commit, regardless of which branch the test ran on. diff --git a/flaky-tests/detection/threshold-monitor.mdx b/flaky-tests/detection/failure-rate-monitor.mdx similarity index 93% rename from flaky-tests/detection/threshold-monitor.mdx rename to flaky-tests/detection/failure-rate-monitor.mdx index 893181d..d22b975 100644 --- a/flaky-tests/detection/threshold-monitor.mdx +++ b/flaky-tests/detection/failure-rate-monitor.mdx @@ -1,14 +1,14 @@ --- -title: "Threshold Monitor" +title: "Failure Rate Monitor" description: "Detect flaky or broken tests based on failure rate over a configurable time window" --- -The threshold monitor detects tests based on failure rate over a rolling time window. Unlike pass-on-retry, which looks for a specific pattern on a single commit, the threshold monitor identifies tests that fail too often over a period of time, even if no individual failure looks like a retry. +The failure rate monitor detects tests based on failure rate over a rolling time window. Unlike pass-on-retry, which looks for a specific pattern on a single commit, the failure rate monitor identifies tests that fail too often over a period of time, even if no individual failure looks like a retry. -You can create multiple threshold monitors with different configurations. This is how you tailor detection to different branches, test volumes, sensitivity levels, and detection types. +You can create multiple failure rate monitors with different configurations. This is how you tailor detection to different branches, test volumes, sensitivity levels, and detection types. ## Detection Type -Each threshold monitor has a **detection type** — either **flaky** or **broken** — which controls what status a test receives when the monitor flags it: +Each failure rate monitor has a **detection type** — either **flaky** or **broken** — which controls what status a test receives when the monitor flags it: * **Flaky monitors** catch tests that fail intermittently (e.g., 20–50% failure rate). These are typically caused by timing issues, shared state, or non-deterministic behavior. * **Broken monitors** catch tests that fail consistently at a high rate (e.g., 80%+ failure rate). These usually indicate a real regression — something in the code or environment is genuinely broken and needs a fix. @@ -23,7 +23,7 @@ The monitor periodically calculates the failure rate for each test within a time ### Example -You configure a threshold monitor with: +You configure a failure rate monitor with: | Setting | Value | | -------------------- | ------- | @@ -161,11 +161,11 @@ Tests that are still running but haven't accumulated enough runs to meet the min ## Muting -You can temporarily mute a threshold monitor for a specific test case. See [Muting monitors](/flaky-tests/detection/..#muting-monitors) for details. +You can temporarily mute a failure rate monitor for a specific test case. See [Muting monitors](/flaky-tests/detection/..#muting-monitors) for details. ## Recommended Configurations -A common setup is to pair two threshold monitors — one to catch broken tests quickly and one to catch flaky tests over a longer window: +A common setup is to pair two failure rate monitors — one to catch broken tests quickly and one to catch flaky tests over a longer window: | Monitor | Detection type | Activation threshold | Window | Purpose | | -------------- | -------------- | -------------------- | ----------- | -------------------------------------------------------------------------------------- | @@ -192,7 +192,7 @@ Failures on your stable branch are a strong signal. Tests should be passing befo On PR branches, tests are expected to fail — that's part of active development. Analyzing failure rate for flakiness on PRs is generally not productive because a new failing test is likely caused by the code change under review, not non-deterministic behavior. Pass-on-retry already handles real flakiness on PRs: if a test fails and then passes on retry within the same commit, it will be detected regardless of branch. -If you do want a threshold monitor on PRs, scope it to catch **broken** tests rather than flaky ones — tests that are consistently failing at a high rate across many PRs, which may indicate a persistent regression or a broken test environment. +If you do want a failure rate monitor on PRs, scope it to catch **broken** tests rather than flaky ones — tests that are consistently failing at a high rate across many PRs, which may indicate a persistent regression or a broken test environment. | Setting | Suggested value | Why | | -------------------- | ------------------------------------ | ----------------------------------------------------------------------------- | diff --git a/flaky-tests/get-started.mdx b/flaky-tests/get-started.mdx index 8c38aeb..93c502f 100644 --- a/flaky-tests/get-started.mdx +++ b/flaky-tests/get-started.mdx @@ -45,12 +45,12 @@ After uploads are flowing, navigate to your repo → **Flaky Tests > Monitors** **Pass-on-retry** is enabled by default and is the recommended baseline for everyone. It catches the most common flakiness pattern — a test that fails and then passes on retry within the same commit — without any configuration needed. -**Threshold monitors** let you detect flakiness based on failure rate over a rolling time window. How you configure them depends on your CI setup: +**Failure rate monitors** let you detect flakiness based on failure rate over a rolling time window. How you configure them depends on your CI setup: -* **If tests must pass before merging to main**, set up a threshold monitor scoped to `main` to catch an elevated failure rate. For example, if you run tests 5 times per day on `main`, a 24-hour rolling window with a minimum of 4 runs and a failure threshold of 25% is a reasonable starting point. This ensures the monitor has enough data before flagging anything. +* **If tests must pass before merging to main**, set up a failure rate monitor scoped to `main` to catch an elevated failure rate. For example, if you run tests 5 times per day on `main`, a 24-hour rolling window with a minimum of 4 runs and a failure threshold of 25% is a reasonable starting point. This ensures the monitor has enough data before flagging anything. * **If you use a merge queue**, consider a dedicated monitor scoped to your merge queue branches (e.g., `trunk-merge/*` or `gh-readonly-queue/*`). Failures here are especially suspicious since the code has already passed PR checks, so a low threshold is appropriate. -[How threshold monitors work →](/flaky-tests/detection/threshold-monitor) +[How failure rate monitors work →](/flaky-tests/detection/failure-rate-monitor) #### Quarantining diff --git a/flaky-tests/get-started/ci-providers/atlassian-bamboo.mdx b/flaky-tests/get-started/ci-providers/atlassian-bamboo.mdx index 2ff4f73..496e385 100644 --- a/flaky-tests/get-started/ci-providers/atlassian-bamboo.mdx +++ b/flaky-tests/get-started/ci-providers/atlassian-bamboo.mdx @@ -41,10 +41,10 @@ Store the Trunk slug and API token obtained in the previous step as [Bamboo plan ### Upload to Trunk -Add an `Upload Test Results` step after running tests in each of your Bamboo jobs that run tests. This should be minimally all jobs that run on pull requests, as well as from jobs that run on your [stable branches](/flaky-tests/detection/threshold-monitor#stable-branch-patterns), for example, `main`, `master`, or `develop`. +Add an `Upload Test Results` step after running tests in each of your Bamboo jobs that run tests. This should be minimally all jobs that run on pull requests, as well as from jobs that run on your [stable branches](/flaky-tests/detection/failure-rate-monitor#stable-branch-patterns), for example, `main`, `master`, or `develop`. -It is important to upload test results from CI runs on [**stable branches**](/flaky-tests/detection/threshold-monitor#stable-branch-patterns), such as `main`, `master`, or `develop`. This will give you a stronger signal about the health of your code and tests. +It is important to upload test results from CI runs on [**stable branches**](/flaky-tests/detection/failure-rate-monitor#stable-branch-patterns), such as `main`, `master`, or `develop`. This will give you a stronger signal about the health of your code and tests. Trunk can also detect test flakes on PR and merge branches. To best detect flaky tests, it is recommended to upload test results from stable, PR, and merge branch CI runs. diff --git a/flaky-tests/get-started/frameworks/jest.mdx b/flaky-tests/get-started/frameworks/jest.mdx index 255b211..c5935af 100644 --- a/flaky-tests/get-started/frameworks/jest.mdx +++ b/flaky-tests/get-started/frameworks/jest.mdx @@ -47,6 +47,33 @@ Update your Jest config to add `jest-junit` as a reporter: The `outputDirectory` and `outputName` options specify the path of the XML report. You'll need this path later when configuring automatic uploads to Trunk. +#### Using `filePathPrefix` + +In a monorepo with `pnpm` workspaces (or similar), Jest runs from within the package directory, so the file paths it records in the XML report are relative to that package — not to the repository root. For example, a test at `packages/my-package/src/__tests__/foo.test.js` would be recorded as `src/__tests__/foo.test.js`. + +This causes codeowners matching to fail because Trunk compares test file paths against the codeowners file at the repo root, which uses full repo-relative paths. + +To fix this, set the `filePathPrefix` option to the path of the package within the repo: + +```json jest.config.json +{ + "reporters": [ + [ + "jest-junit", + { + "outputDirectory": "./", + "outputName": "junit.xml", + "addFileAttribute": "true", + "reportTestSuiteErrors": "true", + "filePathPrefix": "packages/my-package" + } + ] + ] +} +``` + +With `filePathPrefix` set, `jest-junit` will prepend the given path to every file path in the XML output, producing repo-root-relative paths that Trunk can correctly match against your codeowners file. + #### Disable Retries You need to disable automatic retries if you previously enabled them. Retries compromise the accurate detection of flaky tests. You should disable retries for accurate detection and use the [Quarantining](/flaky-tests/quarantining) feature to stop flaky tests from failing your CI jobs. diff --git a/flaky-tests/get-started/frameworks/rspec.mdx b/flaky-tests/get-started/frameworks/rspec.mdx index 364cd30..22a490c 100644 --- a/flaky-tests/get-started/frameworks/rspec.mdx +++ b/flaky-tests/get-started/frameworks/rspec.mdx @@ -102,6 +102,10 @@ After your upload, you can verify that Trunk has received and processed it succe
+ +You do not need to download the `trunk-analytics-cli` when using the Trunk RSpec plugin. Uploads are handled for you as long as you have set `TRUNK_ORG_URL_SLUG` and `TRUNK_API_TOKEN`. + + ### Next Steps Configure your CI to upload test runs to Trunk. Find the guides for your CI framework below: diff --git a/flaky-tests/quarantining.mdx b/flaky-tests/quarantining.mdx index 7409337..372844c 100644 --- a/flaky-tests/quarantining.mdx +++ b/flaky-tests/quarantining.mdx @@ -232,7 +232,7 @@ Trunk provides audit logs for all setting changes and overwrites for individual For advanced use cases, you can interact with quarantining features programmatically. * API: Use the [Flaky Tests API](/flaky-tests/flaky-tests) to fetch a list of all currently quarantined tests in your project. -* Webhooks: Subscribe to the `test_case.quarantining_setting_changed` event to trigger automated workflows whenever a test's quarantine override is modified. Learn more about [Webhooks](https://www.svix.com/event-types/us/org_2eQPL41Ew5XSHxiXZIamIUIXg8H/#test_case.status_changed). +* Webhooks: Subscribe to the `test_case.quarantining_setting_changed` event to trigger automated workflows whenever a test's quarantine override is modified. Learn more about [Webhooks](https://www.svix.com/event-types/us/org_2eQPL41Ew5XSHxiXZIamIUIXg8H/#test_case.quarantining_setting_changed). #### Service Availability and Graceful Degradation diff --git a/flaky-tests/test-labels.mdx b/flaky-tests/test-labels.mdx new file mode 100644 index 0000000..9414a31 --- /dev/null +++ b/flaky-tests/test-labels.mdx @@ -0,0 +1,32 @@ +--- +title: "Test Labels" +description: "Organize and categorize test cases with organization-scoped labels." +--- +Test labels are organization-scoped tags you can apply to individual test cases to organize, filter, and categorize your test suite. Labels are applied manually today; see [Automatic labeling from monitors](#automatic-labeling-from-monitors) for what's coming. + +### Manage labels + +Labels are created, edited, and deleted at **Settings > Organization > Test Labels**. Each label has a name, an optional description, and a color used for its chip in the UI. The settings page also shows how many test cases each label is currently applied to. + + +Deleting a label removes it from every test case it's applied to; this cannot be undone. + + +### Apply and remove labels on a test case + +You apply and remove labels from a test case using the label picker on the test case detail page. The picker lets you search existing labels, toggle them on or off, and create a new label inline if one doesn't already exist. Each assignment records who applied the label and when. + +### Filter tests by label + +On the tests list, you can filter the table down to test cases that have a particular label applied. This makes labels useful for slicing the view by the categories your team cares about. + +### Automatic labeling from monitors + + +**Coming soon.** Monitors will be able to automatically apply and remove labels on test cases based on test behavior. More details will be published when this is available. + + +### Related + +* [Managing detected flaky tests](/flaky-tests/managing-detected-flaky-tests) — a step-by-step process for handling detected flaky tests +* [Flake Detection](/flaky-tests/detection) — monitors that classify tests as flaky or broken diff --git a/flaky-tests/use-mcp-server.mdx b/flaky-tests/use-mcp-server.mdx index 312c9dc..df348d4 100644 --- a/flaky-tests/use-mcp-server.mdx +++ b/flaky-tests/use-mcp-server.mdx @@ -16,7 +16,7 @@ Gemini Code Assist and Windsurf are not supported due to their limited support f Our MCP server is available at `https://mcp.trunk.io/mcp` and exposes the following tools: -
ToolCapability
fix-flaky-testExperimental: Retrieve insights around a failing/flaky test
setup-trunk-uploadsExperimental: Create a setup plan to upload test results
+
ToolCapability
fix-flaky-testExperimental: Retrieve insights around a failing/flaky test
search-testExperimental: Look up a test case ID by test name
investigate-ci-failureExperimental: Investigate a failing CI run
setup-trunk-uploadsExperimental: Create a setup plan to upload test results
### Authorization diff --git a/flaky-tests/use-mcp-server/configuration/bearer-auth.mdx b/flaky-tests/use-mcp-server/configuration/bearer-auth.mdx new file mode 100644 index 0000000..c5e70c4 --- /dev/null +++ b/flaky-tests/use-mcp-server/configuration/bearer-auth.mdx @@ -0,0 +1,17 @@ +--- +title: "Bearer Authentication" +description: "Add Trunk's MCP Server via Bearer Authentication" +--- +You can leverage Trunk's MCP server for all of your agentic needs. When using the MCP in cloud environments, authenticate using Bearer Authentication. + +### API Token + +Retrieve your organization's API token from the settings page in the web app, e.g. `https://app.trunk.io//settings`. + +### Authorization Header + +Set the following header when connecting to the MCP `https://mcp.trunk.io/mcp`: + +| Header Key | Header Value | +| --------------- | ---------------- | +| `Authorization` | `Bearer ` | diff --git a/flaky-tests/use-mcp-server/mcp-tool-reference.mdx b/flaky-tests/use-mcp-server/mcp-tool-reference.mdx index 139cb89..1f183f5 100644 --- a/flaky-tests/use-mcp-server/mcp-tool-reference.mdx +++ b/flaky-tests/use-mcp-server/mcp-tool-reference.mdx @@ -1,6 +1,8 @@ --- title: "MCP Tool Reference" -description: "- Get root cause analysis: MCP tool reference: fix-flaky-test - Set up test uploads: MCP tool reference: setup-trunk-uploads" +description: "Reference for the MCP tools provided by the Trunk MCP server" --- -- [Get root cause analysis](/flaky-tests/use-mcp-server/mcp-tool-reference/get-root-cause-analysis): MCP tool reference: fix-flaky-test +- [Fix Flaky Test](/flaky-tests/use-mcp-server/mcp-tool-reference/fix-flaky-test): MCP tool reference: fix-flaky-test +- [Search Test](/flaky-tests/use-mcp-server/mcp-tool-reference/search-test): MCP tool reference: search-test +- [Investigate CI Failure](/flaky-tests/use-mcp-server/mcp-tool-reference/investigate-ci-failure): MCP tool reference: investigate-ci-failure - [Set up test uploads](/flaky-tests/use-mcp-server/mcp-tool-reference/set-up-test-uploads): MCP tool reference: setup-trunk-uploads diff --git a/flaky-tests/use-mcp-server/mcp-tool-reference/fix-flaky-test.mdx b/flaky-tests/use-mcp-server/mcp-tool-reference/fix-flaky-test.mdx new file mode 100644 index 0000000..55bbe2a --- /dev/null +++ b/flaky-tests/use-mcp-server/mcp-tool-reference/fix-flaky-test.mdx @@ -0,0 +1,68 @@ +--- +title: "Fix Flaky Test" +description: "MCP tool reference: fix-flaky-test" +--- +### Overview + +The `fix-flaky-test` tool retrieves insights and historical failure analysis about a flaky test. This tool allows AI assistants to access investigation results and apply fixes directly in your development environment. For more information, see [Autofix Flaky Tests](/flaky-tests/autofix-flaky-tests). + +**Return Type:** Structured analysis data with fix recommendations. Structure: metadata, summary, facts + +### Parameters + +#### Required Parameters + +| Parameter | Type | Description | +| ------------ | ------ | --------------------------------------------------------------- | +| `repoName` | string | Repository name in `owner/repo` format (e.g., `trunk-io/trunk`) | +| `testCaseId` | string | UUID of the test case to retrieve investigations for | + +#### Optional Parameters + +| Parameter | Type | Description | +| ------------------------ | ------- | ----------------------------------------------------------------------- | +| `orgSlug` | string | The name of your organization in the Trunk app | +| `investigationId` | string | Specific fix identifier from previous investigation queries | +| `createNewInvestigation` | boolean | Whether or not to trigger a new investigation (may take up to 1 minute) | + +### Getting Parameter Values + +If your AI assistant doesn't have direct access to Git information, use these commands: + +**Get repository name:** + +```bash +git remote -v +``` + +Look for the repository name in the output (e.g., `trunk-io/trunk` from `git@github.com:trunk-io/trunk.git`) + +### Usage Examples + +#### With Test ID + +``` +Fix the flaky test with ID +``` + +#### Create New Investigation + +``` +Run a new analysis to help me fix flaky test with ID +``` + +#### With Existing Investigation + +``` +Retrieve the investigation for test with investigationId +``` + +### Error Handling + +| Error | Cause | Resolution | +| ----------------------------------------------------------------------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | +| `Investigation {investigationId} not found` | Invalid or non-existent fix ID | Verify the investigationId from the previous query | +| `testCaseId must be provided` | Missing required query parameter | Test ID is required | +| `This investigation was skipped before producing a completed summary.` | Investigation was skipped | The setting may be disabled, revisit prerequisites in [Autofix Flaky Tests](/flaky-tests/autofix-flaky-tests) | +| `This investigation failed before producing a completed summary. Please contact Trunk support.` | Investigation error | This feature is still in Beta, please contact support | +| Repository authorization error | Insufficient permissions or invalid repo name | Verify repository name format and your access permissions | diff --git a/flaky-tests/use-mcp-server/mcp-tool-reference/get-root-cause-analysis.mdx b/flaky-tests/use-mcp-server/mcp-tool-reference/get-root-cause-analysis.mdx deleted file mode 100644 index 6d05822..0000000 --- a/flaky-tests/use-mcp-server/mcp-tool-reference/get-root-cause-analysis.mdx +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: "Get root cause analysis" -description: "MCP tool reference: fix-flaky-test" ---- -### Overview - -The `fix-flaky-test` tool retrieves insights and historical failure analysis about a flaky test. This tool allows AI assistants to access investigation results and apply fixes directly in your development environment. - -\ -**Return Type:** Structured analysis data with fix recommendations. Structure: issue, root cause, proposed fix - -### Parameters - -#### Required Parameters - -| Parameter | Type | Description | -| ---------- | ------ | --------------------------------------------------------------- | -| `repoName` | string | Repository name in `owner/repo` format (e.g., `trunk-io/trunk`) | - -#### Optional Parameters - -| Parameter | Type | Description | -| --------- | ------ | ---------------------------------------------------------------------- | -| `fixId` | string | Specific fix identifier from CI Autopilot comment (e.g., `FIX-abc123`) | -| `orgSlug` | string | The name of your organization in the Trunk app | - -### Getting Parameter Values - -If your AI assistant doesn't have direct access to Git information, use these commands: - -**Get repository name:** - -```bash -git remote -v -``` - -Look for the repository name in the output (e.g., `trunk-io/trunk` from `git@github.com:trunk-io/trunk.git`) - -### Usage Examples - -#### With Fix ID - -``` -Fix the flaky test with ID -``` - -### Sample Response - -``` -Fix Flaky Tests Insight for - -Issue: The CI failure occurred during the "Run Mysql Migrations" step due to a ValidationException from AWS Secrets Manager. - -Root Cause: The SECRET_NAME being used to retrieve the secret value is malformed. The grep -oP "adminsecret.*" command is extracting the secret name along with surrounding JSON formatting (like quotes), which creates an invalid secret ID when passed to aws secretsmanager get-secret-value. - -Proposed Fix: Replace the problematic grep command with a proper JSON parser: - -- SECRET_NAME=$(aws secretsmanager list-secrets --filters Key=name,Values=adminsecret | grep Name | grep -oP "adminsecret.*") -+ SECRET_NAME=$(aws secretsmanager list-secrets --filters Key=name,Values=adminsecret | jq -r '.SecretList[0].Name') - -This fix is located in .github/actions/setup-k8s-and-migrate/action.yml at line 11. -``` - -### Error Handling - -| Error | Cause | Resolution | -| ------------------------------ | --------------------------------------------- | --------------------------------------------------------- | -| `Fix {fixId} not found` | Invalid or non-existent fix ID | Verify the fix ID from the original CI Autopilot comment | -| `fixId must be provided` | Missing required query parameter | Fix ID is required | -| Repository authorization error | Insufficient permissions or invalid repo name | Verify repository name format and your access permissions | diff --git a/flaky-tests/use-mcp-server/mcp-tool-reference/investigate-ci-failure.mdx b/flaky-tests/use-mcp-server/mcp-tool-reference/investigate-ci-failure.mdx new file mode 100644 index 0000000..6a0cc34 --- /dev/null +++ b/flaky-tests/use-mcp-server/mcp-tool-reference/investigate-ci-failure.mdx @@ -0,0 +1,63 @@ +--- +title: "Investigate CI Failure" +description: "MCP tool reference: investigate-ci-failure" +--- +### Overview + +The `investigate-ci-failure` tool investigates a failing CI run by fetching structured test failure data from Trunk. Given a GitHub Actions workflow URL, this tool looks up test result bundles, parses them to extract test names and error messages, filters out quarantined (known-flaky) tests, and returns structured failure details the agent can act on. For more information, see [Autofix CI Failures](/flaky-tests/autofix-ci-failures). + +**Return Type:** Structured failure details with test names, error messages, stdout, and stderr. If the CI job failed before tests ran (build or compilation failure), the tool suggests pulling raw logs from the workflow URL as a fallback. + +### Prerequisites + +* Your repository must be set up to [upload test results to Trunk](/flaky-tests/get-started) +* For best results, [enable quarantining](/flaky-tests/quarantining) so known-flaky tests are filtered out automatically + +### Parameters + +#### Required Parameters + +| Parameter | Type | Description | +| ------------- | ------ | ---------------------------------------------------------------------------------------------- | +| `workflowUrl` | string | The GitHub Actions workflow URL, e.g. `https://github.com/{owner}/{repo}/actions/runs/{runId}` | + +#### Optional Parameters + +| Parameter | Type | Description | +| --------- | ------ | --------------------------------------------------------------------------------- | +| `orgSlug` | string | The Trunk organization slug (used to disambiguate if you belong to multiple orgs) | + +### Getting Parameter Values + +**Get workflow URL:** + +Navigate to your GitHub Actions run and copy the full URL from your browser's address bar. It follows the pattern: + +``` +https://github.com/{owner}/{repo}/actions/runs/{runId} +``` + +### Usage Examples + +#### Investigate a workflow failure + +``` +Investigate the CI failure at https://github.com/trunk-io/trunk/actions/runs/12345678 +``` + +### What the tool does + +* Looks up test result uploads Trunk has received for that run +* Parses the test runs to extract test names, error messages, stdout and stderr +* Filters out quarantined (known-flaky) tests so you only see real failures +* Returns structured failure details you can act on + +**When tests didn't run:** If the CI job failed before any tests ran (e.g., a build or compilation failure), the tool will tell you so and suggest pulling raw CI logs directly from the workflow URL as a fallback. + +### Error Handling + +| Error | Cause | Resolution | +| ------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `Invalid workflow URL` | Malformed or incorrect workflow URL | Verify the URL follows the pattern `https://github.com/{owner}/{repo}/actions/runs/{runId}` | +| `No test results were uploaded for this CI run` | No test run uploads were uploaded from the provided workflow | Check that the workflow run URL is correct and that it is uploading test results. Compilation and build failures will not upload test results | +| `No test uploads found for this repository` | Repo hasn't configured Trunk test result uploads | Follow setup instructions to [upload test results](/flaky-tests/get-started) | diff --git a/flaky-tests/use-mcp-server/mcp-tool-reference/search-test.mdx b/flaky-tests/use-mcp-server/mcp-tool-reference/search-test.mdx new file mode 100644 index 0000000..7289b36 --- /dev/null +++ b/flaky-tests/use-mcp-server/mcp-tool-reference/search-test.mdx @@ -0,0 +1,52 @@ +--- +title: "Search Test" +description: "MCP tool reference: search-test" +--- +### Overview + +The `search-test` tool looks up the ID of a test case given its name. + +**Return Type:** Metadata about the test, including its ID. + +### Parameters + +#### Required Parameters + +| Parameter | Type | Description | +| ---------------- | ------ | --------------------------------------------------------------- | +| `repoName` | string | Repository name in `owner/repo` format (e.g., `trunk-io/trunk`) | +| `testNameSearch` | string | Search string for the test name. Does not include filepaths | + +#### Optional Parameters + +| Parameter | Type | Description | +| --------- | ------ | ---------------------------------------------- | +| `orgSlug` | string | The name of your organization in the Trunk app | +| `limit` | number | Limit for test results to return, up to 20 | + +### Getting Parameter Values + +If your AI assistant doesn't have direct access to Git information, use these commands: + +**Get repository name:** + +```bash +git remote -v +``` + +Look for the repository name in the output (e.g., `trunk-io/trunk` from `git@github.com:trunk-io/trunk.git`) + +### Usage Examples + +#### Search + +``` +What's the test case ID for the test "clear all filters button appears in empty state and clears filters" +``` + +### Error Handling + +| Error | Cause | Resolution | +| ---------------------------------------------------- | --------------------------------------------- | --------------------------------------------------------- | +| `No tests matched {searchString} in repo {repoName}` | No results found | Check your search string and try again | +| Repository authorization error | Insufficient permissions or invalid repo name | Verify repository name format and your access permissions | diff --git a/flaky-tests/webhooks.mdx b/flaky-tests/webhooks.mdx index d496550..046744a 100644 --- a/flaky-tests/webhooks.mdx +++ b/flaky-tests/webhooks.mdx @@ -10,7 +10,7 @@ Trunk provides webhooks for you to build custom integrations to automate workflo Trunk lets you create custom workflows with **event-triggered webhooks**. Flaky Test events are named with a `test_case` prefix. You can find all the events that Trunk supports in the event catalog: - + Open the referenced resource in a new tab. diff --git a/flaky-tests/webhooks/github-issues-integration.mdx b/flaky-tests/webhooks/github-issues-integration.mdx index 369a510..e4095b2 100644 --- a/flaky-tests/webhooks/github-issues-integration.mdx +++ b/flaky-tests/webhooks/github-issues-integration.mdx @@ -59,7 +59,7 @@ Transformations are custom code snippets you can write to customize the GitHub i 1. In the endpoint configuration view, navigate to the **Advanced** tab. Under **Transformation**, toggle the **Enabled** switch. 2. Click **Edit transformation** to update your transformation code, and click **Save** to update the transformation. -3. You can test the transformation by selecting the `test_case.status_changed` payload and clicking **Run Test**. This will test the transformation but not send a message. You will learn to send a test message in [step 5](#id-5.-test-your-webhook). +3. You can test the transformation by selecting the `v2.test_case.status_changed` payload and clicking **Run Test**. This will test the transformation but not send a message. You will learn to send a test message in [step 5](#id-5.-test-your-webhook). The generated webhook template contains several configurable constants out of the box: @@ -183,7 +183,7 @@ You can uncomment the code block on lines 31-35 or use a snippet similar to: You can create test issues by delivering a mock webhook. You can do this by: 1. In the endpoint configuration view, navigate to the **Testing** tab and select a **Send event** -2. Under **Subscribed events,** select `test_case.status_changed`as the event type to send. +2. Under **Subscribed events,** select `v2.test_case.status_changed`as the event type to send. 3. Click **Send Example** to test your webhook ### 6. Monitoring webhooks @@ -202,7 +202,7 @@ You can see a list of past delivery attempts in the **Message Attempts** modal. A GitHub Issue will now be created when a test's health status changes. You can further modify your transformation script to customize your issues. -[See the Trunk webhook event catalog](https://www.svix.com/event-types/us/org_2eQPL41Ew5XSHxiXZIamIUIXg8H/#test_case.status_changed) +[See the Trunk webhook event catalog](https://www.svix.com/event-types/us/org_2eQPL41Ew5XSHxiXZIamIUIXg8H/#v2.test_case.status_changed) [Learn more about consuming webhooks in the Svix docs](https://docs.svix.com/receiving/introduction) diff --git a/flaky-tests/webhooks/linear-integration.mdx b/flaky-tests/webhooks/linear-integration.mdx index 49637c4..c0567ce 100644 --- a/flaky-tests/webhooks/linear-integration.mdx +++ b/flaky-tests/webhooks/linear-integration.mdx @@ -167,7 +167,7 @@ Transformations are custom code snippets you can write to customize the Linear i 1. In the endpoint configuration view, navigate to the **Advanced** tab. Under **Transformation**, toggle the **Enabled** switch. 2. Click **Edit transformation** to update your transformation code, and click **Save** to update the transformation. -3. You can test the transformation by selecting the `test_case.status_changed` payload and clicking **Run Test**. This will test the transformation but not send a message. You will learn to send a test message[ in step 6](#id-6.-test-your-webhook). +3. You can test the transformation by selecting the `v2.test_case.status_changed` payload and clicking **Run Test**. This will test the transformation but not send a message. You will learn to send a test message[ in step 6](#id-6.-test-your-webhook). The generated webhook template contains several configurable constants out of the box: @@ -321,7 +321,7 @@ webhook.payload = {query: `mutation IssueCreate { You can create test issues by delivering a mock webhook. You can do this by: 1. In the endpoint configuration view, navigate to the **Testing** tab and select a **Send event** -2. Under **Subscribed events,** select `test_case.status_changed`as the event type to send +2. Under **Subscribed events,** select `v2.test_case.status_changed`as the event type to send 3. Click **Send Example** to test your webhook ### 7. Monitoring webhooks @@ -340,7 +340,7 @@ You can see a list of past delivery attempts in the **Message Attempts** modal. A Linear Issue will now be created when a test's health status changes to **flaky** and **impacts more than 2 PRs**. You can further modify your transformation script to customize your issues. -[See the Trunk webhook event catalog](https://www.svix.com/event-types/us/org_2eQPL41Ew5XSHxiXZIamIUIXg8H/#test_case.status_changed) +[See the Trunk webhook event catalog](https://www.svix.com/event-types/us/org_2eQPL41Ew5XSHxiXZIamIUIXg8H/#v2.test_case.status_changed) [Learn more about consuming webhooks in the Svix docs](https://docs.svix.com/receiving/introduction) diff --git a/flaky-tests/webhooks/microsoft-teams-integration.mdx b/flaky-tests/webhooks/microsoft-teams-integration.mdx index b2ec6ec..8d2ec04 100644 --- a/flaky-tests/webhooks/microsoft-teams-integration.mdx +++ b/flaky-tests/webhooks/microsoft-teams-integration.mdx @@ -39,7 +39,7 @@ Transformations are custom code snippets you can write to customize the Microsof 1. In the endpoint configuration view, navigate to the **Advanced** tab. Under **Transformation**, toggle the **Enabled** switch. 2. Click **Edit transformation** to update your transformation code, and click **Save** to update the transformation. -3. You can test the transformation by selecting the `test_case.status_changed` payload and clicking **Run Test**. This will test the transformation but not send a message. You will learn to send a test message in [step 4](#id-4.-test-your-webhook). +3. You can test the transformation by selecting the `v2.test_case.status_changed` payload and clicking **Run Test**. This will test the transformation but not send a message. You will learn to send a test message in [step 4](#id-4.-test-your-webhook). Below is an example of a webhook transformation to format the messages as [Actionable Messages](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using?tabs=cURL%2Ctext1). If you're having trouble adding a new webhook endpoint with Svix, please see the [Adding Endpoint docs from Svix](https://docs.svix.com/receiving/using-app-portal/adding-endpoints). @@ -200,7 +200,7 @@ function summarizeTestCase(payload) { You can send test messages to your Microsoft Teams channels as you make updates. You can do this by: 1. In the endpoint configuration view, navigate to the **Testing** tab and select a **Send event** -2. Under **Subscribed events,** select `test_case.status_changed`as the event type to send. +2. Under **Subscribed events,** select `v2.test_case.status_changed`as the event type to send. 3. Click **Send Example** to test your webhook ### 5. Monitoring webhooks @@ -221,7 +221,7 @@ You should now receive notifications in your Teams channel when a test's status
-[See the Trunk webhook event catalog](https://www.svix.com/event-types/us/org_2eQPL41Ew5XSHxiXZIamIUIXg8H/#test_case.status_changed) +[See the Trunk webhook event catalog](https://www.svix.com/event-types/us/org_2eQPL41Ew5XSHxiXZIamIUIXg8H/#v2.test_case.status_changed) [Learn more about consuming webhooks in the Svix docs](https://docs.svix.com/receiving/introduction) diff --git a/flaky-tests/webhooks/slack-integration.mdx b/flaky-tests/webhooks/slack-integration.mdx index 4499bdf..b58ab3d 100644 --- a/flaky-tests/webhooks/slack-integration.mdx +++ b/flaky-tests/webhooks/slack-integration.mdx @@ -23,7 +23,7 @@ You can add the new Slack Webhook URL to Svix by following these steps:
5. Review the transformation code automatically generated for GitHub issues. You can customize this transformation at any time. Learn more about [customizing transformations](#id-2.-customize-your-transformation). -6. By default, this connection will send messages about Trunk Merge and Flaky Tests events. If you only want Flaky Test events, unselect all events other than `test_case.status_changed`. +6. By default, this connection will send messages about Trunk Merge and Flaky Tests events. If you only want Flaky Test events, unselect all events other than `v2.test_case.status_changed`. 7. Create the new endpoint. You will be redirected to the endpoint configuration view. If you're having trouble adding a new webhook endpoint with Svix, please see the [Adding Endpoint docs from Svix](https://docs.svix.com/receiving/using-app-portal/adding-endpoints). @@ -34,7 +34,7 @@ Transformations are custom code snippets you can write to customize the Slack me 1. In the endpoint configuration view, navigate to the **Advanced** tab. Under **Transformation**, toggle the **Enabled** switch. 2. Click **Edit transformation** to update your transformation code, and click **Save** to update the transformation. -3. You can test the transformation by selecting the `test_case.status_changed` payload and clicking **Run Test**. This will test the transformation but not send a message. You will learn to send a test message in [step 3](#id-3.-test-your-webhook). +3. You can test the transformation by selecting the `v2.test_case.status_changed` payload and clicking **Run Test**. This will test the transformation but not send a message. You will learn to send a test message in [step 3](#id-3.-test-your-webhook). An example transformation script is provided below and you can customize your Slack integration by following the [Slack](https://api.slack.com/messaging/webhooks) and [Svix transformations](https://docs.svix.com/transformations#using-transformations) documentation. @@ -134,7 +134,7 @@ function summarizeTestCase(payload) { You can send test messages to your Slack channels as you make updates. You can do this by: 1. In the endpoint configuration view, navigate to the **Testing** tab and select a **Send event** -2. Under **Subscribed events,** select `test_case.status_changed`as the event type to send. +2. Under **Subscribed events,** select `v2.test_case.status_changed`as the event type to send. 3. Click **Send Example** to test your webhook ### 4. Monitoring webhooks @@ -155,7 +155,7 @@ You can see a list of past delivery attempts in the **Message Attempts** modal. You should now receive notifications in your Slack workspace when a test's status changes. You can further modify your transformation script to customize your messages. -[See the Trunk webhook event catalog](https://www.svix.com/event-types/us/org_2eQPL41Ew5XSHxiXZIamIUIXg8H/#test_case.status_changed) +[See the Trunk webhook event catalog](https://www.svix.com/event-types/us/org_2eQPL41Ew5XSHxiXZIamIUIXg8H/#v2.test_case.status_changed) [Learn more about consuming webhooks in the Svix docs](https://docs.svix.com/receiving/introduction) diff --git a/merge-queue/administration/metrics.mdx b/merge-queue/administration/metrics.mdx index f6aa1da..4e58836 100644 --- a/merge-queue/administration/metrics.mdx +++ b/merge-queue/administration/metrics.mdx @@ -107,6 +107,42 @@ The time in queue can be displayed as different statistical measures. You can sh | P95 | The value below 95% of the time in queue falls. | | P99 | The value below 99% of the time in queue falls. | +### Drill down into metrics + +From the **Conclusion count** and **Time in queue** charts, you can drill into any point or window on the graph to see the exact pull requests that made up those numbers. + +#### Why Drill Down? + +Aggregated charts tell you *that* something happened — drilling down tells you *which PRs* caused it. This makes it easy to: + +* **Track down outliers** — if the P99 on Time in queue spikes, drill into that bucket to find the specific PR that dragged the tail out. +* **Investigate failure spikes** — click a bar on Conclusion count where failures jumped and see exactly which PRs failed and why. +* **Audit a time window** — pull the full list of PRs merged, failed, or canceled during an incident window or release cut. +* **Answer one-off questions** — "which PRs merged between 2pm and 4pm yesterday?" without writing a query against the Prometheus endpoint. + +#### Select Data Points + +You have two ways to select: + +* **Click a single data point** to see the PRs in that time bucket. +* **Click and drag across the chart** to select a range of data points spanning multiple time buckets. + +Once a selection is made, a **View PRs** button appears. Click it to open the list of PRs that make up the selection. + +#### Review the PR List + +The PR list page shows every PR included in your selection, along with: + +* **Conclusion** — whether the PR merged, failed, or was cancelled. +* **Reason** — the specific cause behind the conclusion (for example, Merged by Trunk, Required status failed, PR closed). See the [Conclusion count](#conclusion-count) table for the full list. +* **Time in queue** — how long the PR spent in the merge queue from entry to exit. + +Both columns are sortable, so you can quickly surface the longest-running PRs in a window or group all failures of the same type together. + + +Drill down is currently available on the Conclusion count and Time in queue charts. Additional Health charts will support the same interaction as they land in the UI. + + --- ### Prometheus metrics endpoint diff --git a/merge-queue/administration/terraform.mdx b/merge-queue/administration/terraform.mdx new file mode 100644 index 0000000..cf2d5b2 --- /dev/null +++ b/merge-queue/administration/terraform.mdx @@ -0,0 +1,204 @@ +--- +title: "Terraform Provider" +description: "Manage Trunk Merge Queue configuration as code using the trunk-io/trunk Terraform provider." +--- +The [trunk-io/trunk](https://registry.terraform.io/providers/trunk-io/trunk/latest) Terraform provider lets you manage merge queue configuration as infrastructure as code. Define your queue settings in Terraform, track changes in version control, and apply them consistently across repositories. + +The provider currently supports the `trunk_merge_queue` resource for creating, updating, importing, and deleting merge queues. + +**Current version:** `0.1.2` + +## Prerequisites + +* [Terraform](https://developer.hashicorp.com/terraform/install) >= 1.0 +* An org-level API token from your Trunk organization. See [Organization slug and token](/setup-and-administration/managing-your-organization#organization-slug-and-token) for how to generate one. +* A repository connected to Trunk + +## Authentication + +Set your org-level API token using the `TRUNK_API_KEY` environment variable: + +```bash +export TRUNK_API_KEY="your-org-api-token" +``` + +Alternatively, you can pass it directly in the provider block: + +```hcl +provider "trunk" { + api_key = var.trunk_api_key +} +``` + + +Never commit your API key to version control. Use environment variables or a secrets manager to supply the `TRUNK_API_KEY` value. + + +*** + +## Quick Start + +```hcl +terraform { + required_version = ">= 1.0" + + required_providers { + trunk = { + source = "trunk-io/trunk" + version = "0.1.2" + } + } +} + +provider "trunk" {} + +resource "trunk_merge_queue" "main" { + repo = { + host = "github.com" + owner = "my-org" + name = "my-repo" + } + target_branch = "main" + concurrency = 5 +} +``` + +Run `terraform plan` to preview changes and `terraform apply` to apply them. If a merge queue already exists for the specified repository and branch, the provider will import it automatically rather than creating a duplicate. + +*** + +## Importing Existing Queues + +Merge queues created through the UI or API can be imported into Terraform. This lets you start managing an existing queue as code without recreating it. + +```bash +terraform import trunk_merge_queue.main github.com/my-org/my-repo/main +``` + +The import ID format is `{host}/{owner}/{name}/{target_branch}`. + +After importing, run `terraform plan` to compare the Terraform configuration against the current queue settings. Resolve any differences before running `terraform apply`. + +*** + +## Resource Reference: `trunk_merge_queue` + +### Required Attributes + +| Attribute | Type | Description | +| --------------- | ------ | --------------------------------------------------------------------------------- | +| `repo.host` | string | Repository host (e.g., `github.com`). Changing this forces a new resource. | +| `repo.owner` | string | Repository owner or organization. Changing this forces a new resource. | +| `repo.name` | string | Repository name. Changing this forces a new resource. | +| `target_branch` | string | Branch the merge queue targets (e.g., `main`). Changing this forces a new resource. | + + +The `repo` and `target_branch` attributes are immutable. Changing any of them will destroy the existing queue and create a new one. + + +### Optional Attributes With API Defaults + +These attributes are computed by the API if not specified. You only need to set them if you want to override the defaults. + +| Attribute | Type | Default | Description | +| ------------- | ------- | ------------- | ------------------------------------------------------------------------------------------------------ | +| `mode` | string | `"single"` | Queue mode: `"single"` or `"parallel"`. See [Merge Queue mode](/merge-queue/administration/advanced-settings#merge-queue-mode). | +| `concurrency` | integer | API default | Number of PRs that can test simultaneously (minimum 1). See [Testing concurrency](/merge-queue/administration/advanced-settings#testing-concurrency). | +| `state` | string | `"RUNNING"` | Queue state: `"RUNNING"`, `"PAUSED"`, or `"DRAINING"`. See [Merge Queue state](/merge-queue/administration/advanced-settings#merge-queue-state). | + +### Other Optional Attributes + +| Attribute | Type | Description | +| ---------------------------------- | ------------ | ----------------------------------------------------------------------------------------------------------------- | +| `testing_timeout_minutes` | integer | Maximum minutes to wait for tests before auto-cancellation. | +| `pending_failure_depth` | integer | Number of successor test runs to wait on before transitioning a failed group. See [Pending failure depth](/merge-queue/optimizations/pending-failure-depth). | +| `can_optimistically_merge` | Boolean | Enable [optimistic merging](/merge-queue/optimizations/optimistic-merging). | +| `batch` | Boolean | Enable [batching](/merge-queue/optimizations/batching). | +| `batching_max_wait_time_minutes` | integer | Maximum minutes to wait for a batch to fill. | +| `batching_min_size` | integer | Minimum number of PRs in a batch before testing begins. | +| `merge_method` | string | How PRs are merged: `"MERGE_COMMIT"`, `"SQUASH"`, or `"REBASE"`. | +| `comments_enabled` | Boolean | Whether Trunk posts status comments on PRs. | +| `commands_enabled` | Boolean | Whether `/trunk` slash commands are enabled. | +| `create_prs_for_testing_branches` | Boolean | Create draft PRs for testing branches. | +| `status_check_enabled` | Boolean | Whether Trunk posts a status check on PRs. | +| `direct_merge_mode` | string | `"OFF"` or `"ALWAYS"`. See [Direct merge to main](/merge-queue/optimizations/direct-merge-to-main). | +| `optimization_mode` | string | `"OFF"` or `"BISECTION_SKIP_REDUNDANT_TESTS"`. | +| `bisection_concurrency` | integer | Concurrency for bisection testing during batch failure isolation. | +| `required_statuses` | list(string) | CI status checks that must pass. Set to `null` to use branch protection defaults. Set to `[]` to explicitly require no statuses. | + +*** + +## Managing Drift + +When a merge queue is managed by Terraform, the Trunk UI displays a banner indicating that the queue is under Terraform management. + +Users can still adjust merge queue settings through the UI. However, any changes made in the UI will cause **drift** between the live configuration and your Terraform state. The UI highlights when drift exists so your team is aware of the discrepancy. + +To detect drift, run: + +```bash +terraform plan +``` + +This shows any differences between your Terraform configuration and the current queue state. Run `terraform apply` to reconcile the configuration back to what is defined in Terraform, or update your `.tf` files to match the desired state. + + +If your team adjusts settings through the UI, run `terraform plan` periodically to detect drift. Apply to reconcile, or update your Terraform configuration to match the desired state. + + +*** + +## Deleting a Queue + +A merge queue must be empty before it can be deleted. If the queue still has PRs in it, `terraform destroy` will fail. + +To empty a queue, you can set `state = "DRAINING"` and wait for all in-flight PRs to finish testing and merge. Once the queue is empty, run `terraform destroy` or remove the resource from your configuration and apply. + + +Terraform will fail to delete a queue that still has PRs in it. Ensure the queue is empty before destroying the resource. + + +*** + +## Examples + +### High-Throughput Queue With Batching + +```hcl +resource "trunk_merge_queue" "main" { + repo = { + host = "github.com" + owner = "my-org" + name = "my-repo" + } + target_branch = "main" + mode = "parallel" + concurrency = 20 + batch = true + batching_min_size = 4 + batching_max_wait_time_minutes = 5 + can_optimistically_merge = true +} +``` + +### Queue With Explicit Required Statuses + +```hcl +resource "trunk_merge_queue" "main" { + repo = { + host = "github.com" + owner = "my-org" + name = "my-repo" + } + target_branch = "main" + concurrency = 3 + merge_method = "SQUASH" + commands_enabled = true + comments_enabled = true + required_statuses = [ + "ci/build", + "ci/test", + "ci/lint", + ] +} +``` diff --git a/merge-queue/optimizations/anti-flake-protection.mdx b/merge-queue/optimizations/anti-flake-protection.mdx index ae92f4d..c64692c 100644 --- a/merge-queue/optimizations/anti-flake-protection.mdx +++ b/merge-queue/optimizations/anti-flake-protection.mdx @@ -26,7 +26,7 @@ Optimistic Merging only works when the [Pending Failure Depth](#pending-failure- ### Why use it -* **Eliminate false negatives** - Flaky tests cause 20-40% of PR failures in typical pipelines. Anti-flake protection helps get these under control, so developers don't waste time investigating non-issues. +* **Eliminate false negatives** - Flaky tests frequently cause PR failures unrelated to actual code changes. Anti-flake protection helps get these under control, so developers don't waste time investigating non-issues. * **Maintain developer confidence** - When the queue rejects PRs for real reasons (not flaky tests), developers trust the system. Reduces "it's probably just flaky" dismissiveness of real failures. * **Reduce manual retries** - Developers don't need to manually resubmit PRs or click "retry" when tests flake. Trunk handles it automatically, saving time and frustration. * **Keep queue moving** - Flaky tests don't stall the queue. PRs that would have been blocked by transient failures merge successfully, increasing overall throughput. diff --git a/merge-queue/using-the-queue/force-merge.mdx b/merge-queue/using-the-queue/force-merge.mdx new file mode 100644 index 0000000..ef70d25 --- /dev/null +++ b/merge-queue/using-the-queue/force-merge.mdx @@ -0,0 +1,86 @@ +--- +title: "Force merge" +description: "Admins can push a pull request through Merge Queue even when GitHub branch protection rules aren't satisfied. The PR is still tested; only the final merge bypasses protection." +--- +### What it is + +Force merge lets a GitHub repository admin push a pull request through the Trunk Merge Queue even when branch protection requirements are not satisfied. The PR is still tested by the queue exactly like any other PR — only the final protection gate is bypassed at merge time, using the [Trunk Sudo GitHub App](/setup-and-administration/trunk-sudo-app). + + +**Force merge is admin-only and can only be triggered by a GitHub comment.** Trunk verifies admin identity via GitHub comment authorship, which is why other submission paths (CLI, checkbox, web app) don't support `--force`. If a non-admin posts `/trunk merge --force`, Trunk will reply on the PR with a rejection comment explaining that the command requires admin access. + + +### Why use it + +* **Unblock misconfigured protection.** Ship a PR when a required status check is broken or misconfigured, without disabling the rule for everyone else. +* **Merge emergency fixes safely.** You still get queue validation — predictive testing, batching, failure detection — instead of merging directly to `main` and hoping for the best. +* **Avoid direct-to-`main` bypass.** Force merge is strictly safer than pushing to the protected branch manually, because the PR is fully tested before it lands. + +### Prerequisites + +Before you can use force merge, make sure you have: + +* [ ] [Trunk Sudo GitHub App](/setup-and-administration/trunk-sudo-app) installed and configured for this repository +* [ ] GitHub admin access on the repository + +### How to use it + +#### Via GitHub comment + +On any pull request, post: + +``` +/trunk merge --force +``` + +There is no CLI, checkbox, or web app equivalent. This is intentional: Trunk verifies admin identity through GitHub comment authorship, so the command is only accepted through the PR comment flow. + +### What happens step by step + +1. **Admission.** The PR enters the queue despite branch protection not being satisfied. Normally Trunk Merge Queue waits until GitHub marks a PR as ready to merge; `--force` skips that wait. +2. **Testing.** The PR is tested normally. Batching, ordering, priority, and failure handling all behave exactly as they would for any other PR — nothing about the testing pipeline changes. +3. **Merge.** If tests pass, Trunk Sudo merges the PR, bypassing branch protection. Without Trunk Sudo installed and configured, this step will fail. +4. **Failure.** If tests fail, the PR is handled like any normal queue failure. See [Handle failed pull requests](/merge-queue/using-the-queue/handle-failed-pull-requests). + +### Combining with other flags + +Force merge can be combined with other `/trunk merge` flags. The most common combination is with [priority](/merge-queue/optimizations/priority-merging) when both urgency and protection bypass are needed — for example: + +``` +/trunk merge --force --priority=urgent +``` + +### Tradeoffs and considerations + +#### What you gain + +* **Queue validation is preserved** — tests still run before merge. +* **No direct-to-`main` push** — the PR goes through the same merge flow as every other PR. +* **Unblock stuck PRs** without weakening your default branch protection for everyone. + +#### What you give up + +* **Bypasses the human review gate** if required reviews aren't satisfied. +* **Bypasses required status checks** that would otherwise block the merge. +* Because force merge bypasses protections that every other PR must satisfy, overuse erodes the value of those protections. + +#### When NOT to use force merge + +* **Normal feature work.** If a PR is going to merge eventually, let it wait for reviews and checks. +* **"The required check is slow."** Fix the check or the CI configuration — force merge is not a substitute for unbreaking your pipeline. +* **Non-admin urgency.** If you aren't an admin, don't ask an admin to force merge your PR — escalate via the usual incident or on-call process. + +### Common misconceptions + +* **Misconception:** "Force merge skips testing." + * **Reality:** Tests still run normally. The PR goes through the full merge queue testing pipeline — only the branch protection gate is bypassed at merge time. +* **Misconception:** "I can force merge through the CLI." + * **Reality:** Force merge is comment-only and admin-only. The CLI, web app checkbox, and "Retry" button don't accept `--force`. +* **Misconception:** "Force merge is the same as emergency pull requests." + * **Reality:** [Emergency pull requests](/merge-queue/using-the-queue/emergency-pull-requests) bypass the queue entirely and push directly to your merge branch. Force merge still goes through the queue and still tests the PR — it only bypasses branch protection at merge time. + +### Next steps + +* [Trunk Sudo GitHub App](/setup-and-administration/trunk-sudo-app) — install and configure the app that powers force merge. +* [Emergency pull requests](/merge-queue/using-the-queue/emergency-pull-requests) — when the queue itself needs to be bypassed, not just branch protection. +* [Priority merging](/merge-queue/optimizations/priority-merging) — fast-track a PR without bypassing any rules. diff --git a/merge-queue/using-the-queue/reference.mdx b/merge-queue/using-the-queue/reference.mdx index 3dcf6dd..acadfad 100644 --- a/merge-queue/using-the-queue/reference.mdx +++ b/merge-queue/using-the-queue/reference.mdx @@ -16,6 +16,8 @@ trunk login trunk merge ``` +To submit a chain of dependent PRs as a single unit, see [`/trunk stack`](/merge-queue/using-the-queue/stacked-pull-requests#merge-the-stack-as-one-unit). + We offer similar commands for cancellation. * Posting a GitHub comment `/trunk cancel` on a pull request. diff --git a/merge-queue/using-the-queue/stacked-pull-requests.mdx b/merge-queue/using-the-queue/stacked-pull-requests.mdx index 9114856..8def3a8 100644 --- a/merge-queue/using-the-queue/stacked-pull-requests.mdx +++ b/merge-queue/using-the-queue/stacked-pull-requests.mdx @@ -1,65 +1,178 @@ --- -title: "Work with stacked pull requests" -description: "Yes, Trunk Merge Queue fully supports stacked pull requests. You can use stacked PR workflows with your preferred tooling (GitHub CLI, web interface, or third-party apps)." +title: "Stacked pull requests" +description: "Merge a chain of dependent pull requests through Trunk Merge Queue, either as a single combined unit with /trunk stack or one at a time with /trunk merge." --- -### How it works +Trunk Merge Queue supports merging **stacked pull requests**: a chain of PRs where each one builds on the previous, with the bottom PR targeting your merge queue branch. Trunk gives you two ways to get a stack merged: -Trunk Merge Queue determines PR dependencies by examining each pull request's **base branch** (the branch it will merge into, shown under the PR title on GitHub). +* [`/trunk stack`](#merge-the-stack-as-one-unit): combine the entire stack into a single PR that moves through the queue as one unit. Faster, and requires the [Trunk Sudo GitHub App](/setup-and-administration/trunk-sudo-app). +* [`/trunk merge`](#enqueue-each-pr-individually) on each PR: enqueue each PR in the stack separately and let Trunk process them sequentially. Slower but gives you per-PR test isolation, and has no additional setup requirements. -* If a PR's base branch is your main branch (e.g., `main`), it's ready to process immediately -* If a PR's base branch is another feature branch (indicating it's part of a stack), Merge Queue will wait until that base branch changes to your main branch before processing +## What is a stack -### Merging stacked PRs +A stack is a chain of pull requests connected through their base branches. Each PR targets the branch of the PR below it, and the bottom PR targets your merge queue branch: -#### Step 1: Enqueue all PRs in your stack +``` +merge queue branch <-- PR #1 (base: merge queue branch) + <-- PR #2 (base: PR #1's branch) + <-- PR #3 (base: PR #2's branch) +``` -Each PR in the stack must be enqueued separately. You can: +Trunk discovers the stack automatically by walking base branches. No separate configuration is required to mark PRs as stacked. -* Comment `/trunk merge` on each PR -* Check the box in the Trunk comment on each PR -* Use the CLI: `trunk merge ` for each PR +## Choose your approach -**Why enqueue separately?** Each PR is an independent merge operation in the queue. This gives you control over which PRs in your stack should be merged versus which might need more work. +| | `/trunk stack` (combined) | `/trunk merge` (individual) | +| --- | --- | --- | +| **Enqueue method** | Single `/trunk stack` comment on any PR | `/trunk merge` on each PR separately | +| **Queue processing** | One stacked PR tests and merges as a unit | Each PR tests and merges sequentially | +| **Test runs** | One test run for the combined changes | One test run per PR | +| **Speed** | Faster: one pass through the queue | Slower: each PR waits for the previous one | +| **Isolation** | Less: all changes test together | More: each PR tests against the actual merge queue branch | +| **On merge** | Member PRs closed automatically | Each PR merges individually | +| **Requirements** | [Trunk Sudo GitHub App](/setup-and-administration/trunk-sudo-app) installed and configured | No additional setup | -#### Step 2: Automatic sequential processing +## Merge the stack as one unit -Once enqueued, Trunk handles the rest automatically: +Comment `/trunk stack` on any PR in the stack and Trunk combines every PR in the chain into a single stacked PR that moves through the merge queue together. That stacked PR tests and merges like any other PR in the queue; batching, priority, and failure handling all behave normally. When the stacked PR merges, Trunk automatically closes every member PR, since its code is already in your target branch. -1. The **first PR** in the stack (base branch = `main`) enters the queue, runs tests, and merges -2. When it merges, **GitHub automatically updates** the next PR's base branch from the previous feature branch to `main` -3. The **second PR** now has `main` as its base, so it proceeds through the queue -4. This continues until all PRs in the stack are merged +### Prerequisites -**Example:** For a stack of 5 PRs: +Trunk Sudo is required because the stacked PR Trunk creates is brand-new and auto-generated, so it doesn't inherit the approvals or required status checks that have already been satisfied on the member PRs. Trunk Sudo merges the stacked PR on the strength of those member PRs by bypassing its branch protection. -* PR #1 (base: `main`) → tests → merges -* PR #2's base automatically changes from PR #1's branch to `main` → tests → merges -* PR #3's base automatically changes from PR #2's branch to `main` → tests → merges -* And so on... +* [ ] [Trunk Sudo GitHub App](/setup-and-administration/trunk-sudo-app) installed on your repository. If it isn't installed, `/trunk stack` will fail with an error linking you to the install page. +* [ ] Trunk Sudo configured to bypass branch protection on your target branch. Required status checks must live in a [GitHub ruleset](/setup-and-administration/trunk-sudo-app#option-a-github-rulesets-recommended) (not classic branch protection) with Trunk Sudo listed as an exempt bypass actor. +* [ ] You have write access to the repository, or you're a member of your repository's Trunk organization. ---- +### Stack requirements + +For `/trunk stack` to succeed, the stack must satisfy: + +* The chain terminates at your merge queue branch (e.g., `main`). +* The stack contains **2 to 10 PRs**. +* Every member PR is **open**: not closed, not a draft, not already merged. +* No member PR already belongs to another active stacked PR group. + +If any requirement fails, Trunk rejects the command with a message listing the specific problems (e.g., `#42: is a draft PR`). + +### Command syntax + +Comment on any PR in the stack: + +``` +/trunk stack [--title "Custom title"] [-p ] [--no-batch] +``` + +| Option | Short | Description | +| ------------ | ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--title` | `-t` | Custom title for the stacked PR. Defaults to the title of the **topmost** PR in the stack (the one furthest from the merge queue branch). | +| `--priority` | `-p` | [Priority level](/merge-queue/optimizations/priority-merging) for the stacked PR in the merge queue. | +| `--no-batch` | | Prevent the stacked PR from being [batched](/merge-queue/optimizations/batching) with other items in the queue. | + +**Examples:** + +``` +/trunk stack +/trunk stack --title "Feature: user authentication" +/trunk stack -t "Refactor auth module" -p 1 +/trunk stack --no-batch +``` + +### What happens when you run `/trunk stack` + +1. **Permissions check**: Trunk verifies you have write access to the repository or are a Trunk organization member. +2. **Prerequisite check**: Trunk verifies the Trunk Sudo GitHub App is installed and branch protection is configured. +3. **Stack discovery**: Trunk walks the base branch chain from your PR down to the merge queue branch, collecting all PRs. +4. **Validation**: Trunk checks every member PR is open, not a draft, and not already in another stack. If anything fails, the command is rejected. +5. **Temporary branch**: Trunk creates a branch at the current HEAD of your merge queue branch, named `trunk-stack/`. +6. **Sequential merge**: Trunk merges each member PR into the temporary branch starting from the PR closest to the merge queue branch. If any merge conflicts occur, the operation fails and you'll need to resolve conflicts before retrying. +7. **Stacked PR creation**: Trunk opens a new pull request from `trunk-stack/` to your target branch. +8. **Enqueue**: The stacked PR is automatically added to the merge queue. +9. **Status comments**: Trunk comments on each member PR to note that a stacked PR has been created and is queued. + +Trunk reacts to your `/trunk stack` comment with a 👍 on success, or a 👎 plus an explanation on failure. + +### The stacked PR + +The stacked PR is a real GitHub pull request containing the combined changes from every member PR. + +* **Title**: If you passed `--title`, that title is used exactly. Otherwise it defaults to the title of the topmost PR in the stack. +* **Body**: Auto-generated. Includes the list of member PRs, the target branch, and an explanation of how the stacked PR works (merge behavior, automatic closure of member PRs, cancellation triggers). +* **Branch**: `trunk-stack/`. Managed entirely by Trunk and cleaned up automatically when the stacked PR merges or is cancelled. + +### Lifecycle -### Important considerations +#### On successful merge -#### Sequential testing +1. Each member PR is automatically closed by Trunk, since its code is already in the target branch via the stacked PR. +2. Trunk posts a comment on each member PR: "Stacked PR #N merged successfully. Closing this PR as its code has been merged into ``." +3. The `trunk-stack/` branch is deleted. -PRs in a stack are tested and merged **one at a time** in order. The second PR won't begin testing until the first PR has fully merged. This ensures: +#### On test failure -* Each PR is tested against the actual state of your main branch -* No conflicts arise from dependencies -* Test results are deterministic and reliable +1. Trunk posts a comment on each member PR: "Stacked PR #N failed testing in the merge queue. Please investigate the failure and re-submit the stack." +2. The stacked PR is closed on GitHub. +3. The `trunk-stack/` branch is deleted. -**Tradeoff:** This sequential approach means that a stack of 5 PRs will take longer to merge than 5 independent PRs, since they cannot be tested in parallel. However, it provides the safest merge path for dependent changes. +Fix the issue in the relevant member PR, then run `/trunk stack` again to create a fresh stacked PR. -#### Enqueued PRs with non-main base branches +#### On cancellation -If you enqueue a PR whose base branch is not your main branch and that base never changes to main, the PR will remain in the queue without processing. This typically happens if: +The stacked PR is automatically cancelled if any of the following happens: + +| Trigger | What it means | +| ------------------------------------ | ------------------------------------------------------------------- | +| **Member PR pushed to** | A new commit is pushed to any member PR's branch. | +| **Member PR closed** | Any member PR is closed without merging. | +| **Member PR merged independently** | Any member PR is merged outside of the stacked PR workflow. | +| **Member PR base branch changed** | The base branch of any member PR is changed. | +| **Stacked PR closed** | The stacked PR itself is closed manually. | +| **Stacked PR pushed to** | The stacked PR's branch is pushed to directly. | +| **User cancelled** | Someone runs `/trunk cancel` on the stacked PR. | + +When cancellation occurs, Trunk posts a comment on each member PR explaining the reason (e.g., "Stacked PR #N was cancelled: a member PR was pushed to.") and closes the stacked PR. To re-stack, run `/trunk stack` again on any member PR. This creates a fresh stacked PR with the latest state of all member PRs. + +### Why `/trunk stack` creates a separate PR + +An obvious-sounding shortcut would be to test the stack against `main`, then fast-forward `main` to the top of the stack once tests pass. That doesn't work. + +Trunk Merge Queue uses [predictive testing](/merge-queue/optimizations/predictive-testing): every PR is tested against the projected future state of the target branch, not its current state, and multiple PRs test concurrently against different speculative merge states. By the time your stack finishes testing, the actual target branch tip has almost certainly advanced past where your stack was based: one or more PRs ahead in the queue have merged. You can't fast-forward past those intermediate merges, and pushing over them would skip testing against the new tip: exactly the stale-results blind spot the queue exists to eliminate. + +Wrapping the stack in a synthetic PR hands it off to the same predictive-testing machinery every other PR uses. The queue tests it against the current projected future state and produces a real merge commit incorporating both the stack's changes and anything that landed ahead of it. Everything else falls out for free: batching, priority, optimistic merging, failure handling, `/trunk cancel`, and a real PR visible in GitHub's history. + +## Enqueue each PR individually + +If you prefer per-PR test isolation, or you don't want to install Trunk Sudo, you can enqueue each PR in the stack separately with `/trunk merge`. Trunk processes the PRs sequentially, testing and merging each one against the actual state of your merge queue branch. + +### Step 1: Enqueue every PR in the stack + +Each PR in the stack must be enqueued separately. Use any of the standard submission methods on every PR: + +* Comment `/trunk merge` on each PR. +* Check the box in the Trunk comment on each PR. +* Use the CLI: `trunk merge ` for each PR. + +Enqueuing each PR separately gives you control over which PRs in your stack should be merged versus which might need more work. + +### Step 2: Automatic sequential processing + +Once enqueued, Trunk handles the rest: + +1. The **bottom PR** in the stack (base branch = your merge queue branch) enters the queue, runs tests, and merges. +2. When it merges, **GitHub automatically updates** the next PR's base branch from the previous feature branch to your merge queue branch. +3. The **next PR** now targets the merge queue branch, so it proceeds through the queue. +4. This continues until every PR in the stack is merged. + +For example, a stack of 5 PRs with merge queue branch `main`: + +* PR #1 (base: `main`) → tests → merges +* PR #2's base automatically changes to `main` → tests → merges +* PR #3's base automatically changes to `main` → tests → merges +* …and so on. -* The parent PR in the stack was not enqueued or merged -* You're testing queue behavior with a non-standard workflow +### Considerations -The PR will begin processing as soon as its base branch updates to your main branch. +**Sequential testing.** PRs in the stack are tested and merged one at a time in order. The second PR won't begin testing until the first PR has fully merged. This ensures each PR is tested against the actual state of your merge queue branch and results are deterministic, at the cost of speed. A stack of 5 PRs takes substantially longer than 5 independent PRs, since they can't be tested in parallel. -### Configuration +**Enqueued PRs with non-merge-branch bases.** If you enqueue a PR whose base branch is not your merge queue branch and that base never updates, the PR stays in the queue without processing. This typically means the parent PR in the stack was never enqueued or merged. The PR will begin processing as soon as its base branch updates to the merge queue branch. -No special configuration is required. Trunk Merge Queue automatically detects stacked relationships based on the base branch field in GitHub. +**No special configuration.** Individual enqueuing requires no additional setup beyond a functioning merge queue. Trunk detects the stack relationship automatically from each PR's base branch. diff --git a/setup-and-administration/trunk-sudo-app.mdx b/setup-and-administration/trunk-sudo-app.mdx new file mode 100644 index 0000000..03b0066 --- /dev/null +++ b/setup-and-administration/trunk-sudo-app.mdx @@ -0,0 +1,115 @@ +--- +title: "Trunk Sudo GitHub App" +description: "Install and configure the Trunk Sudo GitHub App, a secondary Trunk app used by features that need to merge pull requests while bypassing GitHub branch protections." +--- +Trunk Sudo is a second Trunk GitHub App, separate from the [main Trunk GitHub App](/setup-and-administration/github-app-permissions). Its only purpose is to programmatically merge pull requests while bypassing GitHub branch protections, on behalf of Trunk features that need that capability. + +Trunk Sudo is a shared prerequisite for bypass-dependent features. Today it powers [Force merge](/merge-queue/using-the-queue/force-merge) and [stacked pull requests with `/trunk stack`](/merge-queue/using-the-queue/stacked-pull-requests#merge-the-stack-as-one-unit). + + +**Trunk Sudo is optional.** You only need to install it if you plan to use a feature that requires it. If you don't use any bypass-dependent features, you can skip this setup. + + +### Prerequisites + +Before you begin, make sure you have: + +* [ ] Admin access to your GitHub organization +* [ ] The [main Trunk GitHub App](/setup-and-administration/github-app-permissions) already installed +* [ ] Branch protection already configured for your merge branch (classic rules, rulesets, or both) + +### Install the Trunk Sudo GitHub App + +You can install Trunk Sudo from either the Trunk web app or directly on GitHub — both paths land at the same GitHub install flow. + +1. **From the Trunk web app (recommended):** Navigate to your repository's **Merge Queue** settings page. The Trunk Sudo setup panel includes an **Install** button that opens GitHub's install flow. +2. **Directly on GitHub:** Go to [https://github.com/apps/trunk-sudo](https://github.com/apps/trunk-sudo) and click **Install**. + +In the GitHub install flow: + +1. Select whether to install on all repositories or only specific ones. You must include every repository where you want to use a bypass-dependent feature. +2. Review and approve the required permissions (see [Permissions reference](#permissions-reference) below). +3. Complete the installation. + +### Configure branch protection for Trunk Sudo + +Installing the app isn't enough on its own — your branch protection configuration must also allow Trunk Sudo to bypass the relevant rules when it merges. GitHub has two systems for branch protection: **classic branch protection rules** and **rulesets**. Both can coexist on the same branch. + +**Rulesets are strongly recommended.** Classic branch protection has rules that cannot be bypassed by any GitHub App (notably required status checks and "Require branches to be up to date"), so using classic protection alone will block Trunk Sudo from merging. Rulesets don't have this limitation. + +#### Option A — GitHub Rulesets (recommended) + +In GitHub, navigate to **Settings → Rules → Rulesets**. For every active ruleset that applies to your merge branch: + +1. Open the ruleset. +2. Under **Bypass list**, add the **Trunk Sudo** GitHub App. +3. Set its bypass mode to **Exempt**. +4. Save. + + +**This is the most common setup mistake.** When you add an actor to a ruleset's bypass list, GitHub defaults the bypass mode to **Always** — which sounds like it covers everything but does not cover pull request merges. Trunk Sudo must be set to **Exempt**; it's the only mode that lets a GitHub App merge a PR without interactive confirmation. If Trunk Sudo isn't set to Exempt, merges will silently fail. + + +#### Option B — Classic branch protection + +If you're using classic branch protection rules, navigate to **Settings → Branches → Branch protection rules** and edit the rule for your merge branch. + +1. If **"Require a pull request before merging" → "Require approvals"** is enabled, enable **"Allow specified actors to bypass required pull requests"** and add **Trunk Sudo** to the allow list. +2. If **"Restrict who can push to matching branches"** is enabled, add **Trunk Sudo** to the allowed actors list. +3. Remove any entries under **"Require status checks to pass before merging"**. Classic branch protection does not allow apps to bypass required status checks. +4. Disable the nested **"Require branches to be up to date before merging"** checkbox. This setting also cannot be bypassed on classic protection. + + +**Classic branch protection has unbypassable rules.** Required status checks and "Require branches to be up to date" cannot be bypassed by any GitHub App. If you need those protections, move the rule to a ruleset with Trunk Sudo listed as an exempt bypass actor — otherwise Trunk Sudo will be unable to merge. + + +### Verify your setup + +The Trunk Merge Queue settings page includes a live checklist that validates every piece of the Trunk Sudo configuration end-to-end. **This checklist is the source of truth for whether your setup is correct** — if the checklist is green, the app is ready to merge. + +Each row shows the status of one check (installation, classic branch protection, and one row per active ruleset on the merge branch). If a row is red, revisit the corresponding section above — the check IDs map directly to the configuration surfaces described here. + +### Permissions reference + +Trunk Sudo requests the following repository permissions. Each one is required for a specific part of the merge bypass flow. + +#### Administration (Read-only) + +This permission includes read-only access to repository settings, teams, and collaborators. + +Trunk Sudo uses this permission to read your current branch protection and ruleset configuration so it can determine whether it is correctly set up to bypass protections before attempting a merge. + +#### Metadata (Read-only) + +This permission includes access to search repositories, list collaborators, and access repository metadata. + +This permission is required by all GitHub applications that access repository information. + +#### Contents (Read and write) + +This permission includes access to repository contents, commits, branches, downloads, releases, and merges. + +Trunk Sudo uses this permission to merge pull requests into your merge branch. + +#### Pull requests (Read and write) + +This permission includes access to pull requests and merges. + +Trunk Sudo uses this permission to read PR state and to complete the merge operation. + +#### Workflows (Read and write) + +This permission includes access to update GitHub Action workflow files. + +Required so Trunk Sudo can merge PRs that modify files under `.github/`. GitHub blocks any merge that touches workflow files unless the merging actor has this permission. + +### Features that use Trunk Sudo + +* [Force merge](/merge-queue/using-the-queue/force-merge) — admins push a PR through Merge Queue even when branch protection isn't satisfied. +* [Stacked pull requests with `/trunk stack`](/merge-queue/using-the-queue/stacked-pull-requests#merge-the-stack-as-one-unit) — combine a chain of dependent PRs into a single stacked PR that moves through the merge queue as one unit. + +### Next steps + +→ [**Force merge**](/merge-queue/using-the-queue/force-merge) — use the Trunk Sudo app to merge PRs through the queue that don't satisfy branch protection. + +→ For the main Trunk GitHub App and its permissions, see [Trunk GitHub App](/setup-and-administration/github-app-permissions).