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
20e0429d
Commit
20e0429d
authored
Apr 24, 2020
by
Vasilii Iakliushin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add mutation to create a new branch in GraphQL
Issue:
https://gitlab.com/gitlab-org/gitlab/-/issues/215617
parent
d408a892
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
503 additions
and
0 deletions
+503
-0
app/graphql/mutations/branches/create.rb
app/graphql/mutations/branches/create.rb
+51
-0
app/graphql/resolvers/branch_commit_resolver.rb
app/graphql/resolvers/branch_commit_resolver.rb
+17
-0
app/graphql/types/branch_type.rb
app/graphql/types/branch_type.rb
+18
-0
app/graphql/types/mutation_type.rb
app/graphql/types/mutation_type.rb
+1
-0
changelogs/unreleased/215617_mutation_to_add_a_new_branch.yml
...gelogs/unreleased/215617_mutation_to_add_a_new_branch.yml
+5
-0
doc/api/graphql/reference/gitlab_schema.graphql
doc/api/graphql/reference/gitlab_schema.graphql
+58
-0
doc/api/graphql/reference/gitlab_schema.json
doc/api/graphql/reference/gitlab_schema.json
+202
-0
doc/api/graphql/reference/index.md
doc/api/graphql/reference/index.md
+17
-0
spec/graphql/mutations/branches/create_spec.rb
spec/graphql/mutations/branches/create_spec.rb
+55
-0
spec/graphql/resolvers/branch_commit_resolver_spec.rb
spec/graphql/resolvers/branch_commit_resolver_spec.rb
+26
-0
spec/graphql/types/branch_type_spec.rb
spec/graphql/types/branch_type_spec.rb
+9
-0
spec/requests/api/graphql/mutations/branches/create_spec.rb
spec/requests/api/graphql/mutations/branches/create_spec.rb
+44
-0
No files found.
app/graphql/mutations/branches/create.rb
0 → 100644
View file @
20e0429d
# frozen_string_literal: true
module
Mutations
module
Branches
class
Create
<
BaseMutation
include
Mutations
::
ResolvesProject
graphql_name
'CreateBranch'
argument
:project_path
,
GraphQL
::
ID_TYPE
,
required:
true
,
description:
'Project full path the branch is associated with'
argument
:name
,
GraphQL
::
STRING_TYPE
,
required:
true
,
description:
'Name of the branch'
argument
:ref
,
GraphQL
::
STRING_TYPE
,
required:
true
,
description:
'Branch name or commit SHA to create branch from'
field
:branch
,
Types
::
BranchType
,
null:
true
,
description:
'Branch after mutation'
authorize
:push_code
def
resolve
(
project_path
:,
name
:,
ref
:)
project
=
authorized_find!
(
full_path:
project_path
)
context
.
scoped_set!
(
:branch_project
,
project
)
result
=
::
Branches
::
CreateService
.
new
(
project
,
current_user
)
.
execute
(
name
,
ref
)
{
branch:
(
result
[
:branch
]
if
result
[
:status
]
==
:success
),
errors:
Array
.
wrap
(
result
[
:message
])
}
end
private
def
find_object
(
full_path
:)
resolve_project
(
full_path:
full_path
)
end
end
end
end
app/graphql/resolvers/branch_commit_resolver.rb
0 → 100644
View file @
20e0429d
# frozen_string_literal: true
module
Resolvers
class
BranchCommitResolver
<
BaseResolver
type
Types
::
CommitType
,
null:
true
alias_method
:branch
,
:object
def
resolve
(
**
args
)
return
unless
branch
commit
=
branch
.
dereferenced_target
::
Commit
.
new
(
commit
,
context
[
:branch_project
])
if
commit
end
end
end
app/graphql/types/branch_type.rb
0 → 100644
View file @
20e0429d
# frozen_string_literal: true
module
Types
# rubocop: disable Graphql/AuthorizeTypes
class
BranchType
<
BaseObject
graphql_name
'Branch'
field
:name
,
GraphQL
::
STRING_TYPE
,
null:
false
,
description:
'Name of the branch'
field
:commit
,
Types
::
CommitType
,
null:
true
,
resolver:
Resolvers
::
BranchCommitResolver
,
description:
'Commit for the branch'
end
# rubocop: enable Graphql/AuthorizeTypes
end
app/graphql/types/mutation_type.rb
View file @
20e0429d
...
...
@@ -10,6 +10,7 @@ module Types
mount_mutation
Mutations
::
AwardEmojis
::
Add
mount_mutation
Mutations
::
AwardEmojis
::
Remove
mount_mutation
Mutations
::
AwardEmojis
::
Toggle
mount_mutation
Mutations
::
Branches
::
Create
,
calls_gitaly:
true
mount_mutation
Mutations
::
Issues
::
SetConfidential
mount_mutation
Mutations
::
Issues
::
SetDueDate
mount_mutation
Mutations
::
Issues
::
Update
...
...
changelogs/unreleased/215617_mutation_to_add_a_new_branch.yml
0 → 100644
View file @
20e0429d
---
title
:
Add mutation to create a new branch in GraphQL
merge_request
:
30388
author
:
type
:
added
doc/api/graphql/reference/gitlab_schema.graphql
View file @
20e0429d
...
...
@@ -651,6 +651,18 @@ type BoardListUpdateLimitMetricsPayload {
list
:
BoardList
}
type
Branch
{
"""
Commit
for
the
branch
"""
commit
:
Commit
"""
Name
of
the
branch
"""
name
:
String
!
}
type
Commit
{
"""
Author
of
the
commit
...
...
@@ -768,6 +780,51 @@ type Commit {
webUrl
:
String
!
}
"""
Autogenerated input type of CreateBranch
"""
input
CreateBranchInput
{
"""
A
unique
identifier
for
the
client
performing
the
mutation
.
"""
clientMutationId
:
String
"""
Name
of
the
branch
"""
name
:
String
!
"""
Project
full
path
the
branch
is
associated
with
"""
projectPath
:
ID
!
"""
Branch
name
or
commit
SHA
to
create
branch
from
"""
ref
:
String
!
}
"""
Autogenerated return type of CreateBranch
"""
type
CreateBranchPayload
{
"""
Branch
after
mutation
"""
branch
:
Branch
"""
A
unique
identifier
for
the
client
performing
the
mutation
.
"""
clientMutationId
:
String
"""
Reasons
why
the
mutation
failed
.
"""
errors
:
[
String
!]!
}
"""
Autogenerated input type of CreateDiffNote
"""
...
...
@@ -5975,6 +6032,7 @@ type Mutation {
addProjectsToSecurityDashboard
(
input
:
AddProjectsToSecurityDashboardInput
!):
AddProjectsToSecurityDashboardPayload
adminSidekiqQueuesDeleteJobs
(
input
:
AdminSidekiqQueuesDeleteJobsInput
!):
AdminSidekiqQueuesDeleteJobsPayload
boardListUpdateLimitMetrics
(
input
:
BoardListUpdateLimitMetricsInput
!):
BoardListUpdateLimitMetricsPayload
createBranch
(
input
:
CreateBranchInput
!):
CreateBranchPayload
createDiffNote
(
input
:
CreateDiffNoteInput
!):
CreateDiffNotePayload
createEpic
(
input
:
CreateEpicInput
!):
CreateEpicPayload
createImageDiffNote
(
input
:
CreateImageDiffNoteInput
!):
CreateImageDiffNotePayload
...
...
doc/api/graphql/reference/gitlab_schema.json
View file @
20e0429d
...
...
@@ -1903,6 +1903,51 @@
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
"kind"
:
"OBJECT"
,
"name"
:
"Branch"
,
"description"
:
null
,
"fields"
:
[
{
"name"
:
"commit"
,
"description"
:
"Commit for the branch"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"OBJECT"
,
"name"
:
"Commit"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"name"
,
"description"
:
"Name of the branch"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
}
],
"inputFields"
:
null
,
"interfaces"
:
[
],
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
"kind"
:
"OBJECT"
,
"name"
:
"Commit"
,
...
...
@@ -2208,6 +2253,136 @@
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
"kind"
:
"INPUT_OBJECT"
,
"name"
:
"CreateBranchInput"
,
"description"
:
"Autogenerated input type of CreateBranch"
,
"fields"
:
null
,
"inputFields"
:
[
{
"name"
:
"projectPath"
,
"description"
:
"Project full path the branch is associated with"
,
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"ID"
,
"ofType"
:
null
}
},
"defaultValue"
:
null
},
{
"name"
:
"name"
,
"description"
:
"Name of the branch"
,
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
}
},
"defaultValue"
:
null
},
{
"name"
:
"ref"
,
"description"
:
"Branch name or commit SHA to create branch from"
,
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"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"
:
"CreateBranchPayload"
,
"description"
:
"Autogenerated return type of CreateBranch"
,
"fields"
:
[
{
"name"
:
"branch"
,
"description"
:
"Branch after mutation"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"OBJECT"
,
"name"
:
"Branch"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"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
}
],
"inputFields"
:
null
,
"interfaces"
:
[
],
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
"kind"
:
"INPUT_OBJECT"
,
"name"
:
"CreateDiffNoteInput"
,
...
...
@@ -17134,6 +17309,33 @@
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"createBranch"
,
"description"
:
null
,
"args"
:
[
{
"name"
:
"input"
,
"description"
:
null
,
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"INPUT_OBJECT"
,
"name"
:
"CreateBranchInput"
,
"ofType"
:
null
}
},
"defaultValue"
:
null
}
],
"type"
:
{
"kind"
:
"OBJECT"
,
"name"
:
"CreateBranchPayload"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"createDiffNote"
,
"description"
:
null
,
...
...
doc/api/graphql/reference/index.md
View file @
20e0429d
...
...
@@ -135,6 +135,13 @@ Autogenerated return type of BoardListUpdateLimitMetrics
|
`errors`
| String! => Array | Reasons why the mutation failed. |
|
`list`
| BoardList | The updated list |
## Branch
| Name | Type | Description |
| --- | ---- | ---------- |
|
`commit`
| Commit | Commit for the branch |
|
`name`
| String! | Name of the branch |
## Commit
| Name | Type | Description |
...
...
@@ -152,6 +159,16 @@ Autogenerated return type of BoardListUpdateLimitMetrics
|
`title`
| String | Title of the commit message |
|
`webUrl`
| String! | Web URL of the commit |
## CreateBranchPayload
Autogenerated return type of CreateBranch
| Name | Type | Description |
| --- | ---- | ---------- |
|
`branch`
| Branch | Branch after mutation |
|
`clientMutationId`
| String | A unique identifier for the client performing the mutation. |
|
`errors`
| String! => Array | Reasons why the mutation failed. |
## CreateDiffNotePayload
Autogenerated return type of CreateDiffNote
...
...
spec/graphql/mutations/branches/create_spec.rb
0 → 100644
View file @
20e0429d
# frozen_string_literal: true
require
'spec_helper'
describe
Mutations
::
Branches
::
Create
do
subject
(
:mutation
)
{
described_class
.
new
(
object:
nil
,
context:
context
,
field:
nil
)
}
let_it_be
(
:project
)
{
create
(
:project
,
:public
,
:repository
)
}
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:context
)
do
GraphQL
::
Query
::
Context
.
new
(
query:
OpenStruct
.
new
(
schema:
nil
),
values:
{
current_user:
user
},
object:
nil
)
end
describe
'#resolve'
do
subject
{
mutation
.
resolve
(
project_path:
project
.
full_path
,
name:
branch
,
ref:
ref
)
}
let
(
:branch
)
{
'new_branch'
}
let
(
:ref
)
{
'master'
}
let
(
:mutated_branch
)
{
subject
[
:branch
]
}
it
'raises an error if the resource is not accessible to the user'
do
expect
{
subject
}.
to
raise_error
(
Gitlab
::
Graphql
::
Errors
::
ResourceNotAvailable
)
end
context
'when the user can create a branch'
do
before
do
project
.
add_developer
(
user
)
allow_next_instance_of
(
::
Branches
::
CreateService
,
project
,
user
)
do
|
create_service
|
allow
(
create_service
).
to
receive
(
:execute
).
with
(
branch
,
ref
)
{
service_result
}
end
end
context
'when service successfully creates a new branch'
do
let
(
:service_result
)
{
{
status: :success
,
branch:
double
(
name:
branch
)
}
}
it
'returns a new branch'
do
expect
(
mutated_branch
.
name
).
to
eq
(
branch
)
expect
(
subject
[
:errors
]).
to
be_empty
end
end
context
'when service fails to create a new branch'
do
let
(
:service_result
)
{
{
status: :error
,
message:
'Branch already exists'
}
}
it
{
expect
(
mutated_branch
).
to
be_nil
}
it
{
expect
(
subject
[
:errors
]).
to
eq
([
'Branch already exists'
])
}
end
end
end
end
spec/graphql/resolvers/branch_commit_resolver_spec.rb
0 → 100644
View file @
20e0429d
# frozen_string_literal: true
require
'spec_helper'
describe
Resolvers
::
BranchCommitResolver
do
include
GraphqlHelpers
subject
(
:commit
)
{
resolve
(
described_class
,
obj:
branch
)
}
let_it_be
(
:repository
)
{
create
(
:project
,
:repository
).
repository
}
let
(
:branch
)
{
repository
.
find_branch
(
'master'
)
}
describe
'#resolve'
do
it
'resolves commit'
do
is_expected
.
to
eq
(
repository
.
commits
(
'master'
,
limit:
1
).
last
)
end
context
'when branch does not exist'
do
let
(
:branch
)
{
nil
}
it
'returns nil'
do
is_expected
.
to
be_nil
end
end
end
end
spec/graphql/types/branch_type_spec.rb
0 → 100644
View file @
20e0429d
# frozen_string_literal: true
require
'spec_helper'
describe
GitlabSchema
.
types
[
'Branch'
]
do
it
{
expect
(
described_class
.
graphql_name
).
to
eq
(
'Branch'
)
}
it
{
expect
(
described_class
).
to
have_graphql_fields
(
:name
,
:commit
)
}
end
spec/requests/api/graphql/mutations/branches/create_spec.rb
0 → 100644
View file @
20e0429d
# frozen_string_literal: true
require
'spec_helper'
describe
'Creation of a new branch'
do
include
GraphqlHelpers
let_it_be
(
:current_user
)
{
create
(
:user
)
}
let
(
:project
)
{
create
(
:project
,
:public
,
:repository
)
}
let
(
:input
)
{
{
project_path:
project
.
full_path
,
name:
new_branch
,
ref:
ref
}
}
let
(
:new_branch
)
{
'new_branch'
}
let
(
:ref
)
{
'master'
}
let
(
:mutation
)
{
graphql_mutation
(
:create_branch
,
input
)
}
let
(
:mutation_response
)
{
graphql_mutation_response
(
:create_branch
)
}
context
'the user is not allowed to create a branch'
do
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 user has permissions to create a branch'
do
before
do
project
.
add_developer
(
current_user
)
end
it
'creates a new branch'
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
expect
(
response
).
to
have_gitlab_http_status
(
:success
)
expect
(
mutation_response
[
'branch'
]).
to
include
(
'name'
=>
new_branch
,
'commit'
=>
a_hash_including
(
'id'
)
)
end
context
'when ref is not correct'
do
let
(
:ref
)
{
'unknown'
}
it_behaves_like
'a mutation that returns errors in the response'
,
errors:
[
'Invalid reference name: new_branch'
]
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