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
1ca9950d
Commit
1ca9950d
authored
Feb 11, 2020
by
GitLab Bot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add latest changes from gitlab-org/gitlab@master
parent
bcc77054
Changes
66
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
66 changed files
with
1007 additions
and
806 deletions
+1007
-806
app/controllers/admin/services_controller.rb
app/controllers/admin/services_controller.rb
+6
-6
app/controllers/projects/serverless/functions_controller.rb
app/controllers/projects/serverless/functions_controller.rb
+11
-4
app/finders/projects/serverless/functions_finder.rb
app/finders/projects/serverless/functions_finder.rb
+12
-4
app/graphql/types/snippets/blob_type.rb
app/graphql/types/snippets/blob_type.rb
+4
-0
app/models/clusters/cluster.rb
app/models/clusters/cluster.rb
+6
-0
app/models/pages_domain.rb
app/models/pages_domain.rb
+4
-0
app/models/project.rb
app/models/project.rb
+7
-7
app/models/project_services/issue_tracker_service.rb
app/models/project_services/issue_tracker_service.rb
+1
-1
app/models/project_services/prometheus_service.rb
app/models/project_services/prometheus_service.rb
+1
-1
app/models/service.rb
app/models/service.rb
+12
-8
app/presenters/snippet_blob_presenter.rb
app/presenters/snippet_blob_presenter.rb
+7
-5
app/serializers/projects/serverless/service_entity.rb
app/serializers/projects/serverless/service_entity.rb
+14
-74
app/services/projects/create_service.rb
app/services/projects/create_service.rb
+4
-4
app/services/projects/propagate_service_template.rb
app/services/projects/propagate_service_template.rb
+14
-14
app/views/projects/services/mattermost_slash_commands/_help.html.haml
...ojects/services/mattermost_slash_commands/_help.html.haml
+2
-2
app/views/projects/services/slack_slash_commands/_help.html.haml
...ws/projects/services/slack_slash_commands/_help.html.haml
+1
-1
app/workers/all_queues.yml
app/workers/all_queues.yml
+1
-1
app/workers/pages_domain_removal_cron_worker.rb
app/workers/pages_domain_removal_cron_worker.rb
+3
-3
app/workers/pages_domain_ssl_renewal_cron_worker.rb
app/workers/pages_domain_ssl_renewal_cron_worker.rb
+5
-3
app/workers/pages_domain_verification_cron_worker.rb
app/workers/pages_domain_verification_cron_worker.rb
+5
-3
app/workers/propagate_service_template_worker.rb
app/workers/propagate_service_template_worker.rb
+26
-0
changelogs/unreleased/fj-add-plain-data-field-to-snippet-blob-type-endpoint.yml
...fj-add-plain-data-field-to-snippet-blob-type-endpoint.yml
+5
-0
changelogs/unreleased/rename_services_template_to_instance.yml
...elogs/unreleased/rename_services_template_to_instance.yml
+0
-5
config/sidekiq_queues.yml
config/sidekiq_queues.yml
+1
-1
db/migrate/20200123092602_rename_services_template_to_instance.rb
...te/20200123092602_rename_services_template_to_instance.rb
+0
-17
db/post_migrate/20191021101942_remove_empty_github_service_templates.rb
...e/20191021101942_remove_empty_github_service_templates.rb
+0
-4
db/post_migrate/20200123101859_cleanup_rename_services_template_to_instance.rb
...123101859_cleanup_rename_services_template_to_instance.rb
+0
-17
db/post_migrate/20200206111847_migrate_propagate_service_template_sidekiq_queue.rb
...11847_migrate_propagate_service_template_sidekiq_queue.rb
+0
-15
db/schema.rb
db/schema.rb
+2
-2
doc/api/graphql/reference/gitlab_schema.graphql
doc/api/graphql/reference/gitlab_schema.graphql
+5
-0
doc/api/graphql/reference/gitlab_schema.json
doc/api/graphql/reference/gitlab_schema.json
+14
-0
doc/api/graphql/reference/index.md
doc/api/graphql/reference/index.md
+1
-0
lib/api/services.rb
lib/api/services.rb
+1
-1
lib/gitlab/import_export/import_export.yml
lib/gitlab/import_export/import_export.yml
+1
-1
lib/gitlab/serverless/service.rb
lib/gitlab/serverless/service.rb
+98
-0
lib/gitlab/usage_data.rb
lib/gitlab/usage_data.rb
+1
-1
qa/qa.rb
qa/qa.rb
+1
-0
qa/qa/vendor/jenkins/page/job.rb
qa/qa/vendor/jenkins/page/job.rb
+23
-0
spec/controllers/admin/services_controller_spec.rb
spec/controllers/admin/services_controller_spec.rb
+6
-6
spec/controllers/projects/serverless/functions_controller_spec.rb
...trollers/projects/serverless/functions_controller_spec.rb
+91
-14
spec/controllers/projects/services_controller_spec.rb
spec/controllers/projects/services_controller_spec.rb
+3
-3
spec/factories/pages_domains.rb
spec/factories/pages_domains.rb
+4
-0
spec/finders/projects/serverless/functions_finder_spec.rb
spec/finders/projects/serverless/functions_finder_spec.rb
+2
-2
spec/fixtures/trace/sample_trace
spec/fixtures/trace/sample_trace
+1
-1
spec/frontend/environments/environments_app_spec.js
spec/frontend/environments/environments_app_spec.js
+168
-0
spec/frontend/monitoring/components/dashboard_spec.js
spec/frontend/monitoring/components/dashboard_spec.js
+77
-123
spec/frontend/monitoring/components/dashboards_dropdown_spec.js
...rontend/monitoring/components/dashboards_dropdown_spec.js
+25
-38
spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js
...nd/monitoring/components/duplicate_dashboard_form_spec.js
+14
-21
spec/frontend/monitoring/components/graph_group_spec.js
spec/frontend/monitoring/components/graph_group_spec.js
+6
-9
spec/frontend/monitoring/components/panel_type_spec.js
spec/frontend/monitoring/components/panel_type_spec.js
+7
-7
spec/graphql/types/snippets/blob_type_spec.rb
spec/graphql/types/snippets/blob_type_spec.rb
+3
-4
spec/javascripts/environments/environments_app_spec.js
spec/javascripts/environments/environments_app_spec.js
+0
-279
spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+2
-2
spec/lib/gitlab/import_export/safe_model_attributes.yml
spec/lib/gitlab/import_export/safe_model_attributes.yml
+1
-1
spec/lib/gitlab/serverless/service_spec.rb
spec/lib/gitlab/serverless/service_spec.rb
+134
-0
spec/lib/gitlab/usage_data_spec.rb
spec/lib/gitlab/usage_data_spec.rb
+1
-1
spec/migrations/migrate_propagate_service_template_sidekiq_queue_spec.rb
.../migrate_propagate_service_template_sidekiq_queue_spec.rb
+0
-29
spec/models/service_spec.rb
spec/models/service_spec.rb
+30
-22
spec/presenters/snippet_blob_presenter_spec.rb
spec/presenters/snippet_blob_presenter_spec.rb
+36
-2
spec/services/projects/create_service_spec.rb
spec/services/projects/create_service_spec.rb
+7
-7
spec/services/projects/propagate_service_template_spec.rb
spec/services/projects/propagate_service_template_spec.rb
+18
-18
spec/support/helpers/kubernetes_helpers.rb
spec/support/helpers/kubernetes_helpers.rb
+8
-8
spec/support/shared_examples/workers/pages_domain_cron_worker_shared_examples.rb
...mples/workers/pages_domain_cron_worker_shared_examples.rb
+21
-0
spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb
spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb
+6
-2
spec/workers/pages_domain_verification_cron_worker_spec.rb
spec/workers/pages_domain_verification_cron_worker_spec.rb
+6
-2
spec/workers/propagate_service_template_worker_spec.rb
spec/workers/propagate_service_template_worker_spec.rb
+31
-0
No files found.
app/controllers/admin/services_controller.rb
View file @
1ca9950d
...
...
@@ -7,7 +7,7 @@ class Admin::ServicesController < Admin::ApplicationController
before_action
:service
,
only:
[
:edit
,
:update
]
def
index
@services
=
instance_level_servic
es
@services
=
services_templat
es
end
def
edit
...
...
@@ -19,7 +19,7 @@ class Admin::ServicesController < Admin::ApplicationController
def
update
if
service
.
update
(
service_params
[
:service
])
Propagate
InstanceLevelServic
eWorker
.
perform_async
(
service
.
id
)
if
service
.
active?
Propagate
ServiceTemplat
eWorker
.
perform_async
(
service
.
id
)
if
service
.
active?
redirect_to
admin_application_settings_services_path
,
notice:
'Application settings saved successfully'
...
...
@@ -31,17 +31,17 @@ class Admin::ServicesController < Admin::ApplicationController
private
# rubocop: disable CodeReuse/ActiveRecord
def
instance_level_servic
es
def
services_templat
es
Service
.
available_services_names
.
map
do
|
service_name
|
service
=
"
#{
service_name
}
_service"
.
camelize
.
constantize
service
.
where
(
instanc
e:
true
).
first_or_create
service
_template
=
"
#{
service_name
}
_service"
.
camelize
.
constantize
service
_template
.
where
(
templat
e:
true
).
first_or_create
end
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def
service
@service
||=
Service
.
where
(
id:
params
[
:id
],
instanc
e:
true
).
first
@service
||=
Service
.
where
(
id:
params
[
:id
],
templat
e:
true
).
first
end
# rubocop: enable CodeReuse/ActiveRecord
...
...
app/controllers/projects/serverless/functions_controller.rb
View file @
1ca9950d
...
...
@@ -8,11 +8,15 @@ module Projects
def
index
respond_to
do
|
format
|
format
.
json
do
functions
=
finder
.
execute
functions
=
finder
.
execute
.
select
do
|
function
|
can?
(
@current_user
,
:read_cluster
,
function
.
cluster
)
end
serialized_functions
=
serialize_function
(
functions
)
render
json:
{
knative_installed:
finder
.
knative_installed
,
functions:
serialize
_function
(
functions
)
functions:
serialize
d_functions
}.
to_json
end
...
...
@@ -23,11 +27,14 @@ module Projects
end
def
show
@service
=
serialize_function
(
finder
.
service
(
params
[
:environment_id
],
params
[
:id
])
)
@prometheus
=
finder
.
has_prometheus?
(
params
[
:environment_id
]
)
function
=
finder
.
service
(
params
[
:environment_id
],
params
[
:id
]
)
return
not_found
unless
function
&&
can?
(
@current_user
,
:read_cluster
,
function
.
cluster
)
@service
=
serialize_function
(
function
)
return
not_found
if
@service
.
nil?
@prometheus
=
finder
.
has_prometheus?
(
params
[
:environment_id
])
respond_to
do
|
format
|
format
.
json
do
render
json:
@service
...
...
app/finders/projects/serverless/functions_finder.rb
View file @
1ca9950d
...
...
@@ -93,24 +93,32 @@ module Projects
.
services
.
select
{
|
svc
|
svc
[
"metadata"
][
"name"
]
==
name
}
add_metadata
(
finder
,
services
).
first
unless
services
.
nil?
attributes
=
add_metadata
(
finder
,
services
).
first
next
unless
attributes
Gitlab
::
Serverless
::
Service
.
new
(
attributes
)
end
end
def
knative_services
services_finders
.
map
do
|
finder
|
services
=
finder
.
services
attributes
=
add_metadata
(
finder
,
finder
.
services
)
add_metadata
(
finder
,
services
)
unless
services
.
nil?
attributes
&
.
map
do
|
attributes
|
Gitlab
::
Serverless
::
Service
.
new
(
attributes
)
end
end
end
def
add_metadata
(
finder
,
services
)
return
if
services
.
nil?
add_pod_count
=
services
.
one?
services
.
each
do
|
s
|
s
[
"environment_scope"
]
=
finder
.
cluster
.
environment_scope
s
[
"cluster_id"
]
=
finder
.
cluster
.
id
s
[
"environment"
]
=
finder
.
environment
s
[
"cluster"
]
=
finder
.
cluster
if
add_pod_count
s
[
"podcount"
]
=
finder
...
...
app/graphql/types/snippets/blob_type.rb
View file @
1ca9950d
...
...
@@ -12,6 +12,10 @@ module Types
description:
'Blob highlighted data'
,
null:
true
field
:plain_highlighted_data
,
GraphQL
::
STRING_TYPE
,
description:
'Blob plain highlighted data'
,
null:
true
field
:raw_path
,
GraphQL
::
STRING_TYPE
,
description:
'Blob raw content endpoint path'
,
null:
false
...
...
app/models/clusters/cluster.rb
View file @
1ca9950d
...
...
@@ -290,6 +290,12 @@ module Clusters
end
end
def
serverless_domain
strong_memoize
(
:serverless_domain
)
do
self
.
application_knative
&
.
serverless_domain_cluster
end
end
private
def
unique_management_project_environment_scope
...
...
app/models/pages_domain.rb
View file @
1ca9950d
...
...
@@ -62,6 +62,8 @@ class PagesDomain < ApplicationRecord
scope
:for_removal
,
->
{
where
(
"remove_at < ?"
,
Time
.
now
)
}
scope
:with_logging_info
,
->
{
includes
(
project:
[
:namespace
,
:route
])
}
def
verified?
!!
verified_at
end
...
...
@@ -285,3 +287,5 @@ class PagesDomain < ApplicationRecord
!
auto_ssl_enabled?
&&
project
&
.
pages_https_only?
end
end
PagesDomain
.
prepend_if_ee
(
'::EE::PagesDomain'
)
app/models/project.rb
View file @
1ca9950d
...
...
@@ -1224,13 +1224,13 @@ class Project < ApplicationRecord
service
=
find_service
(
services
,
name
)
return
service
if
service
# We should check if
an instance-level
service exists
instance_level_service
=
find_service
(
instance_level_servic
es
,
name
)
# We should check if
template for the
service exists
template
=
find_service
(
services_templat
es
,
name
)
if
instance_level_servic
e
Service
.
build_from_
instance
(
id
,
instance_level_servic
e
)
if
templat
e
Service
.
build_from_
template
(
id
,
templat
e
)
else
# If no
instance-level service exists, we should create a new servi
ce. Ex `build_gitlab_ci_service`
# If no
template, we should create an instan
ce. Ex `build_gitlab_ci_service`
public_send
(
"build_
#{
name
}
_service"
)
# rubocop:disable GitlabSecurity/PublicSend
end
end
...
...
@@ -2460,8 +2460,8 @@ class Project < ApplicationRecord
end
end
def
instance_level_servic
es
@
instance_level_services
||=
Service
.
where
(
instanc
e:
true
)
def
services_templat
es
@
services_templates
||=
Service
.
where
(
templat
e:
true
)
end
def
ensure_pages_metadatum
...
...
app/models/project_services/issue_tracker_service.rb
View file @
1ca9950d
...
...
@@ -164,7 +164,7 @@ class IssueTrackerService < Service
end
def
one_issue_tracker
return
if
instanc
e?
return
if
templat
e?
return
if
project
.
blank?
if
project
.
services
.
external_issue_trackers
.
where
.
not
(
id:
id
).
any?
...
...
app/models/project_services/prometheus_service.rb
View file @
1ca9950d
...
...
@@ -85,7 +85,7 @@ class PrometheusService < MonitoringService
end
def
prometheus_available?
return
false
if
instanc
e?
return
false
if
templat
e?
return
false
unless
project
project
.
all_clusters
.
enabled
.
any?
{
|
cluster
|
cluster
.
application_prometheus_available?
}
...
...
app/models/service.rb
View file @
1ca9950d
...
...
@@ -32,7 +32,7 @@ class Service < ApplicationRecord
belongs_to
:project
,
inverse_of: :services
has_one
:service_hook
validates
:project_id
,
presence:
true
,
unless:
proc
{
|
service
|
service
.
instanc
e?
}
validates
:project_id
,
presence:
true
,
unless:
proc
{
|
service
|
service
.
templat
e?
}
validates
:type
,
presence:
true
scope
:visible
,
->
{
where
.
not
(
type:
'GitlabIssueTrackerService'
)
}
...
...
@@ -70,8 +70,8 @@ class Service < ApplicationRecord
true
end
def
instanc
e?
instanc
e
def
templat
e?
templat
e
end
def
category
...
...
@@ -299,15 +299,15 @@ class Service < ApplicationRecord
service_names
.
sort_by
(
&
:downcase
)
end
def
self
.
build_from_
instance
(
project_id
,
instance_level_servic
e
)
service
=
instance_level_servic
e
.
dup
def
self
.
build_from_
template
(
project_id
,
templat
e
)
service
=
templat
e
.
dup
if
instance_level_servic
e
.
supports_data_fields?
data_fields
=
instance_level_servic
e
.
data_fields
.
dup
if
templat
e
.
supports_data_fields?
data_fields
=
templat
e
.
data_fields
.
dup
data_fields
.
service
=
service
end
service
.
instanc
e
=
false
service
.
templat
e
=
false
service
.
project_id
=
project_id
service
.
active
=
false
if
service
.
active?
&&
!
service
.
valid?
service
...
...
@@ -321,6 +321,10 @@ class Service < ApplicationRecord
nil
end
def
self
.
find_by_template
find_by
(
template:
true
)
end
# override if needed
def
supports_data_fields?
false
...
...
app/presenters/snippet_blob_presenter.rb
View file @
1ca9950d
...
...
@@ -4,11 +4,13 @@ class SnippetBlobPresenter < BlobPresenter
def
highlighted_data
return
if
blob
.
binary?
if
blob
.
rich_viewer
&
.
partial_name
==
'markup'
blob
.
rendered_markup
else
highlight
end
highlight
(
plain:
false
)
end
def
plain_highlighted_data
return
if
blob
.
binary?
highlight
(
plain:
true
)
end
def
raw_path
...
...
app/serializers/projects/serverless/service_entity.rb
View file @
1ca9950d
...
...
@@ -5,91 +5,31 @@ module Projects
class
ServiceEntity
<
Grape
::
Entity
include
RequestAwareEntity
expose
:name
do
|
service
|
service
.
dig
(
'metadata'
,
'name'
)
end
expose
:namespace
do
|
service
|
service
.
dig
(
'metadata'
,
'namespace'
)
end
expose
:environment_scope
do
|
service
|
service
.
dig
(
'environment_scope'
)
end
expose
:cluster_id
do
|
service
|
service
.
dig
(
'cluster_id'
)
end
expose
:name
expose
:namespace
expose
:environment_scope
expose
:podcount
expose
:created_at
expose
:image
expose
:description
expose
:url
expose
:detail_url
do
|
service
|
project_serverless_path
(
request
.
project
,
service
.
dig
(
'environment_scope'
),
service
.
dig
(
'metadata'
,
'name'
))
end
expose
:podcount
do
|
service
|
service
.
dig
(
'podcount'
)
service
.
environment_scope
,
service
.
name
)
end
expose
:metrics_url
do
|
service
|
project_serverless_metrics_path
(
request
.
project
,
service
.
dig
(
'environment_scope'
),
service
.
dig
(
'metadata'
,
'name'
))
+
".json"
end
expose
:created_at
do
|
service
|
service
.
dig
(
'metadata'
,
'creationTimestamp'
)
end
expose
:url
do
|
service
|
knative_06_07_url
(
service
)
||
knative_05_url
(
service
)
end
expose
:description
do
|
service
|
knative_07_description
(
service
)
||
knative_05_06_description
(
service
)
service
.
environment_scope
,
service
.
name
,
format: :json
)
end
expose
:image
do
|
service
|
service
.
dig
(
'spec'
,
'runLatest'
,
'configuration'
,
'build'
,
'template'
,
'name'
)
end
private
def
knative_07_description
(
service
)
service
.
dig
(
'spec'
,
'template'
,
'metadata'
,
'annotations'
,
'Description'
)
end
def
knative_05_url
(
service
)
"http://
#{
service
.
dig
(
'status'
,
'domain'
)
}
"
end
def
knative_06_07_url
(
service
)
service
.
dig
(
'status'
,
'url'
)
end
def
knative_05_06_description
(
service
)
service
.
dig
(
'spec'
,
'runLatest'
,
'configuration'
,
'revisionTemplate'
,
'metadata'
,
'annotations'
,
'Description'
)
expose
:cluster_id
do
|
service
|
service
.
cluster
&
.
id
end
end
end
...
...
app/services/projects/create_service.rb
View file @
1ca9950d
...
...
@@ -135,7 +135,7 @@ module Projects
if
@project
.
save
unless
@project
.
gitlab_project_import?
create_services_from_active_
instance_level_servic
es
(
@project
)
create_services_from_active_
templat
es
(
@project
)
@project
.
create_labels
end
...
...
@@ -161,9 +161,9 @@ module Projects
end
# rubocop: disable CodeReuse/ActiveRecord
def
create_services_from_active_
instance_level_servic
es
(
project
)
Service
.
where
(
instanc
e:
true
,
active:
true
).
each
do
|
template
|
service
=
Service
.
build_from_
instanc
e
(
project
.
id
,
template
)
def
create_services_from_active_
templat
es
(
project
)
Service
.
where
(
templat
e:
true
,
active:
true
).
each
do
|
template
|
service
=
Service
.
build_from_
templat
e
(
project
.
id
,
template
)
service
.
save!
end
end
...
...
app/services/projects/propagate_
instance_level_servic
e.rb
→
app/services/projects/propagate_
service_templat
e.rb
View file @
1ca9950d
# frozen_string_literal: true
module
Projects
class
Propagate
InstanceLevelServic
e
class
Propagate
ServiceTemplat
e
BATCH_SIZE
=
100
def
self
.
propagate
(
*
args
)
new
(
*
args
).
propagate
end
def
initialize
(
instance_level_servic
e
)
@
instance_level_service
=
instance_level_servic
e
def
initialize
(
templat
e
)
@
template
=
templat
e
end
def
propagate
return
unless
@
instance_level_servic
e
.
active?
return
unless
@
templat
e
.
active?
Rails
.
logger
.
info
(
"Propagating services for
instance_level_service
#{
@instance_level_servic
e
.
id
}
"
)
# rubocop:disable Gitlab/RailsLogger
Rails
.
logger
.
info
(
"Propagating services for
template
#{
@templat
e
.
id
}
"
)
# rubocop:disable Gitlab/RailsLogger
propagate_projects_with_
instance_level_servic
e
propagate_projects_with_
templat
e
end
private
def
propagate_projects_with_
instance_level_servic
e
def
propagate_projects_with_
templat
e
loop
do
batch
=
Project
.
uncached
{
project_ids_batch
}
bulk_create_from_
instance_level_servic
e
(
batch
)
unless
batch
.
empty?
bulk_create_from_
templat
e
(
batch
)
unless
batch
.
empty?
break
if
batch
.
size
<
BATCH_SIZE
end
end
def
bulk_create_from_
instance_level_servic
e
(
batch
)
def
bulk_create_from_
templat
e
(
batch
)
service_list
=
batch
.
map
do
|
project_id
|
service_hash
.
values
<<
project_id
end
...
...
@@ -52,7 +52,7 @@ module Projects
SELECT true
FROM services
WHERE services.project_id = projects.id
AND services.type = '
#{
@
instance_level_servic
e
.
type
}
'
AND services.type = '
#{
@
templat
e
.
type
}
'
)
AND projects.pending_delete = false
AND projects.archived = false
...
...
@@ -73,9 +73,9 @@ module Projects
def
service_hash
@service_hash
||=
begin
instance_hash
=
@instance_level_service
.
as_json
(
methods: :type
).
except
(
'id'
,
'instanc
e'
,
'project_id'
)
template_hash
=
@template
.
as_json
(
methods: :type
).
except
(
'id'
,
'templat
e'
,
'project_id'
)
instanc
e_hash
.
each_with_object
({})
do
|
(
key
,
value
),
service_hash
|
templat
e_hash
.
each_with_object
({})
do
|
(
key
,
value
),
service_hash
|
value
=
value
.
is_a?
(
Hash
)
?
value
.
to_json
:
value
service_hash
[
ActiveRecord
::
Base
.
connection
.
quote_column_name
(
key
)]
=
...
...
@@ -97,11 +97,11 @@ module Projects
# rubocop: enable CodeReuse/ActiveRecord
def
active_external_issue_tracker?
@
instance_level_service
.
issue_tracker?
&&
!
@instance_level_servic
e
.
default
@
template
.
issue_tracker?
&&
!
@templat
e
.
default
end
def
active_external_wiki?
@
instance_level_servic
e
.
type
==
'ExternalWikiService'
@
templat
e
.
type
==
'ExternalWikiService'
end
end
end
app/views/projects/services/mattermost_slash_commands/_help.html.haml
View file @
1ca9950d
...
...
@@ -10,8 +10,8 @@
%p
.inline
=
s_
(
"MattermostService|See list of available commands in Mattermost after setting up this service, by entering"
)
%kbd
.inline
/
<
trigger
>
help
-
unless
enabled
||
@service
.
instanc
e?
-
unless
enabled
||
@service
.
templat
e?
=
render
'projects/services/mattermost_slash_commands/detailed_help'
,
subject:
@service
-
if
enabled
&&
!
@service
.
instanc
e?
-
if
enabled
&&
!
@service
.
templat
e?
=
render
'projects/services/mattermost_slash_commands/installation_info'
,
subject:
@service
app/views/projects/services/slack_slash_commands/_help.html.haml
View file @
1ca9950d
...
...
@@ -11,7 +11,7 @@
%p
.inline
=
s_
(
"SlackService|See list of available commands in Slack after setting up this service, by entering"
)
%kbd
.inline
/
<
command
>
help
-
unless
@service
.
instanc
e?
-
unless
@service
.
templat
e?
%p
=
_
(
"To set up this service:"
)
%ul
.list-unstyled.indent-list
%li
...
...
app/workers/all_queues.yml
View file @
1ca9950d
...
...
@@ -969,7 +969,7 @@
:latency_sensitive:
:resource_boundary: :unknown
:weight:
1
-
:name: propagate_
instance_level_servic
e
-
:name: propagate_
service_templat
e
:feature_category: :source_code_management
:has_external_dependencies:
:latency_sensitive:
...
...
app/workers/pages_domain_removal_cron_worker.rb
View file @
1ca9950d
...
...
@@ -2,14 +2,14 @@
class
PagesDomainRemovalCronWorker
include
ApplicationWorker
include
CronjobQueue
# rubocop:disable Scalability/CronWorkerContext
include
CronjobQueue
feature_category
:pages
worker_resource_boundary
:cpu
def
perform
PagesDomain
.
for_removal
.
find_each
do
|
domain
|
domain
.
destroy!
PagesDomain
.
for_removal
.
with_logging_info
.
find_each
do
|
domain
|
with_context
(
project:
domain
.
project
)
{
domain
.
destroy!
}
rescue
=>
e
Gitlab
::
ErrorTracking
.
track_exception
(
e
)
end
...
...
app/workers/pages_domain_ssl_renewal_cron_worker.rb
View file @
1ca9950d
...
...
@@ -2,15 +2,17 @@
class
PagesDomainSslRenewalCronWorker
include
ApplicationWorker
include
CronjobQueue
# rubocop:disable Scalability/CronWorkerContext
include
CronjobQueue
feature_category
:pages
def
perform
return
unless
::
Gitlab
::
LetsEncrypt
.
enabled?
PagesDomain
.
need_auto_ssl_renewal
.
find_each
do
|
domain
|
PagesDomainSslRenewalWorker
.
perform_async
(
domain
.
id
)
PagesDomain
.
need_auto_ssl_renewal
.
with_logging_info
.
find_each
do
|
domain
|
with_context
(
project:
domain
.
project
)
do
PagesDomainSslRenewalWorker
.
perform_async
(
domain
.
id
)
end
end
end
end
app/workers/pages_domain_verification_cron_worker.rb
View file @
1ca9950d
...
...
@@ -2,15 +2,17 @@
class
PagesDomainVerificationCronWorker
include
ApplicationWorker
include
CronjobQueue
# rubocop:disable Scalability/CronWorkerContext
include
CronjobQueue
feature_category
:pages
def
perform
return
if
Gitlab
::
Database
.
read_only?
PagesDomain
.
needs_verification
.
find_each
do
|
domain
|
PagesDomainVerificationWorker
.
perform_async
(
domain
.
id
)
PagesDomain
.
needs_verification
.
with_logging_info
.
find_each
do
|
domain
|
with_context
(
project:
domain
.
project
)
do
PagesDomainVerificationWorker
.
perform_async
(
domain
.
id
)
end
end
end
end
app/workers/propagate_
instance_level_servic
e_worker.rb
→
app/workers/propagate_
service_templat
e_worker.rb
View file @
1ca9950d
# frozen_string_literal: true
# Worker for updating any project specific caches.
class
Propagate
InstanceLevelServic
eWorker
class
Propagate
ServiceTemplat
eWorker
include
ApplicationWorker
feature_category
:source_code_management
...
...
@@ -9,18 +9,18 @@ class PropagateInstanceLevelServiceWorker
LEASE_TIMEOUT
=
4
.
hours
.
to_i
# rubocop: disable CodeReuse/ActiveRecord
def
perform
(
instance_level_servic
e_id
)
return
unless
try_obtain_lease_for
(
instance_level_servic
e_id
)
def
perform
(
templat
e_id
)
return
unless
try_obtain_lease_for
(
templat
e_id
)
Projects
::
Propagate
InstanceLevelService
.
propagate
(
Service
.
find_by
(
id:
instance_level_servic
e_id
))
Projects
::
Propagate
ServiceTemplate
.
propagate
(
Service
.
find_by
(
id:
templat
e_id
))
end
# rubocop: enable CodeReuse/ActiveRecord
private
def
try_obtain_lease_for
(
instance_level_servic
e_id
)
def
try_obtain_lease_for
(
templat
e_id
)
Gitlab
::
ExclusiveLease
.
new
(
"propagate_
instance_level_service_worker:
#{
instance_level_servic
e_id
}
"
,
timeout:
LEASE_TIMEOUT
)
.
new
(
"propagate_
service_template_worker:
#{
templat
e_id
}
"
,
timeout:
LEASE_TIMEOUT
)
.
try_obtain
end
end
changelogs/unreleased/fj-add-plain-data-field-to-snippet-blob-type-endpoint.yml
0 → 100644
View file @
1ca9950d
---
title
:
Add plain_highlighted_data field to SnippetBlobType
merge_request
:
24856
author
:
type
:
changed
changelogs/unreleased/rename_services_template_to_instance.yml
deleted
100644 → 0
View file @
bcc77054
---
title
:
'
Service
model:
Rename
template
attribute
to
instance'
merge_request
:
23595
author
:
type
:
other
config/sidekiq_queues.yml
View file @
1ca9950d
...
...
@@ -194,7 +194,7 @@
-
1
-
-
project_update_repository_storage
-
1
-
-
propagate_
instance_level_servic
e
-
-
propagate_
service_templat
e
-
1
-
-
reactive_caching
-
1
...
...
db/migrate/20200123092602_rename_services_template_to_instance.rb
deleted
100644 → 0
View file @
bcc77054
# frozen_string_literal: true
class
RenameServicesTemplateToInstance
<
ActiveRecord
::
Migration
[
5.2
]
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
disable_ddl_transaction!
def
up
rename_column_concurrently
:services
,
:template
,
:instance
end
def
down
undo_rename_column_concurrently
:services
,
:template
,
:instance
end
end
db/post_migrate/20191021101942_remove_empty_github_service_templates.rb
View file @
1ca9950d
...
...
@@ -23,10 +23,6 @@ class RemoveEmptyGithubServiceTemplates < ActiveRecord::Migration[5.2]
private
def
relationship
# The column `template` was renamed to `instance`. Column information needs
# to be resetted to avoid cache problems after migrating down.
RemoveEmptyGithubServiceTemplates
::
Service
.
reset_column_information
RemoveEmptyGithubServiceTemplates
::
Service
.
where
(
template:
true
,
type:
'GithubService'
)
end
end
db/post_migrate/20200123101859_cleanup_rename_services_template_to_instance.rb
deleted
100644 → 0
View file @
bcc77054
# frozen_string_literal: true
class
CleanupRenameServicesTemplateToInstance
<
ActiveRecord
::
Migration
[
5.2
]
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
disable_ddl_transaction!
def
up
cleanup_concurrent_column_rename
:services
,
:template
,
:instance
end
def
down
undo_cleanup_concurrent_column_rename
:services
,
:template
,
:instance
end
end
db/post_migrate/20200206111847_migrate_propagate_service_template_sidekiq_queue.rb
deleted
100644 → 0
View file @
bcc77054
# frozen_string_literal: true
class
MigratePropagateServiceTemplateSidekiqQueue
<
ActiveRecord
::
Migration
[
6.0
]
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
def
up
sidekiq_queue_migrate
'propagate_service_template'
,
to:
'propagate_instance_level_service'
end
def
down
sidekiq_queue_migrate
'propagate_instance_level_service'
,
to:
'propagate_service_template'
end
end
db/schema.rb
View file @
1ca9950d
...
...
@@ -3858,9 +3858,9 @@ ActiveRecord::Schema.define(version: 2020_02_07_151640) do
t
.
boolean
"deployment_events"
,
default:
false
,
null:
false
t
.
string
"description"
,
limit:
500
t
.
boolean
"comment_on_event_enabled"
,
default:
true
,
null:
false
t
.
boolean
"instance"
,
default:
false
t
.
index
[
"instance"
],
name:
"index_services_on_instance"
t
.
boolean
"template"
,
default:
false
t
.
index
[
"project_id"
],
name:
"index_services_on_project_id"
t
.
index
[
"template"
],
name:
"index_services_on_template"
t
.
index
[
"type"
],
name:
"index_services_on_type"
end
...
...
doc/api/graphql/reference/gitlab_schema.graphql
View file @
1ca9950d
...
...
@@ -6777,6 +6777,11 @@ type SnippetBlob {
"""
path
:
String
"""
Blob
plain
highlighted
data
"""
plainHighlightedData
:
String
"""
Blob
raw
content
endpoint
path
"""
...
...
doc/api/graphql/reference/gitlab_schema.json
View file @
1ca9950d
...
...
@@ -7612,6 +7612,20 @@
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"plainHighlightedData"
,
"description"
:
"Blob plain highlighted data"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"rawPath"
,
"description"
:
"Blob raw content endpoint path"
,
...
...
doc/api/graphql/reference/index.md
View file @
1ca9950d
...
...
@@ -1071,6 +1071,7 @@ Represents the snippet blob
|
`mode`
| String | Blob mode |
|
`name`
| String | Blob name |
|
`path`
| String | Blob path |
|
`plainHighlightedData`
| String | Blob plain highlighted data |
|
`rawPath`
| String! | Blob raw content endpoint path |
|
`richViewer`
| SnippetBlobViewer | Blob content rich viewer |
|
`simpleViewer`
| SnippetBlobViewer! | Blob content simple viewer |
...
...
lib/api/services.rb
View file @
1ca9950d
...
...
@@ -132,7 +132,7 @@ module API
helpers
do
# rubocop: disable CodeReuse/ActiveRecord
def
slash_command_service
(
project
,
service_slug
,
params
)
project
.
services
.
active
.
where
(
instanc
e:
false
).
find
do
|
service
|
project
.
services
.
active
.
where
(
templat
e:
false
).
find
do
|
service
|
service
.
try
(
:token
)
==
params
[
:token
]
&&
service
.
to_param
==
service_slug
.
underscore
end
end
...
...
lib/gitlab/import_export/import_export.yml
View file @
1ca9950d
...
...
@@ -257,7 +257,7 @@ excluded_attributes:
-
:token
-
:token_encrypted
services
:
-
:
instanc
e
-
:
templat
e
error_tracking_setting
:
-
:encrypted_token
-
:encrypted_token_iv
...
...
lib/gitlab/serverless/service.rb
0 → 100644
View file @
1ca9950d
# frozen_string_literal: true
class
Gitlab::Serverless::Service
include
Gitlab
::
Utils
::
StrongMemoize
def
initialize
(
attributes
)
@attributes
=
attributes
end
def
name
@attributes
.
dig
(
'metadata'
,
'name'
)
end
def
namespace
@attributes
.
dig
(
'metadata'
,
'namespace'
)
end
def
environment_scope
@attributes
.
dig
(
'environment_scope'
)
end
def
environment
@attributes
.
dig
(
'environment'
)
end
def
podcount
@attributes
.
dig
(
'podcount'
)
end
def
created_at
strong_memoize
(
:created_at
)
do
timestamp
=
@attributes
.
dig
(
'metadata'
,
'creationTimestamp'
)
DateTime
.
parse
(
timestamp
)
if
timestamp
end
end
def
image
@attributes
.
dig
(
'spec'
,
'runLatest'
,
'configuration'
,
'build'
,
'template'
,
'name'
)
end
def
description
knative_07_description
||
knative_05_06_description
end
def
cluster
@attributes
.
dig
(
'cluster'
)
end
def
url
proxy_url
||
knative_06_07_url
||
knative_05_url
end
private
def
proxy_url
if
cluster
&
.
serverless_domain
Gitlab
::
Serverless
::
FunctionURI
.
new
(
function:
name
,
cluster:
cluster
.
serverless_domain
,
environment:
environment
)
end
end
def
knative_07_description
@attributes
.
dig
(
'spec'
,
'template'
,
'metadata'
,
'annotations'
,
'Description'
)
end
def
knative_05_06_description
@attributes
.
dig
(
'spec'
,
'runLatest'
,
'configuration'
,
'revisionTemplate'
,
'metadata'
,
'annotations'
,
'Description'
)
end
def
knative_05_url
domain
=
@attributes
.
dig
(
'status'
,
'domain'
)
return
unless
domain
"http://
#{
domain
}
"
end
def
knative_06_07_url
@attributes
.
dig
(
'status'
,
'url'
)
end
end
lib/gitlab/usage_data.rb
View file @
1ca9950d
...
...
@@ -179,7 +179,7 @@ module Gitlab
# rubocop: disable CodeReuse/ActiveRecord
def
services_usage
service_counts
=
count
(
Service
.
active
.
where
(
instanc
e:
false
).
where
.
not
(
type:
'JiraService'
).
group
(
:type
),
fallback:
Hash
.
new
(
-
1
))
service_counts
=
count
(
Service
.
active
.
where
(
templat
e:
false
).
where
.
not
(
type:
'JiraService'
).
group
(
:type
),
fallback:
Hash
.
new
(
-
1
))
results
=
Service
.
available_services_names
.
each_with_object
({})
do
|
service_name
,
response
|
response
[
"projects_
#{
service_name
}
_active"
.
to_sym
]
=
service_counts
[
"
#{
service_name
}
_service"
.
camelize
]
||
0
...
...
qa/qa.rb
View file @
1ca9950d
...
...
@@ -469,6 +469,7 @@ module QA
autoload
:Configure
,
'qa/vendor/jenkins/page/configure'
autoload
:NewCredentials
,
'qa/vendor/jenkins/page/new_credentials'
autoload
:NewJob
,
'qa/vendor/jenkins/page/new_job'
autoload
:Job
,
'qa/vendor/jenkins/page/job'
autoload
:ConfigureJob
,
'qa/vendor/jenkins/page/configure_job'
end
end
...
...
qa/qa/vendor/jenkins/page/job.rb
0 → 100644
View file @
1ca9950d
# frozen_string_literal: true
require
'capybara/dsl'
module
QA
module
Vendor
module
Jenkins
module
Page
class
Job
<
Page
::
Base
attr_accessor
:job_name
def
path
"/job/
#{
@job_name
}
"
end
def
has_successful_build?
page
.
has_text?
(
"Last successful build"
)
end
end
end
end
end
end
spec/controllers/admin/services_controller_spec.rb
View file @
1ca9950d
...
...
@@ -15,11 +15,11 @@ describe Admin::ServicesController do
Service
.
available_services_names
.
each
do
|
service_name
|
context
"
#{
service_name
}
"
do
let!
(
:service
)
do
service_
instanc
e
=
"
#{
service_name
}
_service"
.
camelize
.
constantize
service_
instance
.
where
(
instanc
e:
true
).
first_or_create
service_
templat
e
=
"
#{
service_name
}
_service"
.
camelize
.
constantize
service_
template
.
where
(
templat
e:
true
).
first_or_create
end
it
'successfully displays the
servic
e'
do
it
'successfully displays the
templat
e'
do
get
:edit
,
params:
{
id:
service
.
id
}
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
...
...
@@ -34,7 +34,7 @@ describe Admin::ServicesController do
RedmineService
.
create
(
project:
project
,
active:
false
,
instanc
e:
true
,
templat
e:
true
,
properties:
{
project_url:
'http://abc'
,
issues_url:
'http://abc'
,
...
...
@@ -44,7 +44,7 @@ describe Admin::ServicesController do
end
it
'calls the propagation worker when service is active'
do
expect
(
Propagate
InstanceLevelServic
eWorker
).
to
receive
(
:perform_async
).
with
(
service
.
id
)
expect
(
Propagate
ServiceTemplat
eWorker
).
to
receive
(
:perform_async
).
with
(
service
.
id
)
put
:update
,
params:
{
id:
service
.
id
,
service:
{
active:
true
}
}
...
...
@@ -52,7 +52,7 @@ describe Admin::ServicesController do
end
it
'does not call the propagation worker when service is not active'
do
expect
(
Propagate
InstanceLevelServic
eWorker
).
not_to
receive
(
:perform_async
)
expect
(
Propagate
ServiceTemplat
eWorker
).
not_to
receive
(
:perform_async
)
put
:update
,
params:
{
id:
service
.
id
,
service:
{
properties:
{}
}
}
...
...
spec/controllers/projects/serverless/functions_controller_spec.rb
View file @
1ca9950d
...
...
@@ -14,9 +14,11 @@ describe Projects::Serverless::FunctionsController do
let!
(
:deployment
)
{
create
(
:deployment
,
:success
,
environment:
environment
,
cluster:
cluster
)
}
let
(
:knative_services_finder
)
{
environment
.
knative_services_finder
}
let
(
:function_description
)
{
'A serverless function'
}
let
(
:function_name
)
{
'some-function-name'
}
let
(
:knative_stub_options
)
do
{
namespace:
namespace
.
namespace
,
name:
cluster
.
project
.
name
,
description:
function_description
}
{
namespace:
namespace
.
namespace
,
name:
function_
name
,
description:
function_description
}
end
let
(
:knative
)
{
create
(
:clusters_applications_knative
,
:installed
,
cluster:
cluster
)
}
let
(
:namespace
)
do
create
(
:cluster_kubernetes_namespace
,
...
...
@@ -87,25 +89,65 @@ describe Projects::Serverless::FunctionsController do
end
context
'when functions were found'
do
let
(
:functions
)
{
[
"asdf"
]
}
let
(
:functions
)
{
[
{},
{}
]
}
before
do
stub_kubeclient_knative_services
(
namespace:
namespace
.
namespace
)
get
:index
,
params:
params
({
format: :json
})
stub_kubeclient_knative_services
(
namespace:
namespace
.
namespace
,
cluster_id:
cluster
.
id
,
name:
function_name
)
end
it
'returns functions'
do
get
:index
,
params:
params
({
format: :json
})
expect
(
json_response
[
"functions"
]).
not_to
be_empty
end
it
{
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
}
it
'filters out the functions whose cluster the user does not have permission to read'
do
allow
(
controller
).
to
receive
(
:can?
).
and_return
(
true
)
expect
(
controller
).
to
receive
(
:can?
).
with
(
user
,
:read_cluster
,
cluster
).
and_return
(
false
)
get
:index
,
params:
params
({
format: :json
})
expect
(
json_response
[
"functions"
]).
to
be_empty
end
it
'returns a successful response status'
do
get
:index
,
params:
params
({
format: :json
})
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
end
context
'when there is serverless domain for a cluster'
do
let!
(
:serverless_domain_cluster
)
do
create
(
:serverless_domain_cluster
,
clusters_applications_knative_id:
knative
.
id
)
end
it
'returns JSON with function details with serverless domain URL'
do
get
:index
,
params:
params
({
format: :json
})
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
json_response
[
"functions"
]).
not_to
be_empty
expect
(
json_response
[
"functions"
]).
to
all
(
include
(
'url'
=>
"https://
#{
function_name
}
-
#{
serverless_domain_cluster
.
uuid
[
0
..
1
]
}
a1
#{
serverless_domain_cluster
.
uuid
[
2
..-
3
]
}
f2
#{
serverless_domain_cluster
.
uuid
[
-
2
..-
1
]
}#{
"%x"
%
environment
.
id
}
-
#{
environment
.
slug
}
.
#{
serverless_domain_cluster
.
domain
}
"
)
)
end
end
context
'when there is no serverless domain for a cluster'
do
it
'keeps function URL as it was'
do
expect
(
Gitlab
::
Serverless
::
Domain
).
not_to
receive
(
:new
)
get
:index
,
params:
params
({
format: :json
})
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
end
end
end
end
end
describe
'GET #show'
do
context
'
invalid data
'
do
it
'
has a bad function name
'
do
context
'
with function that does not exist
'
do
it
'
returns 404
'
do
get
:show
,
params:
params
({
format: :json
,
environment_id:
"*"
,
id:
"foo"
})
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
end
...
...
@@ -113,15 +155,50 @@ describe Projects::Serverless::FunctionsController do
context
'with valid data'
,
:use_clean_rails_memory_store_caching
do
shared_examples
'GET #show with valid data'
do
it
'has a valid function name'
do
get
:show
,
params:
params
({
format: :json
,
environment_id:
"*"
,
id:
cluster
.
project
.
name
})
context
'when there is serverless domain for a cluster'
do
let!
(
:serverless_domain_cluster
)
do
create
(
:serverless_domain_cluster
,
clusters_applications_knative_id:
knative
.
id
)
end
it
'returns JSON with function details with serverless domain URL'
do
get
:show
,
params:
params
({
format: :json
,
environment_id:
"*"
,
id:
function_name
})
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
json_response
).
to
include
(
'url'
=>
"https://
#{
function_name
}
-
#{
serverless_domain_cluster
.
uuid
[
0
..
1
]
}
a1
#{
serverless_domain_cluster
.
uuid
[
2
..-
3
]
}
f2
#{
serverless_domain_cluster
.
uuid
[
-
2
..-
1
]
}#{
"%x"
%
environment
.
id
}
-
#{
environment
.
slug
}
.
#{
serverless_domain_cluster
.
domain
}
"
)
end
it
'returns 404 when user does not have permission to read the cluster'
do
allow
(
controller
).
to
receive
(
:can?
).
and_return
(
true
)
expect
(
controller
).
to
receive
(
:can?
).
with
(
user
,
:read_cluster
,
cluster
).
and_return
(
false
)
get
:show
,
params:
params
({
format: :json
,
environment_id:
"*"
,
id:
function_name
})
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
end
end
context
'when there is no serverless domain for a cluster'
do
it
'keeps function URL as it was'
do
get
:show
,
params:
params
({
format: :json
,
environment_id:
"*"
,
id:
function_name
})
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
json_response
).
to
include
(
'url'
=>
"http://
#{
function_name
}
.
#{
namespace
.
namespace
}
.example.com"
)
end
end
it
'return json with function details'
do
get
:show
,
params:
params
({
format: :json
,
environment_id:
"*"
,
id:
function_name
})
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
json_response
).
to
include
(
'name'
=>
project
.
name
,
'url'
=>
"http://
#{
project
.
name
}
.
#{
namespace
.
namespace
}
.example.com"
,
'name'
=>
function_
name
,
'url'
=>
"http://
#{
function_
name
}
.
#{
namespace
.
namespace
}
.example.com"
,
'description'
=>
function_description
,
'podcount'
=>
1
'podcount'
=>
0
)
end
end
...
...
@@ -180,8 +257,8 @@ describe Projects::Serverless::FunctionsController do
'knative_installed'
=>
'checking'
,
'functions'
=>
[
a_hash_including
(
'name'
=>
project
.
name
,
'url'
=>
"http://
#{
project
.
name
}
.
#{
namespace
.
namespace
}
.example.com"
,
'name'
=>
function_
name
,
'url'
=>
"http://
#{
function_
name
}
.
#{
namespace
.
namespace
}
.example.com"
,
'description'
=>
function_description
)
]
...
...
spec/controllers/projects/services_controller_spec.rb
View file @
1ca9950d
...
...
@@ -154,12 +154,12 @@ describe Projects::ServicesController do
end
end
context
'when activating Jira service from
instance level servic
e'
do
context
'when activating Jira service from
a templat
e'
do
let
(
:service
)
do
create
(
:jira_service
,
project:
project
,
instanc
e:
true
)
create
(
:jira_service
,
project:
project
,
templat
e:
true
)
end
it
'activate Jira service from
instance level servic
e'
do
it
'activate Jira service from
templat
e'
do
expect
(
flash
[
:notice
]).
to
eq
'Jira activated.'
end
end
...
...
spec/factories/pages_domains.rb
View file @
1ca9950d
...
...
@@ -380,5 +380,9 @@ x6zG6WoibsbsJMj70nwseUnPTBQNDP+j61RJjC/r
scope
{
:instance
}
usage
{
:serverless
}
end
trait
:with_project
do
association
:project
end
end
end
spec/finders/projects/serverless/functions_finder_spec.rb
View file @
1ca9950d
...
...
@@ -153,8 +153,8 @@ describe Projects::Serverless::FunctionsFinder do
*
knative_services_finder
.
cache_args
)
result
=
finder
.
service
(
cluster
.
environment_scope
,
cluster
.
project
.
name
)
expect
(
result
).
not_to
be_empty
expect
(
result
[
"metadata"
][
"name"
]
).
to
be_eql
(
cluster
.
project
.
name
)
expect
(
result
).
to
be_present
expect
(
result
.
name
).
to
be_eql
(
cluster
.
project
.
name
)
end
it
'has metrics'
,
:use_clean_rails_memory_store_caching
do
...
...
spec/fixtures/trace/sample_trace
View file @
1ca9950d
...
...
@@ -2736,7 +2736,7 @@ Service
when repository is empty
test runs execute
Template
.build_from_
instanc
e
.build_from_
templat
e
when template is invalid
sets service template to inactive when template is invalid
for pushover service
...
...
spec/frontend/environments/environments_app_spec.js
0 → 100644
View file @
1ca9950d
import
{
mount
,
shallowMount
}
from
'
@vue/test-utils
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
Container
from
'
~/environments/components/container.vue
'
;
import
EmptyState
from
'
~/environments/components/empty_state.vue
'
;
import
EnvironmentsApp
from
'
~/environments/components/environments_app.vue
'
;
import
{
environment
,
folder
}
from
'
./mock_data
'
;
describe
(
'
Environment
'
,
()
=>
{
let
mock
;
let
wrapper
;
const
mockData
=
{
endpoint
:
'
environments.json
'
,
canCreateEnvironment
:
true
,
canReadEnvironment
:
true
,
newEnvironmentPath
:
'
environments/new
'
,
helpPagePath
:
'
help
'
,
canaryDeploymentFeatureId
:
'
canary_deployment
'
,
showCanaryDeploymentCallout
:
true
,
userCalloutsPath
:
'
/callouts
'
,
lockPromotionSvgPath
:
'
/assets/illustrations/lock-promotion.svg
'
,
helpCanaryDeploymentsPath
:
'
help/canary-deployments
'
,
};
const
mockRequest
=
(
response
,
body
)
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
response
,
body
,
{
'
X-nExt-pAge
'
:
'
2
'
,
'
x-page
'
:
'
1
'
,
'
X-Per-Page
'
:
'
1
'
,
'
X-Prev-Page
'
:
''
,
'
X-TOTAL
'
:
'
37
'
,
'
X-Total-Pages
'
:
'
2
'
,
});
};
const
createWrapper
=
(
shallow
=
false
)
=>
{
const
fn
=
shallow
?
shallowMount
:
mount
;
wrapper
=
fn
(
EnvironmentsApp
,
{
propsData
:
mockData
});
return
axios
.
waitForAll
();
};
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
});
afterEach
(()
=>
{
wrapper
.
destroy
();
mock
.
restore
();
});
describe
(
'
successful request
'
,
()
=>
{
describe
(
'
without environments
'
,
()
=>
{
beforeEach
(()
=>
{
mockRequest
(
200
,
{
environments
:
[]
});
return
createWrapper
(
true
);
});
it
(
'
should render the empty state
'
,
()
=>
{
expect
(
wrapper
.
find
(
EmptyState
).
exists
()).
toBe
(
true
);
});
describe
(
'
when it is possible to enable a review app
'
,
()
=>
{
beforeEach
(()
=>
{
mockRequest
(
200
,
{
environments
:
[],
review_app
:
{
can_setup_review_app
:
true
}
});
return
createWrapper
();
});
it
(
'
should render the enable review app button
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
.js-enable-review-app-button
'
).
text
()).
toContain
(
'
Enable review app
'
,
);
});
});
});
describe
(
'
with paginated environments
'
,
()
=>
{
const
environmentList
=
[
environment
];
beforeEach
(()
=>
{
mockRequest
(
200
,
{
environments
:
environmentList
,
stopped_count
:
1
,
available_count
:
0
,
});
return
createWrapper
();
});
it
(
'
should render a conatiner table with environments
'
,
()
=>
{
const
containerTable
=
wrapper
.
find
(
Container
);
expect
(
containerTable
.
exists
()).
toBe
(
true
);
expect
(
containerTable
.
props
(
'
environments
'
).
length
).
toEqual
(
environmentList
.
length
);
expect
(
containerTable
.
find
(
'
.environment-name
'
).
text
()).
toEqual
(
environmentList
[
0
].
name
);
});
describe
(
'
pagination
'
,
()
=>
{
it
(
'
should render pagination
'
,
()
=>
{
expect
(
wrapper
.
findAll
(
'
.gl-pagination li
'
).
length
).
toEqual
(
9
);
});
it
(
'
should make an API request when page is clicked
'
,
()
=>
{
jest
.
spyOn
(
wrapper
.
vm
,
'
updateContent
'
).
mockImplementation
(()
=>
{});
wrapper
.
find
(
'
.gl-pagination li:nth-child(3) .page-link
'
).
trigger
(
'
click
'
);
expect
(
wrapper
.
vm
.
updateContent
).
toHaveBeenCalledWith
({
scope
:
'
available
'
,
page
:
'
2
'
});
});
it
(
'
should make an API request when using tabs
'
,
()
=>
{
jest
.
spyOn
(
wrapper
.
vm
,
'
updateContent
'
).
mockImplementation
(()
=>
{});
wrapper
.
find
(
'
.js-environments-tab-stopped
'
).
trigger
(
'
click
'
);
expect
(
wrapper
.
vm
.
updateContent
).
toHaveBeenCalledWith
({
scope
:
'
stopped
'
,
page
:
'
1
'
});
});
});
});
});
describe
(
'
unsuccessful request
'
,
()
=>
{
beforeEach
(()
=>
{
mockRequest
(
500
,
{});
return
createWrapper
(
true
);
});
it
(
'
should render empty state
'
,
()
=>
{
expect
(
wrapper
.
find
(
EmptyState
).
exists
()).
toBe
(
true
);
});
});
describe
(
'
expandable folders
'
,
()
=>
{
beforeEach
(()
=>
{
mockRequest
(
200
,
{
environments
:
[
folder
],
stopped_count
:
1
,
available_count
:
0
,
});
mock
.
onGet
(
environment
.
folder_path
).
reply
(
200
,
{
environments
:
[
environment
]
});
return
createWrapper
().
then
(()
=>
{
// open folder
wrapper
.
find
(
'
.folder-name
'
).
trigger
(
'
click
'
);
return
axios
.
waitForAll
();
});
});
it
(
'
should open a closed folder
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
.folder-icon.ic-chevron-right
'
).
exists
()).
toBe
(
false
);
});
it
(
'
should close an opened folder
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
.folder-icon.ic-chevron-down
'
).
exists
()).
toBe
(
true
);
// close folder
wrapper
.
find
(
'
.folder-name
'
).
trigger
(
'
click
'
);
wrapper
.
vm
.
$nextTick
(()
=>
{
expect
(
wrapper
.
find
(
'
.folder-icon.ic-chevron-down
'
).
exists
()).
toBe
(
false
);
});
});
it
(
'
should show children environments
'
,
()
=>
{
expect
(
wrapper
.
findAll
(
'
.js-child-row
'
).
length
).
toEqual
(
1
);
});
it
(
'
should show a button to show all environments
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
.text-center > a.btn
'
).
text
()).
toContain
(
'
Show all
'
);
});
});
});
spec/frontend/monitoring/components/dashboard_spec.js
View file @
1ca9950d
This diff is collapsed.
Click to expand it.
spec/frontend/monitoring/components/dashboards_dropdown_spec.js
View file @
1ca9950d
...
...
@@ -131,20 +131,17 @@ describe('DashboardsDropdown', () => {
expect
(
findModal
().
contains
(
DuplicateDashboardForm
)).
toBe
(
true
);
});
it
(
'
saves a new dashboard
'
,
done
=>
{
it
(
'
saves a new dashboard
'
,
()
=>
{
findModal
().
vm
.
$emit
(
'
ok
'
,
okEvent
);
waitForPromises
()
.
then
(()
=>
{
expect
(
okEvent
.
preventDefault
).
toHaveBeenCalled
();
expect
(
wrapper
.
find
(
GlLoadingIcon
).
exists
()).
toBe
(
false
);
expect
(
wrapper
.
vm
.
$refs
.
duplicateDashboardModal
.
hide
).
toHaveBeenCalled
();
expect
(
wrapper
.
emitted
().
selectDashboard
).
toBeTruthy
();
expect
(
findAlert
().
exists
()).
toBe
(
false
);
done
();
})
.
catch
(
done
.
fail
);
return
waitForPromises
().
then
(()
=>
{
expect
(
okEvent
.
preventDefault
).
toHaveBeenCalled
();
expect
(
wrapper
.
find
(
GlLoadingIcon
).
exists
()).
toBe
(
false
);
expect
(
wrapper
.
vm
.
$refs
.
duplicateDashboardModal
.
hide
).
toHaveBeenCalled
();
expect
(
wrapper
.
emitted
().
selectDashboard
).
toBeTruthy
();
expect
(
findAlert
().
exists
()).
toBe
(
false
);
});
});
describe
(
'
when a new dashboard is saved succesfully
'
,
()
=>
{
...
...
@@ -167,52 +164,42 @@ describe('DashboardsDropdown', () => {
findModal
().
vm
.
$emit
(
'
ok
'
,
okEvent
);
};
it
(
'
to the default branch, redirects to the new dashboard
'
,
done
=>
{
it
(
'
to the default branch, redirects to the new dashboard
'
,
()
=>
{
submitForm
({
branch
:
defaultBranch
,
});
waitForPromises
()
.
then
(()
=>
{
expect
(
wrapper
.
emitted
().
selectDashboard
[
0
][
0
]).
toEqual
(
newDashboard
);
done
();
})
.
catch
(
done
.
fail
);
return
waitForPromises
().
then
(()
=>
{
expect
(
wrapper
.
emitted
().
selectDashboard
[
0
][
0
]).
toEqual
(
newDashboard
);
});
});
it
(
'
to a new branch refreshes in the current dashboard
'
,
done
=>
{
it
(
'
to a new branch refreshes in the current dashboard
'
,
()
=>
{
submitForm
({
branch
:
'
another-branch
'
,
});
waitForPromises
()
.
then
(()
=>
{
expect
(
wrapper
.
emitted
().
selectDashboard
[
0
][
0
]).
toEqual
(
dashboardGitResponse
[
0
]);
done
();
})
.
catch
(
done
.
fail
);
return
waitForPromises
().
then
(()
=>
{
expect
(
wrapper
.
emitted
().
selectDashboard
[
0
][
0
]).
toEqual
(
dashboardGitResponse
[
0
]);
});
});
});
it
(
'
handles error when a new dashboard is not saved
'
,
done
=>
{
it
(
'
handles error when a new dashboard is not saved
'
,
()
=>
{
const
errMsg
=
'
An error occurred
'
;
duplicateDashboardAction
.
mockRejectedValueOnce
(
errMsg
);
findModal
().
vm
.
$emit
(
'
ok
'
,
okEvent
);
waitForPromises
()
.
then
(()
=>
{
expect
(
okEvent
.
preventDefault
).
toHaveBeenCalled
();
expect
(
findAlert
().
exists
()).
toBe
(
true
);
expect
(
findAlert
().
text
()).
toBe
(
errMsg
);
return
waitForPromises
().
then
(()
=>
{
expect
(
okEvent
.
preventDefault
).
toHaveBeenCalled
();
expect
(
wrapper
.
find
(
GlLoadingIcon
).
exists
()).
toBe
(
fals
e
);
expect
(
wrapper
.
vm
.
$refs
.
duplicateDashboardModal
.
hide
).
not
.
toHaveBeenCalled
(
);
expect
(
findAlert
().
exists
()).
toBe
(
tru
e
);
expect
(
findAlert
().
text
()).
toBe
(
errMsg
);
done
(
);
})
.
catch
(
done
.
fail
);
expect
(
wrapper
.
find
(
GlLoadingIcon
).
exists
()).
toBe
(
false
);
expect
(
wrapper
.
vm
.
$refs
.
duplicateDashboardModal
.
hide
).
not
.
toHaveBeenCalled
();
}
);
});
it
(
'
id is correct, as the value of modal directive binding matches modal id
'
,
()
=>
{
...
...
spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js
View file @
1ca9950d
...
...
@@ -44,30 +44,27 @@ describe('DuplicateDashboardForm', () => {
describe
(
'
validates the file name
'
,
()
=>
{
const
findInvalidFeedback
=
()
=>
findByRef
(
'
fileNameFormGroup
'
).
find
(
'
.invalid-feedback
'
);
it
(
'
when is empty
'
,
done
=>
{
it
(
'
when is empty
'
,
()
=>
{
setValue
(
'
fileName
'
,
''
);
wrapper
.
vm
.
$nextTick
(()
=>
{
return
wrapper
.
vm
.
$nextTick
(()
=>
{
expect
(
findByRef
(
'
fileNameFormGroup
'
).
is
(
'
.is-valid
'
)).
toBe
(
true
);
expect
(
findInvalidFeedback
().
exists
()).
toBe
(
false
);
done
();
});
});
it
(
'
when is valid
'
,
done
=>
{
it
(
'
when is valid
'
,
()
=>
{
setValue
(
'
fileName
'
,
'
my_dashboard.yml
'
);
wrapper
.
vm
.
$nextTick
(()
=>
{
return
wrapper
.
vm
.
$nextTick
(()
=>
{
expect
(
findByRef
(
'
fileNameFormGroup
'
).
is
(
'
.is-valid
'
)).
toBe
(
true
);
expect
(
findInvalidFeedback
().
exists
()).
toBe
(
false
);
done
();
});
});
it
(
'
when is not valid
'
,
done
=>
{
it
(
'
when is not valid
'
,
()
=>
{
setValue
(
'
fileName
'
,
'
my_dashboard.exe
'
);
wrapper
.
vm
.
$nextTick
(()
=>
{
return
wrapper
.
vm
.
$nextTick
(()
=>
{
expect
(
findByRef
(
'
fileNameFormGroup
'
).
is
(
'
.is-invalid
'
)).
toBe
(
true
);
expect
(
findInvalidFeedback
().
text
()).
toBeTruthy
();
done
();
});
});
});
...
...
@@ -124,30 +121,26 @@ describe('DuplicateDashboardForm', () => {
});
});
it
(
'
when a `default` branch option is set, branch input is invisible and ignored
'
,
done
=>
{
it
(
'
when a `default` branch option is set, branch input is invisible and ignored
'
,
()
=>
{
setChecked
(
wrapper
.
vm
.
$options
.
radioVals
.
DEFAULT
);
setValue
(
'
branchName
'
,
'
a-new-branch
'
);
expect
(
lastChange
()).
resolves
.
toMatchObject
({
branch
:
defaultBranch
,
});
wrapper
.
vm
.
$nextTick
(()
=>
{
return
wrapper
.
vm
.
$nextTick
(()
=>
{
expect
(
findByRef
(
'
branchName
'
).
isVisible
()).
toBe
(
false
);
done
();
});
});
it
(
'
when `new` branch option is chosen, focuses on the branch name input
'
,
done
=>
{
it
(
'
when `new` branch option is chosen, focuses on the branch name input
'
,
()
=>
{
setChecked
(
wrapper
.
vm
.
$options
.
radioVals
.
NEW
);
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
wrapper
.
find
(
'
form
'
).
trigger
(
'
change
'
);
expect
(
findByRef
(
'
branchName
'
).
is
(
'
:focus
'
)).
toBe
(
true
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
return
wrapper
.
vm
.
$nextTick
().
then
(()
=>
{
wrapper
.
find
(
'
form
'
).
trigger
(
'
change
'
);
expect
(
findByRef
(
'
branchName
'
).
is
(
'
:focus
'
)).
toBe
(
true
);
});
});
});
});
spec/frontend/monitoring/components/graph_group_spec.js
View file @
1ca9950d
...
...
@@ -32,25 +32,23 @@ describe('Graph group component', () => {
expect
(
findCaretIcon
().
props
(
'
name
'
)).
toBe
(
'
angle-down
'
);
});
it
(
'
should show the angle-right caret icon when the user collapses the group
'
,
done
=>
{
it
(
'
should show the angle-right caret icon when the user collapses the group
'
,
()
=>
{
wrapper
.
vm
.
collapse
();
wrapper
.
vm
.
$nextTick
(()
=>
{
return
wrapper
.
vm
.
$nextTick
(()
=>
{
expect
(
findContent
().
isVisible
()).
toBe
(
false
);
expect
(
findCaretIcon
().
props
(
'
name
'
)).
toBe
(
'
angle-right
'
);
done
();
});
});
it
(
'
should show the open the group when collapseGroup is set to true
'
,
done
=>
{
it
(
'
should show the open the group when collapseGroup is set to true
'
,
()
=>
{
wrapper
.
setProps
({
collapseGroup
:
true
,
});
wrapper
.
vm
.
$nextTick
(()
=>
{
return
wrapper
.
vm
.
$nextTick
(()
=>
{
expect
(
findContent
().
isVisible
()).
toBe
(
true
);
expect
(
findCaretIcon
().
props
(
'
name
'
)).
toBe
(
'
angle-down
'
);
done
();
});
});
...
...
@@ -102,13 +100,12 @@ describe('Graph group component', () => {
expect
(
findCaretIcon
().
exists
()).
toBe
(
false
);
});
it
(
'
should show the panel content when clicked
'
,
done
=>
{
it
(
'
should show the panel content when clicked
'
,
()
=>
{
wrapper
.
vm
.
collapse
();
wrapper
.
vm
.
$nextTick
(()
=>
{
return
wrapper
.
vm
.
$nextTick
(()
=>
{
expect
(
findContent
().
isVisible
()).
toBe
(
true
);
expect
(
findCaretIcon
().
exists
()).
toBe
(
false
);
done
();
});
});
});
...
...
spec/frontend/monitoring/components/panel_type_spec.js
View file @
1ca9950d
...
...
@@ -28,6 +28,8 @@ describe('Panel Type component', () => {
const
exampleText
=
'
example_text
'
;
const
findCopyLink
=
()
=>
wrapper
.
find
({
ref
:
'
copyChartLink
'
});
const
createWrapper
=
props
=>
{
wrapper
=
shallowMount
(
PanelType
,
{
propsData
:
{
...
...
@@ -96,8 +98,7 @@ describe('Panel Type component', () => {
});
it
(
'
sets no clipboard copy link on dropdown by default
'
,
()
=>
{
const
link
=
()
=>
wrapper
.
find
({
ref
:
'
copyChartLink
'
});
expect
(
link
().
exists
()).
toBe
(
false
);
expect
(
findCopyLink
().
exists
()).
toBe
(
false
);
});
describe
(
'
Time Series Chart panel type
'
,
()
=>
{
...
...
@@ -204,7 +205,6 @@ describe('Panel Type component', () => {
});
describe
(
'
when cliboard data is available
'
,
()
=>
{
const
link
=
()
=>
wrapper
.
find
({
ref
:
'
copyChartLink
'
});
const
clipboardText
=
'
A value to copy.
'
;
beforeEach
(()
=>
{
...
...
@@ -219,16 +219,16 @@ describe('Panel Type component', () => {
});
it
(
'
sets clipboard text on the dropdown
'
,
()
=>
{
expect
(
l
ink
().
exists
()).
toBe
(
true
);
expect
(
l
ink
().
element
.
dataset
.
clipboardText
).
toBe
(
clipboardText
);
expect
(
findCopyL
ink
().
exists
()).
toBe
(
true
);
expect
(
findCopyL
ink
().
element
.
dataset
.
clipboardText
).
toBe
(
clipboardText
);
});
it
(
'
adds a copy button to the dropdown
'
,
()
=>
{
expect
(
l
ink
().
text
()).
toContain
(
'
Generate link to chart
'
);
expect
(
findCopyL
ink
().
text
()).
toContain
(
'
Generate link to chart
'
);
});
it
(
'
opens a toast on click
'
,
()
=>
{
l
ink
().
vm
.
$emit
(
'
click
'
);
findCopyL
ink
().
vm
.
$emit
(
'
click
'
);
expect
(
wrapper
.
vm
.
$toast
.
show
).
toHaveBeenCalled
();
});
...
...
spec/graphql/types/snippets/blob_type_spec.rb
View file @
1ca9950d
...
...
@@ -4,10 +4,9 @@ require 'spec_helper'
describe
GitlabSchema
.
types
[
'SnippetBlob'
]
do
it
'has the correct fields'
do
expected_fields
=
[
:highlighted_data
,
:raw_path
,
:size
,
:binary
,
:name
,
:path
,
:simple_viewer
,
:rich_viewer
,
:mode
]
expected_fields
=
[
:highlighted_data
,
:plain_highlighted_data
,
:raw_path
,
:size
,
:binary
,
:name
,
:path
,
:simple_viewer
,
:rich_viewer
,
:mode
]
is_expected
.
to
have_graphql_fields
(
*
expected_fields
)
end
...
...
spec/javascripts/environments/environments_app_spec.js
deleted
100644 → 0
View file @
bcc77054
import
Vue
from
'
vue
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
mountComponent
from
'
spec/helpers/vue_mount_component_helper
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
environmentsComponent
from
'
~/environments/components/environments_app.vue
'
;
import
{
environment
,
folder
}
from
'
./mock_data
'
;
describe
(
'
Environment
'
,
()
=>
{
const
mockData
=
{
endpoint
:
'
environments.json
'
,
canCreateEnvironment
:
true
,
canReadEnvironment
:
true
,
newEnvironmentPath
:
'
environments/new
'
,
helpPagePath
:
'
help
'
,
canaryDeploymentFeatureId
:
'
canary_deployment
'
,
showCanaryDeploymentCallout
:
true
,
userCalloutsPath
:
'
/callouts
'
,
lockPromotionSvgPath
:
'
/assets/illustrations/lock-promotion.svg
'
,
helpCanaryDeploymentsPath
:
'
help/canary-deployments
'
,
};
let
EnvironmentsComponent
;
let
component
;
let
mock
;
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
EnvironmentsComponent
=
Vue
.
extend
(
environmentsComponent
);
});
afterEach
(()
=>
{
component
.
$destroy
();
mock
.
restore
();
});
describe
(
'
successful request
'
,
()
=>
{
describe
(
'
without environments
'
,
()
=>
{
beforeEach
(
done
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
{
environments
:
[]
});
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
setTimeout
(()
=>
{
done
();
},
0
);
});
it
(
'
should render the empty state
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.js-new-environment-button
'
).
textContent
).
toContain
(
'
New environment
'
,
);
expect
(
component
.
$el
.
querySelector
(
'
.js-blank-state-title
'
).
textContent
).
toContain
(
"
You don't have any environments right now
"
,
);
});
describe
(
'
when it is possible to enable a review app
'
,
()
=>
{
beforeEach
(
done
=>
{
mock
.
onGet
(
mockData
.
endpoint
)
.
reply
(
200
,
{
environments
:
[],
review_app
:
{
can_setup_review_app
:
true
}
});
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
setTimeout
(()
=>
{
done
();
},
0
);
});
it
(
'
should render the enable review app button
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.js-enable-review-app-button
'
).
textContent
).
toContain
(
'
Enable review app
'
,
);
});
});
});
describe
(
'
with paginated environments
'
,
()
=>
{
beforeEach
(
done
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
{
environments
:
[
environment
],
stopped_count
:
1
,
available_count
:
0
,
},
{
'
X-nExt-pAge
'
:
'
2
'
,
'
x-page
'
:
'
1
'
,
'
X-Per-Page
'
:
'
1
'
,
'
X-Prev-Page
'
:
''
,
'
X-TOTAL
'
:
'
37
'
,
'
X-Total-Pages
'
:
'
2
'
,
},
);
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
setTimeout
(()
=>
{
done
();
},
0
);
});
it
(
'
should render a table with environments
'
,
()
=>
{
expect
(
component
.
$el
.
querySelectorAll
(
'
table
'
)).
not
.
toBeNull
();
expect
(
component
.
$el
.
querySelector
(
'
.environment-name
'
).
textContent
.
trim
()).
toEqual
(
environment
.
name
,
);
});
describe
(
'
pagination
'
,
()
=>
{
it
(
'
should render pagination
'
,
()
=>
{
expect
(
component
.
$el
.
querySelectorAll
(
'
.gl-pagination li
'
).
length
).
toEqual
(
9
);
});
it
(
'
should make an API request when page is clicked
'
,
done
=>
{
spyOn
(
component
,
'
updateContent
'
);
setTimeout
(()
=>
{
component
.
$el
.
querySelector
(
'
.gl-pagination li:nth-child(3) .page-link
'
).
click
();
expect
(
component
.
updateContent
).
toHaveBeenCalledWith
({
scope
:
'
available
'
,
page
:
'
2
'
});
done
();
},
0
);
});
it
(
'
should make an API request when using tabs
'
,
done
=>
{
setTimeout
(()
=>
{
spyOn
(
component
,
'
updateContent
'
);
component
.
$el
.
querySelector
(
'
.js-environments-tab-stopped
'
).
click
();
expect
(
component
.
updateContent
).
toHaveBeenCalledWith
({
scope
:
'
stopped
'
,
page
:
'
1
'
});
done
();
},
0
);
});
});
});
});
describe
(
'
unsuccessfull request
'
,
()
=>
{
beforeEach
(
done
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
500
,
{});
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
setTimeout
(()
=>
{
done
();
},
0
);
});
it
(
'
should render empty state
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.js-blank-state-title
'
).
textContent
).
toContain
(
"
You don't have any environments right now
"
,
);
});
});
describe
(
'
expandable folders
'
,
()
=>
{
beforeEach
(()
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
{
environments
:
[
folder
],
stopped_count
:
0
,
available_count
:
1
,
},
{
'
X-nExt-pAge
'
:
'
2
'
,
'
x-page
'
:
'
1
'
,
'
X-Per-Page
'
:
'
1
'
,
'
X-Prev-Page
'
:
''
,
'
X-TOTAL
'
:
'
37
'
,
'
X-Total-Pages
'
:
'
2
'
,
},
);
mock
.
onGet
(
environment
.
folder_path
).
reply
(
200
,
{
environments
:
[
environment
]
});
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
});
it
(
'
should open a closed folder
'
,
done
=>
{
setTimeout
(()
=>
{
component
.
$el
.
querySelector
(
'
.folder-name
'
).
click
();
Vue
.
nextTick
(()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.folder-icon.ic-chevron-right
'
)).
toBe
(
null
);
done
();
});
},
0
);
});
it
(
'
should close an opened folder
'
,
done
=>
{
setTimeout
(()
=>
{
// open folder
component
.
$el
.
querySelector
(
'
.folder-name
'
).
click
();
Vue
.
nextTick
(()
=>
{
// close folder
component
.
$el
.
querySelector
(
'
.folder-name
'
).
click
();
Vue
.
nextTick
(()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.folder-icon.ic-chevron-down
'
)).
toBe
(
null
);
done
();
});
});
},
0
);
});
it
(
'
should show children environments and a button to show all environments
'
,
done
=>
{
setTimeout
(()
=>
{
// open folder
component
.
$el
.
querySelector
(
'
.folder-name
'
).
click
();
Vue
.
nextTick
(()
=>
{
// wait for next async request
setTimeout
(()
=>
{
expect
(
component
.
$el
.
querySelectorAll
(
'
.js-child-row
'
).
length
).
toEqual
(
1
);
expect
(
component
.
$el
.
querySelector
(
'
.text-center > a.btn
'
).
textContent
).
toContain
(
'
Show all
'
,
);
done
();
});
});
},
0
);
});
});
describe
(
'
methods
'
,
()
=>
{
beforeEach
(()
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
{
environments
:
[],
stopped_count
:
0
,
available_count
:
1
,
},
{},
);
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
spyOn
(
window
.
history
,
'
pushState
'
).
and
.
stub
();
});
describe
(
'
updateContent
'
,
()
=>
{
it
(
'
should set given parameters
'
,
done
=>
{
component
.
updateContent
({
scope
:
'
stopped
'
,
page
:
'
3
'
})
.
then
(()
=>
{
expect
(
component
.
page
).
toEqual
(
'
3
'
);
expect
(
component
.
scope
).
toEqual
(
'
stopped
'
);
expect
(
component
.
requestData
.
scope
).
toEqual
(
'
stopped
'
);
expect
(
component
.
requestData
.
page
).
toEqual
(
'
3
'
);
done
();
})
.
catch
(
done
.
fail
);
});
});
describe
(
'
onChangeTab
'
,
()
=>
{
it
(
'
should set page to 1
'
,
()
=>
{
spyOn
(
component
,
'
updateContent
'
);
component
.
onChangeTab
(
'
stopped
'
);
expect
(
component
.
updateContent
).
toHaveBeenCalledWith
({
scope
:
'
stopped
'
,
page
:
'
1
'
});
});
});
describe
(
'
onChangePage
'
,
()
=>
{
it
(
'
should update page and keep scope
'
,
()
=>
{
spyOn
(
component
,
'
updateContent
'
);
component
.
onChangePage
(
4
);
expect
(
component
.
updateContent
).
toHaveBeenCalledWith
({
scope
:
component
.
scope
,
page
:
'
4
'
});
});
});
});
});
spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
View file @
1ca9950d
...
...
@@ -652,10 +652,10 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
setup_import_export_config
(
'light'
)
end
it
'does not import any
instance-level
services'
do
it
'does not import any
templated
services'
do
expect
(
restored_project_json
).
to
eq
(
true
)
expect
(
project
.
services
.
where
(
instanc
e:
true
).
count
).
to
eq
(
0
)
expect
(
project
.
services
.
where
(
templat
e:
true
).
count
).
to
eq
(
0
)
end
it
'imports labels'
do
...
...
spec/lib/gitlab/import_export/safe_model_attributes.yml
View file @
1ca9950d
...
...
@@ -453,7 +453,7 @@ Service:
-
updated_at
-
active
-
properties
-
instanc
e
-
templat
e
-
push_events
-
issues_events
-
commit_events
...
...
spec/lib/gitlab/serverless/service_spec.rb
0 → 100644
View file @
1ca9950d
# frozen_string_literal: true
require
'spec_helper'
describe
Gitlab
::
Serverless
::
Service
do
let
(
:cluster
)
{
create
(
:cluster
)
}
let
(
:environment
)
{
create
(
:environment
)
}
let
(
:attributes
)
do
{
'apiVersion'
=>
'serving.knative.dev/v1alpha1'
,
'kind'
=>
'Service'
,
'metadata'
=>
{
'creationTimestamp'
=>
'2019-10-22T21:19:13Z'
,
'name'
=>
'kubetest'
,
'namespace'
=>
'project1-1-environment1'
},
'spec'
=>
{
'runLatest'
=>
{
'configuration'
=>
{
'build'
=>
{
'template'
=>
{
'name'
=>
'some-image'
}
}
}
}
},
'environment_scope'
=>
'*'
,
'cluster'
=>
cluster
,
'environment'
=>
environment
,
'podcount'
=>
0
}
end
it
'exposes methods extracting data from the attributes hash'
do
service
=
Gitlab
::
Serverless
::
Service
.
new
(
attributes
)
expect
(
service
.
name
).
to
eq
(
'kubetest'
)
expect
(
service
.
namespace
).
to
eq
(
'project1-1-environment1'
)
expect
(
service
.
environment_scope
).
to
eq
(
'*'
)
expect
(
service
.
podcount
).
to
eq
(
0
)
expect
(
service
.
created_at
).
to
eq
(
DateTime
.
parse
(
'2019-10-22T21:19:13Z'
))
expect
(
service
.
image
).
to
eq
(
'some-image'
)
expect
(
service
.
cluster
).
to
eq
(
cluster
)
expect
(
service
.
environment
).
to
eq
(
environment
)
end
it
'returns nil for missing attributes'
do
service
=
Gitlab
::
Serverless
::
Service
.
new
({})
[
:name
,
:namespace
,
:environment_scope
,
:cluster
,
:podcount
,
:created_at
,
:image
,
:description
,
:url
,
:environment
].
each
do
|
method
|
expect
(
service
.
send
(
method
)).
to
be_nil
end
end
describe
'#description'
do
it
'extracts the description in knative 7 format if available'
do
attributes
=
{
'spec'
=>
{
'template'
=>
{
'metadata'
=>
{
'annotations'
=>
{
'Description'
=>
'some description'
}
}
}
}
}
service
=
Gitlab
::
Serverless
::
Service
.
new
(
attributes
)
expect
(
service
.
description
).
to
eq
(
'some description'
)
end
it
'extracts the description in knative 5/6 format if 7 is not available'
do
attributes
=
{
'spec'
=>
{
'runLatest'
=>
{
'configuration'
=>
{
'revisionTemplate'
=>
{
'metadata'
=>
{
'annotations'
=>
{
'Description'
=>
'some description'
}
}
}
}
}
}
}
service
=
Gitlab
::
Serverless
::
Service
.
new
(
attributes
)
expect
(
service
.
description
).
to
eq
(
'some description'
)
end
end
describe
'#url'
do
it
'returns proxy URL if cluster has serverless domain'
do
# cluster = create(:cluster)
knative
=
create
(
:clusters_applications_knative
,
:installed
,
cluster:
cluster
)
create
(
:serverless_domain_cluster
,
clusters_applications_knative_id:
knative
.
id
)
service
=
Gitlab
::
Serverless
::
Service
.
new
(
attributes
.
merge
(
'cluster'
=>
cluster
))
expect
(
Gitlab
::
Serverless
::
FunctionURI
).
to
receive
(
:new
).
with
(
function:
service
.
name
,
cluster:
service
.
cluster
.
serverless_domain
,
environment:
service
.
environment
).
and_return
(
'https://proxy.example.com'
)
expect
(
service
.
url
).
to
eq
(
'https://proxy.example.com'
)
end
it
'returns the URL from the knative 6/7 format'
do
attributes
=
{
'status'
=>
{
'url'
=>
'https://example.com'
}
}
service
=
Gitlab
::
Serverless
::
Service
.
new
(
attributes
)
expect
(
service
.
url
).
to
eq
(
'https://example.com'
)
end
it
'returns the URL from the knative 5 format'
do
attributes
=
{
'status'
=>
{
'domain'
=>
'example.com'
}
}
service
=
Gitlab
::
Serverless
::
Service
.
new
(
attributes
)
expect
(
service
.
url
).
to
eq
(
'http://example.com'
)
end
end
end
spec/lib/gitlab/usage_data_spec.rb
View file @
1ca9950d
...
...
@@ -18,7 +18,7 @@ describe Gitlab::UsageData do
create
(
:service
,
project:
projects
[
1
],
type:
'SlackService'
,
active:
true
)
create
(
:service
,
project:
projects
[
2
],
type:
'SlackService'
,
active:
true
)
create
(
:service
,
project:
projects
[
2
],
type:
'MattermostService'
,
active:
false
)
create
(
:service
,
project:
projects
[
2
],
type:
'MattermostService'
,
active:
true
,
instanc
e:
true
)
create
(
:service
,
project:
projects
[
2
],
type:
'MattermostService'
,
active:
true
,
templat
e:
true
)
create
(
:service
,
project:
projects
[
2
],
type:
'CustomIssueTrackerService'
,
active:
true
)
create
(
:project_error_tracking_setting
,
project:
projects
[
0
])
create
(
:project_error_tracking_setting
,
project:
projects
[
1
],
enabled:
false
)
...
...
spec/migrations/migrate_propagate_service_template_sidekiq_queue_spec.rb
deleted
100644 → 0
View file @
bcc77054
# frozen_string_literal: true
require
'spec_helper'
require
Rails
.
root
.
join
(
'db'
,
'post_migrate'
,
'20200206111847_migrate_propagate_service_template_sidekiq_queue.rb'
)
describe
MigratePropagateServiceTemplateSidekiqQueue
,
:sidekiq
,
:redis
do
include
Gitlab
::
Database
::
MigrationHelpers
include
StubWorker
context
'when there are jobs in the queue'
do
it
'correctly migrates queue when migrating up'
do
Sidekiq
::
Testing
.
disable!
do
stub_worker
(
queue:
'propagate_service_template'
).
perform_async
(
'Something'
,
[
1
])
stub_worker
(
queue:
'propagate_instance_level_service'
).
perform_async
(
'Something'
,
[
1
])
described_class
.
new
.
up
expect
(
sidekiq_queue_length
(
'propagate_service_template'
)).
to
eq
0
expect
(
sidekiq_queue_length
(
'propagate_instance_level_service'
)).
to
eq
2
end
end
end
context
'when there are no jobs in the queues'
do
it
'does not raise error when migrating up'
do
expect
{
described_class
.
new
.
up
}.
not_to
raise_error
end
end
end
spec/models/service_spec.rb
View file @
1ca9950d
...
...
@@ -97,23 +97,23 @@ describe Service do
end
end
describe
"
Instanc
e"
do
describe
"
Templat
e"
do
let
(
:project
)
{
create
(
:project
)
}
describe
'.build_from_
instanc
e'
do
context
'when
instance level integration
is invalid'
do
it
'sets
instance level integration to inactive when instanc
e is invalid'
do
instance
=
build
(
:prometheus_service
,
instanc
e:
true
,
active:
true
,
properties:
{})
instanc
e
.
save
(
validate:
false
)
describe
'.build_from_
templat
e'
do
context
'when
template
is invalid'
do
it
'sets
service template to inactive when templat
e is invalid'
do
template
=
build
(
:prometheus_service
,
templat
e:
true
,
active:
true
,
properties:
{})
templat
e
.
save
(
validate:
false
)
service
=
described_class
.
build_from_
instance
(
project
.
id
,
instanc
e
)
service
=
described_class
.
build_from_
template
(
project
.
id
,
templat
e
)
expect
(
service
).
to
be_valid
expect
(
service
.
active
).
to
be
false
end
end
describe
'build issue tracker from a
instance level integration
'
do
describe
'build issue tracker from a
template
'
do
let
(
:title
)
{
'custom title'
}
let
(
:description
)
{
'custom description'
}
let
(
:url
)
{
'http://jira.example.com'
}
...
...
@@ -127,9 +127,9 @@ describe Service do
}
end
shared_examples
'
integration creation from instance level
'
do
shared_examples
'
service creation from a template
'
do
it
'creates a correct service'
do
service
=
described_class
.
build_from_
instance
(
project
.
id
,
instance_level_integration
)
service
=
described_class
.
build_from_
template
(
project
.
id
,
template
)
expect
(
service
).
to
be_active
expect
(
service
.
title
).
to
eq
(
title
)
...
...
@@ -144,38 +144,38 @@ describe Service do
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
context
'when data are stored in properties'
do
let
(
:properties
)
{
data_params
.
merge
(
title:
title
,
description:
description
)
}
let!
(
:
instance_level_integration
)
do
create
(
:jira_service
,
:without_properties_callback
,
instanc
e:
true
,
properties:
properties
.
merge
(
additional:
'something'
))
let!
(
:
template
)
do
create
(
:jira_service
,
:without_properties_callback
,
templat
e:
true
,
properties:
properties
.
merge
(
additional:
'something'
))
end
it_behaves_like
'
integration creation from instance level
'
it_behaves_like
'
service creation from a template
'
end
context
'when data are stored in separated fields'
do
let
(
:
instance_level_integration
)
do
create
(
:jira_service
,
data_params
.
merge
(
properties:
{},
title:
title
,
description:
description
,
instanc
e:
true
))
let
(
:
template
)
do
create
(
:jira_service
,
data_params
.
merge
(
properties:
{},
title:
title
,
description:
description
,
templat
e:
true
))
end
it_behaves_like
'
integration creation from instance level
'
it_behaves_like
'
service creation from a template
'
end
context
'when data are stored in both properties and separated fields'
do
let
(
:properties
)
{
data_params
.
merge
(
title:
title
,
description:
description
)
}
let
(
:
instance_level_integration
)
do
create
(
:jira_service
,
:without_properties_callback
,
active:
true
,
instanc
e:
true
,
properties:
properties
).
tap
do
|
service
|
let
(
:
template
)
do
create
(
:jira_service
,
:without_properties_callback
,
active:
true
,
templat
e:
true
,
properties:
properties
).
tap
do
|
service
|
create
(
:jira_tracker_data
,
data_params
.
merge
(
service:
service
))
end
end
it_behaves_like
'
integration creation from instance level
'
it_behaves_like
'
service creation from a template
'
end
end
end
describe
"for pushover service"
do
let!
(
:
instance_level_integration
)
do
let!
(
:
service_template
)
do
PushoverService
.
create
(
instanc
e:
true
,
templat
e:
true
,
properties:
{
device:
'MyDevice'
,
sound:
'mic'
,
...
...
@@ -188,7 +188,7 @@ describe Service do
it
"has all fields prefilled"
do
service
=
project
.
find_or_initialize_service
(
'pushover'
)
expect
(
service
.
instanc
e
).
to
eq
(
false
)
expect
(
service
.
templat
e
).
to
eq
(
false
)
expect
(
service
.
device
).
to
eq
(
'MyDevice'
)
expect
(
service
.
sound
).
to
eq
(
'mic'
)
expect
(
service
.
priority
).
to
eq
(
4
)
...
...
@@ -391,6 +391,14 @@ describe Service do
end
end
describe
'.find_by_template'
do
let!
(
:service
)
{
create
(
:service
,
template:
true
)
}
it
'returns service template'
do
expect
(
described_class
.
find_by_template
).
to
eq
(
service
)
end
end
describe
'#api_field_names'
do
let
(
:fake_service
)
do
Class
.
new
(
Service
)
do
...
...
spec/presenters/snippet_blob_presenter_spec.rb
View file @
1ca9950d
...
...
@@ -18,7 +18,7 @@ describe SnippetBlobPresenter do
snippet
.
file_name
=
'test.md'
snippet
.
content
=
'*foo*'
expect
(
subject
).
to
eq
'<
p data-sourcepos="1:1-1:5" dir="auto"><em>foo</em></p
>'
expect
(
subject
).
to
eq
'<
span id="LC1" class="line" lang="markdown"><span class="ge">*foo*</span></span
>'
end
it
'returns syntax highlighted content'
do
...
...
@@ -33,7 +33,41 @@ describe SnippetBlobPresenter do
snippet
.
file_name
=
'test'
snippet
.
content
=
'foo'
expect
(
described_class
.
new
(
snippet
.
blob
).
highlighted_data
).
to
eq
'<span id="LC1" class="line" lang="plaintext">foo</span>'
expect
(
subject
).
to
eq
'<span id="LC1" class="line" lang="plaintext">foo</span>'
end
end
describe
'#plain_highlighted_data'
do
let
(
:snippet
)
{
build
(
:personal_snippet
)
}
subject
{
described_class
.
new
(
snippet
.
blob
).
plain_highlighted_data
}
it
'returns nil when the snippet blob is binary'
do
allow
(
snippet
.
blob
).
to
receive
(
:binary?
).
and_return
(
true
)
expect
(
subject
).
to
be_nil
end
it
'returns plain content when snippet file is markup'
do
snippet
.
file_name
=
'test.md'
snippet
.
content
=
'*foo*'
expect
(
subject
).
to
eq
'<span id="LC1" class="line" lang="">*foo*</span>'
end
it
'returns plain syntax content'
do
snippet
.
file_name
=
'test.rb'
snippet
.
content
=
'class Foo;end'
expect
(
subject
)
.
to
eq
'<span id="LC1" class="line" lang="">class Foo;end</span>'
end
it
'returns plain text highlighted content'
do
snippet
.
file_name
=
'test'
snippet
.
content
=
'foo'
expect
(
subject
).
to
eq
'<span id="LC1" class="line" lang="">foo</span>'
end
end
...
...
spec/services/projects/create_service_spec.rb
View file @
1ca9950d
...
...
@@ -15,7 +15,7 @@ describe Projects::CreateService, '#execute' do
}
end
it
'creates labels on Project creation if there are
instance level servic
es'
do
it
'creates labels on Project creation if there are
templat
es'
do
Label
.
create
(
title:
"bug"
,
template:
true
)
project
=
create_project
(
user
,
opts
)
...
...
@@ -96,7 +96,7 @@ describe Projects::CreateService, '#execute' do
end
it
'sets invalid service as inactive'
do
create
(
:service
,
type:
'JiraService'
,
project:
nil
,
instanc
e:
true
,
active:
true
)
create
(
:service
,
type:
'JiraService'
,
project:
nil
,
templat
e:
true
,
active:
true
)
project
=
create_project
(
user
,
opts
)
service
=
project
.
services
.
first
...
...
@@ -342,22 +342,22 @@ describe Projects::CreateService, '#execute' do
end
end
context
'when there is an active
instance level servic
e'
do
context
'when there is an active
service templat
e'
do
before
do
create
(
:service
,
project:
nil
,
instanc
e:
true
,
active:
true
)
create
(
:service
,
project:
nil
,
templat
e:
true
,
active:
true
)
end
it
'creates a service from
instance level servic
e'
do
it
'creates a service from
this templat
e'
do
project
=
create_project
(
user
,
opts
)
expect
(
project
.
services
.
count
).
to
eq
1
end
end
context
'when a bad
instance level servic
e is created'
do
context
'when a bad
service templat
e is created'
do
it
'sets service to be inactive'
do
opts
[
:import_url
]
=
'http://www.gitlab.com/gitlab-org/gitlab-foss'
create
(
:service
,
type:
'DroneCiService'
,
project:
nil
,
instanc
e:
true
,
active:
true
)
create
(
:service
,
type:
'DroneCiService'
,
project:
nil
,
templat
e:
true
,
active:
true
)
project
=
create_project
(
user
,
opts
)
service
=
project
.
services
.
first
...
...
spec/services/projects/propagate_
instance_level_servic
e_spec.rb
→
spec/services/projects/propagate_
service_templat
e_spec.rb
View file @
1ca9950d
...
...
@@ -2,11 +2,11 @@
require
'spec_helper'
describe
Projects
::
Propagate
InstanceLevelServic
e
do
describe
Projects
::
Propagate
ServiceTemplat
e
do
describe
'.propagate'
do
let!
(
:
instance_level_integration
)
do
let!
(
:
service_template
)
do
PushoverService
.
create
(
instanc
e:
true
,
templat
e:
true
,
active:
true
,
properties:
{
device:
'MyDevice'
,
...
...
@@ -22,14 +22,14 @@ describe Projects::PropagateInstanceLevelService do
it
'creates services for projects'
do
expect
(
project
.
pushover_service
).
to
be_nil
described_class
.
propagate
(
instance_level_integration
)
described_class
.
propagate
(
service_template
)
expect
(
project
.
reload
.
pushover_service
).
to
be_present
end
it
'creates services for a project that has another service'
do
BambooService
.
create
(
instanc
e:
true
,
templat
e:
true
,
active:
true
,
project:
project
,
properties:
{
...
...
@@ -42,14 +42,14 @@ describe Projects::PropagateInstanceLevelService do
expect
(
project
.
pushover_service
).
to
be_nil
described_class
.
propagate
(
instance_level_integration
)
described_class
.
propagate
(
service_template
)
expect
(
project
.
reload
.
pushover_service
).
to
be_present
end
it
'does not create the service if it exists already'
do
other_service
=
BambooService
.
create
(
instanc
e:
true
,
templat
e:
true
,
active:
true
,
properties:
{
bamboo_url:
'http://gitlab.com'
,
...
...
@@ -59,17 +59,17 @@ describe Projects::PropagateInstanceLevelService do
}
)
Service
.
build_from_
instance
(
project
.
id
,
instance_level_integration
).
save!
Service
.
build_from_
instanc
e
(
project
.
id
,
other_service
).
save!
Service
.
build_from_
template
(
project
.
id
,
service_template
).
save!
Service
.
build_from_
templat
e
(
project
.
id
,
other_service
).
save!
expect
{
described_class
.
propagate
(
instance_level_integration
)
}
expect
{
described_class
.
propagate
(
service_template
)
}
.
not_to
change
{
Service
.
count
}
end
it
'creates the service containing the
instanc
e attributes'
do
described_class
.
propagate
(
instance_level_integration
)
it
'creates the service containing the
templat
e attributes'
do
described_class
.
propagate
(
service_template
)
expect
(
project
.
pushover_service
.
properties
).
to
eq
(
instance_level_integration
.
properties
)
expect
(
project
.
pushover_service
.
properties
).
to
eq
(
service_template
.
properties
)
end
describe
'bulk update'
,
:use_sql_query_cache
do
...
...
@@ -80,7 +80,7 @@ describe Projects::PropagateInstanceLevelService do
project_total
.
times
{
create
(
:project
)
}
described_class
.
propagate
(
instance_level_integration
)
described_class
.
propagate
(
service_template
)
end
it
'creates services for all projects'
do
...
...
@@ -90,18 +90,18 @@ describe Projects::PropagateInstanceLevelService do
describe
'external tracker'
do
it
'updates the project external tracker'
do
instance_level_integration
.
update!
(
category:
'issue_tracker'
,
default:
false
)
service_template
.
update!
(
category:
'issue_tracker'
,
default:
false
)
expect
{
described_class
.
propagate
(
instance_level_integration
)
}
expect
{
described_class
.
propagate
(
service_template
)
}
.
to
change
{
project
.
reload
.
has_external_issue_tracker
}.
to
(
true
)
end
end
describe
'external wiki'
do
it
'updates the project external tracker'
do
instance_level_integration
.
update!
(
type:
'ExternalWikiService'
)
service_template
.
update!
(
type:
'ExternalWikiService'
)
expect
{
described_class
.
propagate
(
instance_level_integration
)
}
expect
{
described_class
.
propagate
(
service_template
)
}
.
to
change
{
project
.
reload
.
has_external_wiki
}.
to
(
true
)
end
end
...
...
spec/support/helpers/kubernetes_helpers.rb
View file @
1ca9950d
...
...
@@ -557,7 +557,7 @@ module KubernetesHelpers
end
# noinspection RubyStringKeysInHashInspection
def
knative_06_service
(
name:
'kubetest'
,
namespace:
'default'
,
domain:
'example.com'
,
description:
'a knative service'
,
environment:
'production'
)
def
knative_06_service
(
name:
'kubetest'
,
namespace:
'default'
,
domain:
'example.com'
,
description:
'a knative service'
,
environment:
'production'
,
cluster_id:
9
)
{
"apiVersion"
=>
"serving.knative.dev/v1alpha1"
,
"kind"
=>
"Service"
,
"metadata"
=>
...
...
@@ -612,12 +612,12 @@ module KubernetesHelpers
"url"
=>
"http://
#{
name
}
.
#{
namespace
}
.
#{
domain
}
"
},
"environment_scope"
=>
environment
,
"cluster_id"
=>
9
,
"cluster_id"
=>
cluster_id
,
"podcount"
=>
0
}
end
# noinspection RubyStringKeysInHashInspection
def
knative_07_service
(
name:
'kubetest'
,
namespace:
'default'
,
domain:
'example.com'
,
description:
'a knative service'
,
environment:
'production'
)
def
knative_07_service
(
name:
'kubetest'
,
namespace:
'default'
,
domain:
'example.com'
,
description:
'a knative service'
,
environment:
'production'
,
cluster_id:
5
)
{
"apiVersion"
=>
"serving.knative.dev/v1alpha1"
,
"kind"
=>
"Service"
,
"metadata"
=>
...
...
@@ -664,12 +664,12 @@ module KubernetesHelpers
"traffic"
=>
[{
"latestRevision"
=>
true
,
"percent"
=>
100
,
"revisionName"
=>
"
#{
name
}
-92tsj"
}],
"url"
=>
"http://
#{
name
}
.
#{
namespace
}
.
#{
domain
}
"
},
"environment_scope"
=>
environment
,
"cluster_id"
=>
5
,
"cluster_id"
=>
cluster_id
,
"podcount"
=>
0
}
end
# noinspection RubyStringKeysInHashInspection
def
knative_09_service
(
name:
'kubetest'
,
namespace:
'default'
,
domain:
'example.com'
,
description:
'a knative service'
,
environment:
'production'
)
def
knative_09_service
(
name:
'kubetest'
,
namespace:
'default'
,
domain:
'example.com'
,
description:
'a knative service'
,
environment:
'production'
,
cluster_id:
5
)
{
"apiVersion"
=>
"serving.knative.dev/v1alpha1"
,
"kind"
=>
"Service"
,
"metadata"
=>
...
...
@@ -716,12 +716,12 @@ module KubernetesHelpers
"traffic"
=>
[{
"latestRevision"
=>
true
,
"percent"
=>
100
,
"revisionName"
=>
"
#{
name
}
-92tsj"
}],
"url"
=>
"http://
#{
name
}
.
#{
namespace
}
.
#{
domain
}
"
},
"environment_scope"
=>
environment
,
"cluster_id"
=>
5
,
"cluster_id"
=>
cluster_id
,
"podcount"
=>
0
}
end
# noinspection RubyStringKeysInHashInspection
def
knative_05_service
(
name:
'kubetest'
,
namespace:
'default'
,
domain:
'example.com'
,
description:
'a knative service'
,
environment:
'production'
)
def
knative_05_service
(
name:
'kubetest'
,
namespace:
'default'
,
domain:
'example.com'
,
description:
'a knative service'
,
environment:
'production'
,
cluster_id:
8
)
{
"apiVersion"
=>
"serving.knative.dev/v1alpha1"
,
"kind"
=>
"Service"
,
"metadata"
=>
...
...
@@ -771,7 +771,7 @@ module KubernetesHelpers
"observedGeneration"
=>
1
,
"traffic"
=>
[{
"percent"
=>
100
,
"revisionName"
=>
"
#{
name
}
-58qgr"
}]
},
"environment_scope"
=>
environment
,
"cluster_id"
=>
8
,
"cluster_id"
=>
cluster_id
,
"podcount"
=>
0
}
end
...
...
spec/support/shared_examples/workers/pages_domain_cron_worker_shared_examples.rb
0 → 100644
View file @
1ca9950d
# frozen_string_literal: true
RSpec
.
shared_examples
'a pages cronjob scheduling jobs with context'
do
|
scheduled_worker_class
|
let
(
:worker
)
{
described_class
.
new
}
it
'does not cause extra queries for multiple domains'
do
control
=
ActiveRecord
::
QueryRecorder
.
new
{
worker
.
perform
}
extra_domain
expect
{
worker
.
perform
}.
not_to
exceed_query_limit
(
control
)
end
it
'schedules the renewal with a context'
do
extra_domain
worker
.
perform
expect
(
scheduled_worker_class
.
jobs
.
last
).
to
include
(
"meta.project"
=>
extra_domain
.
project
.
full_path
)
end
end
spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb
View file @
1ca9950d
...
...
@@ -12,7 +12,7 @@ describe PagesDomainSslRenewalCronWorker do
end
describe
'#perform'
do
let
(
:project
)
{
create
:project
}
let
_it_be
(
:project
)
{
create
:project
}
let!
(
:domain
)
{
create
(
:pages_domain
,
project:
project
,
auto_ssl_enabled:
false
)
}
let!
(
:domain_with_enabled_auto_ssl
)
{
create
(
:pages_domain
,
project:
project
,
auto_ssl_enabled:
true
)
}
let!
(
:domain_with_obtained_letsencrypt
)
do
...
...
@@ -35,12 +35,16 @@ describe PagesDomainSslRenewalCronWorker do
[
domain
,
domain_with_obtained_letsencrypt
].
each
do
|
domain
|
expect
(
PagesDomain
Verification
Worker
).
not_to
receive
(
:perform_async
).
with
(
domain
.
id
)
expect
(
PagesDomain
SslRenewal
Worker
).
not_to
receive
(
:perform_async
).
with
(
domain
.
id
)
end
worker
.
perform
end
it_behaves_like
'a pages cronjob scheduling jobs with context'
,
PagesDomainSslRenewalWorker
do
let
(
:extra_domain
)
{
create
(
:pages_domain
,
:with_project
,
auto_ssl_enabled:
true
)
}
end
shared_examples
'does nothing'
do
it
'does nothing'
do
expect
(
PagesDomainSslRenewalWorker
).
not_to
receive
(
:perform_async
)
...
...
spec/workers/pages_domain_verification_cron_worker_spec.rb
View file @
1ca9950d
...
...
@@ -5,9 +5,9 @@ require 'spec_helper'
describe
PagesDomainVerificationCronWorker
do
subject
(
:worker
)
{
described_class
.
new
}
describe
'#perform'
do
describe
'#perform'
,
:sidekiq
do
let!
(
:verified
)
{
create
(
:pages_domain
)
}
let!
(
:reverify
)
{
create
(
:pages_domain
,
:reverify
)
}
let!
(
:reverify
)
{
create
(
:pages_domain
,
:reverify
,
:with_project
)
}
let!
(
:disabled
)
{
create
(
:pages_domain
,
:disabled
)
}
it
'does nothing if the database is read-only'
do
...
...
@@ -26,5 +26,9 @@ describe PagesDomainVerificationCronWorker do
worker
.
perform
end
it_behaves_like
'a pages cronjob scheduling jobs with context'
,
PagesDomainVerificationWorker
do
let
(
:extra_domain
)
{
create
(
:pages_domain
,
:reverify
,
:with_project
)
}
end
end
end
spec/workers/propagate_
instance_level_servic
e_worker_spec.rb
→
spec/workers/propagate_
service_templat
e_worker_spec.rb
View file @
1ca9950d
...
...
@@ -2,13 +2,13 @@
require
'spec_helper'
describe
Propagate
InstanceLevelServic
eWorker
do
describe
Propagate
ServiceTemplat
eWorker
do
include
ExclusiveLeaseHelpers
describe
'#perform'
do
it
'calls the propagate service with the
instance level servic
e'
do
instance_level_servic
e
=
PushoverService
.
create
(
instanc
e:
true
,
it
'calls the propagate service with the
templat
e'
do
templat
e
=
PushoverService
.
create
(
templat
e:
true
,
active:
true
,
properties:
{
device:
'MyDevice'
,
...
...
@@ -18,14 +18,14 @@ describe PropagateInstanceLevelServiceWorker do
api_key:
'123456789'
})
stub_exclusive_lease
(
"propagate_
instance_level_service_worker:
#{
instance_level_servic
e
.
id
}
"
,
timeout:
Propagate
InstanceLevelServic
eWorker
::
LEASE_TIMEOUT
)
stub_exclusive_lease
(
"propagate_
service_template_worker:
#{
templat
e
.
id
}
"
,
timeout:
Propagate
ServiceTemplat
eWorker
::
LEASE_TIMEOUT
)
expect
(
Projects
::
Propagate
InstanceLevelServic
e
)
expect
(
Projects
::
Propagate
ServiceTemplat
e
)
.
to
receive
(
:propagate
)
.
with
(
instance_level_servic
e
)
.
with
(
templat
e
)
subject
.
perform
(
instance_level_servic
e
.
id
)
subject
.
perform
(
templat
e
.
id
)
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