Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-10-28 00:11:00 +00:00
parent 1f992463a9
commit e39b6277eb
54 changed files with 347 additions and 401 deletions

View file

@ -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'

View file

@ -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"

View file

@ -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

View file

@ -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',

View file

@ -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

View file

@ -137,7 +137,7 @@ module ApplicationSettingsHelper
}
end
options.to_json
Gitlab::Json.dump(options)
end
def external_authorization_description

View file

@ -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

View file

@ -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

View file

@ -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')
}

View file

@ -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?

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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?

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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),

View file

@ -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)

View file

@ -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?

View file

@ -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...'))

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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")

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1 @@
d6eb5bb918f12c08f23c228916b7e21432e1e2958832c10be4e46dfa2079103d

View file

@ -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);

View file

@ -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.

View file

@ -4198,6 +4198,25 @@ Input type: `PipelineScheduleDeleteInput`
| <a id="mutationpipelinescheduledeleteclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationpipelinescheduledeleteerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
### `Mutation.pipelineScheduleTakeOwnership`
Input type: `PipelineScheduleTakeOwnershipInput`
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationpipelinescheduletakeownershipclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationpipelinescheduletakeownershipid"></a>`id` | [`CiPipelineScheduleID!`](#cipipelinescheduleid) | ID of the pipeline schedule to mutate. |
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationpipelinescheduletakeownershipclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationpipelinescheduletakeownershiperrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationpipelinescheduletakeownershippipelineschedule"></a>`pipelineSchedule` | [`PipelineSchedule`](#pipelineschedule) | Updated pipeline schedule ownership. |
### `Mutation.projectCiCdSettingsUpdate`
Input type: `ProjectCiCdSettingsUpdateInput`

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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'

View file

@ -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

View file

@ -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 ""

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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