feat: emit parameter-level annotations
What does this MR do and why?
Implements the add-parameter-extensions OpenSpec change from the previous MR in the stack.
-
The new option:
config.parameter_annotations, a Hash defaulting to{}. It maps keys of a param'sdocumentation:hash to OpenAPI vendor extensions. Nothing changes for callers that don't set it. -
Where extensions appear: on query and path parameter objects, after their standard keys. That includes:
- bracketed
filter[x]parameters, each from its owndocumentation:; - params from
with-wrapped helpers, where a param's own value wins; - path parameters borrowed from a sibling route.
They also appear on request-body properties at any depth. On an
Arrayparam the extension sits on the property, not itsitems. - bracketed
-
How values are written: see the previous MR. Symbols become Strings, Hash keys become Symbols and
niladds nothing. Any other value is dropped, with adropped parameter annotationwarning whenconfig.warningsis on. -
One shared reader for both paths: a single concern,
Concerns::ParameterAnnotatable. On the query/path side it's read only afterParameterConverter#convert's early returns, so body params and hidden params never warn twice or by mistake. -
Docs: README gets a new "Parameter annotations" section. The table now includes the new option, and an unterminated code fence in the existing "Annotations" example is closed.
gitlab-org/gitlab impact
On release: none. I compared the monolith's bin/rake gitlab:openapi:v3:generate output with the gem on main and on this branch, with the monolith configuration unchanged. openapi_v3.yaml, stdout and stderr were byte-identical, and stderr was empty on both sides.
With annotations in use, I tried a local-only edit in the monolith:
- set
config.parameter_annotations = { tier: 'x-gitlab-tier' }; - added
documentation: { tier: :premium }toweightinee/lib/ee/api/helpers/issues_helpers.rb(issues_stats_params_ee).
The only change to the document was 6 added lines: x-gitlab-tier: premium on the weight query parameter of the issues list and statistics operations. Those are getApiV4Issues, getApiV4IssuesStatistics, getApiV4GroupsIdIssues, getApiV4GroupsIdIssuesStatistics, getApiV4ProjectsIdIssues and getApiV4ProjectsIdIssuesStatistics.
Before (GET /api/v4/issues):
- name: weight
required: false
description: The weight of the issue
schema:
oneOf:
- type: integer
nullable: true
- type: string
nullable: true
in: queryAfter:
- name: weight
required: false
description: The weight of the issue
schema:
oneOf:
- type: integer
nullable: true
- type: string
nullable: true
in: query
x-gitlab-tier: premiumHow to verify
bundle exec rspec # 1077 examples, 0 failures on Grape 3.2.1 and 2.4.0
bundle exec rubocop
npx -y @fission-ai/openspec@1.13.2 validate --all --strictBefore merging
- Run
/opsx:archiveon this branch, so the MR carries the updatedopenspec/specs/(seeCLAUDE.md).
Closes #32
Stack
- !68 (merged): OpenSpec baseline (
docs/openspec-baseline→main) - !69 (merged): Specification for #32 (
32-specify-parameter-annotations→docs/openspec-baseline) - !70: Implementation for #32 (
32-support-parameter-annotations→32-specify-parameter-annotations) (this MR)
Merge from the bottom up: !68 (merged), then !69 (merged), then !70.