Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
81d7073c
Commit
81d7073c
authored
Mar 17, 2020
by
Jan Provaznik
Committed by
Sean McGivern
Mar 17, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add requirement types
These are present in another MR, but for now include them here and then rebase.
parent
dec11f02
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
956 additions
and
0 deletions
+956
-0
doc/api/graphql/reference/gitlab_schema.graphql
doc/api/graphql/reference/gitlab_schema.graphql
+129
-0
doc/api/graphql/reference/gitlab_schema.json
doc/api/graphql/reference/gitlab_schema.json
+440
-0
doc/api/graphql/reference/index.md
doc/api/graphql/reference/index.md
+38
-0
ee/app/graphql/ee/types/mutation_type.rb
ee/app/graphql/ee/types/mutation_type.rb
+1
-0
ee/app/graphql/mutations/requirements/create.rb
ee/app/graphql/mutations/requirements/create.rb
+55
-0
ee/app/graphql/types/permission_types/requirement.rb
ee/app/graphql/types/permission_types/requirement.rb
+13
-0
ee/app/graphql/types/requirement_state_enum.rb
ee/app/graphql/types/requirement_state_enum.rb
+11
-0
ee/app/graphql/types/requirement_type.rb
ee/app/graphql/types/requirement_type.rb
+33
-0
ee/app/services/requirements/create_service.rb
ee/app/services/requirements/create_service.rb
+20
-0
ee/spec/graphql/mutations/requirements/create_spec.rb
ee/spec/graphql/mutations/requirements/create_spec.rb
+60
-0
ee/spec/graphql/types/requirement_state_enum_spec.rb
ee/spec/graphql/types/requirement_state_enum_spec.rb
+11
-0
ee/spec/graphql/types/requirement_type_spec.rb
ee/spec/graphql/types/requirement_type_spec.rb
+15
-0
ee/spec/requests/api/graphql/mutations/requirements/create_spec.rb
...equests/api/graphql/mutations/requirements/create_spec.rb
+86
-0
ee/spec/services/requirements/create_service_spec.rb
ee/spec/services/requirements/create_service_spec.rb
+44
-0
No files found.
doc/api/graphql/reference/gitlab_schema.graphql
View file @
81d7073c
...
@@ -601,6 +601,46 @@ type CreateNotePayload {
...
@@ -601,6 +601,46 @@ type CreateNotePayload {
note
:
Note
note
:
Note
}
}
"""
Autogenerated input type of CreateRequirement
"""
input
CreateRequirementInput
{
"""
A
unique
identifier
for
the
client
performing
the
mutation
.
"""
clientMutationId
:
String
"""
The
project
full
path
the
requirement
is
associated
with
"""
projectPath
:
ID
!
"""
Title
of
the
requirement
"""
title
:
String
!
}
"""
Autogenerated return type of CreateRequirement
"""
type
CreateRequirementPayload
{
"""
A
unique
identifier
for
the
client
performing
the
mutation
.
"""
clientMutationId
:
String
"""
Reasons
why
the
mutation
failed
.
"""
errors
:
[
String
!]!
"""
The
requirement
after
mutation
"""
requirement
:
Requirement
}
"""
"""
Autogenerated input type of CreateSnippet
Autogenerated input type of CreateSnippet
"""
"""
...
@@ -4952,6 +4992,7 @@ type Mutation {
...
@@ -4952,6 +4992,7 @@ type Mutation {
createEpic
(
input
:
CreateEpicInput
!):
CreateEpicPayload
createEpic
(
input
:
CreateEpicInput
!):
CreateEpicPayload
createImageDiffNote
(
input
:
CreateImageDiffNoteInput
!):
CreateImageDiffNotePayload
createImageDiffNote
(
input
:
CreateImageDiffNoteInput
!):
CreateImageDiffNotePayload
createNote
(
input
:
CreateNoteInput
!):
CreateNotePayload
createNote
(
input
:
CreateNoteInput
!):
CreateNotePayload
createRequirement
(
input
:
CreateRequirementInput
!):
CreateRequirementPayload
createSnippet
(
input
:
CreateSnippetInput
!):
CreateSnippetPayload
createSnippet
(
input
:
CreateSnippetInput
!):
CreateSnippetPayload
designManagementDelete
(
input
:
DesignManagementDeleteInput
!):
DesignManagementDeletePayload
designManagementDelete
(
input
:
DesignManagementDeleteInput
!):
DesignManagementDeletePayload
designManagementUpload
(
input
:
DesignManagementUploadInput
!):
DesignManagementUploadPayload
designManagementUpload
(
input
:
DesignManagementUploadInput
!):
DesignManagementUploadPayload
...
@@ -6574,6 +6615,94 @@ type Repository {
...
@@ -6574,6 +6615,94 @@ type Repository {
):
Tree
):
Tree
}
}
"""
Represents a requirement.
"""
type
Requirement
{
"""
Author
of
the
requirement
"""
author
:
User
!
"""
Timestamp
of
when
the
requirement
was
created
"""
createdAt
:
Time
!
"""
ID
of
the
requirement
"""
id
:
ID
!
"""
Internal
ID
of
the
requirement
"""
iid
:
ID
!
"""
Project
to
which
the
requirement
belongs
"""
project
:
Project
!
"""
State
of
the
requirement
"""
state
:
RequirementState
!
"""
Title
of
the
requirement
"""
title
:
String
"""
Timestamp
of
when
the
requirement
was
last
updated
"""
updatedAt
:
Time
!
"""
Permissions
for
the
current
user
on
the
resource
"""
userPermissions
:
RequirementPermissions
!
}
"""
Check permissions for the current user on a requirement
"""
type
RequirementPermissions
{
"""
Indicates
the
user
can
perform
`
admin_requirement
`
on
this
resource
"""
adminRequirement
:
Boolean
!
"""
Indicates
the
user
can
perform
`
create_requirement
`
on
this
resource
"""
createRequirement
:
Boolean
!
"""
Indicates
the
user
can
perform
`
destroy_requirement
`
on
this
resource
"""
destroyRequirement
:
Boolean
!
"""
Indicates
the
user
can
perform
`
read_requirement
`
on
this
resource
"""
readRequirement
:
Boolean
!
"""
Indicates
the
user
can
perform
`
update_requirement
`
on
this
resource
"""
updateRequirement
:
Boolean
!
}
"""
State of a requirement
"""
enum
RequirementState
{
ARCHIVED
OPENED
}
type
RootStorageStatistics
{
type
RootStorageStatistics
{
"""
"""
The
CI
artifacts
size
in
bytes
The
CI
artifacts
size
in
bytes
...
...
doc/api/graphql/reference/gitlab_schema.json
View file @
81d7073c
...
@@ -1762,6 +1762,122 @@
...
@@ -1762,6 +1762,122 @@
"enumValues"
:
null
,
"enumValues"
:
null
,
"possibleTypes"
:
null
"possibleTypes"
:
null
},
},
{
"kind"
:
"INPUT_OBJECT"
,
"name"
:
"CreateRequirementInput"
,
"description"
:
"Autogenerated input type of CreateRequirement"
,
"fields"
:
null
,
"inputFields"
:
[
{
"name"
:
"title"
,
"description"
:
"Title of the requirement"
,
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
}
},
"defaultValue"
:
null
},
{
"name"
:
"projectPath"
,
"description"
:
"The project full path the requirement is associated with"
,
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"ID"
,
"ofType"
:
null
}
},
"defaultValue"
:
null
},
{
"name"
:
"clientMutationId"
,
"description"
:
"A unique identifier for the client performing the mutation."
,
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"defaultValue"
:
null
}
],
"interfaces"
:
null
,
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
"kind"
:
"OBJECT"
,
"name"
:
"CreateRequirementPayload"
,
"description"
:
"Autogenerated return type of CreateRequirement"
,
"fields"
:
[
{
"name"
:
"clientMutationId"
,
"description"
:
"A unique identifier for the client performing the mutation."
,
"args"
:
[
],
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"errors"
,
"description"
:
"Reasons why the mutation failed."
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"LIST"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
}
}
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"requirement"
,
"description"
:
"The requirement after mutation"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"OBJECT"
,
"name"
:
"Requirement"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
}
],
"inputFields"
:
null
,
"interfaces"
:
[
],
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
{
"kind"
:
"INPUT_OBJECT"
,
"kind"
:
"INPUT_OBJECT"
,
"name"
:
"CreateSnippetInput"
,
"name"
:
"CreateSnippetInput"
,
...
@@ -14390,6 +14506,33 @@
...
@@ -14390,6 +14506,33 @@
"isDeprecated"
:
false
,
"isDeprecated"
:
false
,
"deprecationReason"
:
null
"deprecationReason"
:
null
},
},
{
"name"
:
"createRequirement"
,
"description"
:
null
,
"args"
:
[
{
"name"
:
"input"
,
"description"
:
null
,
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"INPUT_OBJECT"
,
"name"
:
"CreateRequirementInput"
,
"ofType"
:
null
}
},
"defaultValue"
:
null
}
],
"type"
:
{
"kind"
:
"OBJECT"
,
"name"
:
"CreateRequirementPayload"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
{
"name"
:
"createSnippet"
,
"name"
:
"createSnippet"
,
"description"
:
null
,
"description"
:
null
,
...
@@ -19792,6 +19935,303 @@
...
@@ -19792,6 +19935,303 @@
"enumValues"
:
null
,
"enumValues"
:
null
,
"possibleTypes"
:
null
"possibleTypes"
:
null
},
},
{
"kind"
:
"OBJECT"
,
"name"
:
"Requirement"
,
"description"
:
"Represents a requirement."
,
"fields"
:
[
{
"name"
:
"author"
,
"description"
:
"Author of the requirement"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"OBJECT"
,
"name"
:
"User"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"createdAt"
,
"description"
:
"Timestamp of when the requirement was created"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"Time"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"id"
,
"description"
:
"ID of the requirement"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"ID"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"iid"
,
"description"
:
"Internal ID of the requirement"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"ID"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"project"
,
"description"
:
"Project to which the requirement belongs"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"OBJECT"
,
"name"
:
"Project"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"state"
,
"description"
:
"State of the requirement"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"ENUM"
,
"name"
:
"RequirementState"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"title"
,
"description"
:
"Title of the requirement"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"updatedAt"
,
"description"
:
"Timestamp of when the requirement was last updated"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"Time"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"userPermissions"
,
"description"
:
"Permissions for the current user on the resource"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"OBJECT"
,
"name"
:
"RequirementPermissions"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
}
],
"inputFields"
:
null
,
"interfaces"
:
[
],
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
"kind"
:
"OBJECT"
,
"name"
:
"RequirementPermissions"
,
"description"
:
"Check permissions for the current user on a requirement"
,
"fields"
:
[
{
"name"
:
"adminRequirement"
,
"description"
:
"Indicates the user can perform `admin_requirement` on this resource"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"Boolean"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"createRequirement"
,
"description"
:
"Indicates the user can perform `create_requirement` on this resource"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"Boolean"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"destroyRequirement"
,
"description"
:
"Indicates the user can perform `destroy_requirement` on this resource"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"Boolean"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"readRequirement"
,
"description"
:
"Indicates the user can perform `read_requirement` on this resource"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"Boolean"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"updateRequirement"
,
"description"
:
"Indicates the user can perform `update_requirement` on this resource"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"Boolean"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
}
],
"inputFields"
:
null
,
"interfaces"
:
[
],
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
"kind"
:
"ENUM"
,
"name"
:
"RequirementState"
,
"description"
:
"State of a requirement"
,
"fields"
:
null
,
"inputFields"
:
null
,
"interfaces"
:
null
,
"enumValues"
:
[
{
"name"
:
"OPENED"
,
"description"
:
null
,
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"ARCHIVED"
,
"description"
:
null
,
"isDeprecated"
:
false
,
"deprecationReason"
:
null
}
],
"possibleTypes"
:
null
},
{
{
"kind"
:
"OBJECT"
,
"kind"
:
"OBJECT"
,
"name"
:
"RootStorageStatistics"
,
"name"
:
"RootStorageStatistics"
,
...
...
doc/api/graphql/reference/index.md
View file @
81d7073c
...
@@ -129,6 +129,16 @@ Autogenerated return type of CreateNote
...
@@ -129,6 +129,16 @@ Autogenerated return type of CreateNote
|
`errors`
| String! => Array | Reasons why the mutation failed. |
|
`errors`
| String! => Array | Reasons why the mutation failed. |
|
`note`
| Note | The note after mutation |
|
`note`
| Note | The note after mutation |
## CreateRequirementPayload
Autogenerated return type of CreateRequirement
| Name | Type | Description |
| --- | ---- | ---------- |
|
`clientMutationId`
| String | A unique identifier for the client performing the mutation. |
|
`errors`
| String! => Array | Reasons why the mutation failed. |
|
`requirement`
| Requirement | The requirement after mutation |
## CreateSnippetPayload
## CreateSnippetPayload
Autogenerated return type of CreateSnippet
Autogenerated return type of CreateSnippet
...
@@ -982,6 +992,34 @@ Autogenerated return type of RemoveAwardEmoji
...
@@ -982,6 +992,34 @@ Autogenerated return type of RemoveAwardEmoji
|
`rootRef`
| String | Default branch of the repository |
|
`rootRef`
| String | Default branch of the repository |
|
`tree`
| Tree | Tree of the repository |
|
`tree`
| Tree | Tree of the repository |
## Requirement
Represents a requirement.
| Name | Type | Description |
| --- | ---- | ---------- |
|
`author`
| User! | Author of the requirement |
|
`createdAt`
| Time! | Timestamp of when the requirement was created |
|
`id`
| ID! | ID of the requirement |
|
`iid`
| ID! | Internal ID of the requirement |
|
`project`
| Project! | Project to which the requirement belongs |
|
`state`
| RequirementState! | State of the requirement |
|
`title`
| String | Title of the requirement |
|
`updatedAt`
| Time! | Timestamp of when the requirement was last updated |
|
`userPermissions`
| RequirementPermissions! | Permissions for the current user on the resource |
## RequirementPermissions
Check permissions for the current user on a requirement
| Name | Type | Description |
| --- | ---- | ---------- |
|
`adminRequirement`
| Boolean! | Indicates the user can perform
`admin_requirement`
on this resource |
|
`createRequirement`
| Boolean! | Indicates the user can perform
`create_requirement`
on this resource |
|
`destroyRequirement`
| Boolean! | Indicates the user can perform
`destroy_requirement`
on this resource |
|
`readRequirement`
| Boolean! | Indicates the user can perform
`read_requirement`
on this resource |
|
`updateRequirement`
| Boolean! | Indicates the user can perform
`update_requirement`
on this resource |
## RootStorageStatistics
## RootStorageStatistics
| Name | Type | Description |
| Name | Type | Description |
...
...
ee/app/graphql/ee/types/mutation_type.rb
View file @
81d7073c
...
@@ -14,6 +14,7 @@ module EE
...
@@ -14,6 +14,7 @@ module EE
mount_mutation
::
Mutations
::
Epics
::
Create
mount_mutation
::
Mutations
::
Epics
::
Create
mount_mutation
::
Mutations
::
Epics
::
SetSubscription
mount_mutation
::
Mutations
::
Epics
::
SetSubscription
mount_mutation
::
Mutations
::
Epics
::
AddIssue
mount_mutation
::
Mutations
::
Epics
::
AddIssue
mount_mutation
::
Mutations
::
Requirements
::
Create
end
end
end
end
end
end
...
...
ee/app/graphql/mutations/requirements/create.rb
0 → 100644
View file @
81d7073c
# frozen_string_literal: true
module
Mutations
module
Requirements
class
Create
<
BaseMutation
include
Mutations
::
ResolvesProject
graphql_name
'CreateRequirement'
authorize
:create_requirement
field
:requirement
,
Types
::
RequirementType
,
null:
true
,
description:
'The requirement after mutation'
argument
:title
,
GraphQL
::
STRING_TYPE
,
required:
true
,
description:
'Title of the requirement'
argument
:project_path
,
GraphQL
::
ID_TYPE
,
required:
true
,
description:
'The project full path the requirement is associated with'
def
resolve
(
args
)
project_path
=
args
.
delete
(
:project_path
)
project
=
authorized_find!
(
full_path:
project_path
)
validate_flag!
(
project
)
requirement
=
::
Requirements
::
CreateService
.
new
(
project
,
context
[
:current_user
],
args
).
execute
{
requirement:
requirement
.
valid?
?
requirement
:
nil
,
errors:
errors_on_object
(
requirement
)
}
end
private
def
validate_flag!
(
project
)
return
if
::
Feature
.
enabled?
(
:requirements_management
,
project
)
raise
Gitlab
::
Graphql
::
Errors
::
ResourceNotAvailable
,
'requirements_management flag is not enabled on this project'
end
def
find_object
(
full_path
:)
resolve_project
(
full_path:
full_path
)
end
end
end
end
ee/app/graphql/types/permission_types/requirement.rb
0 → 100644
View file @
81d7073c
# frozen_string_literal: true
module
Types
module
PermissionTypes
class
Requirement
<
BasePermissionType
graphql_name
'RequirementPermissions'
description
'Check permissions for the current user on a requirement'
abilities
:read_requirement
,
:update_requirement
,
:destroy_requirement
,
:admin_requirement
,
:create_requirement
end
end
end
ee/app/graphql/types/requirement_state_enum.rb
0 → 100644
View file @
81d7073c
# frozen_string_literal: true
module
Types
class
RequirementStateEnum
<
BaseEnum
graphql_name
'RequirementState'
description
'State of a requirement'
value
'OPENED'
,
value:
'opened'
value
'ARCHIVED'
,
value:
'archived'
end
end
ee/app/graphql/types/requirement_type.rb
0 → 100644
View file @
81d7073c
# frozen_string_literal: true
module
Types
class
RequirementType
<
BaseObject
graphql_name
'Requirement'
description
'Represents a requirement.'
authorize
:read_requirement
expose_permissions
Types
::
PermissionTypes
::
Requirement
field
:id
,
GraphQL
::
ID_TYPE
,
null:
false
,
description:
'ID of the requirement'
field
:iid
,
GraphQL
::
ID_TYPE
,
null:
false
,
description:
'Internal ID of the requirement'
field
:title
,
GraphQL
::
STRING_TYPE
,
null:
true
,
description:
'Title of the requirement'
field
:state
,
RequirementStateEnum
,
null:
false
,
description:
'State of the requirement'
field
:project
,
ProjectType
,
null:
false
,
description:
'Project to which the requirement belongs'
,
resolve:
->
(
obj
,
_args
,
_ctx
)
{
Gitlab
::
Graphql
::
Loaders
::
BatchModelLoader
.
new
(
Project
,
obj
.
project_id
).
find
}
field
:author
,
Types
::
UserType
,
null:
false
,
description:
'Author of the requirement'
,
resolve:
->
(
obj
,
_args
,
_ctx
)
{
Gitlab
::
Graphql
::
Loaders
::
BatchModelLoader
.
new
(
User
,
obj
.
author_id
).
find
}
field
:created_at
,
Types
::
TimeType
,
null:
false
,
description:
'Timestamp of when the requirement was created'
field
:updated_at
,
Types
::
TimeType
,
null:
false
,
description:
'Timestamp of when the requirement was last updated'
end
end
ee/app/services/requirements/create_service.rb
0 → 100644
View file @
81d7073c
# frozen_string_literal: true
module
Requirements
class
CreateService
<
BaseService
include
Gitlab
::
Allowable
def
execute
raise
Gitlab
::
Access
::
AccessDeniedError
unless
can?
(
current_user
,
:create_requirement
,
project
)
attrs
=
whitelisted_requirement_params
.
merge
(
author:
current_user
)
project
.
requirements
.
create
(
attrs
)
end
private
def
whitelisted_requirement_params
params
.
slice
(
:title
)
end
end
end
ee/spec/graphql/mutations/requirements/create_spec.rb
0 → 100644
View file @
81d7073c
# frozen_string_literal: true
require
'spec_helper'
describe
Mutations
::
Requirements
::
Create
do
let_it_be
(
:project
)
{
create
(
:project
)
}
let_it_be
(
:user
)
{
create
(
:user
)
}
subject
(
:mutation
)
{
described_class
.
new
(
object:
nil
,
context:
{
current_user:
user
},
field:
nil
)
}
describe
'#resolve'
do
shared_examples
'requirements not available'
do
it
'raises a not accessible error'
do
expect
{
subject
}.
to
raise_error
(
Gitlab
::
Graphql
::
Errors
::
ResourceNotAvailable
)
end
end
subject
do
mutation
.
resolve
(
project_path:
project
.
full_path
,
title:
'foo'
)
end
it_behaves_like
'requirements not available'
context
'when the user can update the epic'
do
before
do
project
.
add_developer
(
user
)
end
context
'when requirements feature is available'
do
before
do
stub_licensed_features
(
requirements:
true
)
end
it
'creates new requirement'
do
expect
(
subject
[
:requirement
][
:title
]).
to
eq
(
'foo'
)
expect
(
subject
[
:errors
]).
to
be_empty
end
context
'when requirements_management flag is disabled'
do
before
do
stub_feature_flags
(
requirements_management:
false
)
end
it_behaves_like
'requirements not available'
end
end
context
'when requirements feature is disabled'
do
before
do
stub_licensed_features
(
requirements:
false
)
end
it_behaves_like
'requirements not available'
end
end
end
end
ee/spec/graphql/types/requirement_state_enum_spec.rb
0 → 100644
View file @
81d7073c
# frozen_string_literal: true
require
'spec_helper'
describe
GitlabSchema
.
types
[
'RequirementState'
]
do
it
{
expect
(
described_class
.
graphql_name
).
to
eq
(
'RequirementState'
)
}
it
'exposes all the existing requirement states'
do
expect
(
described_class
.
values
.
keys
).
to
include
(
*
%w[OPENED ARCHIVED]
)
end
end
ee/spec/graphql/types/requirement_type_spec.rb
0 → 100644
View file @
81d7073c
# frozen_string_literal: true
require
'spec_helper'
describe
GitlabSchema
.
types
[
'Requirement'
]
do
fields
=
%i[id iid title state project author created_at updated_at user_permissions]
it
{
expect
(
described_class
).
to
expose_permissions_using
(
Types
::
PermissionTypes
::
Requirement
)
}
it
{
expect
(
described_class
.
graphql_name
).
to
eq
(
'Requirement'
)
}
it
{
expect
(
described_class
).
to
require_graphql_authorizations
(
:read_requirement
)
}
it
{
expect
(
described_class
).
to
have_graphql_fields
(
fields
)
}
end
ee/spec/requests/api/graphql/mutations/requirements/create_spec.rb
0 → 100644
View file @
81d7073c
# frozen_string_literal: true
require
'spec_helper'
describe
'Creating a Requirement'
do
include
GraphqlHelpers
let_it_be
(
:current_user
)
{
create
(
:user
)
}
let_it_be
(
:project
)
{
create
(
:project
)
}
let
(
:attributes
)
{
{
title:
'title'
}
}
let
(
:mutation
)
do
params
=
{
project_path:
project
.
full_path
}.
merge
(
attributes
)
graphql_mutation
(
:create_requirement
,
params
)
end
def
mutation_response
graphql_mutation_response
(
:create_requirement
)
end
context
'when the user does not have permission'
do
before
do
stub_licensed_features
(
requirements:
true
)
end
it_behaves_like
'a mutation that returns top-level errors'
,
errors:
[
'The resource that you are attempting to access does not exist '
\
'or you don\'t have permission to perform this action'
]
it
'does not create requirement'
do
expect
{
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
}.
not_to
change
(
Requirement
,
:count
)
end
end
context
'when the user has permission'
do
before
do
project
.
add_reporter
(
current_user
)
end
context
'when requirements are disabled'
do
before
do
stub_licensed_features
(
requirements:
false
)
end
it_behaves_like
'a mutation that returns top-level errors'
,
errors:
[
'The resource that you are attempting to access does not '
\
'exist or you don\'t have permission to perform this action'
]
end
context
'when requirements are enabled'
do
before
do
stub_licensed_features
(
requirements:
true
)
end
it
'creates the requirement'
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
requirement_hash
=
mutation_response
[
'requirement'
]
expect
(
requirement_hash
[
'title'
]).
to
eq
(
'title'
)
expect
(
requirement_hash
[
'state'
]).
to
eq
(
'OPENED'
)
expect
(
requirement_hash
[
'author'
][
'username'
]).
to
eq
(
current_user
.
username
)
end
context
'when there are ActiveRecord validation errors'
do
let
(
:attributes
)
{
{
title:
''
}
}
it_behaves_like
'a mutation that returns errors in the response'
,
errors:
[
"Title can't be blank"
]
it
'does not create the requirement'
do
expect
{
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
}.
not_to
change
(
Requirement
,
:count
)
end
end
context
'when requirements_management flag is dissabled'
do
before
do
stub_feature_flags
(
requirements_management:
false
)
end
it_behaves_like
'a mutation that returns top-level errors'
,
errors:
[
'requirements_management flag is not enabled on this project'
]
end
end
end
end
ee/spec/services/requirements/create_service_spec.rb
0 → 100644
View file @
81d7073c
# frozen_string_literal: true
require
'spec_helper'
describe
Requirements
::
CreateService
do
let_it_be
(
:project
)
{
create
(
:project
)}
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:other_user
)
{
create
(
:user
)
}
let
(
:params
)
{
{
title:
'foo'
,
author_id:
other_user
.
id
,
created_at:
2
.
days
.
ago
}
}
subject
{
described_class
.
new
(
project
,
user
,
params
).
execute
}
describe
'#execute'
do
before
do
stub_licensed_features
(
requirements:
true
)
end
context
'when user can create requirements'
do
before
do
project
.
add_reporter
(
user
)
end
it
'creates new requirement'
do
expect
{
subject
}.
to
change
{
Requirement
.
count
}.
by
(
1
)
end
it
'uses only permitted params'
do
requirement
=
subject
expect
(
requirement
).
to
be_persisted
expect
(
requirement
.
title
).
to
eq
(
params
[
:title
])
expect
(
requirement
.
state
).
to
eq
(
'opened'
)
expect
(
requirement
.
created_at
).
not_to
eq
(
params
[
:created_at
])
expect
(
requirement
.
author_id
).
not_to
eq
(
params
[
:author_id
])
end
end
context
'when user is not allowed to create requirements'
do
it
'raises an exception'
do
expect
{
subject
}.
to
raise_exception
(
Gitlab
::
Access
::
AccessDeniedError
)
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment