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
664c4c7b
Commit
664c4c7b
authored
Oct 21, 2019
by
GitLab Bot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add latest changes from gitlab-org/gitlab@master
parent
6791eefe
Changes
34
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
34 changed files
with
1697 additions
and
28 deletions
+1697
-28
.gitlab/CODEOWNERS
.gitlab/CODEOWNERS
+1
-0
.gitlab/ci/review.gitlab-ci.yml
.gitlab/ci/review.gitlab-ci.yml
+4
-1
.gitlab/issue_templates/Security developer workflow.md
.gitlab/issue_templates/Security developer workflow.md
+1
-1
app/services/create_branch_service.rb
app/services/create_branch_service.rb
+1
-1
app/services/metrics/dashboard/grafana_metric_embed_service.rb
...ervices/metrics/dashboard/grafana_metric_embed_service.rb
+157
-0
app/views/admin/sessions/_new_base.html.haml
app/views/admin/sessions/_new_base.html.haml
+1
-1
app/views/admin/sessions/_tabs_normal.html.haml
app/views/admin/sessions/_tabs_normal.html.haml
+1
-1
app/views/admin/sessions/new.html.haml
app/views/admin/sessions/new.html.haml
+1
-1
app/views/layouts/nav/_dashboard.html.haml
app/views/layouts/nav/_dashboard.html.haml
+18
-9
changelogs/unreleased/34299-enable-color-chip-asciidoc.yml
changelogs/unreleased/34299-enable-color-chip-asciidoc.yml
+5
-0
changelogs/unreleased/34320-error-when-uploading-a-few-designs-in-a-row.yml
...sed/34320-error-when-uploading-a-few-designs-in-a-row.yml
+5
-0
changelogs/unreleased/fix-admin-mode-ui-buttons-missing-on-small-screens.yml
...ed/fix-admin-mode-ui-buttons-missing-on-small-screens.yml
+5
-0
lib/banzai/pipeline/ascii_doc_pipeline.rb
lib/banzai/pipeline/ascii_doc_pipeline.rb
+1
-0
lib/gitlab/metrics/dashboard/errors.rb
lib/gitlab/metrics/dashboard/errors.rb
+5
-0
lib/gitlab/metrics/dashboard/processor.rb
lib/gitlab/metrics/dashboard/processor.rb
+3
-0
lib/gitlab/metrics/dashboard/stages/grafana_formatter.rb
lib/gitlab/metrics/dashboard/stages/grafana_formatter.rb
+224
-0
lib/grafana/client.rb
lib/grafana/client.rb
+13
-1
locale/gitlab.pot
locale/gitlab.pot
+4
-4
spec/factories/grafana_integrations.rb
spec/factories/grafana_integrations.rb
+1
-1
spec/features/admin/admin_settings_spec.rb
spec/features/admin/admin_settings_spec.rb
+29
-2
spec/fixtures/grafana/dashboard_response.json
spec/fixtures/grafana/dashboard_response.json
+764
-0
spec/fixtures/grafana/datasource_response.json
spec/fixtures/grafana/datasource_response.json
+21
-0
spec/fixtures/grafana/expected_grafana_embed.json
spec/fixtures/grafana/expected_grafana_embed.json
+27
-0
spec/fixtures/grafana/simplified_dashboard_response.json
spec/fixtures/grafana/simplified_dashboard_response.json
+40
-0
spec/fixtures/lib/gitlab/metrics/dashboard/schemas/metrics.json
...ixtures/lib/gitlab/metrics/dashboard/schemas/metrics.json
+0
-1
spec/fixtures/lib/gitlab/metrics/dashboard/schemas/panels.json
...fixtures/lib/gitlab/metrics/dashboard/schemas/panels.json
+0
-1
spec/lib/gitlab/metrics/dashboard/processor_spec.rb
spec/lib/gitlab/metrics/dashboard/processor_spec.rb
+8
-0
spec/lib/gitlab/metrics/dashboard/stages/grafana_formatter_spec.rb
...gitlab/metrics/dashboard/stages/grafana_formatter_spec.rb
+106
-0
spec/lib/grafana/client_spec.rb
spec/lib/grafana/client_spec.rb
+25
-1
spec/requests/api/branches_spec.rb
spec/requests/api/branches_spec.rb
+1
-1
spec/services/create_branch_service_spec.rb
spec/services/create_branch_service_spec.rb
+15
-0
spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb
...es/metrics/dashboard/grafana_metric_embed_service_spec.rb
+177
-0
spec/support/helpers/grafana_api_helpers.rb
spec/support/helpers/grafana_api_helpers.rb
+32
-0
spec/support/helpers/login_helpers.rb
spec/support/helpers/login_helpers.rb
+1
-1
No files found.
.gitlab/CODEOWNERS
View file @
664c4c7b
...
@@ -32,4 +32,5 @@ lib/gitlab/github_import/ @gitlab-org/maintainers/database
...
@@ -32,4 +32,5 @@ lib/gitlab/github_import/ @gitlab-org/maintainers/database
/.gitlab/ci/ @gl-quality/eng-prod
/.gitlab/ci/ @gl-quality/eng-prod
Dangerfile @gl-quality/eng-prod
Dangerfile @gl-quality/eng-prod
/danger/ @gl-quality/eng-prod
/danger/ @gl-quality/eng-prod
/lib/gitlab/danger/ @gl-quality/eng-prod
/scripts/ @gl-quality/eng-prod
/scripts/ @gl-quality/eng-prod
.gitlab/ci/review.gitlab-ci.yml
View file @
664c4c7b
...
@@ -97,7 +97,10 @@ schedule:review-build-cng:
...
@@ -97,7 +97,10 @@ schedule:review-build-cng:
variables
:
variables
:
HOST_SUFFIX
:
"
${CI_ENVIRONMENT_SLUG}"
HOST_SUFFIX
:
"
${CI_ENVIRONMENT_SLUG}"
DOMAIN
:
"
-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}"
DOMAIN
:
"
-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}"
GITLAB_HELM_CHART_REF
:
"
v2.3.7"
# v2.3.7 + some stability improvements not yet released:
# - sidekiq readinessProbe should be `pgrep -f sidekiq`: https://gitlab.com/gitlab-org/charts/gitlab/merge_requests/991
# - Allows livenessProbe and readinessProbe to be configured for unicorn: https://gitlab.com/gitlab-org/charts/gitlab/merge_requests/985
GITLAB_HELM_CHART_REF
:
"
df7c52dc69df441909880b8f2fd15e938cdb2047"
GITLAB_EDITION
:
"
ce"
GITLAB_EDITION
:
"
ce"
environment
:
environment
:
name
:
review/${CI_COMMIT_REF_NAME}
name
:
review/${CI_COMMIT_REF_NAME}
...
...
.gitlab/issue_templates/Security developer workflow.md
View file @
664c4c7b
...
@@ -29,7 +29,7 @@ Set the title to: `Description of the original issue`
...
@@ -29,7 +29,7 @@ Set the title to: `Description of the original issue`
#### Documentation and final details
#### Documentation and final details
-
[
] Check the topic on #
security
to see when the next release is going to happen and add a link to the [links section
](
#links
)
-
[
] Check the topic on #
releases
to see when the next release is going to happen and add a link to the [links section
](
#links
)
-
[ ] Add links to this issue and your MRs in the description of the security release issue
-
[ ] Add links to this issue and your MRs in the description of the security release issue
-
[
] Find out the versions affected (the Git history of the files affected may help you with this) and add them to the [details section
](
#details
)
-
[
] Find out the versions affected (the Git history of the files affected may help you with this) and add them to the [details section
](
#details
)
-
[
] Fill in any upgrade notes that users may need to take into account in the [details section
](
#details
)
-
[
] Fill in any upgrade notes that users may need to take into account in the [details section
](
#details
)
...
...
app/services/create_branch_service.rb
View file @
664c4c7b
...
@@ -14,7 +14,7 @@ class CreateBranchService < BaseService
...
@@ -14,7 +14,7 @@ class CreateBranchService < BaseService
if
new_branch
if
new_branch
success
(
new_branch
)
success
(
new_branch
)
else
else
error
(
'Invalid reference name'
)
error
(
"Invalid reference name:
#{
branch_name
}
"
)
end
end
rescue
Gitlab
::
Git
::
PreReceiveError
=>
ex
rescue
Gitlab
::
Git
::
PreReceiveError
=>
ex
error
(
ex
.
message
)
error
(
ex
.
message
)
...
...
app/services/metrics/dashboard/grafana_metric_embed_service.rb
0 → 100644
View file @
664c4c7b
# frozen_string_literal: true
# Responsible for returning a gitlab-compatible dashboard
# containing info based on a grafana dashboard and datasource.
#
# Use Gitlab::Metrics::Dashboard::Finder to retrive dashboards.
module
Metrics
module
Dashboard
class
GrafanaMetricEmbedService
<
::
Metrics
::
Dashboard
::
BaseService
include
ReactiveCaching
SEQUENCE
=
[
::
Gitlab
::
Metrics
::
Dashboard
::
Stages
::
GrafanaFormatter
].
freeze
self
.
reactive_cache_key
=
->
(
service
)
{
service
.
cache_key
}
self
.
reactive_cache_lease_timeout
=
30
.
seconds
self
.
reactive_cache_refresh_interval
=
30
.
minutes
self
.
reactive_cache_lifetime
=
30
.
minutes
self
.
reactive_cache_worker_finder
=
->
(
_id
,
*
args
)
{
from_cache
(
*
args
)
}
class
<<
self
# Determines whether the provided params are sufficient
# to uniquely identify a grafana dashboard.
def
valid_params?
(
params
)
[
params
[
:embedded
],
params
[
:grafana_url
]
].
all?
end
def
from_cache
(
project_id
,
user_id
,
grafana_url
)
project
=
Project
.
find
(
project_id
)
user
=
User
.
find
(
user_id
)
new
(
project
,
user
,
grafana_url:
grafana_url
)
end
end
def
get_dashboard
with_reactive_cache
(
*
cache_key
)
{
|
result
|
result
}
end
# Inherits the primary logic from the parent class and
# maintains the service's API while including ReactiveCache
def
calculate_reactive_cache
(
*
)
::
Metrics
::
Dashboard
::
BaseService
.
instance_method
(
:get_dashboard
)
.
bind
(
self
)
.
call
()
# rubocop:disable Style/MethodCallWithoutArgsParentheses
end
def
cache_key
(
*
args
)
[
project
.
id
,
current_user
.
id
,
grafana_url
]
end
# Required for ReactiveCaching; Usage overridden by
# self.reactive_cache_worker_finder
def
id
nil
end
private
def
get_raw_dashboard
raise
MissingIntegrationError
unless
client
grafana_dashboard
=
fetch_dashboard
datasource
=
fetch_datasource
(
grafana_dashboard
)
params
.
merge!
(
grafana_dashboard:
grafana_dashboard
,
datasource:
datasource
)
{}
end
def
fetch_dashboard
uid
=
GrafanaUidParser
.
new
(
grafana_url
,
project
).
parse
raise
DashboardProcessingError
.
new
(
'Dashboard uid not found'
)
unless
uid
response
=
client
.
get_dashboard
(
uid:
uid
)
parse_json
(
response
.
body
)
end
def
fetch_datasource
(
dashboard
)
name
=
DatasourceNameParser
.
new
(
grafana_url
,
dashboard
).
parse
raise
DashboardProcessingError
.
new
(
'Datasource name not found'
)
unless
name
response
=
client
.
get_datasource
(
name:
name
)
parse_json
(
response
.
body
)
end
def
grafana_url
params
[
:grafana_url
]
end
def
client
project
.
grafana_integration
&
.
client
end
def
allowed?
Ability
.
allowed?
(
current_user
,
:read_project
,
project
)
end
def
sequence
SEQUENCE
end
def
parse_json
(
json
)
JSON
.
parse
(
json
,
symbolize_names:
true
)
rescue
JSON
::
ParserError
raise
DashboardProcessingError
.
new
(
'Grafana response contains invalid json'
)
end
end
# Identifies the uid of the dashboard based on url format
class
GrafanaUidParser
def
initialize
(
grafana_url
,
project
)
@grafana_url
,
@project
=
grafana_url
,
project
end
def
parse
@grafana_url
.
match
(
uid_regex
)
{
|
m
|
m
.
named_captures
[
'uid'
]
}
end
private
# URLs are expected to look like https://domain.com/d/:uid/other/stuff
def
uid_regex
base_url
=
@project
.
grafana_integration
.
grafana_url
.
chomp
(
'/'
)
%r{(
#{
Regexp
.
escape
(
base_url
)
}
\/
d
\/
(?<uid>
\w
+)
\/
)}x
end
end
# Identifies the name of the datasource for a dashboard
# based on the panelId query parameter found in the url
class
DatasourceNameParser
def
initialize
(
grafana_url
,
grafana_dashboard
)
@grafana_url
,
@grafana_dashboard
=
grafana_url
,
grafana_dashboard
end
def
parse
@grafana_dashboard
[
:dashboard
][
:panels
]
.
find
{
|
panel
|
panel
[
:id
].
to_s
==
query_params
[
:panelId
]
}
.
try
(
:[]
,
:datasource
)
end
private
def
query_params
Gitlab
::
Metrics
::
Dashboard
::
Url
.
parse_query
(
@grafana_url
)
end
end
end
end
app/views/admin/sessions/_new_base.html.haml
View file @
664c4c7b
...
@@ -4,4 +4,4 @@
...
@@ -4,4 +4,4 @@
=
password_field_tag
:password
,
nil
,
class:
'form-control'
,
required:
true
,
title:
_
(
'This field is required.'
),
data:
{
qa_selector:
'password_field'
}
=
password_field_tag
:password
,
nil
,
class:
'form-control'
,
required:
true
,
title:
_
(
'This field is required.'
),
data:
{
qa_selector:
'password_field'
}
.submit-container.move-submit-down
.submit-container.move-submit-down
=
submit_tag
_
(
'Enter
admin m
ode'
),
class:
'btn btn-success'
,
data:
{
qa_selector:
'sign_in_button'
}
=
submit_tag
_
(
'Enter
Admin M
ode'
),
class:
'btn btn-success'
,
data:
{
qa_selector:
'sign_in_button'
}
app/views/admin/sessions/_tabs_normal.html.haml
View file @
664c4c7b
%ul
.nav-links.new-session-tabs.nav-tabs.nav
{
role:
'tablist'
}
%ul
.nav-links.new-session-tabs.nav-tabs.nav
{
role:
'tablist'
}
%li
.nav-item
{
role:
'presentation'
}
%li
.nav-item
{
role:
'presentation'
}
%a
.nav-link.active
{
href:
'#login-pane'
,
data:
{
toggle:
'tab'
,
qa_selector:
'sign_in_tab'
},
role:
'tab'
}=
_
(
'Enter
admin m
ode'
)
%a
.nav-link.active
{
href:
'#login-pane'
,
data:
{
toggle:
'tab'
,
qa_selector:
'sign_in_tab'
},
role:
'tab'
}=
_
(
'Enter
Admin M
ode'
)
app/views/admin/sessions/new.html.haml
View file @
664c4c7b
-
@hide_breadcrumbs
=
true
-
@hide_breadcrumbs
=
true
-
page_title
_
(
'Enter
admin m
ode'
)
-
page_title
_
(
'Enter
Admin M
ode'
)
.row.justify-content-center
.row.justify-content-center
.col-6.new-session-forms-container
.col-6.new-session-forms-container
...
...
app/views/layouts/nav/_dashboard.html.haml
View file @
664c4c7b
...
@@ -55,15 +55,15 @@
...
@@ -55,15 +55,15 @@
=
nav_link
(
controller:
'admin/dashboard'
)
do
=
nav_link
(
controller:
'admin/dashboard'
)
do
=
link_to
admin_root_path
,
class:
'admin-icon qa-admin-area-link d-xl-none'
do
=
link_to
admin_root_path
,
class:
'admin-icon qa-admin-area-link d-xl-none'
do
=
_
(
'Admin Area'
)
=
_
(
'Admin Area'
)
-
if
Feature
.
enabled?
(
:user_mode_in_session
)
-
if
Feature
.
enabled?
(
:user_mode_in_session
)
-
if
header_link?
(
:admin_mode
)
-
if
header_link?
(
:admin_mode
)
=
nav_link
(
controller:
'admin/sessions'
)
do
=
nav_link
(
controller:
'admin/sessions'
)
do
=
link_to
destroy_admin_session_path
,
class:
'd-lg-none lock-open-icon'
do
=
link_to
destroy_admin_session_path
,
class:
'd-lg-none lock-open-icon'
do
=
_
(
'Leave admin m
ode'
)
=
_
(
'Leave Admin M
ode'
)
-
elsif
current_user
.
admin?
-
elsif
current_user
.
admin?
=
nav_link
(
controller:
'admin/sessions'
)
do
=
nav_link
(
controller:
'admin/sessions'
)
do
=
link_to
new_admin_session_path
,
class:
'd-lg-none lock-icon'
do
=
link_to
new_admin_session_path
,
class:
'd-lg-none lock-icon'
do
=
_
(
'Enter admin m
ode'
)
=
_
(
'Enter Admin M
ode'
)
-
if
Gitlab
::
Sherlock
.
enabled?
-
if
Gitlab
::
Sherlock
.
enabled?
%li
%li
=
link_to
sherlock_transactions_path
,
class:
'admin-icon'
do
=
link_to
sherlock_transactions_path
,
class:
'admin-icon'
do
...
@@ -74,6 +74,15 @@
...
@@ -74,6 +74,15 @@
=
link_to
admin_root_path
,
class:
'admin-icon qa-admin-area-link'
,
title:
_
(
'Admin Area'
),
aria:
{
label:
_
(
'Admin Area'
)
},
data:
{
toggle:
'tooltip'
,
placement:
'bottom'
,
container:
'body'
}
do
=
link_to
admin_root_path
,
class:
'admin-icon qa-admin-area-link'
,
title:
_
(
'Admin Area'
),
aria:
{
label:
_
(
'Admin Area'
)
},
data:
{
toggle:
'tooltip'
,
placement:
'bottom'
,
container:
'body'
}
do
=
sprite_icon
(
'admin'
,
size:
18
)
=
sprite_icon
(
'admin'
,
size:
18
)
-
if
Feature
.
enabled?
(
:user_mode_in_session
)
-
if
header_link?
(
:admin_mode
)
=
nav_link
(
controller:
'admin/sessions'
,
html_options:
{
class:
"d-none d-lg-block d-xl-block"
})
do
=
link_to
destroy_admin_session_path
,
title:
_
(
'Leave Admin Mode'
),
aria:
{
label:
_
(
'Leave Admin Mode'
)
},
data:
{
toggle:
'tooltip'
,
placement:
'bottom'
,
container:
'body'
}
do
=
sprite_icon
(
'lock-open'
,
size:
18
)
-
elsif
current_user
.
admin?
=
nav_link
(
controller:
'admin/sessions'
,
html_options:
{
class:
"d-none d-lg-block d-xl-block"
})
do
=
link_to
new_admin_session_path
,
title:
_
(
'Enter Admin Mode'
),
aria:
{
label:
_
(
'Enter Admin Mode'
)
},
data:
{
toggle:
'tooltip'
,
placement:
'bottom'
,
container:
'body'
}
do
=
sprite_icon
(
'lock'
,
size:
18
)
-# Shortcut to Dashboard > Projects
-# Shortcut to Dashboard > Projects
-
if
dashboard_nav_link?
(
:projects
)
-
if
dashboard_nav_link?
(
:projects
)
...
...
changelogs/unreleased/34299-enable-color-chip-asciidoc.yml
0 → 100644
View file @
664c4c7b
---
title
:
Enable the color chip in AsciiDoc documents
merge_request
:
18723
author
:
type
:
added
changelogs/unreleased/34320-error-when-uploading-a-few-designs-in-a-row.yml
0 → 100644
View file @
664c4c7b
---
title
:
Resolve Error when uploading a few designs in a row
merge_request
:
18811
author
:
type
:
fixed
changelogs/unreleased/fix-admin-mode-ui-buttons-missing-on-small-screens.yml
0 → 100644
View file @
664c4c7b
---
title
:
Fix missing admin mode UI buttons on bigger screen sizes
merge_request
:
18585
author
:
Diego Louzán
type
:
fixed
lib/banzai/pipeline/ascii_doc_pipeline.rb
View file @
664c4c7b
...
@@ -10,6 +10,7 @@ module Banzai
...
@@ -10,6 +10,7 @@ module Banzai
Filter
::
SyntaxHighlightFilter
,
Filter
::
SyntaxHighlightFilter
,
Filter
::
ExternalLinkFilter
,
Filter
::
ExternalLinkFilter
,
Filter
::
PlantumlFilter
,
Filter
::
PlantumlFilter
,
Filter
::
ColorFilter
,
Filter
::
AsciiDocPostProcessingFilter
Filter
::
AsciiDocPostProcessingFilter
]
]
end
end
...
...
lib/gitlab/metrics/dashboard/errors.rb
View file @
664c4c7b
...
@@ -9,6 +9,7 @@ module Gitlab
...
@@ -9,6 +9,7 @@ module Gitlab
module
Errors
module
Errors
DashboardProcessingError
=
Class
.
new
(
StandardError
)
DashboardProcessingError
=
Class
.
new
(
StandardError
)
PanelNotFoundError
=
Class
.
new
(
StandardError
)
PanelNotFoundError
=
Class
.
new
(
StandardError
)
MissingIntegrationError
=
Class
.
new
(
StandardError
)
LayoutError
=
Class
.
new
(
DashboardProcessingError
)
LayoutError
=
Class
.
new
(
DashboardProcessingError
)
MissingQueryError
=
Class
.
new
(
DashboardProcessingError
)
MissingQueryError
=
Class
.
new
(
DashboardProcessingError
)
...
@@ -22,6 +23,10 @@ module Gitlab
...
@@ -22,6 +23,10 @@ module Gitlab
error
(
"
#{
dashboard_path
}
could not be found."
,
:not_found
)
error
(
"
#{
dashboard_path
}
could not be found."
,
:not_found
)
when
PanelNotFoundError
when
PanelNotFoundError
error
(
error
.
message
,
:not_found
)
error
(
error
.
message
,
:not_found
)
when
::
Grafana
::
Client
::
Error
error
(
error
.
message
,
:service_unavailable
)
when
MissingIntegrationError
error
(
'Proxy support for this API is not available currently'
,
:bad_request
)
else
else
raise
error
raise
error
end
end
...
...
lib/gitlab/metrics/dashboard/processor.rb
View file @
664c4c7b
...
@@ -17,7 +17,10 @@ module Gitlab
...
@@ -17,7 +17,10 @@ module Gitlab
# Returns a new dashboard hash with the results of
# Returns a new dashboard hash with the results of
# running transforms on the dashboard.
# running transforms on the dashboard.
# @return [Hash, nil]
def
process
def
process
return
unless
@dashboard
@dashboard
.
deep_symbolize_keys
.
tap
do
|
dashboard
|
@dashboard
.
deep_symbolize_keys
.
tap
do
|
dashboard
|
@sequence
.
each
do
|
stage
|
@sequence
.
each
do
|
stage
|
stage
.
new
(
@project
,
dashboard
,
@params
).
transform!
stage
.
new
(
@project
,
dashboard
,
@params
).
transform!
...
...
lib/gitlab/metrics/dashboard/stages/grafana_formatter.rb
0 → 100644
View file @
664c4c7b
# frozen_string_literal: true
module
Gitlab
module
Metrics
module
Dashboard
module
Stages
class
GrafanaFormatter
<
BaseStage
include
Gitlab
::
Utils
::
StrongMemoize
CHART_TYPE
=
'area-chart'
PROXY_PATH
=
'api/v1/query_range'
# Reformats the specified panel in the Gitlab
# dashboard-yml format
def
transform!
InputFormatValidator
.
new
(
grafana_dashboard
,
datasource
,
panel
,
query_params
).
validate!
new_dashboard
=
formatted_dashboard
dashboard
.
clear
dashboard
.
merge!
(
new_dashboard
)
end
private
def
formatted_dashboard
{
panel_groups:
[{
panels:
[
formatted_panel
]
}]
}
end
def
formatted_panel
{
title:
panel
[
:title
],
type:
CHART_TYPE
,
y_label:
''
,
# Grafana panels do not include a Y-Axis label
metrics:
panel
[
:targets
].
map
.
with_index
do
|
target
,
idx
|
formatted_metric
(
target
,
idx
)
end
}
end
def
formatted_metric
(
metric
,
idx
)
{
id:
"
#{
metric
[
:legendFormat
]
}
_
#{
idx
}
"
,
query_range:
format_query
(
metric
),
label:
replace_variables
(
metric
[
:legendFormat
]),
prometheus_endpoint_path:
prometheus_endpoint_for_metric
(
metric
)
}.
compact
end
# Panel specified by the url from the Grafana dashboard
def
panel
strong_memoize
(
:panel
)
do
grafana_dashboard
[
:dashboard
][
:panels
].
find
do
|
panel
|
panel
[
:id
].
to_s
==
query_params
[
:panelId
]
end
end
end
# Grafana url query parameters. Includes information
# on which panel to select and time range.
def
query_params
strong_memoize
(
:query_params
)
do
Gitlab
::
Metrics
::
Dashboard
::
Url
.
parse_query
(
grafana_url
)
end
end
# Endpoint which will return prometheus metric data
# for the metric
def
prometheus_endpoint_for_metric
(
metric
)
Gitlab
::
Routing
.
url_helpers
.
project_grafana_api_path
(
project
,
datasource_id:
datasource
[
:id
],
proxy_path:
PROXY_PATH
,
query:
format_query
(
metric
)
)
end
# Reformats query for compatibility with prometheus api.
def
format_query
(
metric
)
expression
=
remove_new_lines
(
metric
[
:expr
])
expression
=
replace_variables
(
expression
)
expression
=
replace_global_variables
(
expression
,
metric
)
expression
end
# Accomodates instance-defined Grafana variables.
# These are variables defined by users, and values
# must be provided in the query parameters.
def
replace_variables
(
expression
)
return
expression
unless
grafana_dashboard
[
:dashboard
][
:templating
]
grafana_dashboard
[
:dashboard
][
:templating
][
:list
]
.
sort_by
{
|
variable
|
variable
[
:name
].
length
}
.
each
do
|
variable
|
variable_value
=
query_params
[
:"var-
#{
variable
[
:name
]
}
"
]
expression
=
expression
.
gsub
(
"$
#{
variable
[
:name
]
}
"
,
variable_value
)
expression
=
expression
.
gsub
(
"[[
#{
variable
[
:name
]
}
]]"
,
variable_value
)
expression
=
expression
.
gsub
(
"{{
#{
variable
[
:name
]
}
}}"
,
variable_value
)
end
expression
end
# Replaces Grafana global built-in variables with values.
# Only $__interval and $__from and $__to are supported.
#
# See https://grafana.com/docs/reference/templating/#global-built-in-variables
def
replace_global_variables
(
expression
,
metric
)
expression
=
expression
.
gsub
(
'$__interval'
,
metric
[
:interval
])
if
metric
[
:interval
]
expression
=
expression
.
gsub
(
'$__from'
,
query_params
[
:from
])
expression
=
expression
.
gsub
(
'$__to'
,
query_params
[
:to
])
expression
end
# Removes new lines from expression.
def
remove_new_lines
(
expression
)
expression
.
gsub
(
/\R+/
,
''
)
end
# Grafana datasource object corresponding to the
# specified dashboard
def
datasource
params
[
:datasource
]
end
# The specified Grafana dashboard
def
grafana_dashboard
params
[
:grafana_dashboard
]
end
# The URL specifying which Grafana panel to embed
def
grafana_url
params
[
:grafana_url
]
end
end
class
InputFormatValidator
include
::
Gitlab
::
Metrics
::
Dashboard
::
Errors
attr_reader
:grafana_dashboard
,
:datasource
,
:panel
,
:query_params
UNSUPPORTED_GRAFANA_GLOBAL_VARS
=
%w(
$__interval_ms
$__timeFilter
$__name
$timeFilter
$interval
)
.
freeze
def
initialize
(
grafana_dashboard
,
datasource
,
panel
,
query_params
)
@grafana_dashboard
=
grafana_dashboard
@datasource
=
datasource
@panel
=
panel
@query_params
=
query_params
end
def
validate!
validate_query_params!
validate_datasource!
validate_panel_type!
validate_variable_definitions!
validate_global_variables!
end
private
def
validate_datasource!
return
if
datasource
[
:access
]
==
'proxy'
&&
datasource
[
:type
]
==
'prometheus'
raise_error
'Only Prometheus datasources with proxy access in Grafana are supported.'
end
def
validate_query_params!
return
if
[
:panelId
,
:from
,
:to
].
all?
{
|
param
|
query_params
.
include?
(
param
)
}
raise_error
'Grafana query parameters must include panelId, from, and to.'
end
def
validate_panel_type!
return
if
panel
[
:type
]
==
'graph'
&&
panel
[
:lines
]
raise_error
'Panel type must be a line graph.'
end
def
validate_variable_definitions!
return
unless
grafana_dashboard
[
:dashboard
][
:templating
]
return
if
grafana_dashboard
[
:dashboard
][
:templating
][
:list
].
all?
do
|
variable
|
query_params
[
:"var-
#{
variable
[
:name
]
}
"
].
present?
end
raise_error
'All Grafana variables must be defined in the query parameters.'
end
def
validate_global_variables!
return
unless
panel_contains_unsupported_vars?
raise_error
'Prometheus must not include'
end
def
panel_contains_unsupported_vars?
panel
[
:targets
].
any?
do
|
target
|
UNSUPPORTED_GRAFANA_GLOBAL_VARS
.
any?
do
|
variable
|
target
[
:expr
].
include?
(
variable
)
end
end
end
def
raise_error
(
message
)
raise
DashboardProcessingError
.
new
(
message
)
end
end
end
end
end
end
lib/grafana/client.rb
View file @
664c4c7b
...
@@ -11,6 +11,18 @@ module Grafana
...
@@ -11,6 +11,18 @@ module Grafana
@token
=
token
@token
=
token
end
end
# @param uid [String] Unique identifier for a Grafana dashboard
def
get_dashboard
(
uid
:)
http_get
(
"
#{
@api_url
}
/api/dashboards/uid/
#{
uid
}
"
)
end
# @param name [String] Unique identifier for a Grafana datasource
def
get_datasource
(
name
:)
# CGI#escape formats strings such that the Grafana endpoint
# will not recognize the dashboard name. Preferring URI#escape.
http_get
(
"
#{
@api_url
}
/api/datasources/name/
#{
URI
.
escape
(
name
)
}
"
)
# rubocop:disable Lint/UriEscapeUnescape
end
# @param datasource_id [String] Grafana ID for the datasource
# @param datasource_id [String] Grafana ID for the datasource
# @param proxy_path [String] Path to proxy - ex) 'api/v1/query_range'
# @param proxy_path [String] Path to proxy - ex) 'api/v1/query_range'
def
proxy_datasource
(
datasource_id
:,
proxy_path
:,
query:
{})
def
proxy_datasource
(
datasource_id
:,
proxy_path
:,
query:
{})
...
@@ -57,7 +69,7 @@ module Grafana
...
@@ -57,7 +69,7 @@ module Grafana
def
handle_response
(
response
)
def
handle_response
(
response
)
return
response
if
response
.
code
==
200
return
response
if
response
.
code
==
200
raise_error
"Grafana response status code:
#{
response
.
code
}
"
raise_error
"Grafana response status code:
#{
response
.
code
}
, Message:
#{
response
.
body
}
"
end
end
def
raise_error
(
message
)
def
raise_error
(
message
)
...
...
locale/gitlab.pot
View file @
664c4c7b
...
@@ -6099,13 +6099,13 @@ msgstr ""
...
@@ -6099,13 +6099,13 @@ msgstr ""
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
msgstr ""
msgid "Enter
IP address rang
e"
msgid "Enter
Admin Mod
e"
msgstr ""
msgstr ""
msgid "Enter
a number
"
msgid "Enter
IP address range
"
msgstr ""
msgstr ""
msgid "Enter a
dmin mode
"
msgid "Enter a
number
"
msgstr ""
msgstr ""
msgid "Enter at least three characters to search"
msgid "Enter at least three characters to search"
...
@@ -9680,7 +9680,7 @@ msgstr ""
...
@@ -9680,7 +9680,7 @@ msgstr ""
msgid "Leave"
msgid "Leave"
msgstr ""
msgstr ""
msgid "Leave
admin m
ode"
msgid "Leave
Admin M
ode"
msgstr ""
msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgid "Leave edit mode? All unsaved changes will be lost."
...
...
spec/factories/grafana_integrations.rb
View file @
664c4c7b
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
FactoryBot
.
define
do
FactoryBot
.
define
do
factory
:grafana_integration
,
class:
GrafanaIntegration
do
factory
:grafana_integration
,
class:
GrafanaIntegration
do
project
project
grafana_url
{
'https://grafana.com'
}
grafana_url
{
'https://grafana.
example.
com'
}
token
{
SecureRandom
.
hex
(
10
)
}
token
{
SecureRandom
.
hex
(
10
)
}
end
end
end
end
spec/features/admin/admin_settings_spec.rb
View file @
664c4c7b
...
@@ -5,6 +5,7 @@ require 'spec_helper'
...
@@ -5,6 +5,7 @@ require 'spec_helper'
describe
'Admin updates settings'
,
:clean_gitlab_redis_shared_state
,
:do_not_mock_admin_mode
do
describe
'Admin updates settings'
,
:clean_gitlab_redis_shared_state
,
:do_not_mock_admin_mode
do
include
StubENV
include
StubENV
include
TermsHelper
include
TermsHelper
include
MobileHelpers
let
(
:admin
)
{
create
(
:admin
)
}
let
(
:admin
)
{
create
(
:admin
)
}
...
@@ -450,6 +451,32 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
...
@@ -450,6 +451,32 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
expect
(
page
).
to
have_link
(
text:
'Support'
,
href:
new_support_url
)
expect
(
page
).
to
have_link
(
text:
'Support'
,
href:
new_support_url
)
end
end
end
end
it
'Shows admin dashboard links on bigger screen'
do
visit
root_dashboard_path
page
.
within
'.navbar'
do
expect
(
page
).
to
have_link
(
text:
'Admin Area'
,
href:
admin_root_path
,
visible:
true
)
expect
(
page
).
to
have_link
(
text:
'Leave Admin Mode'
,
href:
destroy_admin_session_path
,
visible:
true
)
end
end
it
'Relocates admin dashboard links to dropdown list on smaller screen'
,
:js
do
resize_screen_xs
visit
root_dashboard_path
page
.
within
'.navbar'
do
expect
(
page
).
not_to
have_link
(
text:
'Admin Area'
,
href:
admin_root_path
,
visible:
true
)
expect
(
page
).
not_to
have_link
(
text:
'Leave Admin Mode'
,
href:
destroy_admin_session_path
,
visible:
true
)
end
find
(
'.header-more'
).
click
page
.
within
'.navbar'
do
expect
(
page
).
to
have_link
(
text:
'Admin Area'
,
href:
admin_root_path
,
visible:
true
)
expect
(
page
).
to
have_link
(
text:
'Leave Admin Mode'
,
href:
destroy_admin_session_path
,
visible:
true
)
end
end
end
end
context
'when in admin_mode'
do
context
'when in admin_mode'
do
...
@@ -462,7 +489,7 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
...
@@ -462,7 +489,7 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
it
'can leave admin mode'
do
it
'can leave admin mode'
do
page
.
within
(
'.navbar-sub-nav'
)
do
page
.
within
(
'.navbar-sub-nav'
)
do
# Select first, link is also included in mobile view list
# Select first, link is also included in mobile view list
click_on
'Leave
admin m
ode'
,
match: :first
click_on
'Leave
Admin M
ode'
,
match: :first
expect
(
page
).
to
have_link
(
href:
new_admin_session_path
)
expect
(
page
).
to
have_link
(
href:
new_admin_session_path
)
end
end
...
@@ -481,7 +508,7 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
...
@@ -481,7 +508,7 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
before
do
before
do
page
.
within
(
'.navbar-sub-nav'
)
do
page
.
within
(
'.navbar-sub-nav'
)
do
# Select first, link is also included in mobile view list
# Select first, link is also included in mobile view list
click_on
'Leave
admin m
ode'
,
match: :first
click_on
'Leave
Admin M
ode'
,
match: :first
end
end
end
end
...
...
spec/fixtures/grafana/dashboard_response.json
0 → 100644
View file @
664c4c7b
This diff is collapsed.
Click to expand it.
spec/fixtures/grafana/datasource_response.json
0 → 100644
View file @
664c4c7b
{
"id"
:
1
,
"orgId"
:
1
,
"name"
:
"GitLab Omnibus"
,
"type"
:
"prometheus"
,
"typeLogoUrl"
:
""
,
"access"
:
"proxy"
,
"url"
:
"http://localhost:9090"
,
"password"
:
""
,
"user"
:
""
,
"database"
:
""
,
"basicAuth"
:
false
,
"basicAuthUser"
:
""
,
"basicAuthPassword"
:
""
,
"withCredentials"
:
false
,
"isDefault"
:
true
,
"jsonData"
:
{},
"secureJsonFields"
:
{},
"version"
:
1
,
"readOnly"
:
true
}
spec/fixtures/grafana/expected_grafana_embed.json
0 → 100644
View file @
664c4c7b
{
"panel_groups"
:
[
{
"panels"
:
[
{
"title"
:
"Network I/O"
,
"type"
:
"area-chart"
,
"y_label"
:
""
,
"metrics"
:
[
{
"id"
:
"In_0"
,
"query_range"
:
"sum( rate(redis_net_input_bytes_total{instance=~
\"
localhost:9121
\"
}[1m]))"
,
"label"
:
"In"
,
"prometheus_endpoint_path"
:
"/foo/bar/-/grafana/proxy/1/api/v1/query_range?query=sum%28++rate%28redis_net_input_bytes_total%7Binstance%3D~%22localhost%3A9121%22%7D%5B1m%5D%29%29"
},
{
"id"
:
"Out_1"
,
"query_range"
:
"sum( rate(redis_net_output_bytes_total{instance=~
\"
localhost:9121
\"
}[1m]))"
,
"label"
:
"Out"
,
"prometheus_endpoint_path"
:
"/foo/bar/-/grafana/proxy/1/api/v1/query_range?query=sum%28++rate%28redis_net_output_bytes_total%7Binstance%3D~%22localhost%3A9121%22%7D%5B1m%5D%29%29"
}
]
}
]
}
]
}
spec/fixtures/grafana/simplified_dashboard_response.json
0 → 100644
View file @
664c4c7b
{
"dashboard"
:
{
"panels"
:
[
{
"datasource"
:
"GitLab Omnibus"
,
"id"
:
8
,
"lines"
:
true
,
"targets"
:
[
{
"expr"
:
"sum(
\n
rate(redis_net_input_bytes_total{instance=~
\"
$instance
\"
}[$__interval])
\n
)"
,
"format"
:
"time_series"
,
"interval"
:
"1m"
,
"legendFormat"
:
"In"
,
"refId"
:
"A"
},
{
"expr"
:
"sum(
\n
rate(redis_net_output_bytes_total{instance=~
\"
[[instance]]
\"
}[$__interval])
\n
)"
,
"format"
:
"time_series"
,
"interval"
:
"1m"
,
"legendFormat"
:
"Out"
,
"refId"
:
"B"
}
],
"title"
:
"Network I/O"
,
"type"
:
"graph"
,
"yaxes"
:
[{
"format"
:
"Bps"
},
{
"format"
:
"short"
}]
}
],
"templating"
:
{
"list"
:
[
{
"current"
:
{
"value"
:
"localhost:9121"
},
"name"
:
"instance"
}
]
}
}
}
spec/fixtures/lib/gitlab/metrics/dashboard/schemas/metrics.json
View file @
664c4c7b
{
{
"type"
:
"object"
,
"type"
:
"object"
,
"required"
:
[
"required"
:
[
"unit"
,
"label"
,
"label"
,
"prometheus_endpoint_path"
"prometheus_endpoint_path"
],
],
...
...
spec/fixtures/lib/gitlab/metrics/dashboard/schemas/panels.json
View file @
664c4c7b
...
@@ -3,7 +3,6 @@
...
@@ -3,7 +3,6 @@
"required"
:
[
"required"
:
[
"title"
,
"title"
,
"y_label"
,
"y_label"
,
"weight"
,
"metrics"
"metrics"
],
],
"properties"
:
{
"properties"
:
{
...
...
spec/lib/gitlab/metrics/dashboard/processor_spec.rb
View file @
664c4c7b
...
@@ -25,6 +25,14 @@ describe Gitlab::Metrics::Dashboard::Processor do
...
@@ -25,6 +25,14 @@ describe Gitlab::Metrics::Dashboard::Processor do
end
end
end
end
context
'when the dashboard is not present'
do
let
(
:dashboard_yml
)
{
nil
}
it
'returns nil'
do
expect
(
dashboard
).
to
be_nil
end
end
context
'when dashboard config corresponds to common metrics'
do
context
'when dashboard config corresponds to common metrics'
do
let!
(
:common_metric
)
{
create
(
:prometheus_metric
,
:common
,
identifier:
'metric_a1'
)
}
let!
(
:common_metric
)
{
create
(
:prometheus_metric
,
:common
,
identifier:
'metric_a1'
)
}
...
...
spec/lib/gitlab/metrics/dashboard/stages/grafana_formatter_spec.rb
0 → 100644
View file @
664c4c7b
# frozen_string_literal: true
require
'spec_helper'
describe
Gitlab
::
Metrics
::
Dashboard
::
Stages
::
GrafanaFormatter
do
include
GrafanaApiHelpers
let_it_be
(
:namespace
)
{
create
(
:namespace
,
name:
'foo'
)
}
let_it_be
(
:project
)
{
create
(
:project
,
namespace:
namespace
,
name:
'bar'
)
}
describe
'#transform!'
do
let
(
:grafana_dashboard
)
{
JSON
.
parse
(
fixture_file
(
'grafana/simplified_dashboard_response.json'
),
symbolize_names:
true
)
}
let
(
:datasource
)
{
JSON
.
parse
(
fixture_file
(
'grafana/datasource_response.json'
),
symbolize_names:
true
)
}
let
(
:dashboard
)
{
described_class
.
new
(
project
,
{},
params
).
transform!
}
let
(
:params
)
do
{
grafana_dashboard:
grafana_dashboard
,
datasource:
datasource
,
grafana_url:
valid_grafana_dashboard_link
(
'https://grafana.example.com'
)
}
end
context
'when the query and resources are configured correctly'
do
let
(
:expected_dashboard
)
{
JSON
.
parse
(
fixture_file
(
'grafana/expected_grafana_embed.json'
),
symbolize_names:
true
)
}
it
'generates a gitlab-yml formatted dashboard'
do
expect
(
dashboard
).
to
eq
(
expected_dashboard
)
end
end
context
'when the inputs are invalid'
do
shared_examples_for
'processing error'
do
it
'raises a processing error'
do
expect
{
dashboard
}
.
to
raise_error
(
Gitlab
::
Metrics
::
Dashboard
::
Stages
::
InputFormatValidator
::
DashboardProcessingError
)
end
end
context
'when the datasource is not proxyable'
do
before
do
params
[
:datasource
][
:access
]
=
'not-proxy'
end
it_behaves_like
'processing error'
end
context
'when query param "panelId" is not specified'
do
before
do
params
[
:grafana_url
].
gsub!
(
'panelId=8'
,
''
)
end
it_behaves_like
'processing error'
end
context
'when query param "from" is not specified'
do
before
do
params
[
:grafana_url
].
gsub!
(
'from=1570397739557'
,
''
)
end
it_behaves_like
'processing error'
end
context
'when query param "to" is not specified'
do
before
do
params
[
:grafana_url
].
gsub!
(
'to=1570484139557'
,
''
)
end
it_behaves_like
'processing error'
end
context
'when the panel is not a graph'
do
before
do
params
[
:grafana_dashboard
][
:dashboard
][
:panels
][
0
][
:type
]
=
'singlestat'
end
it_behaves_like
'processing error'
end
context
'when the panel is not a line graph'
do
before
do
params
[
:grafana_dashboard
][
:dashboard
][
:panels
][
0
][
:lines
]
=
false
end
it_behaves_like
'processing error'
end
context
'when the query dashboard includes undefined variables'
do
before
do
params
[
:grafana_url
].
gsub!
(
'&var-instance=localhost:9121'
,
''
)
end
it_behaves_like
'processing error'
end
context
'when the expression contains unsupported global variables'
do
before
do
params
[
:grafana_dashboard
][
:dashboard
][
:panels
][
0
][
:targets
][
0
][
:expr
]
=
'sum(important_metric[$__interval_ms])'
end
it_behaves_like
'processing error'
end
end
end
end
spec/lib/grafana/client_spec.rb
View file @
664c4c7b
...
@@ -35,7 +35,7 @@ describe Grafana::Client do
...
@@ -35,7 +35,7 @@ describe Grafana::Client do
it
'does not follow redirects'
do
it
'does not follow redirects'
do
expect
{
subject
}.
to
raise_exception
(
expect
{
subject
}.
to
raise_exception
(
Grafana
::
Client
::
Error
,
Grafana
::
Client
::
Error
,
'Grafana response status code: 302'
'Grafana response status code: 302
, Message: {}
'
)
)
expect
(
redirect_req_stub
).
to
have_been_requested
expect
(
redirect_req_stub
).
to
have_been_requested
...
@@ -67,6 +67,30 @@ describe Grafana::Client do
...
@@ -67,6 +67,30 @@ describe Grafana::Client do
end
end
end
end
describe
'#get_dashboard'
do
let
(
:grafana_api_url
)
{
'https://grafanatest.com/-/grafana-project/api/dashboards/uid/FndfgnX'
}
subject
do
client
.
get_dashboard
(
uid:
'FndfgnX'
)
end
it_behaves_like
'calls grafana api'
it_behaves_like
'no redirects'
it_behaves_like
'handles exceptions'
end
describe
'#get_datasource'
do
let
(
:grafana_api_url
)
{
'https://grafanatest.com/-/grafana-project/api/datasources/name/Test%20Name'
}
subject
do
client
.
get_datasource
(
name:
'Test Name'
)
end
it_behaves_like
'calls grafana api'
it_behaves_like
'no redirects'
it_behaves_like
'handles exceptions'
end
describe
'#proxy_datasource'
do
describe
'#proxy_datasource'
do
let
(
:grafana_api_url
)
do
let
(
:grafana_api_url
)
do
'https://grafanatest.com/-/grafana-project/'
\
'https://grafanatest.com/-/grafana-project/'
\
...
...
spec/requests/api/branches_spec.rb
View file @
664c4c7b
...
@@ -602,7 +602,7 @@ describe API::Branches do
...
@@ -602,7 +602,7 @@ describe API::Branches do
post
api
(
route
,
user
),
params:
{
branch:
'new_design3'
,
ref:
'foo'
}
post
api
(
route
,
user
),
params:
{
branch:
'new_design3'
,
ref:
'foo'
}
expect
(
response
).
to
have_gitlab_http_status
(
400
)
expect
(
response
).
to
have_gitlab_http_status
(
400
)
expect
(
json_response
[
'message'
]).
to
eq
(
'Invalid reference name'
)
expect
(
json_response
[
'message'
]).
to
eq
(
'Invalid reference name
: new_design3
'
)
end
end
end
end
...
...
spec/services/create_branch_service_spec.rb
View file @
664c4c7b
...
@@ -22,5 +22,20 @@ describe CreateBranchService do
...
@@ -22,5 +22,20 @@ describe CreateBranchService do
expect
(
project
.
repository
.
branch_exists?
(
'my-feature'
)).
to
be_truthy
expect
(
project
.
repository
.
branch_exists?
(
'my-feature'
)).
to
be_truthy
end
end
end
end
context
'when creating a branch fails'
do
let
(
:project
)
{
create
(
:project_empty_repo
)
}
before
do
allow
(
project
.
repository
).
to
receive
(
:add_branch
).
and_return
(
false
)
end
it
'retruns an error with the branch name'
do
result
=
service
.
execute
(
'my-feature'
,
'master'
)
expect
(
result
[
:status
]).
to
eq
(
:error
)
expect
(
result
[
:message
]).
to
eq
(
"Invalid reference name: my-feature"
)
end
end
end
end
end
end
spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb
0 → 100644
View file @
664c4c7b
# frozen_string_literal: true
require
'spec_helper'
describe
Metrics
::
Dashboard
::
GrafanaMetricEmbedService
do
include
MetricsDashboardHelpers
include
ReactiveCachingHelpers
include
GrafanaApiHelpers
let_it_be
(
:project
)
{
build
(
:project
)
}
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:grafana_integration
)
{
create
(
:grafana_integration
,
project:
project
)
}
let
(
:grafana_url
)
do
valid_grafana_dashboard_link
(
grafana_integration
.
grafana_url
)
end
before
do
project
.
add_maintainer
(
user
)
end
describe
'.valid_params?'
do
let
(
:valid_params
)
{
{
embedded:
true
,
grafana_url:
grafana_url
}
}
subject
{
described_class
.
valid_params?
(
params
)
}
let
(
:params
)
{
valid_params
}
it
{
is_expected
.
to
be_truthy
}
context
'not embedded'
do
let
(
:params
)
{
valid_params
.
except
(
:embedded
)
}
it
{
is_expected
.
to
be_falsey
}
end
context
'undefined grafana_url'
do
let
(
:params
)
{
valid_params
.
except
(
:grafana_url
)
}
it
{
is_expected
.
to
be_falsey
}
end
end
describe
'.from_cache'
do
let
(
:params
)
{
[
project
.
id
,
user
.
id
,
grafana_url
]
}
subject
{
described_class
.
from_cache
(
*
params
)
}
it
'initializes an instance of GrafanaMetricEmbedService'
do
expect
(
subject
).
to
be_an_instance_of
(
described_class
)
expect
(
subject
.
project
).
to
eq
(
project
)
expect
(
subject
.
current_user
).
to
eq
(
user
)
expect
(
subject
.
params
[
:grafana_url
]).
to
eq
(
grafana_url
)
end
end
describe
'#get_dashboard'
,
:use_clean_rails_memory_store_caching
do
let
(
:service_params
)
do
[
project
,
user
,
{
embedded:
true
,
grafana_url:
grafana_url
}
]
end
let
(
:service
)
{
described_class
.
new
(
*
service_params
)
}
let
(
:service_call
)
{
service
.
get_dashboard
}
context
'without caching'
do
before
do
synchronous_reactive_cache
(
service
)
end
it_behaves_like
'raises error for users with insufficient permissions'
context
'without a grafana integration'
do
before
do
allow
(
project
).
to
receive
(
:grafana_integration
).
and_return
(
nil
)
end
it_behaves_like
'misconfigured dashboard service response'
,
:bad_request
end
context
'when grafana cannot be reached'
do
before
do
allow
(
grafana_integration
.
client
).
to
receive
(
:get_dashboard
).
and_raise
(
::
Grafana
::
Client
::
Error
)
end
it_behaves_like
'misconfigured dashboard service response'
,
:service_unavailable
end
context
'when panelId is missing'
do
let
(
:grafana_url
)
do
grafana_integration
.
grafana_url
+
'/d/XDaNK6amz/gitlab-omnibus-redis'
\
'?from=1570397739557&to=1570484139557'
end
before
do
stub_dashboard_request
(
grafana_integration
.
grafana_url
)
end
it_behaves_like
'misconfigured dashboard service response'
,
:unprocessable_entity
end
context
'when uid is missing'
do
let
(
:grafana_url
)
{
grafana_integration
.
grafana_url
+
'/d/'
}
before
do
stub_dashboard_request
(
grafana_integration
.
grafana_url
)
end
it_behaves_like
'misconfigured dashboard service response'
,
:unprocessable_entity
end
context
'when the dashboard response contains misconfigured json'
do
before
do
stub_dashboard_request
(
grafana_integration
.
grafana_url
,
body:
''
)
end
it_behaves_like
'misconfigured dashboard service response'
,
:unprocessable_entity
end
context
'when the datasource response contains misconfigured json'
do
before
do
stub_dashboard_request
(
grafana_integration
.
grafana_url
)
stub_datasource_request
(
grafana_integration
.
grafana_url
,
body:
''
)
end
it_behaves_like
'misconfigured dashboard service response'
,
:unprocessable_entity
end
context
'when the embed was created successfully'
do
before
do
stub_dashboard_request
(
grafana_integration
.
grafana_url
)
stub_datasource_request
(
grafana_integration
.
grafana_url
)
end
it_behaves_like
'valid embedded dashboard service response'
end
end
context
'with caching'
,
:use_clean_rails_memory_store_caching
do
let
(
:cache_params
)
{
[
project
.
id
,
user
.
id
,
grafana_url
]
}
context
'when value not present in cache'
do
it
'returns nil'
do
expect
(
ReactiveCachingWorker
)
.
to
receive
(
:perform_async
)
.
with
(
service
.
class
,
service
.
id
,
*
cache_params
)
expect
(
service_call
).
to
eq
(
nil
)
end
end
context
'when value present in cache'
do
let
(
:return_value
)
{
{
'http_status'
=>
:ok
,
'dashboard'
=>
'{}'
}
}
before
do
stub_reactive_cache
(
service
,
return_value
,
cache_params
)
end
it
'returns cached value'
do
expect
(
ReactiveCachingWorker
)
.
not_to
receive
(
:perform_async
)
.
with
(
service
.
class
,
service
.
id
,
*
cache_params
)
expect
(
service_call
[
:http_status
]).
to
eq
(
return_value
[
:http_status
])
expect
(
service_call
[
:dashboard
]).
to
eq
(
return_value
[
:dashboard
])
end
end
end
end
end
spec/support/helpers/grafana_api_helpers.rb
0 → 100644
View file @
664c4c7b
# frozen_string_literal: true
module
GrafanaApiHelpers
def
valid_grafana_dashboard_link
(
base_url
)
base_url
+
'/d/XDaNK6amz/gitlab-omnibus-redis'
\
'?from=1570397739557&to=1570484139557'
\
'&var-instance=localhost:9121&panelId=8'
end
def
stub_dashboard_request
(
base_url
,
path:
'/api/dashboards/uid/XDaNK6amz'
,
body:
nil
)
body
||=
fixture_file
(
'grafana/dashboard_response.json'
)
stub_request
(
:get
,
"
#{
base_url
}#{
path
}
"
)
.
to_return
(
status:
200
,
body:
body
,
headers:
{
'Content-Type'
=>
'application/json'
}
)
end
def
stub_datasource_request
(
base_url
,
path:
'/api/datasources/name/GitLab%20Omnibus'
,
body:
nil
)
body
||=
fixture_file
(
'grafana/datasource_response.json'
)
stub_request
(
:get
,
"
#{
base_url
}#{
path
}
"
)
.
to_return
(
status:
200
,
body:
body
,
headers:
{
'Content-Type'
=>
'application/json'
}
)
end
end
spec/support/helpers/login_helpers.rb
View file @
664c4c7b
...
@@ -53,7 +53,7 @@ module LoginHelpers
...
@@ -53,7 +53,7 @@ module LoginHelpers
fill_in
'password'
,
with:
user
.
password
fill_in
'password'
,
with:
user
.
password
click_button
'Enter
admin m
ode'
click_button
'Enter
Admin M
ode'
end
end
def
gitlab_sign_in_via
(
provider
,
user
,
uid
,
saml_response
=
nil
)
def
gitlab_sign_in_via
(
provider
,
user
,
uid
,
saml_response
=
nil
)
...
...
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