diff --git a/src/components/Tables/ConfigOptions.test.tsx b/src/components/Tables/ConfigOptions.test.tsx index 9924ce5179..31c84f694a 100644 --- a/src/components/Tables/ConfigOptions.test.tsx +++ b/src/components/Tables/ConfigOptions.test.tsx @@ -84,6 +84,59 @@ describe('getValueType with x-has-data-type', () => { }); }); +// An untitled $defs entry — pydantic publishes one for a model that overrides +// its JSON schema with a union wrapper (batch_size) — has no label to render, +// so both renderers expand the target instead of emitting an empty type. +const untitledUnionSchema = { + $defs: { + BatchSizeBounds: { + anyOf: [ + { type: 'integer', minimum: 1, maximum: 128 }, + { + type: 'object', + title: 'BatchSizeBounds', + properties: { min: { type: 'integer' }, max: { type: 'integer' } }, + required: ['min', 'max'], + }, + ], + }, + }, +}; + +describe('getValueType with an untitled $ref target', () => { + it('expands the union instead of rendering an empty type', () => { + const html = render(untitledUnionSchema, { $ref: '#/$defs/BatchSizeBounds' }); + expect(html).toContain('integer'); + expect(html).toContain('or'); + expect(html).toContain('{min, max}'); + }); + + it('names the keys of an inline object shape', () => { + const html = render( + {}, + { type: 'object', properties: { min: { type: 'integer' }, max: { type: 'integer' } } } + ); + expect(html).toContain('{min, max}'); + }); + + it('still renders the title of a titled $ref target', () => { + const schema = { $defs: { Commit: { title: 'Commit', type: 'object' } } }; + expect(render(schema, { $ref: '#/$defs/Commit' })).toContain('Commit'); + }); +}); + +describe('getValueTypeText with an untitled $ref target', () => { + it('expands the union instead of emitting an empty cell', () => { + expect( + getValueTypeText(untitledUnionSchema as never, { $ref: '#/$defs/BatchSizeBounds' }) + ).toBe('integer or `{min, max}`'); + }); + + it('does not crash on a dangling $ref', () => { + expect(getValueTypeText({ $defs: {} } as never, { $ref: '#/$defs/Gone' })).toBe(''); + }); +}); + describe('getValueTypeText with x-has-data-type', () => { it('emits a markdown link instead of the enum dump', () => { expect(getValueTypeText({} as never, inlineMarked)).toBe(`[Queue dequeue reason](${HREF})`); diff --git a/src/components/Tables/ConfigOptions.tsx b/src/components/Tables/ConfigOptions.tsx index 9e91dd945a..33c67b0a5a 100644 --- a/src/components/Tables/ConfigOptions.tsx +++ b/src/components/Tables/ConfigOptions.tsx @@ -198,6 +198,15 @@ export function getValueType(schema: object, definition: any): React.ReactElemen valueType = <>list of {typeDescription}; } } else if (definition.$ref !== undefined) { + if (!getTitle(schema, definition.$ref)) { + // An untitled `$defs` entry carries a shape and no label — pydantic + // publishes one whenever a model overrides its JSON schema with a union + // wrapper. Expand the target so the union renders like an inline one, + // instead of showing an empty type. + const target = getItemFromSchema(schema, definition.$ref); + return target ? getValueType(schema, target) : null; + } + const typeLink = getTypeLink(definition.$ref); const typeDescription = (
" so the // templated value type still links to its data-types section. valueType = <>map of {getValueType(schema, definition.additionalProperties)}; + } else if (definition.type === 'object' && definition.properties) { + // An inline object shape has no name to show: list its keys, which is what + // a reader needs to write the value. + valueType = ( + {`{${Object.keys(definition.properties).join(', ')}}`} + ); } else { valueType = {definition.type}; } diff --git a/src/content/docs/merge-queue/monitoring.mdx b/src/content/docs/merge-queue/monitoring.mdx index fee333e4c0..67e3600084 100644 --- a/src/content/docs/merge-queue/monitoring.mdx +++ b/src/content/docs/merge-queue/monitoring.mdx @@ -6,8 +6,8 @@ description: Monitor key metrics of your merge queue to improve throughput and r import { Image } from "astro:assets" import dashboardStatsScreenshot from "../../images/merge-queue/monitoring/dashboard.png" -Monitoring your merge queue's key metrics helps you identify bottlenecks, -optimize throughput, and maintain an efficient development cycle. +The Mergify dashboard reports how your merge queue has performed over time, and +the Mergify CLI reports what it is doing right now. ## The Statistics Page @@ -17,14 +17,29 @@ Open **Merge Queue → Statistics** in your Statistics page on Mergify's dashboard Use the date picker to select the time range you want to review. Presets go up to -"Past 3 months". Queue data is retained for 90 days, so the oldest day or two of -that longest preset can come back empty. A repository selector and filters narrow -every widget on the page at once. +"Past 3 months". Queue data is retained for 90 days: the calendar will not let you +pick a day older than that, and the oldest day or two of the longest preset can +come back empty. + +Three controls apply to every widget on the page at once: + +- The **repository selector** chooses which repository the page reports on. + +- **Filters** restrict the data to a set of branches, + [queue rules](/merge-queue/rules), or + [priority rules](/merge-queue/priority). + +- **Breakdown** keeps all the data but splits each chart into one series per + branch, queue rule, or priority rule, so you can compare them side by side. + Clicking a series narrows the page down to it. **Max Running Checks** is the + one widget that cannot be broken down by priority rule: a running check covers + a batch of pull requests that may come from different priority rules, so it + cannot be attributed to a single one. A row of headline figures sits at the top: pull requests entered and merged, the -merged rate, time spent waiting for CI, max queue size, throughput, queue time, -CI runtime, and CI failure rate. Below it, the widgets are grouped into three -sections. +merged rate, the share of queue time spent waiting for CI capacity, max queue +size, throughput, queue time, CI runtime, and CI failure rate. Below it, the +widgets are grouped into three sections. ### Queue Health @@ -53,8 +68,7 @@ Exit reasons, interruptions, and failure trends. Volume of pull requests processed and queue capacity. - **Entered PRs** and **Merged PRs**: how many pull requests joined and left the - queue over time. A consistent trend indicates a stable development - environment; sudden drops or spikes are worth investigating. + queue over time. Sudden drops or spikes are worth investigating. - **Max Queue Size**: the largest the queue got. The reference line marks your max checks capacity (max batch size × @@ -65,8 +79,10 @@ Volume of pull requests processed and queue capacity. [`batch_size`](/merge-queue/batches) configured across your queue rules. Sitting at the maximum suggests the queue is saturated. -- **Max Running Checks**: peak concurrent checks. If you are often at capacity, - raising `max_parallel_checks` improves throughput. +- **Max Running Checks**: peak concurrent checks. The reference line is your + effective `max_parallel_checks` (the configured value, or the default when it + is unset). If you are often at that line, raising `max_parallel_checks` + improves throughput. ### Performance @@ -131,12 +147,8 @@ mergify queue show ``` This displays the PR's position, priority, queue rule, CI checks summary, and -blocking conditions. Use `--verbose` (`-v`) for the full checks table and -conditions tree: - -```bash -mergify queue show 123 --verbose -``` +blocking conditions. See the +[`mergify queue show` reference](/cli/queue#mergify-queue-show) for its flags. ## Integrations diff --git a/src/content/docs/test-insights.mdx b/src/content/docs/test-insights.mdx index bc6c1a720b..dc6fc1c918 100644 --- a/src/content/docs/test-insights.mdx +++ b/src/content/docs/test-insights.mdx @@ -53,6 +53,11 @@ known flakiness. decisions. The test still runs and results are still collected, preserving full visibility. +- **Default branch scope**: Test health across repositories comes from runs on + the default branch. Pull request runs feed + [Prevention](/test-insights/prevention) instead. See + [which runs Detection reports on](/test-insights/detection#which-runs-detection-reports-on). + ## Setup Test Insights is powered by the same CI integration as diff --git a/src/content/docs/test-insights/detection.mdx b/src/content/docs/test-insights/detection.mdx index ae497fb510..ff0f844653 100644 --- a/src/content/docs/test-insights/detection.mdx +++ b/src/content/docs/test-insights/detection.mdx @@ -12,6 +12,23 @@ see the full picture and prioritize what to fix. Detection dashboard: tests health donut and CI impact chart +## Which runs Detection reports on + +Detection reports on tests that ran on your repository's default branch. +Results uploaded from pull request branches are stored, but they do not +contribute to the metrics shown here. + +A repository whose CI has only ever run on pull requests shows an empty +Detection page, even though uploads are working. Merge to the default branch +and the tests appear after that run completes. + +The same scope applies outside the dashboard: the +[`mergify tests show`](/cli/tests) command and the +[test search API](/api/test-insights) return default-branch results. + +[Prevention](/test-insights/prevention) covers the pull request side of Test +Insights: it reports on tests running on pull request branches. + ## How tests are classified Mergify classifies tests based on their results across multiple CI runs, diff --git a/src/content/images/merge-queue/monitoring/dashboard.png b/src/content/images/merge-queue/monitoring/dashboard.png index 8bb6939d6e..09f844905b 100644 Binary files a/src/content/images/merge-queue/monitoring/dashboard.png and b/src/content/images/merge-queue/monitoring/dashboard.png differ diff --git a/src/util/schemaToMarkdown.ts b/src/util/schemaToMarkdown.ts index 15d418cb3a..c42e24a796 100644 --- a/src/util/schemaToMarkdown.ts +++ b/src/util/schemaToMarkdown.ts @@ -72,7 +72,13 @@ export function getValueTypeText(schema: Schema, definition: any): string { } if (definition.$ref !== undefined) { - return getTitle(schema, definition.$ref); + const title = getTitle(schema, definition.$ref); + if (title) { + return title; + } + // Untitled `$defs` entry: expand the target rather than emit an empty cell. + const target = getItemFromSchema(schema, definition.$ref); + return target ? getValueTypeText(schema, target) : ''; } if (definition.anyOf || definition.oneOf || definition.allOf) { @@ -92,6 +98,10 @@ export function getValueTypeText(schema: Schema, definition: any): string { return definition.format; } + if (definition.type === 'object' && definition.properties) { + return `\`{${Object.keys(definition.properties).join(', ')}}\``; + } + return definition.type || ''; }