Correct the deployments list sort, status and filter docs

What does this MR do?

The "List all project deployments" section of the Deployments API page does not match what the endpoint accepts. This MR corrects three things in doc/api/deployments.md:

  • order_by no longer offers ref. GitLab 16.3 removed ref from DeploymentsFinder::ALLOWED_SORT_VALUES (!127519 (merged)), which the endpoint declares as the values of order_by, so order_by=ref is answered with 400 order_by does not have a valid value.
  • status now lists skipped. The parameter takes every key of Deployment.statuses, skipped included, and filtering by it returns skipped deployments.
  • The note under the endpoint said that with finished_before or finished_after you "should" set order_by=finished_at and status=success. Those are requirements, and they are one of four cases in which the endpoint answers 400 Bad Request. The note now lists all four, taken from DeploymentsFinder#validate!:
    • updated_after or updated_before without order_by=updated_at.
    • finished_after or finished_before without order_by=finished_at, status=success, or both.
    • order_by=finished_at without finished_after, finished_before, or a status of success, failed, or canceled.
    • updated_* and finished_* filters in the same request.

DeploymentsFinder#validate! makes two more checks that a request to this endpoint cannot fail, so the note leaves them out: the environment name filter always has a project here, and status takes one value (status[]=success&status[]=created is refused with status is invalid before the finder runs), so finished and upcoming statuses cannot be asked for together.

The enums in doc/api/openapi/openapi_v3.yaml already agree with the code for both parameters. Only the descriptions there still mention ref and leave out skipped, and those come from the desc strings in lib/api/deployments.rb, which !260551 (merged) is rewriting, so this MR does not touch that file or the OpenAPI document.

This MR implements no issue. I found the two rows by comparing the parameter tables of the API pages with the OpenAPI document, and checked the note while confirming them.

How I checked it

Code, at master d77ac9dd142:

  • lib/api/deployments.rb: order_by declares values: DeploymentsFinder::ALLOWED_SORT_VALUES, status declares type: String, values: Deployment.statuses.keys, and the endpoint answers DeploymentsFinder::InefficientQueryError with bad_request!(e.message).
  • app/finders/deployments_finder.rb: ALLOWED_SORT_VALUES = %w[id iid created_at updated_at finished_at], and validate! raises for the cases above.
  • app/models/deployment.rb: the status enum is created, running, success, failed, canceled, skipped, blocked. FINISHED_STATUSES is success, failed, canceled, and UPCOMING_STATUSES is created, blocked, running.
  • spec/requests/api/deployments_spec.rb and spec/finders/deployments_finder_spec.rb already cover these errors, so this MR adds no spec.

GitLab.com (19.5.0-pre), read only, on the public gitlab-org/gitlab-docs project, on 2026-10-10. A 200 row shows how many deployments came back (per_page=5) and their statuses.

GET /projects/gitlab-org%2Fgitlab-docs/deployments?order_by=ref
400 {"error":"order_by does not have a valid value"}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?status=skipped
200 {"returned":5,"statuses":["skipped"]}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?status=bogus
400 {"error":"status does not have a valid value"}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?status[]=success&status[]=created
400 {"error":"status is invalid"}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?updated_after=2026-01-01T00:00:00Z
400 {"message":"400 Bad request - `updated_at` filter requires `updated_at` sort"}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?updated_before=2026-10-01T00:00:00Z
400 {"message":"400 Bad request - `updated_at` filter requires `updated_at` sort"}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?updated_after=2026-01-01T00:00:00Z&order_by=updated_at
200 {"returned":5,"statuses":["skipped","success"]}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?finished_after=2026-01-01T00:00:00Z
400 {"message":"400 Bad request - `finished_at` filter requires `finished_at` sort."}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?finished_after=2026-01-01T00:00:00Z&order_by=finished_at
400 {"message":"400 Bad request - `finished_at` filter must be combined with `success` status filter."}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?finished_after=2026-01-01T00:00:00Z&order_by=finished_at&status=failed
400 {"message":"400 Bad request - `finished_at` filter must be combined with `success` status filter."}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?finished_before=2026-10-01T00:00:00Z&order_by=finished_at
400 {"message":"400 Bad request - `finished_at` filter must be combined with `success` status filter."}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?finished_after=2026-01-01T00:00:00Z&order_by=finished_at&status=success
200 {"returned":1,"statuses":["success"]}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?order_by=finished_at
400 {"message":"400 Bad request - `finished_at` sort requires `finished_at` filter or a filter with at least one of the finished statuses."}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?order_by=finished_at&status=success
200 {"returned":5,"statuses":["success"]}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?order_by=finished_at&status=failed
200 {"returned":5,"statuses":["failed"]}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?order_by=finished_at&status=canceled
200 {"returned":5,"statuses":["canceled"]}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?order_by=finished_at&status=skipped
400 {"message":"400 Bad request - `finished_at` sort requires `finished_at` filter or a filter with at least one of the finished statuses."}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?order_by=finished_at&status=running
400 (same message)

