[Batch 1] Add tier annotations to Plan API endpoints
What does this MR do and why?
Adds route_setting :tier to the 32 Plan API routes that need a paid subscription to access. This is documentation only.
route_setting :tier, :premium | :ultimate is a Grape route setting. The OpenAPI generator turns it into x-gitlab-tier in doc/api/openapi/openapi_v3.yaml. That lets API consumers see which subscription tier an endpoint needs.
Nothing reads this setting at runtime. There is no behavior change and no permission change.
This is the first (pilot) MR in a series. The series backfills about 308 Premium and Ultimate routes, split by product area. The annotation was introduced in an earlier MR, but only 3 visible routes use it so far. This MR covers Plan: 32 routes in 11 files. Free endpoints need no annotation.
What changed
- 30
route_setting :tierlines in 11 files, each added above the route'sroute_setting :authorization. Two definitions each serve both/epicsand/-/epics, so 30 lines cover 32 routes. - Regenerated
openapi_v3.yaml: +32x-gitlab-tierlines (27 premium, 5 ultimate). Nothing else changed.
Grape route settings do not cascade. They reset after each endpoint, so the setting must be set on every route.
Code is the source of truth and docs are a cross-check. I checked each tier against the licensed-feature check in code (helpers, before blocks, policies). A tracer that recorded license checks during the request specs helped.
Per-route evidence
| Routes | Tier | Gate in code |
|---|---|---|
| Epic boards (4), epics show (2), epic issues GET/POST/PUT (4), epic to-do (1) | Premium | epics licensed feature |
| Epics POST/PUT/DELETE (3), epic issues DELETE (1) | Premium | epics, via class-level before { authorize_epics_feature! } |
| Related epic links (4) | Premium | related_epics and epics, via class-level before block |
| Iterations, project and group (2) | Premium | iterations, via read_iteration policy |
| Group boards POST/DELETE (2) | Premium | multiple_group_issue_boards, via multiple_issue_boards_available? |
| Milestone burndown events, group and project (2) | Premium | milestone_charts (returns 405 without it) |
| Child epics create/assign/re-order/unassign (4) | Ultimate | subepics |
| Child epics list (1) | Ultimate | Rule applied, see reviewer notes |
| Resource iteration events (2) | Premium | Rule applied, see reviewer notes |
Reviewer notes
Tier rule
Annotate the lowest tier at which the endpoint does something useful. Usually that's the route's own license check. When a read endpoint is gated lower than the feature that creates its data (child epics list, iteration events), use the tier that creates the data. The docs are a cross-check, not the source. When they disagree with this rule, flag the doc for a fix.
Notes
- Child epics list: Ultimate. The code only checks the Premium
epicsfeature. Only Ultimate can create child epics, so on Premium the list is usually empty. - Resource iteration events: Premium. The code only needs
read_issue. Iteration events only exist where Premium iterations are used. This matches the docs. - Related epic links: Premium. The routes are gated on the Premium
related_epicsandepicsfeatures. The docs say Ultimate, which looks stale. I flagged it to Portfolio Planning and did not change the docs here.
How to set up and validate locally
- Run
bin/rake gitlab:openapi:v3:generate. Confirm the diff only addsx-gitlab-tierlines. - Run
grep -c x-gitlab-tier doc/api/openapi/openapi_v3.yaml. Expect 35 (was 3). - RuboCop is clean and
spec/lib/api/every_api_endpoint_spec.rbpasses.
Related to #631956