Commit fa519f7c authored by Jan Provaznik's avatar Jan Provaznik

Merge branch '199952-GraphQL-deprecated' into 'master'

Add `deprecated` property for GraphQL

See merge request gitlab-org/gitlab!27464
parents 5ac9eb84 515ff521
...@@ -12,6 +12,7 @@ module Types ...@@ -12,6 +12,7 @@ module Types
kwargs[:complexity] = field_complexity(kwargs[:resolver_class], kwargs[:complexity]) kwargs[:complexity] = field_complexity(kwargs[:resolver_class], kwargs[:complexity])
@feature_flag = kwargs[:feature_flag] @feature_flag = kwargs[:feature_flag]
kwargs = check_feature_flag(kwargs) kwargs = check_feature_flag(kwargs)
kwargs = handle_deprecated(kwargs)
super(*args, **kwargs, &block) super(*args, **kwargs, &block)
end end
...@@ -41,7 +42,7 @@ module Types ...@@ -41,7 +42,7 @@ module Types
attr_reader :feature_flag attr_reader :feature_flag
def feature_documentation_message(key, description) def feature_documentation_message(key, description)
"#{description}. Available only when feature flag `#{key}` is enabled." "#{description}. Available only when feature flag `#{key}` is enabled"
end end
def check_feature_flag(args) def check_feature_flag(args)
...@@ -51,6 +52,27 @@ module Types ...@@ -51,6 +52,27 @@ module Types
args args
end end
def handle_deprecated(kwargs)
if kwargs[:deprecation_reason].present?
raise ArgumentError, 'Use `deprecated` property instead of `deprecation_reason`. ' \
'See https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#deprecating-fields'
end
deprecation = kwargs.delete(:deprecated)
return kwargs unless deprecation
milestone, reason = deprecation.values_at(:milestone, :reason).map(&:presence)
raise ArgumentError, 'Please provide a `milestone` within `deprecated`' unless milestone
raise ArgumentError, 'Please provide a `reason` within `deprecated`' unless reason
deprecated_in = "Deprecated in #{milestone}"
kwargs[:deprecation_reason] = "#{reason}. #{deprecated_in}"
kwargs[:description] += ". #{deprecated_in}: #{reason}" if kwargs[:description]
kwargs
end
def field_complexity(resolver_class, current) def field_complexity(resolver_class, current)
return current if current.present? && current > 0 return current if current.present? && current > 0
......
...@@ -44,8 +44,8 @@ module Types ...@@ -44,8 +44,8 @@ module Types
field :latest_pipeline, field :latest_pipeline,
type: Types::Ci::PipelineType, type: Types::Ci::PipelineType,
null: true, null: true,
description: "Latest pipeline of the commit", deprecated: { reason: 'Use `pipelines`', milestone: 12.5 },
deprecation_reason: 'Use pipelines', description: 'Latest pipeline of the commit',
resolver: Resolvers::CommitPipelinesResolver.last resolver: Resolvers::CommitPipelinesResolver.last
end end
end end
...@@ -18,8 +18,8 @@ module Types ...@@ -18,8 +18,8 @@ module Types
description: 'Timestamp of the issue\'s last activity' description: 'Timestamp of the issue\'s last activity'
field :token, GraphQL::STRING_TYPE, null: false, field :token, GraphQL::STRING_TYPE, null: false,
deprecation_reason: 'Plain text token has been masked for security reasons', deprecated: { reason: 'Plain text token has been masked for security reasons', milestone: 12.7 },
description: 'API token for the Grafana integration. Field is permanently masked.' description: 'API token for the Grafana integration'
def token def token
object.masked_token object.masked_token
......
...@@ -74,8 +74,9 @@ module Types ...@@ -74,8 +74,9 @@ module Types
description: 'Rebase commit SHA of the merge request' description: 'Rebase commit SHA of the merge request'
field :rebase_in_progress, GraphQL::BOOLEAN_TYPE, method: :rebase_in_progress?, null: false, calls_gitaly: true, field :rebase_in_progress, GraphQL::BOOLEAN_TYPE, method: :rebase_in_progress?, null: false, calls_gitaly: true,
description: 'Indicates if there is a rebase currently in progress for the merge request' description: 'Indicates if there is a rebase currently in progress for the merge request'
field :merge_commit_message, GraphQL::STRING_TYPE, method: :default_merge_commit_message, null: true, deprecation_reason: "Renamed to defaultMergeCommitMessage", field :merge_commit_message, GraphQL::STRING_TYPE, method: :default_merge_commit_message, null: true,
description: 'Deprecated - renamed to defaultMergeCommitMessage' deprecated: { reason: 'Use `defaultMergeCommitMessage`', milestone: 11.8 },
description: 'Default merge commit message of the merge request'
field :default_merge_commit_message, GraphQL::STRING_TYPE, null: true, field :default_merge_commit_message, GraphQL::STRING_TYPE, null: true,
description: 'Default merge commit message of the merge request' description: 'Default merge commit message of the merge request'
field :merge_ongoing, GraphQL::BOOLEAN_TYPE, method: :merge_ongoing?, null: false, field :merge_ongoing, GraphQL::BOOLEAN_TYPE, method: :merge_ongoing?, null: false,
......
...@@ -306,7 +306,7 @@ type Commit { ...@@ -306,7 +306,7 @@ type Commit {
id: ID! id: ID!
""" """
Latest pipeline of the commit Latest pipeline of the commit. Deprecated in 12.5: Use `pipelines`
""" """
latestPipeline( latestPipeline(
""" """
...@@ -323,7 +323,7 @@ type Commit { ...@@ -323,7 +323,7 @@ type Commit {
Filter pipelines by their status Filter pipelines by their status
""" """
status: PipelineStatusEnum status: PipelineStatusEnum
): Pipeline @deprecated(reason: "Use pipelines") ): Pipeline @deprecated(reason: "Use `pipelines`. Deprecated in 12.5")
""" """
Raw commit message Raw commit message
...@@ -2493,9 +2493,9 @@ type EpicIssue implements Noteable { ...@@ -2493,9 +2493,9 @@ type EpicIssue implements Noteable {
designCollection: DesignCollection designCollection: DesignCollection
""" """
Deprecated. Use `designCollection` The designs associated with this issue. Deprecated in 12.2: Use `designCollection`
""" """
designs: DesignCollection @deprecated(reason: "Use designCollection") designs: DesignCollection @deprecated(reason: "Use `designCollection`. Deprecated in 12.2")
""" """
Indicates discussion is locked on the issue Indicates discussion is locked on the issue
...@@ -2548,7 +2548,7 @@ type EpicIssue implements Noteable { ...@@ -2548,7 +2548,7 @@ type EpicIssue implements Noteable {
epicIssueId: ID! epicIssueId: ID!
""" """
Current health status. Available only when feature flag `save_issuable_health_status` is enabled. Current health status. Available only when feature flag `save_issuable_health_status` is enabled
""" """
healthStatus: HealthStatus healthStatus: HealthStatus
...@@ -2984,9 +2984,9 @@ type GrafanaIntegration { ...@@ -2984,9 +2984,9 @@ type GrafanaIntegration {
id: ID! id: ID!
""" """
API token for the Grafana integration. Field is permanently masked. API token for the Grafana integration. Deprecated in 12.7: Plain text token has been masked for security reasons
""" """
token: String! @deprecated(reason: "Plain text token has been masked for security reasons") token: String! @deprecated(reason: "Plain text token has been masked for security reasons. Deprecated in 12.7")
""" """
Timestamp of the issue's last activity Timestamp of the issue's last activity
...@@ -3489,9 +3489,9 @@ type Issue implements Noteable { ...@@ -3489,9 +3489,9 @@ type Issue implements Noteable {
designCollection: DesignCollection designCollection: DesignCollection
""" """
Deprecated. Use `designCollection` The designs associated with this issue. Deprecated in 12.2: Use `designCollection`
""" """
designs: DesignCollection @deprecated(reason: "Use designCollection") designs: DesignCollection @deprecated(reason: "Use `designCollection`. Deprecated in 12.2")
""" """
Indicates discussion is locked on the issue Indicates discussion is locked on the issue
...@@ -3539,7 +3539,7 @@ type Issue implements Noteable { ...@@ -3539,7 +3539,7 @@ type Issue implements Noteable {
epic: Epic epic: Epic
""" """
Current health status. Available only when feature flag `save_issuable_health_status` is enabled. Current health status. Available only when feature flag `save_issuable_health_status` is enabled
""" """
healthStatus: HealthStatus healthStatus: HealthStatus
...@@ -4242,9 +4242,9 @@ type MergeRequest implements Noteable { ...@@ -4242,9 +4242,9 @@ type MergeRequest implements Noteable {
): LabelConnection ): LabelConnection
""" """
Deprecated - renamed to defaultMergeCommitMessage Default merge commit message of the merge request. Deprecated in 11.8: Use `defaultMergeCommitMessage`
""" """
mergeCommitMessage: String @deprecated(reason: "Renamed to defaultMergeCommitMessage") mergeCommitMessage: String @deprecated(reason: "Use `defaultMergeCommitMessage`. Deprecated in 11.8")
""" """
SHA of the merge request commit (set once merged) SHA of the merge request commit (set once merged)
...@@ -6191,7 +6191,7 @@ type Project { ...@@ -6191,7 +6191,7 @@ type Project {
visibility: String visibility: String
""" """
Vulnerabilities reported on the project. Available only when feature flag `first_class_vulnerabilities` is enabled. Vulnerabilities reported on the project. Available only when feature flag `first_class_vulnerabilities` is enabled
""" """
vulnerabilities( vulnerabilities(
""" """
......
...@@ -968,7 +968,7 @@ ...@@ -968,7 +968,7 @@
}, },
{ {
"name": "latestPipeline", "name": "latestPipeline",
"description": "Latest pipeline of the commit", "description": "Latest pipeline of the commit. Deprecated in 12.5: Use `pipelines`",
"args": [ "args": [
{ {
"name": "status", "name": "status",
...@@ -1007,7 +1007,7 @@ ...@@ -1007,7 +1007,7 @@
"ofType": null "ofType": null
}, },
"isDeprecated": true, "isDeprecated": true,
"deprecationReason": "Use pipelines" "deprecationReason": "Use `pipelines`. Deprecated in 12.5"
}, },
{ {
"name": "message", "name": "message",
...@@ -7244,7 +7244,7 @@ ...@@ -7244,7 +7244,7 @@
}, },
{ {
"name": "designs", "name": "designs",
"description": "Deprecated. Use `designCollection`", "description": "The designs associated with this issue. Deprecated in 12.2: Use `designCollection`",
"args": [ "args": [
], ],
...@@ -7254,7 +7254,7 @@ ...@@ -7254,7 +7254,7 @@
"ofType": null "ofType": null
}, },
"isDeprecated": true, "isDeprecated": true,
"deprecationReason": "Use designCollection" "deprecationReason": "Use `designCollection`. Deprecated in 12.2"
}, },
{ {
"name": "discussionLocked", "name": "discussionLocked",
...@@ -7397,7 +7397,7 @@ ...@@ -7397,7 +7397,7 @@
}, },
{ {
"name": "healthStatus", "name": "healthStatus",
"description": "Current health status. Available only when feature flag `save_issuable_health_status` is enabled.", "description": "Current health status. Available only when feature flag `save_issuable_health_status` is enabled",
"args": [ "args": [
], ],
...@@ -8659,7 +8659,7 @@ ...@@ -8659,7 +8659,7 @@
}, },
{ {
"name": "token", "name": "token",
"description": "API token for the Grafana integration. Field is permanently masked.", "description": "API token for the Grafana integration. Deprecated in 12.7: Plain text token has been masked for security reasons",
"args": [ "args": [
], ],
...@@ -8673,7 +8673,7 @@ ...@@ -8673,7 +8673,7 @@
} }
}, },
"isDeprecated": true, "isDeprecated": true,
"deprecationReason": "Plain text token has been masked for security reasons" "deprecationReason": "Plain text token has been masked for security reasons. Deprecated in 12.7"
}, },
{ {
"name": "updatedAt", "name": "updatedAt",
...@@ -9990,7 +9990,7 @@ ...@@ -9990,7 +9990,7 @@
}, },
{ {
"name": "designs", "name": "designs",
"description": "Deprecated. Use `designCollection`", "description": "The designs associated with this issue. Deprecated in 12.2: Use `designCollection`",
"args": [ "args": [
], ],
...@@ -10000,7 +10000,7 @@ ...@@ -10000,7 +10000,7 @@
"ofType": null "ofType": null
}, },
"isDeprecated": true, "isDeprecated": true,
"deprecationReason": "Use designCollection" "deprecationReason": "Use `designCollection`. Deprecated in 12.2"
}, },
{ {
"name": "discussionLocked", "name": "discussionLocked",
...@@ -10125,7 +10125,7 @@ ...@@ -10125,7 +10125,7 @@
}, },
{ {
"name": "healthStatus", "name": "healthStatus",
"description": "Current health status. Available only when feature flag `save_issuable_health_status` is enabled.", "description": "Current health status. Available only when feature flag `save_issuable_health_status` is enabled",
"args": [ "args": [
], ],
...@@ -12105,7 +12105,7 @@ ...@@ -12105,7 +12105,7 @@
}, },
{ {
"name": "mergeCommitMessage", "name": "mergeCommitMessage",
"description": "Deprecated - renamed to defaultMergeCommitMessage", "description": "Default merge commit message of the merge request. Deprecated in 11.8: Use `defaultMergeCommitMessage`",
"args": [ "args": [
], ],
...@@ -12115,7 +12115,7 @@ ...@@ -12115,7 +12115,7 @@
"ofType": null "ofType": null
}, },
"isDeprecated": true, "isDeprecated": true,
"deprecationReason": "Renamed to defaultMergeCommitMessage" "deprecationReason": "Use `defaultMergeCommitMessage`. Deprecated in 11.8"
}, },
{ {
"name": "mergeCommitSha", "name": "mergeCommitSha",
...@@ -18522,7 +18522,7 @@ ...@@ -18522,7 +18522,7 @@
}, },
{ {
"name": "vulnerabilities", "name": "vulnerabilities",
"description": "Vulnerabilities reported on the project. Available only when feature flag `first_class_vulnerabilities` is enabled.", "description": "Vulnerabilities reported on the project. Available only when feature flag `first_class_vulnerabilities` is enabled",
"args": [ "args": [
{ {
"name": "after", "name": "after",
......
...@@ -82,7 +82,7 @@ Represents a project or group board ...@@ -82,7 +82,7 @@ Represents a project or group board
| `authoredDate` | Time | Timestamp of when the commit was authored | | `authoredDate` | Time | Timestamp of when the commit was authored |
| `description` | String | Description of the commit message | | `description` | String | Description of the commit message |
| `id` | ID! | ID (global ID) of the commit | | `id` | ID! | ID (global ID) of the commit |
| `latestPipeline` **{warning-solid}** | Pipeline | **Deprecated:** Use pipelines | | `latestPipeline` **{warning-solid}** | Pipeline | **Deprecated:** Use `pipelines`. Deprecated in 12.5 |
| `message` | String | Raw commit message | | `message` | String | Raw commit message |
| `sha` | String! | SHA1 ID of the commit | | `sha` | String! | SHA1 ID of the commit |
| `signatureHtml` | String | Rendered HTML of the commit signature | | `signatureHtml` | String | Rendered HTML of the commit signature |
...@@ -413,13 +413,13 @@ Relationship between an epic and an issue ...@@ -413,13 +413,13 @@ Relationship between an epic and an issue
| `description` | String | Description of the issue | | `description` | String | Description of the issue |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` | | `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
| `designCollection` | DesignCollection | Collection of design images associated with this issue | | `designCollection` | DesignCollection | Collection of design images associated with this issue |
| `designs` **{warning-solid}** | DesignCollection | **Deprecated:** Use designCollection | | `designs` **{warning-solid}** | DesignCollection | **Deprecated:** Use `designCollection`. Deprecated in 12.2 |
| `discussionLocked` | Boolean! | Indicates discussion is locked on the issue | | `discussionLocked` | Boolean! | Indicates discussion is locked on the issue |
| `downvotes` | Int! | Number of downvotes the issue has received | | `downvotes` | Int! | Number of downvotes the issue has received |
| `dueDate` | Time | Due date of the issue | | `dueDate` | Time | Due date of the issue |
| `epic` | Epic | Epic to which this issue belongs | | `epic` | Epic | Epic to which this issue belongs |
| `epicIssueId` | ID! | ID of the epic-issue relation | | `epicIssueId` | ID! | ID of the epic-issue relation |
| `healthStatus` | HealthStatus | Current health status. Available only when feature flag `save_issuable_health_status` is enabled. | | `healthStatus` | HealthStatus | Current health status. Available only when feature flag `save_issuable_health_status` is enabled |
| `id` | ID | Global ID of the epic-issue relation | | `id` | ID | Global ID of the epic-issue relation |
| `iid` | ID! | Internal ID of the issue | | `iid` | ID! | Internal ID of the issue |
| `milestone` | Milestone | Milestone of the issue | | `milestone` | Milestone | Milestone of the issue |
...@@ -483,7 +483,7 @@ Autogenerated return type of EpicTreeReorder ...@@ -483,7 +483,7 @@ Autogenerated return type of EpicTreeReorder
| `enabled` | Boolean! | Indicates whether Grafana integration is enabled | | `enabled` | Boolean! | Indicates whether Grafana integration is enabled |
| `grafanaUrl` | String! | Url for the Grafana host for the Grafana integration | | `grafanaUrl` | String! | Url for the Grafana host for the Grafana integration |
| `id` | ID! | Internal ID of the Grafana integration | | `id` | ID! | Internal ID of the Grafana integration |
| `token` **{warning-solid}** | String! | **Deprecated:** Plain text token has been masked for security reasons | | `token` **{warning-solid}** | String! | **Deprecated:** Plain text token has been masked for security reasons. Deprecated in 12.7 |
| `updatedAt` | Time! | Timestamp of the issue's last activity | | `updatedAt` | Time! | Timestamp of the issue's last activity |
## Group ## Group
...@@ -535,12 +535,12 @@ Autogenerated return type of EpicTreeReorder ...@@ -535,12 +535,12 @@ Autogenerated return type of EpicTreeReorder
| `description` | String | Description of the issue | | `description` | String | Description of the issue |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` | | `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
| `designCollection` | DesignCollection | Collection of design images associated with this issue | | `designCollection` | DesignCollection | Collection of design images associated with this issue |
| `designs` **{warning-solid}** | DesignCollection | **Deprecated:** Use designCollection | | `designs` **{warning-solid}** | DesignCollection | **Deprecated:** Use `designCollection`. Deprecated in 12.2 |
| `discussionLocked` | Boolean! | Indicates discussion is locked on the issue | | `discussionLocked` | Boolean! | Indicates discussion is locked on the issue |
| `downvotes` | Int! | Number of downvotes the issue has received | | `downvotes` | Int! | Number of downvotes the issue has received |
| `dueDate` | Time | Due date of the issue | | `dueDate` | Time | Due date of the issue |
| `epic` | Epic | Epic to which this issue belongs | | `epic` | Epic | Epic to which this issue belongs |
| `healthStatus` | HealthStatus | Current health status. Available only when feature flag `save_issuable_health_status` is enabled. | | `healthStatus` | HealthStatus | Current health status. Available only when feature flag `save_issuable_health_status` is enabled |
| `iid` | ID! | Internal ID of the issue | | `iid` | ID! | Internal ID of the issue |
| `milestone` | Milestone | Milestone of the issue | | `milestone` | Milestone | Milestone of the issue |
| `reference` | String! | Internal reference of the issue. Returned in shortened format by default | | `reference` | String! | Internal reference of the issue. Returned in shortened format by default |
...@@ -644,7 +644,7 @@ Autogenerated return type of MarkAsSpamSnippet ...@@ -644,7 +644,7 @@ Autogenerated return type of MarkAsSpamSnippet
| `id` | ID! | ID of the merge request | | `id` | ID! | ID of the merge request |
| `iid` | String! | Internal ID of the merge request | | `iid` | String! | Internal ID of the merge request |
| `inProgressMergeCommitSha` | String | Commit SHA of the merge request if merge is in progress | | `inProgressMergeCommitSha` | String | Commit SHA of the merge request if merge is in progress |
| `mergeCommitMessage` **{warning-solid}** | String | **Deprecated:** Renamed to defaultMergeCommitMessage | | `mergeCommitMessage` **{warning-solid}** | String | **Deprecated:** Use `defaultMergeCommitMessage`. Deprecated in 11.8 |
| `mergeCommitSha` | String | SHA of the merge request commit (set once merged) | | `mergeCommitSha` | String | SHA of the merge request commit (set once merged) |
| `mergeError` | String | Error message due to a merge error | | `mergeError` | String | Error message due to a merge error |
| `mergeOngoing` | Boolean! | Indicates if a merge is currently occurring | | `mergeOngoing` | Boolean! | Indicates if a merge is currently occurring |
......
...@@ -283,6 +283,51 @@ the `some_feature_flag` feature flag is enabled. ...@@ -283,6 +283,51 @@ the `some_feature_flag` feature flag is enabled.
If the feature flag is not enabled, an error will be returned saying the field does not exist. If the feature flag is not enabled, an error will be returned saying the field does not exist.
## Deprecating fields
GitLab's GraphQL API is versionless, which means we maintain backwards
compatibility with older versions of the API with every change. Rather
than removing a field, we need to _deprecate_ the field instead. In
future, GitLab
[may remove deprecated fields](https://gitlab.com/gitlab-org/gitlab/issues/32292).
Fields are deprecated using the `deprecated` property. The value
of the property is a `Hash` of:
- `reason` - Reason for the deprecation.
- `milestone` - Milestone that the field was deprecated.
Example:
```ruby
field :token, GraphQL::STRING_TYPE, null: true,
deprecated: { reason: 'Login via token has been removed', milestone: 10.0 },
description: 'Token for login'
```
The original `description:` of the field should be maintained, and should
_not_ be updated to mention the deprecation.
### Deprecation reason styleguide
Where the reason for deprecation is due to the field being replaced
with another field, the `reason` must be:
```plaintext
Use `otherFieldName`
```
Example:
```ruby
field :designs, ::Types::DesignManagement::DesignCollectionType, null: true,
deprecated: { reason: 'Use `designCollection`', milestone: 10.0 },
description: 'The designs associated with this issue',
```
If the field is not being replaced by another field, a descriptive
deprecation `reason` should be given.
## Enums ## Enums
GitLab GraphQL enums are defined in `app/graphql/types`. When defining new enums, the GitLab GraphQL enums are defined in `app/graphql/types`. When defining new enums, the
......
...@@ -14,9 +14,9 @@ module EE ...@@ -14,9 +14,9 @@ module EE
resolve: -> (obj, _args, _ctx) { obj.supports_weight? ? obj.weight : nil } resolve: -> (obj, _args, _ctx) { obj.supports_weight? ? obj.weight : nil }
field :designs, ::Types::DesignManagement::DesignCollectionType, null: true, field :designs, ::Types::DesignManagement::DesignCollectionType, null: true,
description: "Deprecated. Use `designCollection`",
method: :design_collection, method: :design_collection,
deprecation_reason: 'Use designCollection' deprecated: { reason: 'Use `designCollection`', milestone: 12.2 },
description: 'The designs associated with this issue'
field :design_collection, ::Types::DesignManagement::DesignCollectionType, null: true, field :design_collection, ::Types::DesignManagement::DesignCollectionType, null: true,
description: 'Collection of design images associated with this issue' description: 'Collection of design images associated with this issue'
......
...@@ -175,7 +175,7 @@ describe Types::BaseField do ...@@ -175,7 +175,7 @@ describe Types::BaseField do
let(:flag) { :test_flag } let(:flag) { :test_flag }
it 'prepends the description' do it 'prepends the description' do
expect(field.description). to eq 'Test description. Available only when feature flag `test_flag` is enabled.' expect(field.description). to eq 'Test description. Available only when feature flag `test_flag` is enabled'
end end
context 'falsey feature_flag values' do context 'falsey feature_flag values' do
...@@ -196,4 +196,64 @@ describe Types::BaseField do ...@@ -196,4 +196,64 @@ describe Types::BaseField do
end end
end end
end end
describe '`deprecated` property' do
def test_field(args = {})
base_args = { name: 'test', type: GraphQL::STRING_TYPE, null: true }
described_class.new(**base_args.merge(args))
end
describe 'validations' do
it 'raises an informative error if `deprecation_reason` is used' do
expect { test_field(deprecation_reason: 'foo') }.to raise_error(
ArgumentError,
'Use `deprecated` property instead of `deprecation_reason`. ' \
'See https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#deprecating-fields'
)
end
it 'raises an error if a required property is missing', :aggregate_failures do
expect { test_field(deprecated: { milestone: 1.0 }) }.to raise_error(
ArgumentError,
'Please provide a `reason` within `deprecated`'
)
expect { test_field(deprecated: { reason: 'Deprecation reason' }) }.to raise_error(
ArgumentError,
'Please provide a `milestone` within `deprecated`'
)
end
end
it 'adds a formatted `deprecated_reason` to the field' do
field = test_field(deprecated: { milestone: 1.0, reason: 'Deprecation reason' })
expect(field.deprecation_reason).to eq('Deprecation reason. Deprecated in 1.0')
end
it 'appends to the description if given' do
field = test_field(
deprecated: { milestone: 1.0, reason: 'Deprecation reason' },
description: 'Field description'
)
expect(field.description).to eq('Field description. Deprecated in 1.0: Deprecation reason')
end
it 'does not append to the description if it is absent' do
field = test_field(deprecated: { milestone: 1.0, reason: 'Deprecation reason' })
expect(field.description).to be_nil
end
it 'interacts well with the `feature_flag` property' do
field = test_field(
deprecated: { milestone: 1.0, reason: 'Deprecation reason' },
description: 'Field description',
feature_flag: 'foo_flag'
)
expect(field.description).to eq('Field description. Available only when feature flag `foo_flag` is enabled. Deprecated in 1.0: Deprecation reason')
end
end
end end
...@@ -6,7 +6,7 @@ describe Gitlab::Graphql::Docs::Renderer do ...@@ -6,7 +6,7 @@ describe Gitlab::Graphql::Docs::Renderer do
describe '#contents' do describe '#contents' do
# Returns a Schema that uses the given `type` # Returns a Schema that uses the given `type`
def mock_schema(type) def mock_schema(type)
query_type = Class.new(GraphQL::Schema::Object) do query_type = Class.new(Types::BaseObject) do
graphql_name 'QueryType' graphql_name 'QueryType'
field :foo, type, null: true field :foo, type, null: true
...@@ -27,7 +27,7 @@ describe Gitlab::Graphql::Docs::Renderer do ...@@ -27,7 +27,7 @@ describe Gitlab::Graphql::Docs::Renderer do
context 'A type with a field with a [Array] return type' do context 'A type with a field with a [Array] return type' do
let(:type) do let(:type) do
Class.new(GraphQL::Schema::Object) do Class.new(Types::BaseObject) do
graphql_name 'ArrayTest' graphql_name 'ArrayTest'
field :foo, [GraphQL::STRING_TYPE], null: false, description: 'A description' field :foo, [GraphQL::STRING_TYPE], null: false, description: 'A description'
...@@ -49,7 +49,7 @@ describe Gitlab::Graphql::Docs::Renderer do ...@@ -49,7 +49,7 @@ describe Gitlab::Graphql::Docs::Renderer do
context 'A type with fields defined in reverse alphabetical order' do context 'A type with fields defined in reverse alphabetical order' do
let(:type) do let(:type) do
Class.new(GraphQL::Schema::Object) do Class.new(Types::BaseObject) do
graphql_name 'OrderingTest' graphql_name 'OrderingTest'
field :foo, GraphQL::STRING_TYPE, null: false, description: 'A description of foo field' field :foo, GraphQL::STRING_TYPE, null: false, description: 'A description of foo field'
...@@ -73,10 +73,10 @@ describe Gitlab::Graphql::Docs::Renderer do ...@@ -73,10 +73,10 @@ describe Gitlab::Graphql::Docs::Renderer do
context 'A type with a deprecated field' do context 'A type with a deprecated field' do
let(:type) do let(:type) do
Class.new(GraphQL::Schema::Object) do Class.new(Types::BaseObject) do
graphql_name 'DeprecatedTest' graphql_name 'DeprecatedTest'
field :foo, GraphQL::STRING_TYPE, null: false, deprecation_reason: 'This is deprecated', description: 'A description' field :foo, GraphQL::STRING_TYPE, null: false, deprecated: { reason: 'This is deprecated', milestone: 1.0 }, description: 'A description'
end end
end end
...@@ -86,7 +86,7 @@ describe Gitlab::Graphql::Docs::Renderer do ...@@ -86,7 +86,7 @@ describe Gitlab::Graphql::Docs::Renderer do
| Name | Type | Description | | Name | Type | Description |
| --- | ---- | ---------- | | --- | ---- | ---------- |
| `foo` **{warning-solid}** | String! | **Deprecated:** This is deprecated | | `foo` **{warning-solid}** | String! | **Deprecated:** This is deprecated. Deprecated in 1.0 |
DOC DOC
is_expected.to include(expectation) is_expected.to include(expectation)
......
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