GET /projects/gitlab-org%2Fgitlab-docs/deployments?order_by=finished_at&status=created
400 (same message)

GET /projects/gitlab-org%2Fgitlab-docs/deployments?order_by=finished_at&status=blocked
400 (same message)

GET /projects/gitlab-org%2Fgitlab-docs/deployments?updated_after=2026-01-01T00:00:00Z&order_by=updated_at&finished_after=2026-01-01T00:00:00Z
400 {"message":"400 Bad request - Both `updated_at` filter and `finished_at` filter can not be specified"}

GET /projects/gitlab-org%2Fgitlab-docs/deployments?updated_before=2026-10-01T00:00:00Z&finished_before=2026-10-01T00:00:00Z&order_by=finished_at&status=success
400 {"message":"400 Bad request - Both `updated_at` filter and `finished_at` filter can not be specified"}
Lint
  • scripts/lint-doc.sh doc/api/deployments.md, run in the lint image the script names (markdownlint-cli2 0.23.2, Vale 3.21.0): passed, with no markdownlint issues.
  • Vale at suggestion level on this branch and on master: the same two suggestions on both (ReadingLevel on line 1, which goes from 9.29 to 8.41, and an existing CurrentStatus further down), so this MR adds none.
  • lychee --offline --no-progress --include-fragments doc/api/deployments.md, as the docs-lint links job runs it: 0 errors.
  • The commit message passes scripts/lint/commit_linter.rb and the Danger commit linter (gitlab-dangerfiles 4.12.0).

Related to #410437 (closed), #334210 and !260551 (merged)

Author's checklist

If you are a GitLab team member and only adding documentation, do not add any of the following labels:

  • ~"frontend"
  • ~"backend"
  • ~"type::bug"
  • ~"database"

These labels cause the MR to be added to code verification QA issues.

Reviewer's checklist

Documentation-related MRs should be reviewed by a Technical Writer for a non-blocking review, based on Documentation Guidelines and the Style Guide.

If you aren't sure which tech writer to ask, use roulette or ask in the #docs Slack channel.

  • If the content requires it, ensure the information is reviewed by a subject matter expert.
  • Technical writer review items:
    • Ensure docs metadata is present and up-to-date.
    • Ensure the appropriate labels are added to this MR.
    • Ensure a release milestone is set.
    • If relevant to this MR, ensure content topic type principles are in use, including:
      • The headings should be something you'd do a Google search for. Instead of Default behavior, say something like Default behavior when you close an issue.
      • The headings (other than the page title) should be active. Instead of Configuring GDK, say something like Configure GDK.
      • Any task steps should be written as a numbered list.
      • If the content still needs to be edited for topic types, you can create a follow-up issue with the docs-technical-debt label.
  • Review by assigned maintainer, who can always request/require the reviews above. Maintainer's review can occur before or after a technical writer review.

Merge request reports

Loading
Loading