From 023f194cb86f13134174ab91ac2291235242549c Mon Sep 17 00:00:00 2001 From: Thomas Berdy Date: Sat, 18 Jul 2026 21:53:16 +0200 Subject: [PATCH] feat: link typed template variables to their data type section Template variables whose value is drawn from an enumerated data type now render as a link to the matching data-types section instead of as a free-form string. The engine tags such variables with a `type` token in `x-mergify-template-variables`; the docs map the token to its section (currently `queue_dequeue_reason` -> Queue Dequeue Reason). Keying off the schema-published token replaces the earlier hardcoded variable-name special-case, so a future typed variable needs only its engine annotation plus one entry in the docs token map. The bundled schema update pre-syncs the marker ahead of the automated JSON Schema sync; the bot will reconcile it identically once the engine change lands. Co-Authored-By: Claude Opus 4.8 (1M context) Change-Id: Ib15295d0fa731301b3b8d29b5af205df496f458a --- public/mergify-configuration-schema.json | 9 +++-- .../Tables/TemplateVariablesTable.tsx | 35 ++++++++++++++----- src/util/templateVariables.test.ts | 23 ++++++++++++ src/util/templateVariables.ts | 5 +++ 4 files changed, 61 insertions(+), 11 deletions(-) diff --git a/public/mergify-configuration-schema.json b/public/mergify-configuration-schema.json index d235c340a6..c0949ce973 100644 --- a/public/mergify-configuration-schema.json +++ b/public/mergify-configuration-schema.json @@ -606,7 +606,8 @@ }, { "description": "Why the pull request left the merge queue; empty outside queue contexts.", - "name": "queue_dequeue_reason" + "name": "queue_dequeue_reason", + "type": "queue-dequeue-reason" } ] } @@ -800,7 +801,8 @@ }, { "description": "Why the pull request left the merge queue; empty outside queue contexts.", - "name": "queue_dequeue_reason" + "name": "queue_dequeue_reason", + "type": "queue-dequeue-reason" } ] }, @@ -4754,7 +4756,8 @@ }, { "description": "Why the pull request left the merge queue; empty outside queue contexts.", - "name": "queue_dequeue_reason" + "name": "queue_dequeue_reason", + "type": "queue-dequeue-reason" } ] }, diff --git a/src/components/Tables/TemplateVariablesTable.tsx b/src/components/Tables/TemplateVariablesTable.tsx index 3db0f174e5..5b28595925 100644 --- a/src/components/Tables/TemplateVariablesTable.tsx +++ b/src/components/Tables/TemplateVariablesTable.tsx @@ -8,6 +8,16 @@ interface TemplateVariablesTableProps extends Def { field: string; } +// A template variable whose value is drawn from an enumerated data type carries a +// `type` token in the schema (`x-mergify-template-variables[].type`). Map that token +// to the data type section listing the accepted values, mirroring how option value +// types link to their data type (see ConfigOptions `valueTypeFormatLinks`). Keying +// off the schema-published token means a new typed variable needs only its engine +// annotation plus one entry here — no per-variable-name special-casing. +const variableTypeLinks: Record = { + 'queue-dequeue-reason': '/configuration/data-types#queue-dequeue-reason', +}; + export default function TemplateVariablesTable({ def, field }: TemplateVariablesTableProps) { const schema = configSchema as unknown as ConfigSchema; const definition = schema.$defs[def]?.properties?.[field]; @@ -31,14 +41,23 @@ export default function TemplateVariablesTable({ def, field }: TemplateVariables - {variables.map((variable) => ( - - - {`{{ ${variable.name} }}`} - - - - ))} + {variables.map((variable) => { + const typeLink = variable.type ? variableTypeLinks[variable.type] : undefined; + return ( + + + {typeLink !== undefined ? ( + + {`{{ ${variable.name} }}`} + + ) : ( + {`{{ ${variable.name} }}`} + )} + + + + ); + })} diff --git a/src/util/templateVariables.test.ts b/src/util/templateVariables.test.ts index 45f1ca534d..3d67afd010 100644 --- a/src/util/templateVariables.test.ts +++ b/src/util/templateVariables.test.ts @@ -50,6 +50,29 @@ describe('extractTemplateVariables', () => { ]); }); + it('carries the optional type token through for enumerated-value variables', () => { + const definition = { + type: 'string', + format: 'simple-template', + 'x-mergify-template-variables': [ + { name: 'author', description: 'PR author login' }, + { + name: 'queue_dequeue_reason', + description: 'Why the PR left the queue', + type: 'queue-dequeue-reason', + }, + ], + }; + expect(extractTemplateVariables(definition)).toEqual([ + { name: 'author', description: 'PR author login' }, + { + name: 'queue_dequeue_reason', + description: 'Why the PR left the queue', + type: 'queue-dequeue-reason', + }, + ]); + }); + it('returns [] when no template variables are present', () => { expect(extractTemplateVariables({ type: 'string' })).toEqual([]); expect(extractTemplateVariables(null)).toEqual([]); diff --git a/src/util/templateVariables.ts b/src/util/templateVariables.ts index 35ceedfff7..8b9b7c4913 100644 --- a/src/util/templateVariables.ts +++ b/src/util/templateVariables.ts @@ -1,6 +1,11 @@ export interface TemplateVariable { name: string; description: string; + // Some variables resolve to a value drawn from an enumerated data type rather than + // a free-form string. The schema tags those with a stable token (e.g. + // `queue-dequeue-reason`) that renderers map to the matching data type section. + // Absent for free-form string variables. + type?: string; } // Field definitions publish their allowlist under this custom JSON-schema key.