diff --git a/.rubocop_todo/gitlab/json.yml b/.rubocop_todo/gitlab/json.yml
index 799d90f0048..727ccda4983 100644
--- a/.rubocop_todo/gitlab/json.yml
+++ b/.rubocop_todo/gitlab/json.yml
@@ -18,31 +18,6 @@ Gitlab/Json:
- 'app/controllers/projects/templates_controller.rb'
- 'app/controllers/projects_controller.rb'
- 'app/controllers/search_controller.rb'
- - 'app/helpers/access_tokens_helper.rb'
- - 'app/helpers/application_settings_helper.rb'
- - 'app/helpers/breadcrumbs_helper.rb'
- - 'app/helpers/ci/builds_helper.rb'
- - 'app/helpers/ci/pipelines_helper.rb'
- - 'app/helpers/compare_helper.rb'
- - 'app/helpers/emails_helper.rb'
- - 'app/helpers/environment_helper.rb'
- - 'app/helpers/groups_helper.rb'
- - 'app/helpers/ide_helper.rb'
- - 'app/helpers/integrations_helper.rb'
- - 'app/helpers/invite_members_helper.rb'
- - 'app/helpers/issuables_description_templates_helper.rb'
- - 'app/helpers/issuables_helper.rb'
- - 'app/helpers/jira_connect_helper.rb'
- - 'app/helpers/learn_gitlab_helper.rb'
- - 'app/helpers/namespaces_helper.rb'
- - 'app/helpers/notes_helper.rb'
- - 'app/helpers/operations_helper.rb'
- - 'app/helpers/packages_helper.rb'
- - 'app/helpers/projects/project_members_helper.rb'
- - 'app/helpers/projects_helper.rb'
- - 'app/helpers/search_helper.rb'
- - 'app/helpers/terms_helper.rb'
- - 'app/helpers/users_helper.rb'
- 'app/mailers/emails/members.rb'
- 'app/models/concerns/redis_cacheable.rb'
- 'app/models/diff_discussion.rb'
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue
index 0127df730b8..27186281c42 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue
@@ -194,6 +194,7 @@ export default {
ref="dropdown"
:text="buttonText"
class="gl-w-full"
+ block
data-testid="labels-select-dropdown-contents"
data-qa-selector="labels_dropdown_content"
@hide="handleDropdownHide"
diff --git a/app/graphql/mutations/ci/pipeline_schedule/take_ownership.rb b/app/graphql/mutations/ci/pipeline_schedule/take_ownership.rb
new file mode 100644
index 00000000000..2e4312f0045
--- /dev/null
+++ b/app/graphql/mutations/ci/pipeline_schedule/take_ownership.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Ci
+ module PipelineSchedule
+ class TakeOwnership < Base
+ graphql_name 'PipelineScheduleTakeOwnership'
+
+ authorize :take_ownership_pipeline_schedule
+
+ field :pipeline_schedule,
+ Types::Ci::PipelineScheduleType,
+ description: 'Updated pipeline schedule ownership.'
+
+ def resolve(id:)
+ schedule = authorized_find!(id: id)
+
+ service_response = ::Ci::PipelineSchedules::TakeOwnershipService.new(schedule, current_user).execute
+ {
+ pipeline_schedule: schedule,
+ errors: service_response.errors
+ }
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index 5ffc1aeacad..e4b705245ed 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -115,6 +115,7 @@ module Types
mount_mutation Mutations::Ci::Pipeline::Destroy
mount_mutation Mutations::Ci::Pipeline::Retry
mount_mutation Mutations::Ci::PipelineSchedule::Delete
+ mount_mutation Mutations::Ci::PipelineSchedule::TakeOwnership
mount_mutation Mutations::Ci::CiCdSettingsUpdate, deprecated: {
reason: :renamed,
replacement: 'ProjectCiCdSettingsUpdate',
diff --git a/app/helpers/access_tokens_helper.rb b/app/helpers/access_tokens_helper.rb
index 44200e84afb..07e61b7f552 100644
--- a/app/helpers/access_tokens_helper.rb
+++ b/app/helpers/access_tokens_helper.rb
@@ -9,7 +9,7 @@ module AccessTokensHelper
end
def tokens_app_data
- {
+ data = {
feed_token: {
enabled: !Gitlab::CurrentSettings.disable_feed_token,
token: current_user.feed_token,
@@ -25,7 +25,9 @@ module AccessTokensHelper
token: current_user.enabled_static_object_token,
reset_path: reset_static_object_token_profile_path
}
- }.to_json
+ }
+
+ Gitlab::Json.dump(data)
end
def expires_at_field_data
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index b48f843135d..c57f355b487 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -137,7 +137,7 @@ module ApplicationSettingsHelper
}
end
- options.to_json
+ Gitlab::Json.dump(options)
end
def external_authorization_description
diff --git a/app/helpers/breadcrumbs_helper.rb b/app/helpers/breadcrumbs_helper.rb
index 38ed6e95a44..a14bc8e00bf 100644
--- a/app/helpers/breadcrumbs_helper.rb
+++ b/app/helpers/breadcrumbs_helper.rb
@@ -40,11 +40,11 @@ module BreadcrumbsHelper
end
def schema_breadcrumb_json
- {
+ Gitlab::Json.dump({
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
'itemListElement': build_item_list_elements
- }.to_json
+ })
end
private
diff --git a/app/helpers/ci/builds_helper.rb b/app/helpers/ci/builds_helper.rb
index afd0af18ba7..265969a6370 100644
--- a/app/helpers/ci/builds_helper.rb
+++ b/app/helpers/ci/builds_helper.rb
@@ -38,13 +38,13 @@ module Ci
end
def prepare_failed_jobs_summary_data(failed_builds)
- failed_builds.map do |build|
+ Gitlab::Json.dump(failed_builds.map do |build|
{
id: build.id,
failure: build.present.callout_failure_message,
failure_summary: build_summary(build)
}
- end.to_json
+ end)
end
end
end
diff --git a/app/helpers/ci/pipelines_helper.rb b/app/helpers/ci/pipelines_helper.rb
index c93c8dd8d76..80632f2ea10 100644
--- a/app/helpers/ci/pipelines_helper.rb
+++ b/app/helpers/ci/pipelines_helper.rb
@@ -87,7 +87,7 @@ module Ci
endpoint: list_url,
project_id: project.id,
default_branch_name: project.default_branch,
- params: params.to_json,
+ params: Gitlab::Json.dump(params),
artifacts_endpoint: downloadable_artifacts_project_pipeline_path(project, artifacts_endpoint_placeholder, format: :json),
artifacts_endpoint_placeholder: artifacts_endpoint_placeholder,
pipeline_schedule_url: pipeline_schedules_path(project),
@@ -100,7 +100,7 @@ module Ci
reset_cache_path: can?(current_user, :admin_pipeline, project) && reset_cache_project_settings_ci_cd_path(project),
has_gitlab_ci: has_gitlab_ci?(project).to_s,
pipeline_editor_path: can?(current_user, :create_pipeline, project) && project_ci_pipeline_editor_path(project),
- suggested_ci_templates: suggested_ci_templates.to_json,
+ suggested_ci_templates: Gitlab::Json.dump(suggested_ci_templates),
ci_runner_settings_path: project_settings_ci_cd_path(project, ci_runner_templates: true, anchor: 'js-runners-settings')
}
diff --git a/app/helpers/compare_helper.rb b/app/helpers/compare_helper.rb
index 9ecf780f55b..91f8567aa2d 100644
--- a/app/helpers/compare_helper.rb
+++ b/app/helpers/compare_helper.rb
@@ -37,17 +37,17 @@ module CompareHelper
def project_compare_selector_data(project, merge_request, params)
{
project_compare_index_path: project_compare_index_path(project),
- source_project: { id: project.id, name: project.full_path }.to_json,
- target_project: { id: @target_project.id, name: @target_project.full_path }.to_json,
+ source_project: Gitlab::Json.dump({ id: project.id, name: project.full_path }),
+ target_project: Gitlab::Json.dump({ id: @target_project.id, name: @target_project.full_path }),
source_project_refs_path: refs_project_path(project),
target_project_refs_path: refs_project_path(@target_project),
params_from: params[:from],
params_to: params[:to],
straight: params[:straight]
}.tap do |data|
- data[:projects_from] = target_projects(project).map do |target_project|
+ data[:projects_from] = Gitlab::Json.dump(target_projects(project).map do |target_project|
{ id: target_project.id, name: target_project.full_path }
- end.to_json
+ end)
data[:project_merge_request_path] =
if merge_request.present?
diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb
index 54733fa9101..fe3324120eb 100644
--- a/app/helpers/emails_helper.rb
+++ b/app/helpers/emails_helper.rb
@@ -36,7 +36,7 @@ module EmailsHelper
}
content_tag :script, type: 'application/ld+json' do
- data.to_json.html_safe
+ Gitlab::Json.dump(data).html_safe
end
end
diff --git a/app/helpers/environment_helper.rb b/app/helpers/environment_helper.rb
index b6997b6fb70..677892e7d32 100644
--- a/app/helpers/environment_helper.rb
+++ b/app/helpers/environment_helper.rb
@@ -91,6 +91,6 @@ module EnvironmentHelper
end
def environments_detail_data_json(user, project, environment)
- environments_detail_data(user, project, environment).to_json
+ Gitlab::Json.dump(environments_detail_data(user, project, environment))
end
end
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index 6b00c213875..1612c161f01 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -119,7 +119,7 @@ module GroupsHelper
{ id: group.id, text: group.human_name }
end
- groups.to_json
+ Gitlab::Json.dump(groups)
end
def render_setting_to_allow_project_access_token_creation?(group)
diff --git a/app/helpers/ide_helper.rb b/app/helpers/ide_helper.rb
index 5b3ca25b5af..cdc3804d192 100644
--- a/app/helpers/ide_helper.rb
+++ b/app/helpers/ide_helper.rb
@@ -56,7 +56,7 @@ module IdeHelper
def convert_to_project_entity_json(project)
return unless project
- API::Entities::Project.represent(project, current_user: current_user).to_json
+ Gitlab::Json.dump(API::Entities::Project.represent(project, current_user: current_user))
end
def enable_environments_guidance?
diff --git a/app/helpers/integrations_helper.rb b/app/helpers/integrations_helper.rb
index abfa55cff24..14eec407d15 100644
--- a/app/helpers/integrations_helper.rb
+++ b/app/helpers/integrations_helper.rb
@@ -114,7 +114,7 @@ module IntegrationsHelper
learn_more_path: integrations_help_page_path,
about_pricing_url: Gitlab::Saas.about_pricing_url,
trigger_events: trigger_events_for_integration(integration),
- sections: integration.sections.to_json,
+ sections: Gitlab::Json.dump(integration.sections),
fields: fields_for_integration(integration),
inherit_from_id: integration.inherit_from_id,
integration_level: integration_level(integration),
@@ -144,7 +144,7 @@ module IntegrationsHelper
def integration_list_data(integrations, group: nil, project: nil)
{
- integrations: integrations.map { |i| serialize_integration(i, group: group, project: project) }.to_json
+ integrations: Gitlab::Json.dump(integrations.map { |i| serialize_integration(i, group: group, project: project) })
}
end
@@ -237,11 +237,15 @@ module IntegrationsHelper
end
def trigger_events_for_integration(integration)
- Integrations::EventSerializer.new(integration: integration).represent(integration.configurable_events).to_json
+ serializer = Integrations::EventSerializer.new(integration: integration).represent(integration.configurable_events)
+
+ Gitlab::Json.dump(serializer)
end
def fields_for_integration(integration)
- Integrations::FieldSerializer.new(integration: integration).represent(integration.form_fields).to_json
+ serializer = Integrations::FieldSerializer.new(integration: integration).represent(integration.form_fields)
+
+ Gitlab::Json.dump(serializer)
end
def integration_level(integration)
diff --git a/app/helpers/invite_members_helper.rb b/app/helpers/invite_members_helper.rb
index 5d537767eaf..8672dfb39dc 100644
--- a/app/helpers/invite_members_helper.rb
+++ b/app/helpers/invite_members_helper.rb
@@ -29,7 +29,7 @@ module InviteMembersHelper
invalid_groups: source.related_group_ids,
help_link: help_page_url('user/permissions'),
is_project: is_project,
- access_levels: member_class.permissible_access_level_roles(current_user, source).to_json
+ access_levels: Gitlab::Json.dump(member_class.permissible_access_level_roles(current_user, source))
}.merge(group_select_data(source))
end
@@ -44,8 +44,8 @@ module InviteMembersHelper
if show_invite_members_for_task?(source)
dataset.merge!(
- tasks_to_be_done_options: tasks_to_be_done_options.to_json,
- projects: projects_for_source(source).to_json,
+ tasks_to_be_done_options: Gitlab::Json.dump(tasks_to_be_done_options),
+ projects: Gitlab::Json.dump(projects_for_source(source)),
new_project_path: source.is_a?(Group) ? new_project_path(namespace_id: source.id) : ''
)
end
diff --git a/app/helpers/issuables_description_templates_helper.rb b/app/helpers/issuables_description_templates_helper.rb
index 58b86dca1e0..075b2710722 100644
--- a/app/helpers/issuables_description_templates_helper.rb
+++ b/app/helpers/issuables_description_templates_helper.rb
@@ -53,7 +53,7 @@ module IssuablesDescriptionTemplatesHelper
end
def available_service_desk_templates_for(project)
- issuable_templates(project, 'issue').flatten.to_json
+ Gitlab::Json.dump(issuable_templates(project, 'issue').flatten)
end
def template_names_path(parent, issuable)
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index e9e6241a6a7..0a5d02cbcc7 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -73,10 +73,9 @@ module IssuablesHelper
MergeRequestSerializer
end
- serializer_klass
+ Gitlab::Json.dump(serializer_klass
.new(current_user: current_user, project: issuable.project)
- .represent(issuable, opts)
- .to_json
+ .represent(issuable, opts))
end
def users_dropdown_label(selected_users)
@@ -441,7 +440,7 @@ module IssuablesHelper
labels_manage_path: project_labels_path(project),
project_issues_path: issuable_sidebar[:project_issuables_path],
project_path: project.full_path,
- selected_labels: issuable_sidebar[:labels].to_json
+ selected_labels: Gitlab::Json.dump(issuable_sidebar[:labels])
}
end
diff --git a/app/helpers/jira_connect_helper.rb b/app/helpers/jira_connect_helper.rb
index 0971fdae8dd..70e1f7ca4f6 100644
--- a/app/helpers/jira_connect_helper.rb
+++ b/app/helpers/jira_connect_helper.rb
@@ -6,12 +6,12 @@ module JiraConnectHelper
{
groups_path: api_v4_groups_path(params: { min_access_level: Gitlab::Access::MAINTAINER, skip_groups: skip_groups }),
- subscriptions: subscriptions.map { |s| serialize_subscription(s) }.to_json,
+ subscriptions: Gitlab::Json.dump(subscriptions.map { |s| serialize_subscription(s) }),
add_subscriptions_path: jira_connect_subscriptions_path,
subscriptions_path: jira_connect_subscriptions_path(format: :json),
users_path: current_user ? nil : jira_connect_users_path, # users_path is used to determine if user is signed in
gitlab_user_path: current_user ? user_path(current_user) : nil,
- oauth_metadata: Feature.enabled?(:jira_connect_oauth, current_user) ? jira_connect_oauth_data(installation).to_json : nil
+ oauth_metadata: Feature.enabled?(:jira_connect_oauth, current_user) ? Gitlab::Json.dump(jira_connect_oauth_data(installation)) : nil
}
end
diff --git a/app/helpers/learn_gitlab_helper.rb b/app/helpers/learn_gitlab_helper.rb
index a07922e451a..485a85cc73f 100644
--- a/app/helpers/learn_gitlab_helper.rb
+++ b/app/helpers/learn_gitlab_helper.rb
@@ -14,9 +14,9 @@ module LearnGitlabHelper
def learn_gitlab_data(project)
{
- actions: onboarding_actions_data(project).to_json,
- sections: onboarding_sections_data.to_json,
- project: onboarding_project_data(project).to_json
+ actions: Gitlab::Json.dump(onboarding_actions_data(project)),
+ sections: Gitlab::Json.dump(onboarding_sections_data),
+ project: Gitlab::Json.dump(onboarding_project_data(project))
}
end
diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb
index 60796e628a3..3d4f7254c18 100644
--- a/app/helpers/namespaces_helper.rb
+++ b/app/helpers/namespaces_helper.rb
@@ -67,7 +67,7 @@ module NamespacesHelper
end
{
- popover_data: popover_data.to_json,
+ popover_data: Gitlab::Json.dump(popover_data),
testid: 'cascading-settings-lock-icon'
}
end
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index b47f4633348..c0d26d4759d 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -22,12 +22,14 @@ module NotesHelper
end
def noteable_json(noteable)
- {
+ data = {
id: noteable.id,
class: noteable.class.name,
resources: noteable.class.table_name,
project_id: noteable.project.id
- }.to_json
+ }
+
+ Gitlab::Json.dump(data)
end
def diff_view_data
diff --git a/app/helpers/operations_helper.rb b/app/helpers/operations_helper.rb
index baeb9a477c3..542b8260d20 100644
--- a/app/helpers/operations_helper.rb
+++ b/app/helpers/operations_helper.rb
@@ -26,7 +26,7 @@ module OperationsHelper
'disabled' => disabled.to_s,
'project_path' => @project.full_path,
'multi_integrations' => 'false',
- 'templates' => templates.to_json,
+ 'templates' => Gitlab::Json.dump(templates),
'create_issue' => setting.create_issue.to_s,
'issue_template_key' => setting.issue_template_key.to_s,
'send_email' => setting.send_email.to_s,
diff --git a/app/helpers/packages_helper.rb b/app/helpers/packages_helper.rb
index f9ec20bdd01..9f72acf40b5 100644
--- a/app/helpers/packages_helper.rb
+++ b/app/helpers/packages_helper.rb
@@ -24,7 +24,7 @@ module PackagesHelper
def package_from_presenter(package)
presenter = ::Packages::Detail::PackagePresenter.new(package)
- presenter.detail_view.to_json
+ Gitlab::Json.dump(presenter.detail_view)
end
def pypi_registry_url(project_id)
@@ -68,9 +68,9 @@ module PackagesHelper
{
project_id: @project.id,
project_path: @project.full_path,
- cadence_options: cadence_options.to_json,
- keep_n_options: keep_n_options.to_json,
- older_than_options: older_than_options.to_json,
+ cadence_options: Gitlab::Json.dump(cadence_options),
+ keep_n_options: Gitlab::Json.dump(keep_n_options),
+ older_than_options: Gitlab::Json.dump(older_than_options),
is_admin: current_user&.admin.to_s,
admin_settings_path: ci_cd_admin_application_settings_path(anchor: 'js-registry-settings'),
project_settings_path: project_settings_packages_and_registries_path(@project),
diff --git a/app/helpers/projects/project_members_helper.rb b/app/helpers/projects/project_members_helper.rb
index 51a7d3e35d0..e35277eabaa 100644
--- a/app/helpers/projects/project_members_helper.rb
+++ b/app/helpers/projects/project_members_helper.rb
@@ -2,14 +2,14 @@
module Projects::ProjectMembersHelper
def project_members_app_data_json(project, members:, invited:, access_requests:, include_relations:, search:)
- {
+ Gitlab::Json.dump({
user: project_members_list_data(project, members, { param_name: :page, params: { search_groups: nil } }),
group: project_group_links_list_data(project, include_relations, search),
invite: project_members_list_data(project, invited.nil? ? [] : invited),
access_request: project_members_list_data(project, access_requests.nil? ? [] : access_requests),
source_id: project.id,
can_manage_members: Ability.allowed?(current_user, :admin_project_member, project)
- }.to_json
+ })
end
def project_member_header_subtext(project)
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 122a0ae5277..53c29a3c8b4 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -300,13 +300,15 @@ module ProjectsHelper
return if setting.blank? || setting.project_slug.blank? ||
setting.organization_slug.blank?
- {
+ data = {
sentry_project_id: setting.sentry_project_id,
name: setting.project_name,
organization_name: setting.organization_name,
organization_slug: setting.organization_slug,
slug: setting.project_slug
- }.to_json
+ }
+
+ Gitlab::Json.dump(data)
end
def directory?
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index 7741f714134..b3f82e89dfa 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -440,9 +440,9 @@ module SearchHelper
end
def search_navigation_json
- search_navigation.each_with_object({}) do |(key, value), hash|
+ Gitlab::Json.dump(search_navigation.each_with_object({}) do |(key, value), hash|
hash[key] = search_filter_link_json(key, value[:label], value[:data], value[:search]) if value[:condition]
- end.to_json
+ end)
end
def search_filter_input_options(type, placeholder = _('Search or filter results...'))
diff --git a/app/helpers/terms_helper.rb b/app/helpers/terms_helper.rb
index 5f321551413..1dc5e4f1974 100644
--- a/app/helpers/terms_helper.rb
+++ b/app/helpers/terms_helper.rb
@@ -4,7 +4,7 @@ module TermsHelper
def terms_data(terms, redirect)
redirect_params = { redirect: redirect } if redirect
- {
+ data = {
terms: markdown_field(terms, :terms),
permissions: {
can_accept: can?(current_user, :accept_terms, terms),
@@ -15,6 +15,8 @@ module TermsHelper
decline: decline_term_path(terms, redirect_params),
root: root_path
}
- }.to_json
+ }
+
+ Gitlab::Json.dump(data)
end
end
diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb
index 4f345fdeb9c..d66942c2884 100644
--- a/app/helpers/users_helper.rb
+++ b/app/helpers/users_helper.rb
@@ -3,8 +3,8 @@
module UsersHelper
def admin_users_data_attributes(users)
{
- users: Admin::UserSerializer.new.represent(users, { current_user: current_user }).to_json,
- paths: admin_users_paths.to_json
+ users: Gitlab::Json.dump(Admin::UserSerializer.new.represent(users, { current_user: current_user })),
+ paths: Gitlab::Json.dump(admin_users_paths)
}
end
@@ -163,8 +163,8 @@ module UsersHelper
def admin_user_actions_data_attributes(user)
{
- user: Admin::UserEntity.represent(user, { current_user: current_user }).to_json,
- paths: admin_users_paths.to_json
+ user: Gitlab::Json.dump(Admin::UserEntity.represent(user, { current_user: current_user })),
+ paths: Gitlab::Json.dump(admin_users_paths)
}
end
diff --git a/app/models/container_repository.rb b/app/models/container_repository.rb
index 14520b2da26..c8b8fe5c951 100644
--- a/app/models/container_repository.rb
+++ b/app/models/container_repository.rb
@@ -224,6 +224,13 @@ class ContainerRepository < ApplicationRecord
end
end
+ # Container Repository model and the code that makes API calls
+ # are tied. Sometimes (mainly in Geo) we need to work with Registry
+ # when Container Repository record doesn't even exist.
+ # The ability to create a not-persisted record with a certain "path" parameter
+ # is very useful
+ attr_writer :path
+
def self.exists_by_path?(path)
where(
project: path.repository_project,
diff --git a/app/services/ci/pipeline_schedules/take_ownership_service.rb b/app/services/ci/pipeline_schedules/take_ownership_service.rb
new file mode 100644
index 00000000000..9b4001c74bd
--- /dev/null
+++ b/app/services/ci/pipeline_schedules/take_ownership_service.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Ci
+ module PipelineSchedules
+ class TakeOwnershipService
+ def initialize(schedule, user)
+ @schedule = schedule
+ @user = user
+ end
+
+ def execute
+ return forbidden unless allowed?
+
+ if schedule.update(owner: user)
+ ServiceResponse.success(payload: schedule)
+ else
+ ServiceResponse.error(message: schedule.errors.full_messages)
+ end
+ end
+
+ private
+
+ attr_reader :schedule, :user
+
+ def allowed?
+ user.can?(:take_ownership_pipeline_schedule, schedule)
+ end
+
+ def forbidden
+ ServiceResponse.error(message: _('Failed to change the owner'), reason: :access_denied)
+ end
+ end
+ end
+end
diff --git a/app/services/clusters/applications/create_service.rb b/app/services/clusters/applications/create_service.rb
deleted file mode 100644
index 2a626a402e4..00000000000
--- a/app/services/clusters/applications/create_service.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Applications
- class CreateService < Clusters::Applications::BaseService
- private
-
- def worker_class(application)
- application.updateable? ? ClusterUpgradeAppWorker : ClusterInstallAppWorker
- end
-
- def builder
- cluster.public_send(application_class.association_name) || # rubocop:disable GitlabSecurity/PublicSend
- cluster.public_send(:"build_application_#{application_name}") # rubocop:disable GitlabSecurity/PublicSend
- end
- end
- end
-end
diff --git a/app/views/admin/application_settings/_user_restrictions.html.haml b/app/views/admin/application_settings/_user_restrictions.html.haml
index de8faa6705f..82f5e6def9f 100644
--- a/app/views/admin/application_settings/_user_restrictions.html.haml
+++ b/app/views/admin/application_settings/_user_restrictions.html.haml
@@ -3,4 +3,4 @@
.form-group
= label_tag _('User restrictions')
= render_if_exists 'admin/application_settings/updating_name_disabled_for_users', form: form
- = form.gitlab_ui_checkbox_component :can_create_group, _("Allow users to create top-level groups")
+ = form.gitlab_ui_checkbox_component :can_create_group, _("Allow new users to create top-level groups")
diff --git a/app/workers/cluster_install_app_worker.rb b/app/workers/cluster_install_app_worker.rb
index e16e6e9ca71..0c94f8cad6a 100644
--- a/app/workers/cluster_install_app_worker.rb
+++ b/app/workers/cluster_install_app_worker.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+# DEPRECATED
+#
+# To be removed by https://gitlab.com/gitlab-org/gitlab/-/issues/366573
class ClusterInstallAppWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
@@ -12,9 +15,5 @@ class ClusterInstallAppWorker # rubocop:disable Scalability/IdempotentWorker
worker_has_external_dependencies!
loggable_arguments 0
- def perform(app_name, app_id)
- find_application(app_name, app_id) do |app|
- Clusters::Applications::InstallService.new(app).execute
- end
- end
+ def perform(app_name, app_id); end
end
diff --git a/app/workers/cluster_upgrade_app_worker.rb b/app/workers/cluster_upgrade_app_worker.rb
index bbe0cb7f0c2..40feee9374d 100644
--- a/app/workers/cluster_upgrade_app_worker.rb
+++ b/app/workers/cluster_upgrade_app_worker.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+# DEPRECATED
+#
+# To be removed by https://gitlab.com/gitlab-org/gitlab/-/issues/366573
class ClusterUpgradeAppWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
@@ -12,9 +15,5 @@ class ClusterUpgradeAppWorker # rubocop:disable Scalability/IdempotentWorker
worker_has_external_dependencies!
loggable_arguments 0
- def perform(app_name, app_id)
- find_application(app_name, app_id) do |app|
- Clusters::Applications::UpgradeService.new(app).execute
- end
- end
+ def perform(app_name, app_id); end
end
diff --git a/config/feature_flags/development/split_background_migration_on_query_canceled.yml b/config/feature_flags/development/split_background_migration_on_query_canceled.yml
new file mode 100644
index 00000000000..48409041f1a
--- /dev/null
+++ b/config/feature_flags/development/split_background_migration_on_query_canceled.yml
@@ -0,0 +1,8 @@
+---
+name: split_background_migration_on_query_canceled
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101825
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/378846
+milestone: '15.6'
+type: development
+group: group::database
+default_enabled: false
diff --git a/db/post_migrate/20221025220607_add_index_id_on_scan_finding_approval_merge_request_rules.rb b/db/post_migrate/20221025220607_add_index_id_on_scan_finding_approval_merge_request_rules.rb
new file mode 100644
index 00000000000..4e72e7f95ec
--- /dev/null
+++ b/db/post_migrate/20221025220607_add_index_id_on_scan_finding_approval_merge_request_rules.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddIndexIdOnScanFindingApprovalMergeRequestRules < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = 'scan_finding_approval_mr_rule_index_id'
+ SCAN_FINDING_REPORT_TYPE = 4
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :approval_merge_request_rules, :id,
+ where: "report_type = #{SCAN_FINDING_REPORT_TYPE}", name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :approval_merge_request_rules, INDEX_NAME
+ end
+end
diff --git a/db/schema_migrations/20221025220607 b/db/schema_migrations/20221025220607
new file mode 100644
index 00000000000..30322b1ab3f
--- /dev/null
+++ b/db/schema_migrations/20221025220607
@@ -0,0 +1 @@
+d6eb5bb918f12c08f23c228916b7e21432e1e2958832c10be4e46dfa2079103d
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 570417ccbb6..7f9d177a3ea 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -31078,6 +31078,8 @@ CREATE UNIQUE INDEX partial_index_sop_configs_on_project_id ON security_orchestr
CREATE INDEX partial_index_user_id_app_id_created_at_token_not_revoked ON oauth_access_tokens USING btree (resource_owner_id, application_id, created_at) WHERE (revoked_at IS NULL);
+CREATE INDEX scan_finding_approval_mr_rule_index_id ON approval_merge_request_rules USING btree (id) WHERE (report_type = 4);
+
CREATE INDEX scan_finding_approval_mr_rule_index_merge_request_id ON approval_merge_request_rules USING btree (merge_request_id) WHERE (report_type = 4);
CREATE INDEX scan_finding_approval_project_rule_index_created_at_project_id ON approval_project_rules USING btree (created_at, project_id) WHERE (report_type = 4);
diff --git a/doc/administration/user_settings.md b/doc/administration/user_settings.md
index a767132db0f..c96a6311208 100644
--- a/doc/administration/user_settings.md
+++ b/doc/administration/user_settings.md
@@ -14,7 +14,7 @@ By default, new users can create top-level groups. To disable new users'
ability to create top-level groups (does not affect existing users' setting), GitLab administrators can modify this setting:
- In GitLab 15.5 and later, using either:
- - The [GitLab UI](../user/admin_area/settings/account_and_limit_settings.md#prevent-users-from-creating-top-level-groups).
+ - The [GitLab UI](../user/admin_area/settings/account_and_limit_settings.md#prevent-new-users-from-creating-top-level-groups).
- The [application setting API](../api/settings.md#change-application-settings).
- In GitLab 15.4 and earlier, in a configuration file by following the steps in this section.
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index a68ae262686..1a2ddc6eea8 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -4198,6 +4198,25 @@ Input type: `PipelineScheduleDeleteInput`
| `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| `errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+### `Mutation.pipelineScheduleTakeOwnership`
+
+Input type: `PipelineScheduleTakeOwnershipInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| `id` | [`CiPipelineScheduleID!`](#cipipelinescheduleid) | ID of the pipeline schedule to mutate. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| `errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| `pipelineSchedule` | [`PipelineSchedule`](#pipelineschedule) | Updated pipeline schedule ownership. |
+
### `Mutation.projectCiCdSettingsUpdate`
Input type: `ProjectCiCdSettingsUpdateInput`
diff --git a/doc/ci/testing/code_quality.md b/doc/ci/testing/code_quality.md
index 7345c7ca5eb..d1ed28b79c0 100644
--- a/doc/ci/testing/code_quality.md
+++ b/doc/ci/testing/code_quality.md
@@ -339,6 +339,20 @@ This example is specific to GitLab Code Quality. For more general
instructions on how to configure DinD with a registry mirror, see the
relevant [documentation](../docker/using_docker_build.md#enable-registry-mirror-for-dockerdind-service).
+#### List of images to be stored in the private container registry
+
+The following images are needed for the [default `.codeclimate.yml`](https://gitlab.com/gitlab-org/ci-cd/codequality/-/blob/master/codeclimate_defaults/.codeclimate.yml.template):
+
+- `codeclimate/codeclimate-structure:latest`
+- `codeclimate/codeclimate-csslint:latest`
+- `codeclimate/codeclimate-coffeelint:latest`
+- `codeclimate/codeclimate-duplication:latest`
+- `codeclimate/codeclimate-eslint:latest`
+- `codeclimate/codeclimate-fixme:latest`
+- `codeclimate/codeclimate-rubocop:rubocop-0-92`
+
+If you are using a custom `.codeclimate.yml` configuration file, you must add the specified plugins in your private container registry.
+
#### Configure Code Quality to use the Dependency Proxy
Prerequisite:
diff --git a/doc/user/admin_area/settings/account_and_limit_settings.md b/doc/user/admin_area/settings/account_and_limit_settings.md
index 3d05aa120cf..44a6bbb9d8e 100644
--- a/doc/user/admin_area/settings/account_and_limit_settings.md
+++ b/doc/user/admin_area/settings/account_and_limit_settings.md
@@ -276,11 +276,11 @@ When this ability is disabled, GitLab administrators can still use the
[Admin Area](../index.md#administering-users) or the
[API](../../../api/users.md#user-modification) to update usernames.
-## Prevent users from creating top-level groups
+## Prevent new users from creating top-level groups
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/367754) in GitLab 15.5.
-By default, new users can create top-level groups. GitLab administrators can prevent users from creating top-level groups:
+By default, new users can create top-level groups. GitLab administrators can prevent new users from creating top-level groups:
- In GitLab 15.5 and later, using either:
- The GitLab UI using the steps in this section.
@@ -289,7 +289,7 @@ By default, new users can create top-level groups. GitLab administrators can pre
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > General**, then expand **Account and limit**.
-1. Clear the **Allow users to create top-level groups** checkbox.
+1. Clear the **Allow new users to create top-level groups** checkbox.
## Troubleshooting
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 37ed8f8659c..7a3631b2036 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -170,6 +170,7 @@ module API
# Mount endpoints to include in the OpenAPI V2 documentation here
namespace do
mount ::API::AccessRequests
+ mount ::API::Appearance
mount ::API::Deployments
mount ::API::Metadata
mount ::API::UserCounts
@@ -186,7 +187,6 @@ module API
mount ::API::Admin::PlanLimits
mount ::API::Admin::Sidekiq
mount ::API::AlertManagementAlerts
- mount ::API::Appearance
mount ::API::Applications
mount ::API::Avatar
mount ::API::AwardEmoji
diff --git a/lib/api/appearance.rb b/lib/api/appearance.rb
index e599abf4aaf..69f1521ef2a 100644
--- a/lib/api/appearance.rb
+++ b/lib/api/appearance.rb
@@ -22,6 +22,7 @@ module API
desc 'Modify appearance' do
success Entities::Appearance
+ consumes ['multipart/form-data']
end
params do
optional :title, type: String, desc: 'Instance title on the sign in / sign up page'
diff --git a/lib/gitlab/database/background_migration/batched_job.rb b/lib/gitlab/database/background_migration/batched_job.rb
index 81898a59da7..9ac6d1442a2 100644
--- a/lib/gitlab/database/background_migration/batched_job.rb
+++ b/lib/gitlab/database/background_migration/batched_job.rb
@@ -112,7 +112,7 @@ module Gitlab
end
def can_split?(exception)
- attempts >= MAX_ATTEMPTS && TIMEOUT_EXCEPTIONS.include?(exception&.class) && batch_size > sub_batch_size && batch_size > 1
+ attempts >= MAX_ATTEMPTS && timeout_exception?(exception&.class) && batch_size > sub_batch_size && batch_size > 1
end
def split_and_retry!
@@ -161,6 +161,15 @@ module Gitlab
end
end
end
+
+ private
+
+ def timeout_exception?(exception_class)
+ return false unless exception_class
+
+ TIMEOUT_EXCEPTIONS.include?(exception_class) ||
+ (Feature.enabled?(:split_background_migration_on_query_canceled) && exception_class == ActiveRecord::QueryCanceled)
+ end
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index efbbf7d49ca..a353ed4e544 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -3976,6 +3976,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -4012,9 +4015,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
diff --git a/qa/Gemfile b/qa/Gemfile
index bd02aaa9dbf..77507e2b0b0 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -26,7 +26,7 @@ gem 'octokit', '~> 6.0.0'
gem "faraday-retry", "~> 2.0"
gem 'webdrivers', '~> 5.2'
gem 'zeitwerk', '~> 2.4'
-gem 'influxdb-client', '~> 2.7'
+gem 'influxdb-client', '~> 2.8'
gem 'terminal-table', '~> 3.0.2', require: false
gem 'slack-notifier', '~> 2.4', require: false
gem 'fog-google', '~> 1.19', require: false
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index 8e64739df58..f8a857e67ec 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -156,7 +156,7 @@ GEM
httpclient (2.8.3)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
- influxdb-client (2.7.0)
+ influxdb-client (2.8.0)
jwt (2.5.0)
knapsack (4.0.0)
rake
@@ -315,7 +315,7 @@ DEPENDENCIES
fog-core (= 2.1.0)
fog-google (~> 1.19)
gitlab-qa (~> 8, >= 8.9.0)
- influxdb-client (~> 2.7)
+ influxdb-client (~> 2.8)
knapsack (~> 4.0)
nokogiri (~> 1.13, >= 1.13.9)
octokit (~> 6.0.0)
diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb
index c2c78be6a0f..6971ec83ce2 100644
--- a/spec/helpers/users_helper_spec.rb
+++ b/spec/helpers/users_helper_spec.rb
@@ -391,7 +391,7 @@ RSpec.describe UsersHelper do
expect_next_instance_of(Admin::UserSerializer) do |instance|
expect(instance).to receive(:represent).with([user], { current_user: user }).and_return(entity)
end
- expect(entity).to receive(:to_json).and_return("{\"username\":\"admin\"}")
+ expect(entity).to receive(:as_json).and_return({ "username" => "admin" })
expect(data[:users]).to eq "{\"username\":\"admin\"}"
end
diff --git a/spec/lib/gitlab/database/background_migration/batched_job_spec.rb b/spec/lib/gitlab/database/background_migration/batched_job_spec.rb
index 32746a46308..332c9618cb5 100644
--- a/spec/lib/gitlab/database/background_migration/batched_job_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/batched_job_spec.rb
@@ -272,7 +272,21 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedJob, type: :model d
context 'when is a timeout exception' do
let(:exception) { ActiveRecord::StatementTimeout.new }
- it { expect(subject).to be_truthy }
+ it { expect(subject).to be_truthy }
+ end
+
+ context 'when is a QueryCanceled exception' do
+ let(:exception) { ActiveRecord::QueryCanceled.new }
+
+ it { expect(subject).to be_truthy }
+
+ context 'when split_background_migration_on_query_canceled feature flag is disabled' do
+ before do
+ stub_feature_flags(split_background_migration_on_query_canceled: false)
+ end
+
+ it { expect(subject).to be_falsey }
+ end
end
context 'when is not a timeout exception' do
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_schedule_take_ownership_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_schedule_take_ownership_spec.rb
new file mode 100644
index 00000000000..8dfbf20d00b
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ci/pipeline_schedule_take_ownership_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'PipelineScheduleTakeOwnership' do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:owner) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: owner) }
+
+ let(:mutation) do
+ graphql_mutation(
+ :pipeline_schedule_take_ownership,
+ { id: pipeline_schedule_id },
+ <<-QL
+ errors
+ QL
+ )
+ end
+
+ let(:pipeline_schedule_id) { pipeline_schedule.to_global_id.to_s }
+
+ before_all do
+ project.add_maintainer(user)
+ end
+
+ it 'returns an error if the user is not allowed to take ownership of the schedule' do
+ post_graphql_mutation(mutation, current_user: create(:user))
+
+ expect(graphql_errors).not_to be_empty
+ end
+
+ it 'takes ownership of the schedule' do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(graphql_errors).to be_nil
+ end
+end
diff --git a/spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb b/spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb
new file mode 100644
index 00000000000..9a3aad20d89
--- /dev/null
+++ b/spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::PipelineSchedules::TakeOwnershipService do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:owner) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: owner) }
+
+ before_all do
+ project.add_maintainer(user)
+ project.add_maintainer(owner)
+ project.add_reporter(reporter)
+ end
+
+ describe '#execute' do
+ context 'when user does not have permission' do
+ subject(:service) { described_class.new(pipeline_schedule, reporter) }
+
+ it 'returns ServiceResponse.error' do
+ result = service.execute
+
+ expect(result).to be_a(ServiceResponse)
+ expect(result.error?).to be(true)
+ expect(result.message).to eq(_('Failed to change the owner'))
+ end
+ end
+
+ context 'when user has permission' do
+ subject(:service) { described_class.new(pipeline_schedule, user) }
+
+ it 'returns ServiceResponse.success' do
+ result = service.execute
+
+ expect(result).to be_a(ServiceResponse)
+ expect(result.success?).to be(true)
+ expect(result.payload).to eq(pipeline_schedule)
+ end
+
+ context 'when schedule update fails' do
+ subject(:service) { described_class.new(pipeline_schedule, owner) }
+
+ before do
+ allow(pipeline_schedule).to receive(:update).and_return(false)
+
+ errors = ActiveModel::Errors.new(pipeline_schedule)
+ errors.add(:base, 'An error occurred')
+ allow(pipeline_schedule).to receive(:errors).and_return(errors)
+ end
+
+ it 'returns ServiceResponse.error' do
+ result = service.execute
+
+ expect(result).to be_a(ServiceResponse)
+ expect(result.error?).to be(true)
+ expect(result.message).to eq(['An error occurred'])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/clusters/applications/create_service_spec.rb b/spec/services/clusters/applications/create_service_spec.rb
deleted file mode 100644
index 00a67a9b2ef..00000000000
--- a/spec/services/clusters/applications/create_service_spec.rb
+++ /dev/null
@@ -1,279 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Clusters::Applications::CreateService do
- include TestRequestHelpers
-
- let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
- let(:user) { create(:user) }
- let(:params) { { application: 'ingress' } }
- let(:service) { described_class.new(cluster, user, params) }
-
- describe '#execute' do
- before do
- allow(ClusterInstallAppWorker).to receive(:perform_async)
- allow(ClusterUpgradeAppWorker).to receive(:perform_async)
- end
-
- subject { service.execute(test_request) }
-
- it 'creates an application' do
- expect do
- subject
-
- cluster.reload
- end.to change(cluster, :application_ingress)
- end
-
- context 'application already installed' do
- let!(:application) { create(:clusters_applications_ingress, :installed, cluster: cluster) }
-
- it 'does not create a new application' do
- expect do
- subject
- end.not_to change(Clusters::Applications::Ingress, :count)
- end
-
- it 'schedules an upgrade for the application' do
- expect(ClusterUpgradeAppWorker).to receive(:perform_async)
-
- subject
- end
- end
-
- context 'known applications' do
- context 'ingress application' do
- let(:params) do
- {
- application: 'ingress'
- }
- end
-
- before do
- expect_any_instance_of(Clusters::Applications::Ingress)
- .to receive(:make_scheduled!)
- .and_call_original
- end
-
- it 'creates the application' do
- expect do
- subject
-
- cluster.reload
- end.to change(cluster, :application_ingress)
- end
- end
-
- context 'cert manager application' do
- let(:params) do
- {
- application: 'cert_manager',
- email: 'test@example.com'
- }
- end
-
- before do
- expect_any_instance_of(Clusters::Applications::CertManager)
- .to receive(:make_scheduled!)
- .and_call_original
- end
-
- it 'creates the application' do
- expect do
- subject
-
- cluster.reload
- end.to change(cluster, :application_cert_manager)
- end
-
- it 'sets the email' do
- expect(subject.email).to eq('test@example.com')
- end
- end
-
- context 'jupyter application' do
- let(:params) do
- {
- application: 'jupyter',
- hostname: 'example.com'
- }
- end
-
- before do
- create(:clusters_applications_ingress, :installed, external_ip: "127.0.0.0", cluster: cluster)
- expect_any_instance_of(Clusters::Applications::Jupyter)
- .to receive(:make_scheduled!)
- .and_call_original
- end
-
- it 'creates the application' do
- expect do
- subject
-
- cluster.reload
- end.to change(cluster, :application_jupyter)
- end
-
- it 'sets the hostname' do
- expect(subject.hostname).to eq('example.com')
- end
-
- it 'sets the oauth_application' do
- expect(subject.oauth_application).to be_present
- end
- end
-
- context 'knative application' do
- let(:params) do
- {
- application: 'knative',
- hostname: 'example.com',
- pages_domain_id: domain.id
- }
- end
-
- let(:domain) { create(:pages_domain, :instance_serverless) }
- let(:associate_domain_service) { double('AssociateDomainService') }
-
- before do
- expect_any_instance_of(Clusters::Applications::Knative)
- .to receive(:make_scheduled!)
- .and_call_original
- end
-
- it 'creates the application' do
- expect do
- subject
-
- cluster.reload
- end.to change(cluster, :application_knative)
- end
-
- it 'sets the hostname' do
- expect(subject.hostname).to eq('example.com')
- end
-
- it 'executes AssociateDomainService' do
- expect(Serverless::AssociateDomainService).to receive(:new) do |knative, args|
- expect(knative).to be_a(Clusters::Applications::Knative)
- expect(args[:pages_domain_id]).to eq(params[:pages_domain_id])
- expect(args[:creator]).to eq(user)
-
- associate_domain_service
- end
-
- expect(associate_domain_service).to receive(:execute)
-
- subject
- end
- end
- end
-
- context 'invalid application' do
- let(:params) { { application: 'non-existent' } }
-
- it 'raises an error' do
- expect { subject }.to raise_error(Clusters::Applications::CreateService::InvalidApplicationError)
- end
- end
-
- context 'group cluster' do
- let(:cluster) { create(:cluster, :provided_by_gcp, :group) }
-
- using RSpec::Parameterized::TableSyntax
-
- where(:application, :association, :allowed, :pre_create_ingress) do
- 'ingress' | :application_ingress | true | false
- 'runner' | :application_runner | true | false
- 'prometheus' | :application_prometheus | true | false
- 'jupyter' | :application_jupyter | true | true
- end
-
- with_them do
- before do
- klass = "Clusters::Applications::#{application.titleize}"
- allow_any_instance_of(klass.constantize).to receive(:make_scheduled!).and_call_original
- create(:clusters_applications_ingress, :installed, cluster: cluster, external_hostname: 'example.com') if pre_create_ingress
- end
-
- let(:params) { { application: application } }
-
- it 'executes for each application' do
- if allowed
- expect do
- subject
-
- cluster.reload
- end.to change(cluster, association)
- else
- expect { subject }.to raise_error(Clusters::Applications::CreateService::InvalidApplicationError)
- end
- end
- end
- end
-
- context 'when application is installable' do
- shared_examples 'installable applications' do
- it 'makes the application scheduled' do
- expect do
- subject
- end.to change { Clusters::Applications::Ingress.with_status(:scheduled).count }.by(1)
- end
-
- it 'schedules an install via worker' do
- expect(ClusterInstallAppWorker)
- .to receive(:perform_async)
- .with(*worker_arguments)
- .once
-
- subject
- end
- end
-
- context 'when application is associated with a cluster' do
- let(:application) { create(:clusters_applications_ingress, :installable, cluster: cluster) }
- let(:worker_arguments) { [application.name, application.id] }
-
- it_behaves_like 'installable applications'
- end
-
- context 'when application is not associated with a cluster' do
- let(:worker_arguments) { [params[:application], kind_of(Numeric)] }
-
- it_behaves_like 'installable applications'
- end
- end
-
- context 'when installation is already in progress' do
- let!(:application) { create(:clusters_applications_ingress, :installing, cluster: cluster) }
-
- it 'raises an exception' do
- expect { subject }
- .to raise_exception(StateMachines::InvalidTransition)
- .and not_change(application.class.with_status(:scheduled), :count)
- end
-
- it 'does not schedule a cluster worker' do
- expect(ClusterInstallAppWorker).not_to receive(:perform_async)
- end
- end
-
- context 'when application is installed' do
- %i(installed updated).each do |status|
- let(:application) { create(:clusters_applications_ingress, status, cluster: cluster) }
-
- it 'schedules an upgrade via worker' do
- expect(ClusterUpgradeAppWorker)
- .to receive(:perform_async)
- .with(application.name, application.id)
- .once
-
- subject
-
- expect(application.reload).to be_scheduled
- end
- end
- end
- end
-end