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
680decd0
Commit
680decd0
authored
Dec 02, 2020
by
GitLab Bot
Browse files
Options
Browse Files
Download
Plain Diff
Automatic merge of gitlab-org/gitlab master
parents
1a57f833
fa60193b
Changes
27
Show whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
413 additions
and
277 deletions
+413
-277
app/graphql/resolvers/issues_resolver.rb
app/graphql/resolvers/issues_resolver.rb
+1
-1
app/graphql/resolvers/merge_requests_resolver.rb
app/graphql/resolvers/merge_requests_resolver.rb
+1
-1
app/graphql/resolvers/users_resolver.rb
app/graphql/resolvers/users_resolver.rb
+1
-1
app/graphql/types/sort_enum.rb
app/graphql/types/sort_enum.rb
+4
-4
changelogs/unreleased/improve-feature-flag-logging.yml
changelogs/unreleased/improve-feature-flag-logging.yml
+5
-0
doc/administration/logs.md
doc/administration/logs.md
+25
-0
doc/development/feature_flags/controls.md
doc/development/feature_flags/controls.md
+10
-2
doc/development/graphql_guide/pagination.md
doc/development/graphql_guide/pagination.md
+13
-11
doc/user/permissions.md
doc/user/permissions.md
+3
-3
ee/app/finders/requirements_management/requirements_finder.rb
...pp/finders/requirements_management/requirements_finder.rb
+1
-1
ee/spec/lib/ee/feature_spec.rb
ee/spec/lib/ee/feature_spec.rb
+0
-40
ee/spec/requests/api/graphql/boards/board_lists_query_spec.rb
...pec/requests/api/graphql/boards/board_lists_query_spec.rb
+5
-11
ee/spec/requests/api/graphql/group_query_spec.rb
ee/spec/requests/api/graphql/group_query_spec.rb
+14
-16
ee/spec/requests/api/graphql/namespace/projects_spec.rb
ee/spec/requests/api/graphql/namespace/projects_spec.rb
+46
-0
ee/spec/requests/api/graphql/project/issues_spec.rb
ee/spec/requests/api/graphql/project/issues_spec.rb
+9
-13
ee/spec/requests/api/graphql/project/requirements_management/requirements_spec.rb
...phql/project/requirements_management/requirements_spec.rb
+5
-9
ee/spec/requests/api/graphql/project/requirements_management/test_reports_spec.rb
...phql/project/requirements_management/test_reports_spec.rb
+15
-13
lib/feature.rb
lib/feature.rb
+19
-8
lib/feature/logger.rb
lib/feature/logger.rb
+9
-0
spec/lib/feature_spec.rb
spec/lib/feature_spec.rb
+112
-0
spec/requests/api/graphql/boards/board_lists_query_spec.rb
spec/requests/api/graphql/boards/board_lists_query_spec.rb
+5
-11
spec/requests/api/graphql/namespace/projects_spec.rb
spec/requests/api/graphql/namespace/projects_spec.rb
+20
-24
spec/requests/api/graphql/project/issues_spec.rb
spec/requests/api/graphql/project/issues_spec.rb
+13
-15
spec/requests/api/graphql/project/merge_requests_spec.rb
spec/requests/api/graphql/project/merge_requests_spec.rb
+5
-42
spec/requests/api/graphql/users_spec.rb
spec/requests/api/graphql/users_spec.rb
+5
-9
spec/support/shared_examples/graphql/sorted_paginated_query_shared_examples.rb
...xamples/graphql/sorted_paginated_query_shared_examples.rb
+62
-31
spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb
...graphql/group_and_project_boards_query_shared_examples.rb
+5
-11
No files found.
app/graphql/resolvers/issues_resolver.rb
View file @
680decd0
...
...
@@ -10,7 +10,7 @@ module Resolvers
argument
:sort
,
Types
::
IssueSortEnum
,
description:
'Sort issues by this criteria'
,
required:
false
,
default_value:
'created_desc'
default_value:
:created_desc
type
Types
::
IssueType
.
connection_type
,
null:
true
...
...
app/graphql/resolvers/merge_requests_resolver.rb
View file @
680decd0
...
...
@@ -52,7 +52,7 @@ module Resolvers
argument
:sort
,
Types
::
MergeRequestSortEnum
,
description:
'Sort merge requests by this criteria'
,
required:
false
,
default_value:
'created_desc'
default_value:
:created_desc
def
self
.
single
::
Resolvers
::
MergeRequestResolver
...
...
app/graphql/resolvers/users_resolver.rb
View file @
680decd0
...
...
@@ -17,7 +17,7 @@ module Resolvers
argument
:sort
,
Types
::
SortEnum
,
description:
'Sort users by this criteria'
,
required:
false
,
default_value:
'created_desc'
default_value:
:created_desc
argument
:search
,
GraphQL
::
STRING_TYPE
,
required:
false
,
...
...
app/graphql/types/sort_enum.rb
View file @
680decd0
...
...
@@ -7,10 +7,10 @@ module Types
# Deprecated, as we prefer uppercase enums
# https://gitlab.com/groups/gitlab-org/-/epics/1838
value
'updated_desc'
,
'Updated at descending order'
,
deprecated:
{
reason:
'Use UPDATED_DESC'
,
milestone:
'13.5'
}
value
'updated_asc'
,
'Updated at ascending order'
,
deprecated:
{
reason:
'Use UPDATED_ASC'
,
milestone:
'13.5'
}
value
'created_desc'
,
'Created at descending order'
,
deprecated:
{
reason:
'Use CREATED_DESC'
,
milestone:
'13.5'
}
value
'created_asc'
,
'Created at ascending order'
,
deprecated:
{
reason:
'Use CREATED_ASC'
,
milestone:
'13.5'
}
value
'updated_desc'
,
'Updated at descending order'
,
value: :updated_desc
,
deprecated:
{
reason:
'Use UPDATED_DESC'
,
milestone:
'13.5'
}
value
'updated_asc'
,
'Updated at ascending order'
,
value: :updated_asc
,
deprecated:
{
reason:
'Use UPDATED_ASC'
,
milestone:
'13.5'
}
value
'created_desc'
,
'Created at descending order'
,
value: :created_desc
,
deprecated:
{
reason:
'Use CREATED_DESC'
,
milestone:
'13.5'
}
value
'created_asc'
,
'Created at ascending order'
,
value: :created_asc
,
deprecated:
{
reason:
'Use CREATED_ASC'
,
milestone:
'13.5'
}
value
'UPDATED_DESC'
,
'Updated at descending order'
,
value: :updated_desc
value
'UPDATED_ASC'
,
'Updated at ascending order'
,
value: :updated_asc
...
...
changelogs/unreleased/improve-feature-flag-logging.yml
0 → 100644
View file @
680decd0
---
title
:
Improve logging on feature flag modification
merge_request
:
48417
author
:
type
:
other
doc/administration/logs.md
View file @
680decd0
...
...
@@ -665,6 +665,31 @@ installations from source.
It logs the progress of the export process.
## `features_json.log`
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/59587) in GitLab 13.7.
This file's location depends on how you installed GitLab:
-
For Omnibus GitLab packages:
`/var/log/gitlab/gitlab-rails/features_json.log`
-
For installations from source:
`/home/git/gitlab/log/features_json.log`
The modification events from
[
Feature flags in development of GitLab
](
../development/feature_flags/index.md
)
are recorded in this file. For example:
```
json
{
"severity"
:
"INFO"
,
"time"
:
"2020-11-24T02:30:59.860Z"
,
"correlation_id"
:
null
,
"key"
:
"cd_auto_rollback"
,
"action"
:
"enable"
,
"extra.thing"
:
"true"
}
{
"severity"
:
"INFO"
,
"time"
:
"2020-11-24T02:31:29.108Z"
,
"correlation_id"
:
null
,
"key"
:
"cd_auto_rollback"
,
"action"
:
"enable"
,
"extra.thing"
:
"true"
}
{
"severity"
:
"INFO"
,
"time"
:
"2020-11-24T02:31:29.129Z"
,
"correlation_id"
:
null
,
"key"
:
"cd_auto_rollback"
,
"action"
:
"disable"
,
"extra.thing"
:
"false"
}
{
"severity"
:
"INFO"
,
"time"
:
"2020-11-24T02:31:29.177Z"
,
"correlation_id"
:
null
,
"key"
:
"cd_auto_rollback"
,
"action"
:
"enable"
,
"extra.thing"
:
"Project:1"
}
{
"severity"
:
"INFO"
,
"time"
:
"2020-11-24T02:31:29.183Z"
,
"correlation_id"
:
null
,
"key"
:
"cd_auto_rollback"
,
"action"
:
"disable"
,
"extra.thing"
:
"Project:1"
}
{
"severity"
:
"INFO"
,
"time"
:
"2020-11-24T02:31:29.188Z"
,
"correlation_id"
:
null
,
"key"
:
"cd_auto_rollback"
,
"action"
:
"enable_percentage_of_time"
,
"extra.percentage"
:
"50"
}
{
"severity"
:
"INFO"
,
"time"
:
"2020-11-24T02:31:29.193Z"
,
"correlation_id"
:
null
,
"key"
:
"cd_auto_rollback"
,
"action"
:
"disable_percentage_of_time"
}
{
"severity"
:
"INFO"
,
"time"
:
"2020-11-24T02:31:29.198Z"
,
"correlation_id"
:
null
,
"key"
:
"cd_auto_rollback"
,
"action"
:
"enable_percentage_of_actors"
,
"extra.percentage"
:
"50"
}
{
"severity"
:
"INFO"
,
"time"
:
"2020-11-24T02:31:29.203Z"
,
"correlation_id"
:
null
,
"key"
:
"cd_auto_rollback"
,
"action"
:
"disable_percentage_of_actors"
}
{
"severity"
:
"INFO"
,
"time"
:
"2020-11-24T02:31:29.329Z"
,
"correlation_id"
:
null
,
"key"
:
"cd_auto_rollback"
,
"action"
:
"remove"
}
```
## `auth.log`
> Introduced in GitLab 12.0.
...
...
doc/development/feature_flags/controls.md
View file @
680decd0
...
...
@@ -228,8 +228,10 @@ existing gates (e.g. `--group=gitlab-org`) in the above processes.
### Feature flag change logging
Any feature flag change that affects GitLab.com (production) will
automatically be logged in an issue.
#### Chatops level
Any feature flag change that affects GitLab.com (production) via
[
Chatops
](
https://gitlab.com/gitlab-com/chatops
)
is automatically logged in an issue.
The issue is created in the
[
gl-infra/feature-flag-log
](
https://gitlab.com/gitlab-com/gl-infra/feature-flag-log/-/issues?scope=all&utf8=%E2%9C%93&state=closed
)
...
...
@@ -243,6 +245,12 @@ marker to make the change even more visible.
Changes to the issue format can be submitted in the
[
Chatops project
](
https://gitlab.com/gitlab-com/chatops
)
.
#### Instance level
Any feature flag change that affects any GitLab instance is automatically logged in
[
features_json.log
](
../../administration/logs.md#features_jsonlog
)
.
You can search the change history in
[
Kibana
](
https://about.gitlab.com/handbook/support/workflows/kibana.html
)
.
## Cleaning up
A feature flag should be removed as soon as it is no longer needed. Each additional
...
...
doc/development/graphql_guide/pagination.md
View file @
680decd0
...
...
@@ -294,28 +294,30 @@ The shared example requires certain `let` variables and methods to be set up:
```
ruby
describe
'sorting and pagination'
do
let
(
:sort_project
)
{
create
(
:project
,
:public
)
}
let
_it_be
(
:sort_project
)
{
create
(
:project
,
:public
)
}
let
(
:data_path
)
{
[
:project
,
:issues
]
}
def
pagination_query
(
params
,
page_info
)
graphql_query_for
(
'project'
,
{
'fullPath'
=>
sort_project
.
full_path
},
query_graphql_field
(
'issues'
,
params
,
"
#{
page_info
}
edges { node { id } }"
)
def
pagination_query
(
params
)
graphql_query_for
(
:project
,
{
full_path:
sort_project
.
full_path
},
query_nodes
(
:issues
,
:id
,
include_pagination_info:
true
,
args:
params
))
)
end
def
pagination_results_data
(
data
)
data
.
map
{
|
issue
|
issue
.
dig
(
'node'
,
'iid'
)
.
to_i
}
def
pagination_results_data
(
nodes
)
nodes
.
map
{
|
issue
|
issue
[
'iid'
]
.
to_i
}
end
context
'when sorting by weight'
do
...
let_it_be
(
:issues
)
{
make_some_issues_with_weights
}
context
'when ascending'
do
let
(
:ordered_issues
)
{
issues
.
sort_by
(
&
:weight
)
}
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'WEIGHT_ASC'
}
let
(
:sort_param
)
{
:WEIGHT_ASC
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
[
weight_issue3
.
iid
,
weight_issue5
.
iid
,
weight_issue1
.
iid
,
weight_issue4
.
iid
,
weight_issue2
.
iid
]
}
let
(
:expected_results
)
{
ordered_issues
.
map
(
&
:iid
)
}
end
end
end
```
doc/user/permissions.md
View file @
680decd0
...
...
@@ -245,8 +245,8 @@ group.
| Browse group | ✓ | ✓ | ✓ | ✓ | ✓ |
| View group wiki pages
**(PREMIUM)**
| ✓ (6) | ✓ | ✓ | ✓ | ✓ |
| View Insights charts
**(ULTIMATE)**
| ✓ | ✓ | ✓ | ✓ | ✓ |
| View group epic
**(
ULTIMATE
)**
| ✓ | ✓ | ✓ | ✓ | ✓ |
| Create/edit group epic
**(
ULTIMATE
)**
| | ✓ | ✓ | ✓ | ✓ |
| View group epic
**(
PREMIUM
)**
| ✓ | ✓ | ✓ | ✓ | ✓ |
| Create/edit group epic
**(
PREMIUM
)**
| | ✓ | ✓ | ✓ | ✓ |
| Manage group labels | | ✓ | ✓ | ✓ | ✓ |
| See a container registry | | ✓ | ✓ | ✓ | ✓ |
| Pull
[
packages
](
packages/index.md
)
| | ✓ | ✓ | ✓ | ✓ |
...
...
@@ -270,7 +270,7 @@ group.
| Create/Delete group deploy tokens | | | | | ✓ |
| Manage group members | | | | | ✓ |
| Delete group | | | | | ✓ |
| Delete group epic
**(
ULTIMATE
)**
| | | | | ✓ |
| Delete group epic
**(
PREMIUM
)**
| | | | | ✓ |
| Edit SAML SSO Billing
**(SILVER ONLY)**
| ✓ | ✓ | ✓ | ✓ | ✓ (4) |
| View group Audit Events | | | | | ✓ |
| Disable notification emails | | | | | ✓ |
...
...
ee/app/finders/requirements_management/requirements_finder.rb
View file @
680decd0
...
...
@@ -79,7 +79,7 @@ module RequirementsManagement
def
sort
(
items
)
sorts
=
RequirementsManagement
::
Requirement
.
simple_sorts
.
keys
sort
=
sorts
.
include?
(
params
[
:sort
])
?
params
[
:sort
]
:
'id_desc'
sort
=
sorts
.
include?
(
params
[
:sort
]
&
.
to_s
)
?
params
[
:sort
]
:
'id_desc'
items
.
order_by
(
sort
)
end
...
...
ee/spec/lib/ee/feature_spec.rb
View file @
680decd0
...
...
@@ -44,44 +44,4 @@ RSpec.describe Feature, stub_feature_flags: false do
end
end
end
describe
'.enable_group'
do
context
'when running on a Geo primary node'
do
before
do
stub_primary_node
end
it
'does not create a Geo::CacheInvalidationEvent if there are no Geo secondary nodes'
do
allow
(
Gitlab
::
Geo
).
to
receive
(
:secondary_nodes
)
{
[]
}
expect
{
described_class
.
enable_group
(
:foo
,
:bar
)
}.
not_to
change
(
Geo
::
CacheInvalidationEvent
,
:count
)
end
it
'creates a Geo::CacheInvalidationEvent'
do
allow
(
Gitlab
::
Geo
).
to
receive
(
:secondary_nodes
)
{
[
double
]
}
expect
{
described_class
.
enable_group
(
:foo
,
:bar
)
}.
to
change
(
Geo
::
CacheInvalidationEvent
,
:count
).
by
(
1
)
end
end
end
describe
'.disable_group'
do
context
'when running on a Geo primary node'
do
before
do
stub_primary_node
end
it
'does not create a Geo::CacheInvalidationEvent if there are no Geo secondary nodes'
do
allow
(
Gitlab
::
Geo
).
to
receive
(
:secondary_nodes
)
{
[]
}
expect
{
described_class
.
disable_group
(
:foo
,
:bar
)
}.
not_to
change
(
Geo
::
CacheInvalidationEvent
,
:count
)
end
it
'creates a Geo::CacheInvalidationEvent'
do
allow
(
Gitlab
::
Geo
).
to
receive
(
:secondary_nodes
)
{
[
double
]
}
expect
{
described_class
.
disable_group
(
:foo
,
:bar
)
}.
to
change
(
Geo
::
CacheInvalidationEvent
,
:count
).
by
(
1
)
end
end
end
end
ee/spec/requests/api/graphql/boards/board_lists_query_spec.rb
View file @
680decd0
...
...
@@ -64,28 +64,22 @@ RSpec.describe 'get board lists' do
end
describe
'sorting and pagination'
do
let
(
:data_path
)
{
[
board_parent_type
,
:boards
,
:
edges
,
0
,
:node
,
:lists
]
}
let
(
:data_path
)
{
[
board_parent_type
,
:boards
,
:
nodes
,
0
,
:lists
]
}
def
pagination_query
(
params
,
page_info
)
def
pagination_query
(
params
)
graphql_query_for
(
board_parent_type
,
{
'fullPath'
=>
board_parent
.
full_path
},
<<~
BOARDS
boards(first: 1) {
edges {
node {
#{
query_graphql_field
(
'lists'
,
params
,
"
#{
page_info
}
edges { node { id } }"
)
}
}
nodes {
#{
query_nodes
(
:lists
,
:id
,
args:
params
,
include_pagination_info:
true
)
}
}
}
BOARDS
)
end
def
pagination_results_data
(
data
)
data
.
map
{
|
list
|
list
.
dig
(
'node'
,
'id'
)
}
end
context
'when using default sorting'
do
let!
(
:milestone_list
)
{
create
(
:milestone_list
,
board:
board
,
milestone:
milestone
,
position:
10
)
}
let!
(
:milestone_list2
)
{
create
(
:milestone_list
,
board:
board
,
milestone:
milestone2
,
position:
2
)
}
...
...
@@ -98,7 +92,7 @@ RSpec.describe 'get board lists' do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
lists
.
map
{
|
list
|
list
.
to_global_id
.
to_s
}
}
let
(
:expected_results
)
{
lists
.
map
{
|
list
|
global_id_of
(
list
)
}
}
end
end
end
...
...
ee/spec/requests/api/graphql/group_query_spec.rb
View file @
680decd0
...
...
@@ -359,35 +359,33 @@ RSpec.describe 'getting group information' do
let
(
:data_path
)
{
[
:group
,
:codeCoverageActivities
]
}
def
pagination_query
(
params
,
page_info
)
def
pagination_query
(
params
)
graphql_query_for
(
'group'
,
{
'fullPath'
=>
group
.
full_path
},
:group
,
{
full_path:
group
.
full_path
},
<<~
QUERY
codeCoverageActivities(startDate: "
#{
start_date
}
"
#{
params
}
) {
#{
page_info
}
edges {
node {
averageCoverage
}
}
#{
page_info
}
nodes { averageCoverage }
}
QUERY
)
end
def
pagination_results_data
(
data
)
data
.
map
{
|
coverage
|
coverage
.
dig
(
'node'
,
'averageCoverage'
)
}
end
context
'when default sorting'
do
let!
(
:coverage_1
)
{
create
(
:ci_daily_build_group_report_result
,
project:
project_1
)
}
let!
(
:coverage_2
)
{
create
(
:ci_daily_build_group_report_result
,
project:
project_2
,
coverage:
88.8
,
date:
1
.
week
.
ago
)
}
let
(
:start_date
)
{
1
.
week
.
ago
.
to_date
.
to_s
}
let_it_be
(
:cov_1
)
{
create
(
:ci_daily_build_group_report_result
,
project:
project_1
,
coverage:
77.0
)
}
let_it_be
(
:cov_2
)
{
create
(
:ci_daily_build_group_report_result
,
project:
project_2
,
coverage:
88.8
,
date:
1
.
week
.
ago
)
}
let_it_be
(
:cov_3
)
{
create
(
:ci_daily_build_group_report_result
,
project:
project_1
,
coverage:
66.6
,
date:
2
.
weeks
.
ago
)
}
let_it_be
(
:cov_4
)
{
create
(
:ci_daily_build_group_report_result
,
project:
project_2
,
coverage:
99.9
,
date:
3
.
weeks
.
ago
)
}
let_it_be
(
:cov_5
)
{
create
(
:ci_daily_build_group_report_result
,
project:
project_1
,
coverage:
44.4
,
date:
4
.
weeks
.
ago
)
}
let_it_be
(
:cov_6
)
{
create
(
:ci_daily_build_group_report_result
,
project:
project_1
,
coverage:
100.0
,
date:
6
.
weeks
.
ago
)
}
let
(
:start_date
)
{
5
.
weeks
.
ago
.
to_date
.
to_s
}
it_behaves_like
'sorted paginated query'
do
let
(
:node_path
)
{
[
'averageCoverage'
]
}
let
(
:sort_param
)
{
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
[
88.8
,
77.0
]
}
let
(
:expected_results
)
{
[
cov_1
,
cov_2
,
cov_3
,
cov_4
,
cov_5
].
reverse
.
map
(
&
:coverage
)
}
end
end
end
...
...
ee/spec/requests/api/graphql/namespace/projects_spec.rb
0 → 100644
View file @
680decd0
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
'Namespace.projects'
do
include
GraphqlHelpers
describe
'sorting and pagination'
do
let_it_be
(
:ns
)
{
create
(
:group
)
}
let_it_be
(
:current_user
)
{
create
(
:user
)
}
let!
(
:project_1
)
{
create
(
:project
,
namespace:
ns
,
name:
'Project'
,
path:
'project'
)
}
let!
(
:project_2
)
{
create
(
:project
,
namespace:
ns
,
name:
'Test Project'
,
path:
'test-project'
)
}
let!
(
:project_3
)
{
create
(
:project
,
namespace:
ns
,
name:
'Test'
,
path:
'test'
)
}
let!
(
:project_4
)
{
create
(
:project
,
namespace:
ns
,
name:
'Test Project Other'
,
path:
'other-test-project'
)
}
let
(
:data_path
)
{
[
:namespace
,
:projects
]
}
let
(
:ns_args
)
{
graphql_args
(
full_path:
ns
.
full_path
)
}
let
(
:project_args
)
{
graphql_args
(
include_subgroups:
true
,
search:
'test'
)
}
before
do
ns
.
add_owner
(
current_user
)
end
def
pagination_query
(
params
)
graphql_query_for
(
:namespace
,
ns_args
,
query_nodes
(
:projects
,
:name
,
include_pagination_info:
true
,
args:
params
+
project_args
))
end
context
'when sorting by STORAGE'
do
before
do
project_4
.
statistics
.
update!
(
lfs_objects_size:
1
,
repository_size:
4
.
gigabytes
)
project_2
.
statistics
.
update!
(
lfs_objects_size:
1
,
repository_size:
2
.
gigabytes
)
project_3
.
statistics
.
update!
(
lfs_objects_size:
2
,
repository_size:
1
.
gigabytes
)
end
it_behaves_like
'sorted paginated query'
do
let
(
:node_path
)
{
%w[name]
}
let
(
:sort_param
)
{
:STORAGE
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
[
project_4
,
project_2
,
project_3
].
map
(
&
:name
)
}
end
end
end
end
ee/spec/requests/api/graphql/project/issues_spec.rb
View file @
680decd0
...
...
@@ -11,18 +11,12 @@ RSpec.describe 'getting an issue list for a project' do
let
(
:sort_project
)
{
create
(
:project
,
:public
)
}
let
(
:data_path
)
{
[
:project
,
:issues
]
}
def
pagination_query
(
params
,
page_info
)
graphql_query_for
(
'project'
,
{
'fullPath'
=>
sort_project
.
full_path
},
query_graphql_field
(
'issues'
,
params
,
"
#{
page_info
}
edges { node { iid weight} }"
)
def
pagination_query
(
params
)
graphql_query_for
(
:project
,
{
full_path:
sort_project
.
full_path
},
query_nodes
(
:issues
,
:iid
,
args:
params
,
include_pagination_info:
true
)
)
end
def
pagination_results_data
(
data
)
data
.
map
{
|
issue
|
issue
.
dig
(
'node'
,
'iid'
).
to_i
}
end
context
'when sorting by weight'
do
let!
(
:weight_issue1
)
{
create
(
:issue
,
project:
sort_project
,
weight:
5
)
}
let!
(
:weight_issue2
)
{
create
(
:issue
,
project:
sort_project
,
weight:
nil
)
}
...
...
@@ -32,17 +26,19 @@ RSpec.describe 'getting an issue list for a project' do
context
'when ascending'
do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'WEIGHT_ASC'
}
let
(
:node_path
)
{
%w[iid]
}
let
(
:sort_param
)
{
:WEIGHT_ASC
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
[
weight_issue3
.
iid
,
weight_issue5
.
iid
,
weight_issue1
.
iid
,
weight_issue4
.
iid
,
weight_issue2
.
iid
]
}
let
(
:expected_results
)
{
[
weight_issue3
,
weight_issue5
,
weight_issue1
,
weight_issue4
,
weight_issue2
].
map
{
|
i
|
i
.
iid
.
to_s
}
}
end
end
context
'when descending'
do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'WEIGHT_DESC'
}
let
(
:node_path
)
{
%w[iid]
}
let
(
:sort_param
)
{
:WEIGHT_DESC
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
[
weight_issue1
.
iid
,
weight_issue5
.
iid
,
weight_issue3
.
iid
,
weight_issue4
.
iid
,
weight_issue2
.
iid
]
}
let
(
:expected_results
)
{
[
weight_issue1
,
weight_issue5
,
weight_issue3
,
weight_issue4
,
weight_issue2
].
map
{
|
i
|
i
.
iid
.
to_s
}
}
end
end
end
...
...
ee/spec/requests/api/graphql/project/requirements_management/requirements_spec.rb
View file @
680decd0
...
...
@@ -161,16 +161,12 @@ RSpec.describe 'getting a requirement list for a project' do
describe
'sorting and pagination'
do
let_it_be
(
:data_path
)
{
[
:project
,
:requirements
]
}
def
pagination_query
(
params
,
page_info
)
graphql_query_for
(
'project'
,
{
'fullPath'
=>
sort_project
.
full_path
},
query_graphql_field
(
'requirements'
,
params
,
"
#{
page_info
}
edges { node { iid createdAt} }"
)
)
def
pagination_query
(
params
)
nested_internal_id_query
(
:project
,
sort_project
,
:requirements
,
params
)
end
def
pagination_results_data
(
data
)
data
.
map
{
|
issue
|
issue
.
dig
(
'
node'
,
'
iid'
).
to_i
}
data
.
map
{
|
issue
|
issue
.
dig
(
'iid'
).
to_i
}
end
context
'when sorting by created_at'
do
...
...
@@ -183,7 +179,7 @@ RSpec.describe 'getting a requirement list for a project' do
context
'when ascending'
do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'created_asc'
}
let
(
:sort_param
)
{
:CREATED_ASC
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
[
requirement4
.
iid
,
requirement3
.
iid
,
requirement5
.
iid
,
requirement1
.
iid
,
requirement2
.
iid
]
}
end
...
...
@@ -191,7 +187,7 @@ RSpec.describe 'getting a requirement list for a project' do
context
'when descending'
do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'created_desc'
}
let
(
:sort_param
)
{
:CREATED_DESC
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
[
requirement2
.
iid
,
requirement1
.
iid
,
requirement5
.
iid
,
requirement3
.
iid
,
requirement4
.
iid
]
}
end
...
...
ee/spec/requests/api/graphql/project/requirements_management/test_reports_spec.rb
View file @
680decd0
...
...
@@ -63,27 +63,29 @@ RSpec.describe 'getting test reports of a requirement' do
let_it_be
(
:data_path
)
{
[
:project
,
:requirement
,
:testReports
]
}
let_it_be
(
:test_report_3
)
{
create
(
:test_report
,
requirement:
requirement
,
created_at:
4
.
days
.
ago
)
}
def
pagination_query
(
params
,
page_info
)
graphql_query_for
(
'project'
,
{
'fullPath'
=>
project
.
full_path
},
"requirement { testReports(
#{
params
}
) {
#{
page_info
}
edges { node { id } } } }"
def
pagination_query
(
params
)
graphql_query_for
(
:project
,
{
full_path:
project
.
full_path
},
"requirement { testReports(
#{
params
}
) {
#{
page_info
}
nodes { id } } }"
)
end
def
pagination_results_data
(
data
)
data
.
map
{
|
test_report
|
test_report
.
dig
(
'node'
,
'id'
)
}
let
(
:in_creation_order
)
do
[
test_report_3
,
test_report_2
,
test_report_1
]
end
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
:CREATED_ASC
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
do
in_creation_order
.
map
{
|
r
|
global_id_of
(
r
)
}
end
end
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'created_asc'
}
let
(
:sort_param
)
{
:CREATED_DESC
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
do
[
test_report_3
.
to_global_id
.
to_s
,
test_report_2
.
to_global_id
.
to_s
,
test_report_1
.
to_global_id
.
to_s
]
in_creation_order
.
reverse
.
map
{
|
r
|
global_id_of
(
r
)
}
end
end
end
...
...
lib/feature.rb
View file @
680decd0
...
...
@@ -87,40 +87,39 @@ class Feature
end
def
enable
(
key
,
thing
=
true
)
log
(
key:
key
,
action:
__method__
,
thing:
thing
)
get
(
key
).
enable
(
thing
)
end
def
disable
(
key
,
thing
=
false
)
log
(
key:
key
,
action:
__method__
,
thing:
thing
)
get
(
key
).
disable
(
thing
)
end
def
enable_group
(
key
,
group
)
get
(
key
).
enable_group
(
group
)
end
def
disable_group
(
key
,
group
)
get
(
key
).
disable_group
(
group
)
end
def
enable_percentage_of_time
(
key
,
percentage
)
log
(
key:
key
,
action:
__method__
,
percentage:
percentage
)
get
(
key
).
enable_percentage_of_time
(
percentage
)
end
def
disable_percentage_of_time
(
key
)
log
(
key:
key
,
action:
__method__
)
get
(
key
).
disable_percentage_of_time
end
def
enable_percentage_of_actors
(
key
,
percentage
)
log
(
key:
key
,
action:
__method__
,
percentage:
percentage
)
get
(
key
).
enable_percentage_of_actors
(
percentage
)
end
def
disable_percentage_of_actors
(
key
)
log
(
key:
key
,
action:
__method__
)
get
(
key
).
disable_percentage_of_actors
end
def
remove
(
key
)
return
unless
persisted_name?
(
key
)
log
(
key:
key
,
action:
__method__
)
get
(
key
).
remove
end
...
...
@@ -145,6 +144,10 @@ class Feature
Feature
::
Definition
.
register_hot_reloader!
end
def
logger
@logger
||=
Feature
::
Logger
.
build
end
private
def
flipper
...
...
@@ -192,6 +195,14 @@ class Feature
def
l2_cache_backend
Rails
.
cache
end
def
log
(
key
:,
action
:,
**
extra
)
extra
||=
{}
extra
=
extra
.
transform_keys
{
|
k
|
"extra.
#{
k
}
"
}
extra
=
extra
.
transform_values
{
|
v
|
v
.
respond_to?
(
:flipper_id
)
?
v
.
flipper_id
:
v
}
extra
=
extra
.
transform_values
(
&
:to_s
)
logger
.
info
(
key:
key
,
action:
action
,
**
extra
)
end
end
class
Target
...
...
lib/feature/logger.rb
0 → 100644
View file @
680decd0
# frozen_string_literal: true
class
Feature
class
Logger
<
::
Gitlab
::
JsonLogger
def
self
.
file_name_noext
'features_json'
end
end
end
spec/lib/feature_spec.rb
View file @
680decd0
...
...
@@ -300,7 +300,119 @@ RSpec.describe Feature, stub_feature_flags: false do
end
end
shared_examples_for
'logging'
do
let
(
:expected_action
)
{
}
let
(
:expected_extra
)
{
}
it
'logs the event'
do
expect
(
Feature
.
logger
).
to
receive
(
:info
).
with
(
key:
key
,
action:
expected_action
,
**
expected_extra
)
subject
end
end
describe
'.enable'
do
subject
{
described_class
.
enable
(
key
,
thing
)
}
let
(
:key
)
{
:awesome_feature
}
let
(
:thing
)
{
true
}
it_behaves_like
'logging'
do
let
(
:expected_action
)
{
:enable
}
let
(
:expected_extra
)
{
{
"extra.thing"
=>
"true"
}
}
end
context
'when thing is an actor'
do
let
(
:thing
)
{
create
(
:project
)
}
it_behaves_like
'logging'
do
let
(
:expected_action
)
{
:enable
}
let
(
:expected_extra
)
{
{
"extra.thing"
=>
"
#{
thing
.
flipper_id
}
"
}
}
end
end
end
describe
'.disable'
do
subject
{
described_class
.
disable
(
key
,
thing
)
}
let
(
:key
)
{
:awesome_feature
}
let
(
:thing
)
{
false
}
it_behaves_like
'logging'
do
let
(
:expected_action
)
{
:disable
}
let
(
:expected_extra
)
{
{
"extra.thing"
=>
"false"
}
}
end
context
'when thing is an actor'
do
let
(
:thing
)
{
create
(
:project
)
}
it_behaves_like
'logging'
do
let
(
:expected_action
)
{
:disable
}
let
(
:expected_extra
)
{
{
"extra.thing"
=>
"
#{
thing
.
flipper_id
}
"
}
}
end
end
end
describe
'.enable_percentage_of_time'
do
subject
{
described_class
.
enable_percentage_of_time
(
key
,
percentage
)
}
let
(
:key
)
{
:awesome_feature
}
let
(
:percentage
)
{
50
}
it_behaves_like
'logging'
do
let
(
:expected_action
)
{
:enable_percentage_of_time
}
let
(
:expected_extra
)
{
{
"extra.percentage"
=>
"
#{
percentage
}
"
}
}
end
end
describe
'.disable_percentage_of_time'
do
subject
{
described_class
.
disable_percentage_of_time
(
key
)
}
let
(
:key
)
{
:awesome_feature
}
it_behaves_like
'logging'
do
let
(
:expected_action
)
{
:disable_percentage_of_time
}
let
(
:expected_extra
)
{
{}
}
end
end
describe
'.enable_percentage_of_actors'
do
subject
{
described_class
.
enable_percentage_of_actors
(
key
,
percentage
)
}
let
(
:key
)
{
:awesome_feature
}
let
(
:percentage
)
{
50
}
it_behaves_like
'logging'
do
let
(
:expected_action
)
{
:enable_percentage_of_actors
}
let
(
:expected_extra
)
{
{
"extra.percentage"
=>
"
#{
percentage
}
"
}
}
end
end
describe
'.disable_percentage_of_actors'
do
subject
{
described_class
.
disable_percentage_of_actors
(
key
)
}
let
(
:key
)
{
:awesome_feature
}
it_behaves_like
'logging'
do
let
(
:expected_action
)
{
:disable_percentage_of_actors
}
let
(
:expected_extra
)
{
{}
}
end
end
describe
'.remove'
do
subject
{
described_class
.
remove
(
key
)
}
let
(
:key
)
{
:awesome_feature
}
before
do
described_class
.
enable
(
key
)
end
it_behaves_like
'logging'
do
let
(
:expected_action
)
{
:remove
}
let
(
:expected_extra
)
{
{}
}
end
context
'for a non-persisted feature'
do
it
'returns nil'
do
expect
(
described_class
.
remove
(
:non_persisted_feature_flag
)).
to
be_nil
...
...
spec/requests/api/graphql/boards/board_lists_query_spec.rb
View file @
680decd0
...
...
@@ -66,28 +66,22 @@ RSpec.describe 'get board lists' do
describe
'sorting and pagination'
do
let_it_be
(
:current_user
)
{
user
}
let
(
:data_path
)
{
[
board_parent_type
,
:boards
,
:
edges
,
0
,
:node
,
:lists
]
}
let
(
:data_path
)
{
[
board_parent_type
,
:boards
,
:
nodes
,
0
,
:lists
]
}
def
pagination_query
(
params
,
page_info
)
def
pagination_query
(
params
)
graphql_query_for
(
board_parent_type
,
{
'fullPath'
=>
board_parent
.
full_path
},
<<~
BOARDS
boards(first: 1) {
edges {
node {
#{
query_graphql_field
(
'lists'
,
params
,
"
#{
page_info
}
edges { node { id } }"
)
}
}
nodes {
#{
query_graphql_field
(
:lists
,
params
,
"
#{
page_info
}
nodes { id }"
)
}
}
}
BOARDS
)
end
def
pagination_results_data
(
data
)
data
.
map
{
|
list
|
list
.
dig
(
'node'
,
'id'
)
}
end
context
'when using default sorting'
do
let!
(
:label_list
)
{
create
(
:list
,
board:
board
,
label:
label
,
position:
10
)
}
let!
(
:label_list2
)
{
create
(
:list
,
board:
board
,
label:
label2
,
position:
2
)
}
...
...
@@ -99,7 +93,7 @@ RSpec.describe 'get board lists' do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
lists
.
map
{
|
list
|
list
.
to_global_id
.
to_s
}
}
let
(
:expected_results
)
{
lists
.
map
{
|
list
|
global_id_of
(
list
)
}
}
end
end
end
...
...
spec/requests/api/graphql/namespace/projects_spec.rb
View file @
680decd0
...
...
@@ -80,38 +80,34 @@ RSpec.describe 'getting projects' do
end
describe
'sorting and pagination'
do
let_it_be
(
:ns
)
{
create
(
:group
)
}
let_it_be
(
:current_user
)
{
create
(
:user
)
}
let_it_be
(
:project_1
)
{
create
(
:project
,
name:
'Project'
,
path:
'project'
,
namespace:
ns
)
}
let_it_be
(
:project_2
)
{
create
(
:project
,
name:
'Test Project'
,
path:
'test-project'
,
namespace:
ns
)
}
let_it_be
(
:project_3
)
{
create
(
:project
,
name:
'Test'
,
path:
'test'
,
namespace:
ns
)
}
let_it_be
(
:project_4
)
{
create
(
:project
,
name:
'Test Project Other'
,
path:
'other-test-project'
,
namespace:
ns
)
}
let
(
:data_path
)
{
[
:namespace
,
:projects
]
}
def
pagination_query
(
params
,
page_info
)
graphql_query_for
(
'namespace'
,
{
'fullPath'
=>
subject
.
full_path
},
<<~
QUERY
projects(includeSubgroups:
#{
include_subgroups
}
, search: "
#{
search
}
",
#{
params
}
) {
#{
page_info
}
edges {
node {
#{
all_graphql_fields_for
(
'Project'
)
}
}
}
}
QUERY
)
let
(
:ns_args
)
{
{
full_path:
ns
.
full_path
}
}
let
(
:search
)
{
'test'
}
before
do
ns
.
add_owner
(
current_user
)
end
def
pagination_results_data
(
data
)
data
.
map
{
|
project
|
project
.
dig
(
'node'
,
'name'
)
}
def
pagination_query
(
params
)
arguments
=
params
.
merge
(
include_subgroups:
include_subgroups
,
search:
search
)
graphql_query_for
(
:namespace
,
ns_args
,
query_graphql_field
(
:projects
,
arguments
,
<<~
GQL
))
#{
page_info
}
nodes { name }
GQL
end
context
'when sorting by similarity'
do
let!
(
:project_1
)
{
create
(
:project
,
name:
'Project'
,
path:
'project'
,
namespace:
subject
)
}
let!
(
:project_2
)
{
create
(
:project
,
name:
'Test Project'
,
path:
'test-project'
,
namespace:
subject
)
}
let!
(
:project_3
)
{
create
(
:project
,
name:
'Test'
,
path:
'test'
,
namespace:
subject
)
}
let!
(
:project_4
)
{
create
(
:project
,
name:
'Test Project Other'
,
path:
'other-test-project'
,
namespace:
subject
)
}
let
(
:search
)
{
'test'
}
let
(
:current_user
)
{
user
}
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'SIMILARITY'
}
let
(
:node_path
)
{
%w[name]
}
let
(
:sort_param
)
{
:SIMILARITY
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
[
project_3
.
name
,
project_2
.
name
,
project_4
.
name
]
}
end
...
...
spec/requests/api/graphql/project/issues_spec.rb
View file @
680decd0
...
...
@@ -142,16 +142,14 @@ RSpec.describe 'getting an issue list for a project' do
describe
'sorting and pagination'
do
let_it_be
(
:data_path
)
{
[
:project
,
:issues
]
}
def
pagination_query
(
params
,
page_info
)
graphql_query_for
(
'project'
,
{
'fullPath'
=>
sort_project
.
full_path
},
query_graphql_field
(
'issues'
,
params
,
"
#{
page_info
}
edges { node { iid dueDate} }"
)
def
pagination_query
(
params
)
graphql_query_for
(
:project
,
{
full_path:
sort_project
.
full_path
},
query_graphql_field
(
:issues
,
params
,
"
#{
page_info
}
nodes { iid }"
)
)
end
def
pagination_results_data
(
data
)
data
.
map
{
|
issue
|
issue
.
dig
(
'
node'
,
'
iid'
).
to_i
}
data
.
map
{
|
issue
|
issue
.
dig
(
'iid'
).
to_i
}
end
context
'when sorting by due date'
do
...
...
@@ -164,7 +162,7 @@ RSpec.describe 'getting an issue list for a project' do
context
'when ascending'
do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'DUE_DATE_ASC'
}
let
(
:sort_param
)
{
:DUE_DATE_ASC
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
[
due_issue3
.
iid
,
due_issue5
.
iid
,
due_issue1
.
iid
,
due_issue4
.
iid
,
due_issue2
.
iid
]
}
end
...
...
@@ -172,7 +170,7 @@ RSpec.describe 'getting an issue list for a project' do
context
'when descending'
do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'DUE_DATE_DESC'
}
let
(
:sort_param
)
{
:DUE_DATE_DESC
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
[
due_issue1
.
iid
,
due_issue5
.
iid
,
due_issue3
.
iid
,
due_issue4
.
iid
,
due_issue2
.
iid
]
}
end
...
...
@@ -189,7 +187,7 @@ RSpec.describe 'getting an issue list for a project' do
context
'when ascending'
do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'RELATIVE_POSITION_ASC'
}
let
(
:sort_param
)
{
:RELATIVE_POSITION_ASC
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
[
relative_issue5
.
iid
,
relative_issue3
.
iid
,
relative_issue1
.
iid
,
relative_issue4
.
iid
,
relative_issue2
.
iid
]
}
end
...
...
@@ -209,7 +207,7 @@ RSpec.describe 'getting an issue list for a project' do
context
'when ascending'
do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'PRIORITY_ASC'
}
let
(
:sort_param
)
{
:PRIORITY_ASC
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
[
priority_issue3
.
iid
,
priority_issue1
.
iid
,
priority_issue2
.
iid
,
priority_issue4
.
iid
]
}
end
...
...
@@ -217,7 +215,7 @@ RSpec.describe 'getting an issue list for a project' do
context
'when descending'
do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'PRIORITY_DESC'
}
let
(
:sort_param
)
{
:PRIORITY_DESC
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
[
priority_issue1
.
iid
,
priority_issue3
.
iid
,
priority_issue2
.
iid
,
priority_issue4
.
iid
]
}
end
...
...
@@ -236,7 +234,7 @@ RSpec.describe 'getting an issue list for a project' do
context
'when ascending'
do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'LABEL_PRIORITY_ASC'
}
let
(
:sort_param
)
{
:LABEL_PRIORITY_ASC
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
[
label_issue3
.
iid
,
label_issue1
.
iid
,
label_issue2
.
iid
,
label_issue4
.
iid
]
}
end
...
...
@@ -244,7 +242,7 @@ RSpec.describe 'getting an issue list for a project' do
context
'when descending'
do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'LABEL_PRIORITY_DESC'
}
let
(
:sort_param
)
{
:LABEL_PRIORITY_DESC
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
[
label_issue2
.
iid
,
label_issue3
.
iid
,
label_issue1
.
iid
,
label_issue4
.
iid
]
}
end
...
...
@@ -261,7 +259,7 @@ RSpec.describe 'getting an issue list for a project' do
context
'when ascending'
do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'MILESTONE_DUE_ASC'
}
let
(
:sort_param
)
{
:MILESTONE_DUE_ASC
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
[
milestone_issue2
.
iid
,
milestone_issue3
.
iid
,
milestone_issue1
.
iid
]
}
end
...
...
@@ -269,7 +267,7 @@ RSpec.describe 'getting an issue list for a project' do
context
'when descending'
do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'MILESTONE_DUE_DESC'
}
let
(
:sort_param
)
{
:MILESTONE_DUE_DESC
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
{
[
milestone_issue3
.
iid
,
milestone_issue2
.
iid
,
milestone_issue1
.
iid
]
}
end
...
...
spec/requests/api/graphql/project/merge_requests_spec.rb
View file @
680decd0
...
...
@@ -259,29 +259,19 @@ RSpec.describe 'getting merge request listings nested in a project' do
describe
'sorting and pagination'
do
let
(
:data_path
)
{
[
:project
,
:mergeRequests
]
}
def
pagination_query
(
params
,
page_info
)
graphql_query_for
(
:project
,
{
full_path:
project
.
full_path
},
def
pagination_query
(
params
)
graphql_query_for
(
:project
,
{
full_path:
project
.
full_path
},
<<~
QUERY
mergeRequests(
#{
params
}
) {
#{
page_info
}
edges {
node {
id
}
}
#{
page_info
}
nodes { id }
}
QUERY
)
end
def
pagination_results_data
(
data
)
data
.
map
{
|
project
|
project
.
dig
(
'node'
,
'id'
)
}
end
context
'when sorting by merged_at DESC'
do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'MERGED_AT_DESC'
}
let
(
:sort_param
)
{
:MERGED_AT_DESC
}
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
do
...
...
@@ -291,7 +281,7 @@ RSpec.describe 'getting merge request listings nested in a project' do
merge_request_c
,
merge_request_e
,
merge_request_a
].
map
(
&
:to_gid
).
map
(
&
:to_s
)
].
map
{
|
mr
|
global_id_of
(
mr
)
}
end
before
do
...
...
@@ -304,33 +294,6 @@ RSpec.describe 'getting merge request listings nested in a project' do
merge_request_b
.
metrics
.
update!
(
merged_at:
1
.
day
.
ago
)
end
context
'when paginating backwards'
do
let
(
:params
)
{
'first: 2, sort: MERGED_AT_DESC'
}
let
(
:page_info
)
{
'pageInfo { startCursor endCursor }'
}
before
do
post_graphql
(
pagination_query
(
params
,
page_info
),
current_user:
current_user
)
end
it
'paginates backwards correctly'
do
# first page
first_page_response_data
=
graphql_dig_at
(
Gitlab
::
Json
.
parse
(
response
.
body
),
:data
,
*
data_path
,
:edges
)
end_cursor
=
graphql_dig_at
(
Gitlab
::
Json
.
parse
(
response
.
body
),
:data
,
:project
,
:mergeRequests
,
:pageInfo
,
:endCursor
)
# second page
params
=
"first: 2, after:
\"
#{
end_cursor
}
\"
, sort: MERGED_AT_DESC"
post_graphql
(
pagination_query
(
params
,
page_info
),
current_user:
current_user
)
start_cursor
=
graphql_dig_at
(
Gitlab
::
Json
.
parse
(
response
.
body
),
:data
,
:project
,
:mergeRequests
,
:pageInfo
,
:start_cursor
)
# going back to the first page
params
=
"last: 2, before:
\"
#{
start_cursor
}
\"
, sort: MERGED_AT_DESC"
post_graphql
(
pagination_query
(
params
,
page_info
),
current_user:
current_user
)
backward_paginated_response_data
=
graphql_dig_at
(
Gitlab
::
Json
.
parse
(
response
.
body
),
:data
,
*
data_path
,
:edges
)
expect
(
first_page_response_data
).
to
eq
(
backward_paginated_response_data
)
end
end
end
end
end
...
...
spec/requests/api/graphql/users_spec.rb
View file @
680decd0
...
...
@@ -59,20 +59,16 @@ RSpec.describe 'Users' do
describe
'sorting and pagination'
do
let_it_be
(
:data_path
)
{
[
:users
]
}
def
pagination_query
(
params
,
page_info
)
graphql_query_for
(
"users"
,
params
,
"
#{
page_info
}
edges { node { id } }"
)
end
def
pagination_results_data
(
data
)
data
.
map
{
|
user
|
user
.
dig
(
'node'
,
'id'
)
}
def
pagination_query
(
params
)
graphql_query_for
(
:users
,
params
,
"
#{
page_info
}
nodes { id }"
)
end
context
'when sorting by created_at'
do
let_it_be
(
:ascending_users
)
{
[
user3
,
user2
,
user1
,
current_user
].
map
(
&
:to_global_id
).
map
(
&
:to_s
)
}
let_it_be
(
:ascending_users
)
{
[
user3
,
user2
,
user1
,
current_user
].
map
{
|
u
|
global_id_of
(
u
)
}
}
context
'when ascending'
do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'created_asc'
}
let
(
:sort_param
)
{
:CREATED_ASC
}
let
(
:first_param
)
{
1
}
let
(
:expected_results
)
{
ascending_users
}
end
...
...
@@ -80,7 +76,7 @@ RSpec.describe 'Users' do
context
'when descending'
do
it_behaves_like
'sorted paginated query'
do
let
(
:sort_param
)
{
'created_desc'
}
let
(
:sort_param
)
{
:CREATED_DESC
}
let
(
:first_param
)
{
1
}
let
(
:expected_results
)
{
ascending_users
.
reverse
}
end
...
...
spec/support/shared_examples/graphql/sorted_paginated_query_shared_examples.rb
View file @
680decd0
...
...
@@ -16,80 +16,111 @@
#
# Example:
# describe 'sorting and pagination' do
# let(:sort_project) { create(:project, :public) }
# let
_it_be
(:sort_project) { create(:project, :public) }
# let(:data_path) { [:project, :issues] }
#
# def pagination_query(params, page_info)
# graphql_query_for(
# 'project',
# { 'fullPath' => sort_project.full_path },
# query_graphql_field('issues', params, "#{page_info} edges { node { id } }")
# def pagination_query(arguments)
# graphql_query_for(:project, { full_path: sort_project.full_path },
# query_nodes(:issues, :iid, include_pagination_info: true, args: arguments)
# )
# end
#
# def pagination_results_data(data)
# data.map { |issue| issue.dig('node', 'iid').to_i }
# # A method transforming nodes to data to match against
# # default: the identity function
# def pagination_results_data(issues)
# issues.map { |issue| issue['iid].to_i }
# end
#
# context 'when sorting by weight' do
# ...
# let_it_be(:issues) { make_some_issues_with_weights }
#
# context 'when ascending' do
# let(:ordered_issues) { issues.sort_by(&:weight) }
#
# it_behaves_like 'sorted paginated query' do
# let(:sort_param) {
'WEIGHT_ASC'
}
# let(:sort_param) {
:WEIGHT_ASC
}
# let(:first_param) { 2 }
# let(:expected_results) {
[weight_issue3.iid, weight_issue5.iid, weight_issue1.iid, weight_issue4.iid, weight_issue2.iid]
}
# let(:expected_results) {
ordered_issues.map(&:iid)
}
# end
# end
#
RSpec
.
shared_examples
'sorted paginated query'
do
# Provided as a convenience when constructing queries using string concatenation
let
(
:page_info
)
{
'pageInfo { startCursor endCursor }'
}
# Convenience for using default implementation of pagination_results_data
let
(
:node_path
)
{
[
'id'
]
}
it_behaves_like
'requires variables'
do
let
(
:required_variables
)
{
[
:sort_param
,
:first_param
,
:expected_results
,
:data_path
,
:current_user
]
}
end
describe
do
let
(
:sort_argument
)
{
"sort:
#{
sort_param
}
"
if
sort_param
.
present?
}
let
(
:first_argument
)
{
"first:
#{
first_param
}
"
if
first_param
.
present?
}
let
(
:sort_argument
)
{
graphql_args
(
sort:
sort_param
)
}
let
(
:params
)
{
sort_argument
}
let
(
:start_cursor
)
{
graphql_data_at
(
*
data_path
,
:pageInfo
,
:startCursor
)
}
let
(
:end_cursor
)
{
graphql_data_at
(
*
data_path
,
:pageInfo
,
:endCursor
)
}
let
(
:sorted_edges
)
{
graphql_data_at
(
*
data_path
,
:edges
)
}
let
(
:page_info
)
{
"pageInfo { startCursor endCursor }"
}
def
pagination_query
(
params
,
page_info
)
raise
(
'pagination_query(params, page_info) must be defined in the test, see example in comment'
)
unless
defined?
(
super
)
# Convenience helper for the large number of queries defined as a projection
# from some root value indexed by full_path to a collection of objects with IID
def
nested_internal_id_query
(
root_field
,
parent
,
field
,
args
,
selection: :iid
)
graphql_query_for
(
root_field
,
{
full_path:
parent
.
full_path
},
query_nodes
(
field
,
selection
,
args:
args
,
include_pagination_info:
true
)
)
end
def
pagination_query
(
params
)
raise
(
'pagination_query(params) must be defined in the test, see example in comment'
)
unless
defined?
(
super
)
super
end
def
pagination_results_data
(
data
)
raise
(
'pagination_results_data(data) must be defined in the test, see example in comment'
)
unless
defined?
(
super
)
def
pagination_results_data
(
nodes
)
if
defined?
(
super
)
super
(
nodes
)
else
nodes
.
map
{
|
n
|
n
.
dig
(
*
node_path
)
}
end
end
def
results
nodes
=
graphql_dig_at
(
graphql_data
(
fresh_response_data
),
*
data_path
,
:nodes
)
pagination_results_data
(
nodes
)
end
def
end_cursor
graphql_dig_at
(
graphql_data
(
fresh_response_data
),
*
data_path
,
:page_info
,
:end_cursor
)
end
super
(
data
)
def
start_cursor
graphql_dig_at
(
graphql_data
(
fresh_response_data
),
*
data_path
,
:page_info
,
:start_cursor
)
end
let
(
:query
)
{
pagination_query
(
params
)
}
before
do
post_graphql
(
pagination_query
(
params
,
page_info
)
,
current_user:
current_user
)
post_graphql
(
query
,
current_user:
current_user
)
end
context
'when sorting'
do
it
'sorts correctly'
do
expect
(
pagination_results_data
(
sorted_edges
)
).
to
eq
expected_results
expect
(
results
).
to
eq
expected_results
end
context
'when paginating'
do
let
(
:params
)
{
[
sort_argument
,
first_argument
].
compact
.
join
(
','
)
}
let
(
:params
)
{
sort_argument
.
merge
(
first:
first_param
)
}
let
(
:first_page
)
{
expected_results
.
first
(
first_param
)
}
let
(
:rest
)
{
expected_results
.
drop
(
first_param
)
}
it
'paginates correctly'
do
expect
(
pagination_results_data
(
sorted_edges
)).
to
eq
expected_results
.
first
(
first_param
)
expect
(
results
).
to
eq
first_page
cursored_query
=
pagination_query
([
sort_argument
,
"after:
\"
#{
end_cursor
}
\"
"
].
compact
.
join
(
','
),
page_info
)
post_graphql
(
cursored_query
,
current_user:
current_user
)
fwds
=
pagination_query
(
sort_argument
.
merge
(
after:
end_cursor
)
)
post_graphql
(
fwds
,
current_user:
current_user
)
expect
(
res
ponse
).
to
have_gitlab_http_status
(
:ok
)
expect
(
res
ults
).
to
eq
rest
response_data
=
graphql_dig_at
(
Gitlab
::
Json
.
parse
(
response
.
body
),
:data
,
*
data_path
,
:edges
)
bwds
=
pagination_query
(
sort_argument
.
merge
(
before:
start_cursor
))
post_graphql
(
bwds
,
current_user:
current_user
)
expect
(
pagination_results_data
(
response_data
)).
to
eq
expected_results
.
drop
(
first_param
)
expect
(
results
).
to
eq
first_page
end
end
end
...
...
spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb
View file @
680decd0
...
...
@@ -47,18 +47,12 @@ RSpec.shared_examples 'group and project boards query' do
describe
'sorting and pagination'
do
let
(
:data_path
)
{
[
board_parent_type
,
:boards
]
}
def
pagination_query
(
params
,
page_info
)
graphql_query_for
(
board_parent_type
,
{
'fullPath'
=>
board_parent
.
full_path
},
query_graphql_field
(
'boards'
,
params
,
"
#{
page_info
}
edges { node { id } }"
)
def
pagination_query
(
params
)
graphql_query_for
(
board_parent_type
,
{
full_path:
board_parent
.
full_path
},
query_nodes
(
:boards
,
:id
,
include_pagination_info:
true
,
args:
params
)
)
end
def
pagination_results_data
(
data
)
data
.
map
{
|
board
|
board
.
dig
(
'node'
,
'id'
)
}
end
context
'when using default sorting'
do
let!
(
:board_B
)
{
create
(
:board
,
resource_parent:
board_parent
,
name:
'B'
)
}
let!
(
:board_C
)
{
create
(
:board
,
resource_parent:
board_parent
,
name:
'C'
)
}
...
...
@@ -72,9 +66,9 @@ RSpec.shared_examples 'group and project boards query' do
let
(
:first_param
)
{
2
}
let
(
:expected_results
)
do
if
board_parent
.
multiple_issue_boards_available?
boards
.
map
{
|
board
|
board
.
to_global_id
.
to_s
}
boards
.
map
{
|
board
|
global_id_of
(
board
)
}
else
[
boards
.
first
.
to_global_id
.
to_s
]
[
global_id_of
(
boards
.
first
)
]
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