Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
李少辉-开发者
gitlab-foss
提交
27c6c4bf
G
gitlab-foss
项目概览
李少辉-开发者
/
gitlab-foss
通知
15
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
gitlab-foss
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
27c6c4bf
编写于
5月 26, 2020
作者:
G
GitLab Bot
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add latest changes from gitlab-org/gitlab@master
上级
47a2a65f
变更
28
隐藏空白更改
内联
并排
Showing
28 changed file
with
929 addition
and
326 deletion
+929
-326
app/assets/stylesheets/components/related_items_list.scss
app/assets/stylesheets/components/related_items_list.scss
+14
-4
app/controllers/concerns/check_codeowner_rules.rb
app/controllers/concerns/check_codeowner_rules.rb
+0
-9
app/controllers/projects/blob_controller.rb
app/controllers/projects/blob_controller.rb
+3
-14
app/finders/ci/runners_finder.rb
app/finders/ci/runners_finder.rb
+2
-2
app/finders/issuable_finder.rb
app/finders/issuable_finder.rb
+1
-1
app/graphql/mutations/merge_requests/create.rb
app/graphql/mutations/merge_requests/create.rb
+63
-0
app/graphql/types/milestone_type.rb
app/graphql/types/milestone_type.rb
+12
-0
app/graphql/types/mutation_type.rb
app/graphql/types/mutation_type.rb
+1
-0
app/models/concerns/featurable.rb
app/models/concerns/featurable.rb
+99
-0
app/models/concerns/issuable.rb
app/models/concerns/issuable.rb
+8
-1
app/models/milestone.rb
app/models/milestone.rb
+4
-0
app/models/project_feature.rb
app/models/project_feature.rb
+7
-99
changelogs/unreleased/208412-featurable.yml
changelogs/unreleased/208412-featurable.yml
+5
-0
changelogs/unreleased/215619_add_mutation_to_create_mr.yml
changelogs/unreleased/215619_add_mutation_to_create_mr.yml
+5
-0
changelogs/unreleased/216160-fix-label-any-with-custom-sorting.yml
...s/unreleased/216160-fix-label-any-with-custom-sorting.yml
+5
-0
changelogs/unreleased/Fix-spelling-error.yml
changelogs/unreleased/Fix-spelling-error.yml
+5
-0
doc/api/graphql/reference/gitlab_schema.graphql
doc/api/graphql/reference/gitlab_schema.graphql
+71
-0
doc/api/graphql/reference/gitlab_schema.json
doc/api/graphql/reference/gitlab_schema.json
+235
-0
doc/api/graphql/reference/index.md
doc/api/graphql/reference/index.md
+13
-0
lib/banzai/filter/external_issue_reference_filter.rb
lib/banzai/filter/external_issue_reference_filter.rb
+10
-9
locale/gitlab.pot
locale/gitlab.pot
+9
-0
spec/controllers/projects/blob_controller_spec.rb
spec/controllers/projects/blob_controller_spec.rb
+0
-56
spec/graphql/mutations/merge_requests/create_spec.rb
spec/graphql/mutations/merge_requests/create_spec.rb
+87
-0
spec/models/concerns/featurable_spec.rb
spec/models/concerns/featurable_spec.rb
+184
-0
spec/models/concerns/issuable_spec.rb
spec/models/concerns/issuable_spec.rb
+16
-0
spec/models/milestone_spec.rb
spec/models/milestone_spec.rb
+19
-0
spec/models/project_feature_spec.rb
spec/models/project_feature_spec.rb
+0
-131
spec/requests/api/graphql/mutations/merge_requests/create_spec.rb
...uests/api/graphql/mutations/merge_requests/create_spec.rb
+51
-0
未找到文件。
app/assets/stylesheets/components/related_items_list.scss
浏览文件 @
27c6c4bf
...
...
@@ -23,6 +23,11 @@ $item-remove-button-space: 42px;
.sortable-link
{
white-space
:
normal
;
}
.item-assignees
.avatar
{
height
:
$gl-padding
;
width
:
$gl-padding
;
}
}
.item-body
{
...
...
@@ -276,10 +281,6 @@ $item-remove-button-space: 42px;
/* Small devices (landscape phones, 768px and up) */
@include
media-breakpoint-up
(
md
)
{
.item-body
.item-contents
{
max-width
:
95%
;
}
.related-items-tree
.item-contents
,
.item-body
.item-title
{
max-width
:
100%
;
...
...
@@ -348,6 +349,11 @@ $item-remove-button-space: 42px;
}
.item-assignees
{
.avatar
{
height
:
$gl-padding-24
;
width
:
$gl-padding-24
;
}
.avatar-counter
{
height
:
$gl-padding-24
;
min-width
:
$gl-padding-24
;
...
...
@@ -366,6 +372,10 @@ $item-remove-button-space: 42px;
.sortable-link
{
line-height
:
1
.3
;
}
.item-info-area
{
flex-basis
:
auto
;
}
}
@media
only
screen
and
(
min-width
:
1500px
)
{
...
...
app/controllers/concerns/check_codeowner_rules.rb
已删除
100644 → 0
浏览文件 @
47a2a65f
# frozen_string_literal: true
module
CheckCodeownerRules
extend
ActiveSupport
::
Concern
def
codeowners_check_error
(
project
,
branch_name
,
paths
)
::
Gitlab
::
CodeOwners
::
Validator
.
new
(
project
,
branch_name
,
paths
).
execute
end
end
app/controllers/projects/blob_controller.rb
浏览文件 @
27c6c4bf
...
...
@@ -9,7 +9,6 @@ class Projects::BlobController < Projects::ApplicationController
include
ActionView
::
Helpers
::
SanitizeHelper
include
RedirectsForMissingPathOnTree
include
SourcegraphDecorator
include
CheckCodeownerRules
prepend_before_action
:authenticate_user!
,
only:
[
:edit
]
...
...
@@ -29,7 +28,6 @@ class Projects::BlobController < Projects::ApplicationController
before_action
:editor_variables
,
except:
[
:show
,
:preview
,
:diff
]
before_action
:validate_diff_params
,
only: :diff
before_action
:set_last_commit_sha
,
only:
[
:edit
,
:update
]
before_action
:validate_codeowner_rules
,
only:
[
:create
,
:update
]
before_action
only: :show
do
push_frontend_feature_flag
(
:code_navigation
,
@project
)
...
...
@@ -118,18 +116,7 @@ class Projects::BlobController < Projects::ApplicationController
private
def
validate_codeowner_rules
return
if
params
[
:file_path
].
blank?
codeowners_error
=
codeowners_check_error
(
@project
,
@branch_name
,
params
[
:file_path
])
if
codeowners_error
.
present?
flash
.
now
[
:alert
]
=
codeowners_error
view
=
params
[
:action
]
==
'update'
?
:edit
:
:new
render
view
end
end
attr_reader
:branch_name
def
blob
@blob
||=
@repository
.
blob_at
(
@commit
.
id
,
@path
)
...
...
@@ -270,3 +257,5 @@ class Projects::BlobController < Projects::ApplicationController
params
.
permit
(
:full
,
:since
,
:to
,
:bottom
,
:unfold
,
:offset
,
:indent
)
end
end
Projects
::
BlobController
.
prepend_if_ee
(
'EE::Projects::BlobController'
)
app/finders/ci/runners_finder.rb
浏览文件 @
27c6c4bf
...
...
@@ -52,9 +52,9 @@ module Ci
raise
Gitlab
::
Access
::
AccessDeniedError
unless
can?
(
@current_user
,
:admin_group
,
@group
)
# Getting all runners from the group itself and all its descendants
descen
t
ant_projects
=
Project
.
for_group_and_its_subgroups
(
@group
)
descen
d
ant_projects
=
Project
.
for_group_and_its_subgroups
(
@group
)
@runners
=
Ci
::
Runner
.
belonging_to_group_or_project
(
@group
.
self_and_descendants
,
descen
t
ant_projects
)
@runners
=
Ci
::
Runner
.
belonging_to_group_or_project
(
@group
.
self_and_descendants
,
descen
d
ant_projects
)
end
def
filter_by_status!
...
...
app/finders/issuable_finder.rb
浏览文件 @
27c6c4bf
...
...
@@ -451,7 +451,7 @@ class IssuableFinder
if
params
.
filter_by_no_label?
items
.
without_label
elsif
params
.
filter_by_any_label?
items
.
any_label
items
.
any_label
(
params
[
:sort
])
else
items
.
with_label
(
params
.
label_names
,
params
[
:sort
])
end
...
...
app/graphql/mutations/merge_requests/create.rb
0 → 100644
浏览文件 @
27c6c4bf
# frozen_string_literal: true
module
Mutations
module
MergeRequests
class
Create
<
BaseMutation
include
Mutations
::
ResolvesProject
graphql_name
'MergeRequestCreate'
argument
:project_path
,
GraphQL
::
ID_TYPE
,
required:
true
,
description:
'Project full path the merge request is associated with'
argument
:title
,
GraphQL
::
STRING_TYPE
,
required:
true
,
description:
copy_field_description
(
Types
::
MergeRequestType
,
:title
)
argument
:source_branch
,
GraphQL
::
STRING_TYPE
,
required:
true
,
description:
copy_field_description
(
Types
::
MergeRequestType
,
:source_branch
)
argument
:target_branch
,
GraphQL
::
STRING_TYPE
,
required:
true
,
description:
copy_field_description
(
Types
::
MergeRequestType
,
:target_branch
)
argument
:description
,
GraphQL
::
STRING_TYPE
,
required:
false
,
description:
copy_field_description
(
Types
::
MergeRequestType
,
:description
)
field
:merge_request
,
Types
::
MergeRequestType
,
null:
true
,
description:
'The merge request after mutation'
authorize
:create_merge_request_from
def
resolve
(
project_path
:,
title
:,
source_branch
:,
target_branch
:,
description:
nil
)
project
=
authorized_find!
(
full_path:
project_path
)
attributes
=
{
title:
title
,
source_branch:
source_branch
,
target_branch:
target_branch
,
author_id:
current_user
.
id
,
description:
description
}
merge_request
=
::
MergeRequests
::
CreateService
.
new
(
project
,
current_user
,
attributes
).
execute
{
merge_request:
merge_request
.
valid?
?
merge_request
:
nil
,
errors:
errors_on_object
(
merge_request
)
}
end
private
def
find_object
(
full_path
:)
resolve_project
(
full_path:
full_path
)
end
end
end
end
app/graphql/types/milestone_type.rb
浏览文件 @
27c6c4bf
...
...
@@ -35,5 +35,17 @@ module Types
field
:updated_at
,
Types
::
TimeType
,
null:
false
,
description:
'Timestamp of last milestone update'
field
:project_milestone
,
GraphQL
::
BOOLEAN_TYPE
,
null:
false
,
description:
'Indicates if milestone is at project level'
,
method: :project_milestone?
field
:group_milestone
,
GraphQL
::
BOOLEAN_TYPE
,
null:
false
,
description:
'Indicates if milestone is at group level'
,
method: :group_milestone?
field
:subgroup_milestone
,
GraphQL
::
BOOLEAN_TYPE
,
null:
false
,
description:
'Indicates if milestone is at subgroup level'
,
method: :subgroup_milestone?
end
end
app/graphql/types/mutation_type.rb
浏览文件 @
27c6c4bf
...
...
@@ -16,6 +16,7 @@ module Types
mount_mutation
Mutations
::
Issues
::
SetConfidential
mount_mutation
Mutations
::
Issues
::
SetDueDate
mount_mutation
Mutations
::
Issues
::
Update
mount_mutation
Mutations
::
MergeRequests
::
Create
mount_mutation
Mutations
::
MergeRequests
::
SetLabels
mount_mutation
Mutations
::
MergeRequests
::
SetLocked
mount_mutation
Mutations
::
MergeRequests
::
SetMilestone
...
...
app/models/concerns/featurable.rb
0 → 100644
浏览文件 @
27c6c4bf
# frozen_string_literal: true
# == Featurable concern
#
# This concern adds features (tools) functionality to Project and Group
# To enable features you need to call `set_available_features`
#
# Example:
#
# class ProjectFeature
# include Featurable
# set_available_features %i(wiki merge_request)
module
Featurable
extend
ActiveSupport
::
Concern
# Can be enabled only for members, everyone or disabled
# Access control is made only for non private containers.
#
# Permission levels:
#
# Disabled: not enabled for anyone
# Private: enabled only for team members
# Enabled: enabled for everyone able to access the project
# Public: enabled for everyone (only allowed for pages)
DISABLED
=
0
PRIVATE
=
10
ENABLED
=
20
PUBLIC
=
30
STRING_OPTIONS
=
HashWithIndifferentAccess
.
new
({
'disabled'
=>
DISABLED
,
'private'
=>
PRIVATE
,
'enabled'
=>
ENABLED
,
'public'
=>
PUBLIC
}).
freeze
class_methods
do
def
set_available_features
(
available_features
=
[])
@available_features
=
available_features
class_eval
do
available_features
.
each
do
|
feature
|
define_method
(
"
#{
feature
}
_enabled?"
)
do
public_send
(
"
#{
feature
}
_access_level"
)
>
DISABLED
# rubocop:disable GitlabSecurity/PublicSend
end
end
end
end
def
available_features
@available_features
end
def
access_level_attribute
(
feature
)
feature
=
ensure_feature!
(
feature
)
"
#{
feature
}
_access_level"
.
to_sym
end
def
quoted_access_level_column
(
feature
)
attribute
=
connection
.
quote_column_name
(
access_level_attribute
(
feature
))
table
=
connection
.
quote_table_name
(
table_name
)
"
#{
table
}
.
#{
attribute
}
"
end
def
access_level_from_str
(
level
)
STRING_OPTIONS
.
fetch
(
level
)
end
def
str_from_access_level
(
level
)
STRING_OPTIONS
.
key
(
level
)
end
def
ensure_feature!
(
feature
)
feature
=
feature
.
model_name
.
plural
if
feature
.
respond_to?
(
:model_name
)
feature
=
feature
.
to_sym
raise
ArgumentError
,
"invalid feature:
#{
feature
}
"
unless
available_features
.
include?
(
feature
)
feature
end
end
def
access_level
(
feature
)
public_send
(
self
.
class
.
access_level_attribute
(
feature
))
# rubocop:disable GitlabSecurity/PublicSend
end
def
feature_available?
(
feature
,
user
)
# This feature might not be behind a feature flag at all, so default to true
return
false
unless
::
Feature
.
enabled?
(
feature
,
user
,
default_enabled:
true
)
get_permission
(
user
,
feature
)
end
def
string_access_level
(
feature
)
self
.
class
.
str_from_access_level
(
access_level
(
feature
))
end
end
app/models/concerns/issuable.rb
浏览文件 @
27c6c4bf
...
...
@@ -139,7 +139,6 @@ module Issuable
scope
:without_label
,
->
{
joins
(
"LEFT OUTER JOIN label_links ON label_links.target_type = '
#{
name
}
' AND label_links.target_id =
#{
table_name
}
.id"
).
where
(
label_links:
{
id:
nil
})
}
scope
:with_label_ids
,
->
(
label_ids
)
{
joins
(
:label_links
).
where
(
label_links:
{
label_id:
label_ids
})
}
scope
:any_label
,
->
{
joins
(
:label_links
).
distinct
}
scope
:join_project
,
->
{
joins
(
:project
)
}
scope
:inc_notes_with_associations
,
->
{
includes
(
notes:
[
:project
,
:author
,
:award_emoji
])
}
scope
:references_project
,
->
{
references
(
:project
)
}
...
...
@@ -316,6 +315,14 @@ module Issuable
end
end
def
any_label
(
sort
=
nil
)
if
sort
joins
(
:label_links
).
group
(
*
grouping_columns
(
sort
))
else
joins
(
:label_links
).
distinct
end
end
# Includes table keys in group by clause when sorting
# preventing errors in postgres
#
...
...
app/models/milestone.rb
浏览文件 @
27c6c4bf
...
...
@@ -179,6 +179,10 @@ class Milestone < ApplicationRecord
end
end
def
subgroup_milestone?
group_milestone?
&&
parent
.
subgroup?
end
private
def
milestone_format_reference
(
format
=
:iid
)
...
...
app/models/project_feature.rb
浏览文件 @
27c6c4bf
# frozen_string_literal: true
class
ProjectFeature
<
ApplicationRecord
# == Project features permissions
#
# Grants access level to project tools
#
# Tools can be enabled only for users, everyone or disabled
# Access control is made only for non private projects
#
# levels:
#
# Disabled: not enabled for anyone
# Private: enabled only for team members
# Enabled: enabled for everyone able to access the project
# Public: enabled for everyone (only allowed for pages)
#
# Permission levels
DISABLED
=
0
PRIVATE
=
10
ENABLED
=
20
PUBLIC
=
30
include
Featurable
FEATURES
=
%i(issues forking merge_requests wiki snippets builds repository pages metrics_dashboard)
.
freeze
set_available_features
(
FEATURES
)
PRIVATE_FEATURES_MIN_ACCESS_LEVEL
=
{
merge_requests:
Gitlab
::
Access
::
REPORTER
,
metrics_dashboard:
Gitlab
::
Access
::
REPORTER
}.
freeze
PRIVATE_FEATURES_MIN_ACCESS_LEVEL_FOR_PRIVATE_PROJECT
=
{
repository:
Gitlab
::
Access
::
REPORTER
}.
freeze
STRING_OPTIONS
=
HashWithIndifferentAccess
.
new
({
'disabled'
=>
DISABLED
,
'private'
=>
PRIVATE
,
'enabled'
=>
ENABLED
,
'public'
=>
PUBLIC
}).
freeze
class
<<
self
def
access_level_attribute
(
feature
)
feature
=
ensure_feature!
(
feature
)
"
#{
feature
}
_access_level"
.
to_sym
end
def
quoted_access_level_column
(
feature
)
attribute
=
connection
.
quote_column_name
(
access_level_attribute
(
feature
))
table
=
connection
.
quote_table_name
(
table_name
)
"
#{
table
}
.
#{
attribute
}
"
end
def
required_minimum_access_level
(
feature
)
feature
=
ensure_feature!
(
feature
)
...
...
@@ -60,24 +25,6 @@ class ProjectFeature < ApplicationRecord
required_minimum_access_level
(
feature
)
end
end
def
access_level_from_str
(
level
)
STRING_OPTIONS
.
fetch
(
level
)
end
def
str_from_access_level
(
level
)
STRING_OPTIONS
.
key
(
level
)
end
private
def
ensure_feature!
(
feature
)
feature
=
feature
.
model_name
.
plural
if
feature
.
respond_to?
(
:model_name
)
feature
=
feature
.
to_sym
raise
ArgumentError
,
"invalid project feature:
#{
feature
}
"
unless
FEATURES
.
include?
(
feature
)
feature
end
end
# Default scopes force us to unscope here since a service may need to check
...
...
@@ -107,45 +54,6 @@ class ProjectFeature < ApplicationRecord
end
end
def
feature_available?
(
feature
,
user
)
# This feature might not be behind a feature flag at all, so default to true
return
false
unless
::
Feature
.
enabled?
(
feature
,
user
,
default_enabled:
true
)
get_permission
(
user
,
feature
)
end
def
access_level
(
feature
)
public_send
(
ProjectFeature
.
access_level_attribute
(
feature
))
# rubocop:disable GitlabSecurity/PublicSend
end
def
string_access_level
(
feature
)
ProjectFeature
.
str_from_access_level
(
access_level
(
feature
))
end
def
builds_enabled?
builds_access_level
>
DISABLED
end
def
wiki_enabled?
wiki_access_level
>
DISABLED
end
def
merge_requests_enabled?
merge_requests_access_level
>
DISABLED
end
def
forking_enabled?
forking_access_level
>
DISABLED
end
def
issues_enabled?
issues_access_level
>
DISABLED
end
def
pages_enabled?
pages_access_level
>
DISABLED
end
def
public_pages?
return
true
unless
Gitlab
.
config
.
pages
.
access_control
...
...
@@ -164,7 +72,7 @@ class ProjectFeature < ApplicationRecord
# which cannot be higher than repository access level
def
repository_children_level
validator
=
lambda
do
|
field
|
level
=
public_send
(
field
)
||
ProjectFeature
::
ENABLED
# rubocop:disable GitlabSecurity/PublicSend
level
=
public_send
(
field
)
||
ENABLED
# rubocop:disable GitlabSecurity/PublicSend
not_allowed
=
level
>
repository_access_level
self
.
errors
.
add
(
field
,
"cannot have higher visibility level than repository access level"
)
if
not_allowed
end
...
...
@@ -175,8 +83,8 @@ class ProjectFeature < ApplicationRecord
# Validates access level for other than pages cannot be PUBLIC
def
allowed_access_levels
validator
=
lambda
do
|
field
|
level
=
public_send
(
field
)
||
ProjectFeature
::
ENABLED
# rubocop:disable GitlabSecurity/PublicSend
not_allowed
=
level
>
ProjectFeature
::
ENABLED
level
=
public_send
(
field
)
||
ENABLED
# rubocop:disable GitlabSecurity/PublicSend
not_allowed
=
level
>
ENABLED
self
.
errors
.
add
(
field
,
"cannot have public visibility level"
)
if
not_allowed
end
...
...
changelogs/unreleased/208412-featurable.yml
0 → 100644
浏览文件 @
27c6c4bf
---
title
:
Extract featurable concern from ProjectFeature
merge_request
:
31700
author
:
Alexander Randa
type
:
other
changelogs/unreleased/215619_add_mutation_to_create_mr.yml
0 → 100644
浏览文件 @
27c6c4bf
---
title
:
Add mutation to create a merge request in GraphQL
merge_request
:
31867
author
:
type
:
added
changelogs/unreleased/216160-fix-label-any-with-custom-sorting.yml
0 → 100644
浏览文件 @
27c6c4bf
---
title
:
Fix issuable listings with any label filter
merge_request
:
31729
author
:
type
:
fixed
changelogs/unreleased/Fix-spelling-error.yml
0 → 100644
浏览文件 @
27c6c4bf
---
title
:
Fix spelling error on Ci::RunnersFinder
merge_request
:
32985
author
:
Arthur de Lapertosa Lisboa
type
:
fixed
doc/api/graphql/reference/gitlab_schema.graphql
浏览文件 @
27c6c4bf
...
...
@@ -6188,6 +6188,61 @@ type MergeRequestConnection {
pageInfo
:
PageInfo
!
}
"""
Autogenerated input type of MergeRequestCreate
"""
input
MergeRequestCreateInput
{
"""
A
unique
identifier
for
the
client
performing
the
mutation
.
"""
clientMutationId
:
String
"""
Description
of
the
merge
request
(
Markdown
rendered
as
HTML
for
caching
)
"""
description
:
String
"""
Project
full
path
the
merge
request
is
associated
with
"""
projectPath
:
ID
!
"""
Source
branch
of
the
merge
request
"""
sourceBranch
:
String
!
"""
Target
branch
of
the
merge
request
"""
targetBranch
:
String
!
"""
Title
of
the
merge
request
"""
title
:
String
!
}
"""
Autogenerated return type of MergeRequestCreate
"""
type
MergeRequestCreatePayload
{
"""
A
unique
identifier
for
the
client
performing
the
mutation
.
"""
clientMutationId
:
String
"""
Errors
encountered
during
execution
of
the
mutation
.
"""
errors
:
[
String
!]!
"""
The
merge
request
after
mutation
"""
mergeRequest
:
MergeRequest
}
"""
An edge in a connection.
"""
...
...
@@ -6673,11 +6728,21 @@ type Milestone {
"""
dueDate
:
Time
"""
Indicates
if
milestone
is
at
group
level
"""
groupMilestone
:
Boolean
!
"""
ID
of
the
milestone
"""
id
:
ID
!
"""
Indicates
if
milestone
is
at
project
level
"""
projectMilestone
:
Boolean
!
"""
Timestamp
of
the
milestone
start
date
"""
...
...
@@ -6688,6 +6753,11 @@ type Milestone {
"""
state
:
MilestoneStateEnum
!
"""
Indicates
if
milestone
is
at
subgroup
level
"""
subgroupMilestone
:
Boolean
!
"""
Title
of
the
milestone
"""
...
...
@@ -6788,6 +6858,7 @@ type Mutation {
issueSetWeight
(
input
:
IssueSetWeightInput
!):
IssueSetWeightPayload
jiraImportStart
(
input
:
JiraImportStartInput
!):
JiraImportStartPayload
markAsSpamSnippet
(
input
:
MarkAsSpamSnippetInput
!):
MarkAsSpamSnippetPayload
mergeRequestCreate
(
input
:
MergeRequestCreateInput
!):
MergeRequestCreatePayload
mergeRequestSetAssignees
(
input
:
MergeRequestSetAssigneesInput
!):
MergeRequestSetAssigneesPayload
mergeRequestSetLabels
(
input
:
MergeRequestSetLabelsInput
!):
MergeRequestSetLabelsPayload
mergeRequestSetLocked
(
input
:
MergeRequestSetLockedInput
!):
MergeRequestSetLockedPayload
...
...
doc/api/graphql/reference/gitlab_schema.json
浏览文件 @
27c6c4bf
...
...
@@ -17302,6 +17302,160 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "MergeRequestCreateInput",
"description": "Autogenerated input type of MergeRequestCreate",
"fields": null,
"inputFields": [
{
"name": "projectPath",
"description": "Project full path the merge request is associated with",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "title",
"description": "Title of the merge request",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "sourceBranch",
"description": "Source branch of the merge request",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "targetBranch",
"description": "Target branch of the merge request",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "description",
"description": "Description of the merge request (Markdown rendered as HTML for caching)",
"type": {
"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": "MergeRequestCreatePayload",
"description": "Autogenerated return type of MergeRequestCreate",
"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": "Errors encountered during execution of the mutation.",
"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": "mergeRequest",
"description": "The merge request after mutation",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "MergeRequest",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "MergeRequestEdge",
...
...
@@ -18754,6 +18908,24 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "groupMilestone",
"description": "Indicates if milestone is at group level",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "id",
"description": "ID of the milestone",
...
...
@@ -18772,6 +18944,24 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "projectMilestone",
"description": "Indicates if milestone is at project level",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "startDate",
"description": "Timestamp of the milestone start date",
...
...
@@ -18804,6 +18994,24 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "subgroupMilestone",
"description": "Indicates if milestone is at subgroup level",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "title",
"description": "Title of the milestone",
...
...
@@ -19785,6 +19993,33 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "mergeRequestCreate",
"description": null,
"args": [
{
"name": "input",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "MergeRequestCreateInput",
"ofType": null
}
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "MergeRequestCreatePayload",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "mergeRequestSetAssignees",
"description": null,
doc/api/graphql/reference/index.md
浏览文件 @
27c6c4bf
...
...
@@ -912,6 +912,16 @@ Autogenerated return type of MarkAsSpamSnippet
|
`webUrl`
| String | Web URL of the merge request |
|
`workInProgress`
| Boolean! | Indicates if the merge request is a work in progress (WIP) |
## MergeRequestCreatePayload
Autogenerated return type of MergeRequestCreate
| Name | Type | Description |
| --- | ---- | ---------- |
|
`clientMutationId`
| String | A unique identifier for the client performing the mutation. |
|
`errors`
| String! => Array | Errors encountered during execution of the mutation. |
|
`mergeRequest`
| MergeRequest | The merge request after mutation |
## MergeRequestPermissions
Check permissions for the current user on a merge request
...
...
@@ -1019,9 +1029,12 @@ Represents a milestone.
|
`createdAt`
| Time! | Timestamp of milestone creation |
|
`description`
| String | Description of the milestone |
|
`dueDate`
| Time | Timestamp of the milestone due date |
|
`groupMilestone`
| Boolean! | Indicates if milestone is at group level |
|
`id`
| ID! | ID of the milestone |
|
`projectMilestone`
| Boolean! | Indicates if milestone is at project level |
|
`startDate`
| Time | Timestamp of the milestone start date |
|
`state`
| MilestoneStateEnum! | State of the milestone |
|
`subgroupMilestone`
| Boolean! | Indicates if milestone is at subgroup level |
|
`title`
| String! | Title of the milestone |
|
`updatedAt`
| Time! | Timestamp of last milestone update |
|
`webPath`
| String! | Web path of the milestone |
...
...
lib/banzai/filter/external_issue_reference_filter.rb
浏览文件 @
27c6c4bf
...
...
@@ -54,6 +54,8 @@ module Banzai
doc
end
private
# Replace `JIRA-123` issue references in text with links to the referenced
# issue's details page.
#
...
...
@@ -63,21 +65,14 @@ module Banzai
# Returns a String with `JIRA-123` references replaced with links. All
# links have `gfm` and `gfm-issue` class names attached for styling.
def
issue_link_filter
(
text
,
link_content:
nil
)
project
=
context
[
:project
]
self
.
class
.
references_in
(
text
,
issue_reference_pattern
)
do
|
match
,
id
|
ExternalIssue
.
new
(
id
,
project
)
url
=
url_for_issue
(
id
,
project
,
only_path:
context
[
:only_path
])
title
=
"Issue in
#{
project
.
external_issue_tracker
.
title
}
"
klass
=
reference_class
(
:issue
)
data
=
data_attribute
(
project:
project
.
id
,
external_issue:
id
)
content
=
link_content
||
match
%(<a href="#{url}" #{data}
title="#{escape_once(title)}"
title="#{escape_once(
issue_
title)}"
class="#{klass}">#{content}</a>)
end
end
...
...
@@ -94,7 +89,13 @@ module Banzai
external_issues_cached
(
:external_issue_reference_pattern
)
end
private
def
project
context
[
:project
]
end
def
issue_title
"Issue in
#{
project
.
external_issue_tracker
.
title
}
"
end
def
external_issues_cached
(
attribute
)
cached_attributes
=
Gitlab
::
SafeRequestStore
[
:banzai_external_issues_tracker_attributes
]
||=
Hash
.
new
{
|
h
,
k
|
h
[
k
]
=
{}
}
...
...
locale/gitlab.pot
浏览文件 @
27c6c4bf
...
...
@@ -10797,6 +10797,9 @@ msgstr ""
msgid "Group members"
msgstr ""
msgid "Group milestone"
msgstr ""
msgid "Group name"
msgstr ""
...
...
@@ -16628,6 +16631,9 @@ msgstr ""
msgid "Project members"
msgstr ""
msgid "Project milestone"
msgstr ""
msgid "Project name"
msgstr ""
...
...
@@ -20778,6 +20784,9 @@ msgstr ""
msgid "StorageSize|Unknown"
msgstr ""
msgid "Subgroup milestone"
msgstr ""
msgid "Subgroup overview"
msgstr ""
...
...
spec/controllers/projects/blob_controller_spec.rb
浏览文件 @
27c6c4bf
...
...
@@ -250,56 +250,6 @@ describe Projects::BlobController do
end
end
shared_examples
"file matches a codeowners rule"
do
let
(
:error_msg
)
{
"Example error msg"
}
it
"renders to the edit page with an error msg"
do
default_params
[
:file_path
]
=
"CHANGELOG"
expect_next_instance_of
(
Gitlab
::
CodeOwners
::
Validator
)
do
|
validator
|
expect
(
validator
).
to
receive
(
:execute
).
and_return
(
error_msg
)
end
subject
expect
(
flash
[
:alert
]).
to
eq
(
error_msg
)
expect
(
response
).
to
render_template
(
expected_view
)
end
end
describe
'POST create'
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:default_params
)
do
{
namespace_id:
project
.
namespace
,
project_id:
project
,
id:
'master'
,
branch_name:
'master'
,
file_name:
'CHANGELOG'
,
content:
'Added changes'
,
commit_message:
'Create CHANGELOG'
}
end
before
do
project
.
add_developer
(
user
)
sign_in
(
user
)
end
it
'redirects to blob'
do
post
:create
,
params:
default_params
expect
(
response
).
to
be_ok
end
it_behaves_like
"file matches a codeowners rule"
do
subject
{
post
:create
,
params:
default_params
}
let
(
:expected_view
)
{
:new
}
end
end
describe
'PUT update'
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:default_params
)
do
...
...
@@ -329,12 +279,6 @@ describe Projects::BlobController do
expect
(
response
).
to
redirect_to
(
blob_after_edit_path
)
end
it_behaves_like
"file matches a codeowners rule"
do
subject
{
put
:update
,
params:
default_params
}
let
(
:expected_view
)
{
:edit
}
end
context
'?from_merge_request_iid'
do
let
(
:merge_request
)
{
create
(
:merge_request
,
source_project:
project
,
target_project:
project
)
}
let
(
:mr_params
)
{
default_params
.
merge
(
from_merge_request_iid:
merge_request
.
iid
)
}
...
...
spec/graphql/mutations/merge_requests/create_spec.rb
0 → 100644
浏览文件 @
27c6c4bf
# frozen_string_literal: true
require
'spec_helper'
describe
Mutations
::
MergeRequests
::
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
do
mutation
.
resolve
(
project_path:
project
.
full_path
,
title:
title
,
source_branch:
source_branch
,
target_branch:
target_branch
,
description:
description
)
end
let
(
:title
)
{
'MergeRequest'
}
let
(
:source_branch
)
{
'feature'
}
let
(
:target_branch
)
{
'master'
}
let
(
:description
)
{
nil
}
let
(
:mutated_merge_request
)
{
subject
[
:merge_request
]
}
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 user does not have enough permissions to create a merge request'
do
before
do
project
.
add_guest
(
user
)
end
it
'raises an error if the resource is not accessible to the user'
do
expect
{
subject
}.
to
raise_error
(
Gitlab
::
Graphql
::
Errors
::
ResourceNotAvailable
)
end
end
context
'when the user can create a merge request'
do
before_all
do
project
.
add_developer
(
user
)
end
it
'creates a new merge request'
do
expect
{
mutated_merge_request
}.
to
change
(
MergeRequest
,
:count
).
by
(
1
)
end
it
'returns a new merge request'
do
expect
(
mutated_merge_request
.
title
).
to
eq
(
title
)
expect
(
subject
[
:errors
]).
to
be_empty
end
context
'when optional description field is set'
do
let
(
:description
)
{
'content'
}
it
'returns a new merge request with a description'
do
expect
(
mutated_merge_request
.
description
).
to
eq
(
description
)
expect
(
subject
[
:errors
]).
to
be_empty
end
end
context
'when service cannot create a merge request'
do
let
(
:title
)
{
nil
}
it
'does not create a new merge request'
do
expect
{
mutated_merge_request
}.
not_to
change
(
MergeRequest
,
:count
)
end
it
'returns errors'
do
expect
(
mutated_merge_request
).
to
be_nil
expect
(
subject
[
:errors
]).
to
eq
([
'Title can\'t be blank'
])
end
end
end
end
end
spec/models/concerns/featurable_spec.rb
0 → 100644
浏览文件 @
27c6c4bf
# frozen_string_literal: true
require
'spec_helper'
describe
Featurable
do
let_it_be
(
:user
)
{
create
(
:user
)
}
let
(
:project
)
{
create
(
:project
)
}
let
(
:feature_class
)
{
subject
.
class
}
let
(
:features
)
{
feature_class
::
FEATURES
}
subject
{
project
.
project_feature
}
describe
'.quoted_access_level_column'
do
it
'returns the table name and quoted column name for a feature'
do
expected
=
'"project_features"."issues_access_level"'
expect
(
feature_class
.
quoted_access_level_column
(
:issues
)).
to
eq
(
expected
)
end
end
describe
'.access_level_attribute'
do
it
{
expect
(
feature_class
.
access_level_attribute
(
:wiki
)).
to
eq
:wiki_access_level
}
it
'raises error for unspecified feature'
do
expect
{
feature_class
.
access_level_attribute
(
:unknown
)
}
.
to
raise_error
(
ArgumentError
,
/invalid feature: unknown/
)
end
end
describe
'.set_available_features'
do
let!
(
:klass
)
do
Class
.
new
do
include
Featurable
set_available_features
%i(feature1 feature2)
def
feature1_access_level
Featurable
::
DISABLED
end
def
feature2_access_level
Featurable
::
ENABLED
end
end
end
let!
(
:instance
)
{
klass
.
new
}
it
{
expect
(
klass
.
available_features
).
to
eq
[
:feature1
,
:feature2
]
}
it
{
expect
(
instance
.
feature1_enabled?
).
to
be_falsey
}
it
{
expect
(
instance
.
feature2_enabled?
).
to
be_truthy
}
end
describe
'.available_features'
do
it
{
expect
(
feature_class
.
available_features
).
to
include
(
*
features
)
}
end
describe
'#access_level'
do
it
'returns access level'
do
expect
(
subject
.
access_level
(
:wiki
)).
to
eq
(
subject
.
wiki_access_level
)
end
end
describe
'#feature_available?'
do
let
(
:features
)
{
%w(issues wiki builds merge_requests snippets repository pages metrics_dashboard)
}
context
'when features are disabled'
do
it
"returns false"
do
update_all_project_features
(
project
,
features
,
ProjectFeature
::
DISABLED
)
features
.
each
do
|
feature
|
expect
(
project
.
feature_available?
(
feature
.
to_sym
,
user
)).
to
eq
(
false
),
"
#{
feature
}
failed"
end
end
end
context
'when features are enabled only for team members'
do
it
"returns false when user is not a team member"
do
update_all_project_features
(
project
,
features
,
ProjectFeature
::
PRIVATE
)
features
.
each
do
|
feature
|
expect
(
project
.
feature_available?
(
feature
.
to_sym
,
user
)).
to
eq
(
false
),
"
#{
feature
}
failed"
end
end
it
"returns true when user is a team member"
do
project
.
add_developer
(
user
)
update_all_project_features
(
project
,
features
,
ProjectFeature
::
PRIVATE
)
features
.
each
do
|
feature
|
expect
(
project
.
feature_available?
(
feature
.
to_sym
,
user
)).
to
eq
(
true
),
"
#{
feature
}
failed"
end
end
it
"returns true when user is a member of project group"
do
group
=
create
(
:group
)
project
=
create
(
:project
,
namespace:
group
)
group
.
add_developer
(
user
)
update_all_project_features
(
project
,
features
,
ProjectFeature
::
PRIVATE
)
features
.
each
do
|
feature
|
expect
(
project
.
feature_available?
(
feature
.
to_sym
,
user
)).
to
eq
(
true
),
"
#{
feature
}
failed"
end
end
context
'when admin mode is enabled'
,
:enable_admin_mode
do
it
"returns true if user is an admin"
do
user
.
update_attribute
(
:admin
,
true
)
update_all_project_features
(
project
,
features
,
ProjectFeature
::
PRIVATE
)
features
.
each
do
|
feature
|
expect
(
project
.
feature_available?
(
feature
.
to_sym
,
user
)).
to
eq
(
true
),
"
#{
feature
}
failed"
end
end
end
context
'when admin mode is disabled'
do
it
"returns false when user is an admin"
do
user
.
update_attribute
(
:admin
,
true
)
update_all_project_features
(
project
,
features
,
ProjectFeature
::
PRIVATE
)
features
.
each
do
|
feature
|
expect
(
project
.
feature_available?
(
feature
.
to_sym
,
user
)).
to
eq
(
false
),
"
#{
feature
}
failed"
end
end
end
end
context
'when feature is enabled for everyone'
do
it
"returns true"
do
expect
(
project
.
feature_available?
(
:issues
,
user
)).
to
eq
(
true
)
end
end
context
'when feature is disabled by a feature flag'
do
it
'returns false'
do
stub_feature_flags
(
issues:
false
)
expect
(
project
.
feature_available?
(
:issues
,
user
)).
to
eq
(
false
)
end
end
context
'when feature is enabled by a feature flag'
do
it
'returns true'
do
stub_feature_flags
(
issues:
true
)
expect
(
project
.
feature_available?
(
:issues
,
user
)).
to
eq
(
true
)
end
end
end
describe
'#*_enabled?'
do
let
(
:features
)
{
%w(wiki builds merge_requests)
}
it
"returns false when feature is disabled"
do
update_all_project_features
(
project
,
features
,
ProjectFeature
::
DISABLED
)
features
.
each
do
|
feature
|
expect
(
project
.
public_send
(
"
#{
feature
}
_enabled?"
)).
to
eq
(
false
),
"
#{
feature
}
failed"
end
end
it
"returns true when feature is enabled only for team members"
do
update_all_project_features
(
project
,
features
,
ProjectFeature
::
PRIVATE
)
features
.
each
do
|
feature
|
expect
(
project
.
public_send
(
"
#{
feature
}
_enabled?"
)).
to
eq
(
true
),
"
#{
feature
}
failed"
end
end
it
"returns true when feature is enabled for everyone"
do
features
.
each
do
|
feature
|
expect
(
project
.
public_send
(
"
#{
feature
}
_enabled?"
)).
to
eq
(
true
),
"
#{
feature
}
failed"
end
end
end
def
update_all_project_features
(
project
,
features
,
value
)
project_feature_attributes
=
features
.
map
{
|
f
|
[
"
#{
f
}
_access_level"
,
value
]
}.
to_h
project
.
project_feature
.
update
(
project_feature_attributes
)
end
end
spec/models/concerns/issuable_spec.rb
浏览文件 @
27c6c4bf
...
...
@@ -102,6 +102,22 @@ describe Issuable do
end
end
describe
'.any_label'
do
let_it_be
(
:issue_with_label
)
{
create
(
:labeled_issue
,
labels:
[
create
(
:label
)])
}
let_it_be
(
:issue_with_multiple_labels
)
{
create
(
:labeled_issue
,
labels:
[
create
(
:label
),
create
(
:label
)])
}
let_it_be
(
:issue_without_label
)
{
create
(
:issue
)
}
it
'returns an issuable with at least one label'
do
expect
(
issuable_class
.
any_label
).
to
match_array
([
issue_with_label
,
issue_with_multiple_labels
])
end
context
'for custom sorting'
do
it
'returns an issuable with at least one label'
do
expect
(
issuable_class
.
any_label
(
'created_at'
)).
to
eq
([
issue_with_label
,
issue_with_multiple_labels
])
end
end
end
describe
".search"
do
let!
(
:searchable_issue
)
{
create
(
:issue
,
title:
"Searchable awesome issue"
)
}
let!
(
:searchable_issue2
)
{
create
(
:issue
,
title:
'Aw'
)
}
...
...
spec/models/milestone_spec.rb
浏览文件 @
27c6c4bf
...
...
@@ -498,4 +498,23 @@ describe Milestone do
end
end
end
describe
'#subgroup_milestone'
do
context
'parent is subgroup'
do
it
'returns true'
do
group
=
create
(
:group
)
subgroup
=
create
(
:group
,
:private
,
parent:
group
)
expect
(
build
(
:milestone
,
group:
subgroup
).
subgroup_milestone?
).
to
eq
(
true
)
end
end
context
'parent is not subgroup'
do
it
'returns false'
do
group
=
create
(
:group
)
expect
(
build
(
:milestone
,
group:
group
).
subgroup_milestone?
).
to
eq
(
false
)
end
end
end
end
spec/models/project_feature_spec.rb
浏览文件 @
27c6c4bf
...
...
@@ -18,106 +18,6 @@ describe ProjectFeature do
end
end
describe
'.quoted_access_level_column'
do
it
'returns the table name and quoted column name for a feature'
do
expected
=
'"project_features"."issues_access_level"'
expect
(
described_class
.
quoted_access_level_column
(
:issues
)).
to
eq
(
expected
)
end
end
describe
'#feature_available?'
do
let
(
:features
)
{
%w(issues wiki builds merge_requests snippets repository pages metrics_dashboard)
}
context
'when features are disabled'
do
it
"returns false"
do
update_all_project_features
(
project
,
features
,
ProjectFeature
::
DISABLED
)
features
.
each
do
|
feature
|
expect
(
project
.
feature_available?
(
feature
.
to_sym
,
user
)).
to
eq
(
false
),
"
#{
feature
}
failed"
end
end
end
context
'when features are enabled only for team members'
do
it
"returns false when user is not a team member"
do
update_all_project_features
(
project
,
features
,
ProjectFeature
::
PRIVATE
)
features
.
each
do
|
feature
|
expect
(
project
.
feature_available?
(
feature
.
to_sym
,
user
)).
to
eq
(
false
),
"
#{
feature
}
failed"
end
end
it
"returns true when user is a team member"
do
project
.
add_developer
(
user
)
update_all_project_features
(
project
,
features
,
ProjectFeature
::
PRIVATE
)
features
.
each
do
|
feature
|
expect
(
project
.
feature_available?
(
feature
.
to_sym
,
user
)).
to
eq
(
true
),
"
#{
feature
}
failed"
end
end
it
"returns true when user is a member of project group"
do
group
=
create
(
:group
)
project
=
create
(
:project
,
namespace:
group
)
group
.
add_developer
(
user
)
update_all_project_features
(
project
,
features
,
ProjectFeature
::
PRIVATE
)
features
.
each
do
|
feature
|
expect
(
project
.
feature_available?
(
feature
.
to_sym
,
user
)).
to
eq
(
true
),
"
#{
feature
}
failed"
end
end
context
'when admin mode is enabled'
,
:enable_admin_mode
do
it
"returns true if user is an admin"
do
user
.
update_attribute
(
:admin
,
true
)
update_all_project_features
(
project
,
features
,
ProjectFeature
::
PRIVATE
)
features
.
each
do
|
feature
|
expect
(
project
.
feature_available?
(
feature
.
to_sym
,
user
)).
to
eq
(
true
),
"
#{
feature
}
failed"
end
end
end
context
'when admin mode is disabled'
do
it
"returns false when user is an admin"
do
user
.
update_attribute
(
:admin
,
true
)
update_all_project_features
(
project
,
features
,
ProjectFeature
::
PRIVATE
)
features
.
each
do
|
feature
|
expect
(
project
.
feature_available?
(
feature
.
to_sym
,
user
)).
to
eq
(
false
),
"
#{
feature
}
failed"
end
end
end
end
context
'when feature is enabled for everyone'
do
it
"returns true"
do
expect
(
project
.
feature_available?
(
:issues
,
user
)).
to
eq
(
true
)
end
end
context
'when feature is disabled by a feature flag'
do
it
'returns false'
do
stub_feature_flags
(
issues:
false
)
expect
(
project
.
feature_available?
(
:issues
,
user
)).
to
eq
(
false
)
end
end
context
'when feature is enabled by a feature flag'
do
it
'returns true'
do
stub_feature_flags
(
issues:
true
)
expect
(
project
.
feature_available?
(
:issues
,
user
)).
to
eq
(
true
)
end
end
end
context
'repository related features'
do
before
do
project
.
project_feature
.
update
(
...
...
@@ -153,32 +53,6 @@ describe ProjectFeature do
end
end
describe
'#*_enabled?'
do
let
(
:features
)
{
%w(wiki builds merge_requests)
}
it
"returns false when feature is disabled"
do
update_all_project_features
(
project
,
features
,
ProjectFeature
::
DISABLED
)
features
.
each
do
|
feature
|
expect
(
project
.
public_send
(
"
#{
feature
}
_enabled?"
)).
to
eq
(
false
),
"
#{
feature
}
failed"
end
end
it
"returns true when feature is enabled only for team members"
do
update_all_project_features
(
project
,
features
,
ProjectFeature
::
PRIVATE
)
features
.
each
do
|
feature
|
expect
(
project
.
public_send
(
"
#{
feature
}
_enabled?"
)).
to
eq
(
true
),
"
#{
feature
}
failed"
end
end
it
"returns true when feature is enabled for everyone"
do
features
.
each
do
|
feature
|
expect
(
project
.
public_send
(
"
#{
feature
}
_enabled?"
)).
to
eq
(
true
),
"
#{
feature
}
failed"
end
end
end
describe
'default pages access level'
do
subject
{
project_feature
.
pages_access_level
}
...
...
@@ -313,9 +187,4 @@ describe ProjectFeature do
expect
(
described_class
.
required_minimum_access_level_for_private_project
(
:issues
)).
to
eq
(
Gitlab
::
Access
::
GUEST
)
end
end
def
update_all_project_features
(
project
,
features
,
value
)
project_feature_attributes
=
features
.
map
{
|
f
|
[
"
#{
f
}
_access_level"
,
value
]
}.
to_h
project
.
project_feature
.
update
(
project_feature_attributes
)
end
end
spec/requests/api/graphql/mutations/merge_requests/create_spec.rb
0 → 100644
浏览文件 @
27c6c4bf
# frozen_string_literal: true
require
'spec_helper'
describe
'Creation of a new merge request'
do
include
GraphqlHelpers
let_it_be
(
:current_user
)
{
create
(
:user
)
}
let
(
:project
)
{
create
(
:project
,
:public
,
:repository
)
}
let
(
:input
)
do
{
project_path:
project
.
full_path
,
title:
title
,
source_branch:
source_branch
,
target_branch:
target_branch
}
end
let
(
:title
)
{
'MergeRequest'
}
let
(
:source_branch
)
{
'new_branch'
}
let
(
:target_branch
)
{
'master'
}
let
(
:mutation
)
{
graphql_mutation
(
:merge_request_create
,
input
)
}
let
(
:mutation_response
)
{
graphql_mutation_response
(
:merge_request_create
)
}
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 merge request'
do
before
do
project
.
add_developer
(
current_user
)
end
it
'creates a new merge request'
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
expect
(
response
).
to
have_gitlab_http_status
(
:success
)
expect
(
mutation_response
[
'mergeRequest'
]).
to
include
(
'title'
=>
title
)
end
context
'when source branch is equal to the target branch'
do
let
(
:source_branch
)
{
target_branch
}
it_behaves_like
'a mutation that returns errors in the response'
,
errors:
[
'Branch conflict You can\'t use same project/branch for source and target'
]
end
end
end
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录