Commit f25f4e2d authored by Rémy Coutable's avatar Rémy Coutable

Merge branch '30019-warn-about-stale-graphql-docs' into 'master'

Add test for stale GraphQL docs to CI

Closes #30019

See merge request gitlab-org/gitlab!18549
parents 7f378abc 348ed9e2
...@@ -67,3 +67,18 @@ docs lint: ...@@ -67,3 +67,18 @@ docs lint:
- bundle exec nanoc check internal_links - bundle exec nanoc check internal_links
# Check the internal anchor links # Check the internal anchor links
- bundle exec nanoc check internal_anchors - bundle exec nanoc check internal_anchors
graphql-docs-verify:
extends:
- .default-tags
- .default-retry
- .default-cache
- .default-only
- .default-before_script
- .only-graphql-changes
variables:
SETUP_DB: "false"
stage: test
needs: ["setup-test-env"]
script:
- bundle exec rake gitlab:graphql:check_docs
...@@ -71,6 +71,12 @@ ...@@ -71,6 +71,12 @@
- "doc/**/*" - "doc/**/*"
- ".markdownlint.json" - ".markdownlint.json"
.only-graphql-changes:
only:
changes:
- "{,ee/}app/graphql/**/*"
- "{,ee/}lib/gitlab/graphql/**/*"
.only-code-qa-changes: .only-code-qa-changes:
only: only:
changes: changes:
......
...@@ -54,9 +54,87 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph ...@@ -54,9 +54,87 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `message` | String | | | `message` | String | |
| `authoredDate` | Time | | | `authoredDate` | Time | |
| `webUrl` | String! | | | `webUrl` | String! | |
| `signatureHtml` | String | Rendered html for the commit signature |
| `author` | User | | | `author` | User | |
| `latestPipeline` | Pipeline | Latest pipeline for this commit | | `latestPipeline` | Pipeline | Latest pipeline for this commit |
### CreateDiffNotePayload
| Name | Type | Description |
| --- | ---- | ---------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Reasons why the mutation failed. |
| `note` | Note | The note after mutation |
### CreateImageDiffNotePayload
| Name | Type | Description |
| --- | ---- | ---------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Reasons why the mutation failed. |
| `note` | Note | The note after mutation |
### CreateNotePayload
| Name | Type | Description |
| --- | ---- | ---------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Reasons why the mutation failed. |
| `note` | Note | The note after mutation |
### Design
| Name | Type | Description |
| --- | ---- | ---------- |
| `id` | ID! | |
| `project` | Project! | |
| `issue` | Issue! | |
| `notesCount` | Int! | The total count of user-created notes for this design |
| `filename` | String! | |
| `fullPath` | String! | |
| `event` | DesignVersionEvent! | The change that happened to the design at this version |
| `image` | String! | |
| `diffRefs` | DiffRefs! | |
### DesignCollection
| Name | Type | Description |
| --- | ---- | ---------- |
| `project` | Project! | |
| `issue` | Issue! | |
### DesignManagementDeletePayload
| Name | Type | Description |
| --- | ---- | ---------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Reasons why the mutation failed. |
| `version` | DesignVersion | The new version in which the designs are deleted |
### DesignManagementUploadPayload
| Name | Type | Description |
| --- | ---- | ---------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Reasons why the mutation failed. |
| `designs` | Design! => Array | The designs that were uploaded by the mutation |
| `skippedDesigns` | Design! => Array | Any designs that were skipped from the upload due to there being no change to their content since their last version |
### DesignVersion
| Name | Type | Description |
| --- | ---- | ---------- |
| `id` | ID! | |
| `sha` | ID! | |
### DestroyNotePayload
| Name | Type | Description |
| --- | ---- | ---------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Reasons why the mutation failed. |
| `note` | Note | The note after mutation |
### DetailedStatus ### DetailedStatus
| Name | Type | Description | | Name | Type | Description |
...@@ -74,9 +152,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph ...@@ -74,9 +152,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description | | Name | Type | Description |
| --- | ---- | ---------- | | --- | ---- | ---------- |
| `headSha` | String! | The sha of the head at the time the comment was made | | `diffRefs` | DiffRefs! | |
| `baseSha` | String | The merge base of the branch the comment was made on |
| `startSha` | String! | The sha of the branch being compared against |
| `filePath` | String! | The path of the file that was changed | | `filePath` | String! | The path of the file that was changed |
| `oldPath` | String | The path of the file on the start sha. | | `oldPath` | String | The path of the file on the start sha. |
| `newPath` | String | The path of the file on the head sha. | | `newPath` | String | The path of the file on the head sha. |
...@@ -88,13 +164,146 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph ...@@ -88,13 +164,146 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `width` | Int | The total width of the image | | `width` | Int | The total width of the image |
| `height` | Int | The total height of the image | | `height` | Int | The total height of the image |
### DiffRefs
| Name | Type | Description |
| --- | ---- | ---------- |
| `headSha` | String! | The sha of the head at the time the comment was made |
| `baseSha` | String! | The merge base of the branch the comment was made on |
| `startSha` | String! | The sha of the branch being compared against |
### Discussion ### Discussion
| Name | Type | Description | | Name | Type | Description |
| --- | ---- | ---------- | | --- | ---- | ---------- |
| `id` | ID! | | | `id` | ID! | |
| `replyId` | ID! | The ID used to reply to this discussion |
| `createdAt` | Time! | | | `createdAt` | Time! | |
### Epic
| Name | Type | Description |
| --- | ---- | ---------- |
| `userPermissions` | EpicPermissions! | Permissions for the current user on the resource |
| `id` | ID! | |
| `iid` | ID! | |
| `title` | String | |
| `description` | String | |
| `state` | EpicState! | |
| `group` | Group! | |
| `parent` | Epic | |
| `author` | User! | |
| `startDate` | Time | |
| `startDateIsFixed` | Boolean | |
| `startDateFixed` | Time | |
| `startDateFromMilestones` | Time | |
| `dueDate` | Time | |
| `dueDateIsFixed` | Boolean | |
| `dueDateFixed` | Time | |
| `dueDateFromMilestones` | Time | |
| `closedAt` | Time | |
| `createdAt` | Time | |
| `updatedAt` | Time | |
| `hasChildren` | Boolean! | |
| `hasIssues` | Boolean! | |
| `webPath` | String! | |
| `webUrl` | String! | |
| `relativePosition` | Int | The relative position of the epic in the Epic tree |
| `relationPath` | String | |
| `reference` | String! | |
### EpicIssue
| Name | Type | Description |
| --- | ---- | ---------- |
| `userPermissions` | IssuePermissions! | Permissions for the current user on the resource |
| `iid` | ID! | |
| `title` | String! | |
| `titleHtml` | String | The GitLab Flavored Markdown rendering of `title` |
| `description` | String | |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
| `state` | IssueState! | |
| `reference` | String! | |
| `author` | User! | |
| `milestone` | Milestone | |
| `dueDate` | Time | |
| `confidential` | Boolean! | |
| `discussionLocked` | Boolean! | |
| `upvotes` | Int! | |
| `downvotes` | Int! | |
| `userNotesCount` | Int! | |
| `webPath` | String! | |
| `webUrl` | String! | |
| `relativePosition` | Int | |
| `timeEstimate` | Int! | The time estimate on the issue |
| `totalTimeSpent` | Int! | Total time reported as spent on the issue |
| `closedAt` | Time | |
| `createdAt` | Time! | |
| `updatedAt` | Time! | |
| `taskCompletionStatus` | TaskCompletionStatus! | |
| `epic` | Epic | The epic to which issue belongs |
| `weight` | Int | |
| `designs` | DesignCollection | |
| `designCollection` | DesignCollection | |
| `epicIssueId` | ID! | |
| `relationPath` | String | |
| `id` | ID | The global id of the epic-issue relation |
### EpicPermissions
| Name | Type | Description |
| --- | ---- | ---------- |
| `readEpic` | Boolean! | Whether or not a user can perform `read_epic` on this resource |
| `readEpicIid` | Boolean! | Whether or not a user can perform `read_epic_iid` on this resource |
| `updateEpic` | Boolean! | Whether or not a user can perform `update_epic` on this resource |
| `destroyEpic` | Boolean! | Whether or not a user can perform `destroy_epic` on this resource |
| `adminEpic` | Boolean! | Whether or not a user can perform `admin_epic` on this resource |
| `createEpic` | Boolean! | Whether or not a user can perform `create_epic` on this resource |
| `createNote` | Boolean! | Whether or not a user can perform `create_note` on this resource |
| `awardEmoji` | Boolean! | Whether or not a user can perform `award_emoji` on this resource |
### EpicTreeReorderPayload
| Name | Type | Description |
| --- | ---- | ---------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Reasons why the mutation failed. |
### ExtendedIssue
| Name | Type | Description |
| --- | ---- | ---------- |
| `userPermissions` | IssuePermissions! | Permissions for the current user on the resource |
| `iid` | ID! | |
| `title` | String! | |
| `titleHtml` | String | The GitLab Flavored Markdown rendering of `title` |
| `description` | String | |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
| `state` | IssueState! | |
| `reference` | String! | |
| `author` | User! | |
| `milestone` | Milestone | |
| `dueDate` | Time | |
| `confidential` | Boolean! | |
| `discussionLocked` | Boolean! | |
| `upvotes` | Int! | |
| `downvotes` | Int! | |
| `userNotesCount` | Int! | |
| `webPath` | String! | |
| `webUrl` | String! | |
| `relativePosition` | Int | |
| `timeEstimate` | Int! | The time estimate on the issue |
| `totalTimeSpent` | Int! | Total time reported as spent on the issue |
| `closedAt` | Time | |
| `createdAt` | Time! | |
| `updatedAt` | Time! | |
| `taskCompletionStatus` | TaskCompletionStatus! | |
| `epic` | Epic | The epic to which issue belongs |
| `weight` | Int | |
| `designs` | DesignCollection | |
| `designCollection` | DesignCollection | |
| `subscribed` | Boolean! | Boolean flag for whether the currently logged in user is subscribed to this issue |
### Group ### Group
| Name | Type | Description | | Name | Type | Description |
...@@ -109,11 +318,13 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph ...@@ -109,11 +318,13 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `visibility` | String | | | `visibility` | String | |
| `lfsEnabled` | Boolean | | | `lfsEnabled` | Boolean | |
| `requestAccessEnabled` | Boolean | | | `requestAccessEnabled` | Boolean | |
| `rootStorageStatistics` | RootStorageStatistics | The aggregated storage statistics. Only available if the namespace has no parent | | `rootStorageStatistics` | RootStorageStatistics | The aggregated storage statistics. Only available for root namespaces |
| `userPermissions` | GroupPermissions! | Permissions for the current user on the resource | | `userPermissions` | GroupPermissions! | Permissions for the current user on the resource |
| `webUrl` | String! | | | `webUrl` | String! | |
| `avatarUrl` | String | | | `avatarUrl` | String | |
| `parent` | Group | | | `parent` | Group | |
| `epicsEnabled` | Boolean | |
| `epic` | Epic | |
### GroupPermissions ### GroupPermissions
...@@ -144,10 +355,16 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph ...@@ -144,10 +355,16 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `webPath` | String! | | | `webPath` | String! | |
| `webUrl` | String! | | | `webUrl` | String! | |
| `relativePosition` | Int | | | `relativePosition` | Int | |
| `timeEstimate` | Int! | The time estimate on the issue |
| `totalTimeSpent` | Int! | Total time reported as spent on the issue |
| `closedAt` | Time | | | `closedAt` | Time | |
| `createdAt` | Time! | | | `createdAt` | Time! | |
| `updatedAt` | Time! | | | `updatedAt` | Time! | |
| `taskCompletionStatus` | TaskCompletionStatus! | | | `taskCompletionStatus` | TaskCompletionStatus! | |
| `epic` | Epic | The epic to which issue belongs |
| `weight` | Int | |
| `designs` | DesignCollection | |
| `designCollection` | DesignCollection | |
### IssuePermissions ### IssuePermissions
...@@ -158,6 +375,9 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph ...@@ -158,6 +375,9 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `updateIssue` | Boolean! | Whether or not a user can perform `update_issue` on this resource | | `updateIssue` | Boolean! | Whether or not a user can perform `update_issue` on this resource |
| `createNote` | Boolean! | Whether or not a user can perform `create_note` on this resource | | `createNote` | Boolean! | Whether or not a user can perform `create_note` on this resource |
| `reopenIssue` | Boolean! | Whether or not a user can perform `reopen_issue` on this resource | | `reopenIssue` | Boolean! | Whether or not a user can perform `reopen_issue` on this resource |
| `readDesign` | Boolean! | Whether or not a user can perform `read_design` on this resource |
| `createDesign` | Boolean! | Whether or not a user can perform `create_design` on this resource |
| `destroyDesign` | Boolean! | Whether or not a user can perform `destroy_design` on this resource |
### Label ### Label
...@@ -185,6 +405,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph ...@@ -185,6 +405,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `updatedAt` | Time! | | | `updatedAt` | Time! | |
| `sourceProject` | Project | | | `sourceProject` | Project | |
| `targetProject` | Project! | | | `targetProject` | Project! | |
| `diffRefs` | DiffRefs | |
| `project` | Project! | | | `project` | Project! | |
| `projectId` | Int! | | | `projectId` | Int! | |
| `sourceProjectId` | Int | | | `sourceProjectId` | Int | |
...@@ -271,6 +492,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph ...@@ -271,6 +492,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `visibility` | String | | | `visibility` | String | |
| `lfsEnabled` | Boolean | | | `lfsEnabled` | Boolean | |
| `requestAccessEnabled` | Boolean | | | `requestAccessEnabled` | Boolean | |
| `rootStorageStatistics` | RootStorageStatistics | The aggregated storage statistics. Only available for root namespaces |
### Note ### Note
...@@ -381,7 +603,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph ...@@ -381,7 +603,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `statistics` | ProjectStatistics | | | `statistics` | ProjectStatistics | |
| `repository` | Repository | | | `repository` | Repository | |
| `mergeRequest` | MergeRequest | | | `mergeRequest` | MergeRequest | |
| `issue` | Issue | | | `issue` | ExtendedIssue | |
### ProjectPermissions ### ProjectPermissions
...@@ -424,6 +646,10 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph ...@@ -424,6 +646,10 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `createPages` | Boolean! | Whether or not a user can perform `create_pages` on this resource | | `createPages` | Boolean! | Whether or not a user can perform `create_pages` on this resource |
| `destroyPages` | Boolean! | Whether or not a user can perform `destroy_pages` on this resource | | `destroyPages` | Boolean! | Whether or not a user can perform `destroy_pages` on this resource |
| `readPagesContent` | Boolean! | Whether or not a user can perform `read_pages_content` on this resource | | `readPagesContent` | Boolean! | Whether or not a user can perform `read_pages_content` on this resource |
| `adminOperations` | Boolean! | Whether or not a user can perform `admin_operations` on this resource |
| `readDesign` | Boolean! | Whether or not a user can perform `read_design` on this resource |
| `createDesign` | Boolean! | Whether or not a user can perform `create_design` on this resource |
| `destroyDesign` | Boolean! | Whether or not a user can perform `destroy_design` on this resource |
### ProjectStatistics ### ProjectStatistics
...@@ -458,12 +684,12 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph ...@@ -458,12 +684,12 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description | | Name | Type | Description |
| --- | ---- | ---------- | | --- | ---- | ---------- |
| `storageSize` | Int! | The total storage in Bytes | | `storageSize` | Int! | The total storage in bytes |
| `repositorySize` | Int! | The Git repository size in Bytes | | `repositorySize` | Int! | The git repository size in bytes |
| `lfsObjectsSize` | Int! | The LFS objects size in Bytes | | `lfsObjectsSize` | Int! | The LFS objects size in bytes |
| `buildArtifactsSize` | Int! | The CI artifacts size in Bytes | | `buildArtifactsSize` | Int! | The CI artifacts size in bytes |
| `packagesSize` | Int! | The packages size in Bytes | | `packagesSize` | Int! | The packages size in bytes |
| `wikiSize` | Int! | The wiki size in Bytes | | `wikiSize` | Int! | The wiki size in bytes |
### Submodule ### Submodule
...@@ -474,6 +700,8 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph ...@@ -474,6 +700,8 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `type` | EntryType! | | | `type` | EntryType! | |
| `path` | String! | | | `path` | String! | |
| `flatPath` | String! | | | `flatPath` | String! | |
| `webUrl` | String | |
| `treeUrl` | String | |
### TaskCompletionStatus ### TaskCompletionStatus
...@@ -495,7 +723,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph ...@@ -495,7 +723,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description | | Name | Type | Description |
| --- | ---- | ---------- | | --- | ---- | ---------- |
| `lastCommit` | Commit | | | `lastCommit` | Commit | Last commit for the tree |
### TreeEntry ### TreeEntry
...@@ -508,6 +736,14 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph ...@@ -508,6 +736,14 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `flatPath` | String! | | | `flatPath` | String! | |
| `webUrl` | String | | | `webUrl` | String | |
### UpdateNotePayload
| Name | Type | Description |
| --- | ---- | ---------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Reasons why the mutation failed. |
| `note` | Note | The note after mutation |
### User ### User
| Name | Type | Description | | Name | Type | Description |
......
...@@ -115,6 +115,7 @@ from a commit or MR by extending from the following CI definitions: ...@@ -115,6 +115,7 @@ from a commit or MR by extending from the following CI definitions:
- `.only-qa-changes`: Allows a job to only be created upon QA-related changes. - `.only-qa-changes`: Allows a job to only be created upon QA-related changes.
- `.only-docs-changes`: Allows a job to only be created upon docs-related changes. - `.only-docs-changes`: Allows a job to only be created upon docs-related changes.
- `.only-code-qa-changes`: Allows a job to only be created upon code-related or QA-related changes. - `.only-code-qa-changes`: Allows a job to only be created upon code-related or QA-related changes.
- `.only-graphql-changes`: Allows a job to only be created upon graphql-related changes.
**See <https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab/ci/global.gitlab-ci.yml> **See <https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab/ci/global.gitlab-ci.yml>
for the list of exact patterns.** for the list of exact patterns.**
...@@ -175,6 +176,7 @@ subgraph "`test` stage" ...@@ -175,6 +176,7 @@ subgraph "`test` stage"
db:* --> |needs| A; db:* --> |needs| A;
gitlab:setup --> |needs| A; gitlab:setup --> |needs| A;
downtime_check --> |needs and depends on| A; downtime_check --> |needs and depends on| A;
graphql-docs-verify --> |needs| A;
end end
subgraph "`review-prepare` stage" subgraph "`review-prepare` stage"
......
...@@ -23,15 +23,12 @@ module Gitlab ...@@ -23,15 +23,12 @@ module Gitlab
@parsed_schema = GraphQLDocs::Parser.new(schema, {}).parse @parsed_schema = GraphQLDocs::Parser.new(schema, {}).parse
end end
def render def contents
contents = @layout.render(self) # Render and remove an extra trailing new line
@contents ||= @layout.render(self).sub!(/\n(?=\Z)/, '')
write_file(contents)
end end
private def write
def write_file(contents)
filename = File.join(@output_dir, 'index.md') filename = File.join(@output_dir, 'index.md')
FileUtils.mkdir_p(@output_dir) FileUtils.mkdir_p(@output_dir)
......
...@@ -20,6 +20,3 @@ ...@@ -20,6 +20,3 @@
- type[:fields].each do |field| - type[:fields].each do |field|
= "| `#{field[:name]}` | #{render_field_type(field[:type][:info])} | #{field[:description]} |" = "| `#{field[:name]}` | #{render_field_type(field[:type][:info])} | #{field[:description]} |"
\ \
...@@ -11,10 +11,28 @@ namespace :gitlab do ...@@ -11,10 +11,28 @@ namespace :gitlab do
task compile_docs: :environment do task compile_docs: :environment do
renderer = Gitlab::Graphql::Docs::Renderer.new(GitlabSchema.graphql_definition, render_options) renderer = Gitlab::Graphql::Docs::Renderer.new(GitlabSchema.graphql_definition, render_options)
renderer.render renderer.write
puts "Documentation compiled." puts "Documentation compiled."
end end
desc 'GitLab | Check if GraphQL docs are up to date'
task check_docs: :environment do
renderer = Gitlab::Graphql::Docs::Renderer.new(GitlabSchema.graphql_definition, render_options)
doc = File.read(Rails.root.join(OUTPUT_DIR, 'index.md'))
if doc == renderer.contents
puts "GraphQL documentation is up to date"
else
puts '#' * 10
puts '#'
puts '# GraphQL documentation is outdated! Please update it by running `bundle exec rake gitlab:graphql:compile_docs`.'
puts '#'
puts '#' * 10
abort
end
end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment