Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
339b34679c
commit
61066c990c
|
|
@ -58,6 +58,10 @@ config/bounded_contexts.yml @fabiopitino @grzesiek @stanhu @cwoolley-gitlab @tku
|
|||
/spec/frontend_integration/
|
||||
/ee/spec/frontend_integration/
|
||||
|
||||
[Data Seeder] @gl-dx
|
||||
/ee/db/seeds/data_seeder/
|
||||
/scripts/data_seeder/
|
||||
|
||||
[Clickhouse] @gitlab-org/maintainers/clickhouse
|
||||
/db/click_house/
|
||||
/ee/db/click_house/
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ variables:
|
|||
# Helm chart ref used by test-on-cng pipeline
|
||||
GITLAB_HELM_CHART_REF: "074bb942c9c65613c2576ce418f59b8577fff37c"
|
||||
# Specific ref for cng-mirror project to trigger builds for
|
||||
GITLAB_CNG_MIRROR_REF: "0df7d62154535093ae256da75efb702ef11b69a4"
|
||||
GITLAB_CNG_MIRROR_REF: "01f587c24c52e4bbf8a67135ae4f6adafa19fa2b"
|
||||
# Makes sure some of the common scripts from pipeline-common use bundler to execute commands
|
||||
RUN_WITH_BUNDLE: "true"
|
||||
# Makes sure reporting script defined in .gitlab-qa-report from pipeline-common is executed from correct folder
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ Layout/LineBreakAfterFinalMixin:
|
|||
- 'app/services/authorized_project_update/project_recalculate_service.rb'
|
||||
- 'app/services/batched_git_ref_updates/cleanup_scheduler_service.rb'
|
||||
- 'app/services/jira_connect_subscriptions/create_service.rb'
|
||||
- 'app/services/merge_requests/refresh_service.rb'
|
||||
- 'app/services/projects/transfer_service.rb'
|
||||
- 'app/workers/admin_email_worker.rb'
|
||||
- 'app/workers/ci/delete_unit_tests_worker.rb'
|
||||
|
|
|
|||
|
|
@ -777,7 +777,7 @@
|
|||
{"name":"view_component","version":"3.21.0","platform":"ruby","checksum":"7f5a77bca29e7385495fad2b7c1acdcd2c581b3cd2e573a831a9808f6710df5c"},
|
||||
{"name":"virtus","version":"2.0.0","platform":"ruby","checksum":"8841dae4eb7fcc097320ba5ea516bf1839e5d056c61ee27138aa4bddd6e3d1c2"},
|
||||
{"name":"vite_rails","version":"3.0.19","platform":"ruby","checksum":"195c44677bc05c1f94e7a69f1264e49d4bad2729ab06538ee858c2962f5bb500"},
|
||||
{"name":"vite_ruby","version":"3.9.1","platform":"ruby","checksum":"e4584a4ba1578602f13a3ac73402007aed044bd660daaac220523a97c49a4cc4"},
|
||||
{"name":"vite_ruby","version":"3.9.2","platform":"ruby","checksum":"e10a7c851b590cccab57904bc96c2eb078ed6e22560a778db1dcefa3818a4972"},
|
||||
{"name":"vmstat","version":"2.3.1","platform":"ruby","checksum":"5587cb430a54dbfc4a5c29dd01bd6a4031b2ff4c1d387504d74ff246f3b39104"},
|
||||
{"name":"warden","version":"1.2.9","platform":"ruby","checksum":"46684f885d35a69dbb883deabf85a222c8e427a957804719e143005df7a1efd0"},
|
||||
{"name":"warning","version":"1.5.0","platform":"ruby","checksum":"0f12c49fea0c06757778eefdcc7771e4fd99308901e3d55c504d87afdd718c53"},
|
||||
|
|
|
|||
|
|
@ -1955,7 +1955,7 @@ GEM
|
|||
vite_rails (3.0.19)
|
||||
railties (>= 5.1, < 9)
|
||||
vite_ruby (~> 3.0, >= 3.2.2)
|
||||
vite_ruby (3.9.1)
|
||||
vite_ruby (3.9.2)
|
||||
dry-cli (>= 0.7, < 2)
|
||||
logger (~> 1.6)
|
||||
mutex_m
|
||||
|
|
|
|||
|
|
@ -790,7 +790,7 @@
|
|||
{"name":"view_component","version":"3.21.0","platform":"ruby","checksum":"7f5a77bca29e7385495fad2b7c1acdcd2c581b3cd2e573a831a9808f6710df5c"},
|
||||
{"name":"virtus","version":"2.0.0","platform":"ruby","checksum":"8841dae4eb7fcc097320ba5ea516bf1839e5d056c61ee27138aa4bddd6e3d1c2"},
|
||||
{"name":"vite_rails","version":"3.0.19","platform":"ruby","checksum":"195c44677bc05c1f94e7a69f1264e49d4bad2729ab06538ee858c2962f5bb500"},
|
||||
{"name":"vite_ruby","version":"3.9.1","platform":"ruby","checksum":"e4584a4ba1578602f13a3ac73402007aed044bd660daaac220523a97c49a4cc4"},
|
||||
{"name":"vite_ruby","version":"3.9.2","platform":"ruby","checksum":"e10a7c851b590cccab57904bc96c2eb078ed6e22560a778db1dcefa3818a4972"},
|
||||
{"name":"vmstat","version":"2.3.1","platform":"ruby","checksum":"5587cb430a54dbfc4a5c29dd01bd6a4031b2ff4c1d387504d74ff246f3b39104"},
|
||||
{"name":"warden","version":"1.2.9","platform":"ruby","checksum":"46684f885d35a69dbb883deabf85a222c8e427a957804719e143005df7a1efd0"},
|
||||
{"name":"warning","version":"1.5.0","platform":"ruby","checksum":"0f12c49fea0c06757778eefdcc7771e4fd99308901e3d55c504d87afdd718c53"},
|
||||
|
|
|
|||
|
|
@ -1989,7 +1989,7 @@ GEM
|
|||
vite_rails (3.0.19)
|
||||
railties (>= 5.1, < 9)
|
||||
vite_ruby (~> 3.0, >= 3.2.2)
|
||||
vite_ruby (3.9.1)
|
||||
vite_ruby (3.9.2)
|
||||
dry-cli (>= 0.7, < 2)
|
||||
logger (~> 1.6)
|
||||
mutex_m
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ export default {
|
|||
},
|
||||
icon() {
|
||||
return this.canPlay
|
||||
? { name: 'check-circle-filled', class: 'gl-fill-green-500' }
|
||||
: { name: 'timer', class: 'gl-fill-current' };
|
||||
? { name: 'check-circle-filled', variant: 'success' }
|
||||
: { name: 'timer', variant: 'current' };
|
||||
},
|
||||
text() {
|
||||
return this.canPlay ? this.$options.i18n.ready : this.$options.i18n.waiting;
|
||||
|
|
|
|||
|
|
@ -154,6 +154,6 @@ export default {
|
|||
:is-icon-button="true"
|
||||
@click.stop.prevent="toggleTodo"
|
||||
>
|
||||
<gl-icon :class="{ '!gl-fill-blue-500': pendingTodo }" :name="buttonIcon" />
|
||||
<gl-icon :name="buttonIcon" :variant="pendingTodo ? 'info' : null" />
|
||||
</todo-button>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -424,9 +424,10 @@ export default {
|
|||
<gl-icon
|
||||
v-if="isClosed(item)"
|
||||
name="issue-close"
|
||||
class="gl-ml-2 gl-shrink-0 gl-fill-blue-500"
|
||||
class="gl-ml-2 gl-shrink-0"
|
||||
:size="16"
|
||||
data-testid="incident-closed"
|
||||
variant="info"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import {
|
|||
GlLink,
|
||||
GlSprintf,
|
||||
} from '@gitlab/ui';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { s__, __, n__, sprintf } from '~/locale';
|
||||
import { queryToObject, setUrlParams, updateHistory } from '~/lib/utils/url_utility';
|
||||
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
|
|
@ -79,7 +78,6 @@ export default {
|
|||
directives: {
|
||||
GlModal: GlModalDirective,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
inject: ['group'],
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -141,9 +139,6 @@ export default {
|
|||
|
||||
return PLACEHOLDER_USER_STATUS.REASSIGNED;
|
||||
},
|
||||
isCsvReassignmentEnabled() {
|
||||
return this.glFeatures.importerUserMappingReassignmentCsv;
|
||||
},
|
||||
sortOptions() {
|
||||
return [
|
||||
{
|
||||
|
|
@ -403,17 +398,15 @@ export default {
|
|||
|
||||
<template #tabs-end>
|
||||
<div class="gl-ml-auto gl-flex gl-gap-2">
|
||||
<template v-if="isCsvReassignmentEnabled">
|
||||
<gl-button
|
||||
v-gl-modal="$options.uploadCsvModalId"
|
||||
variant="link"
|
||||
icon="media"
|
||||
data-testid="reassign-csv-button"
|
||||
>
|
||||
{{ s__('UserMapping|Reassign with CSV file') }}
|
||||
</gl-button>
|
||||
<csv-upload-modal :modal-id="$options.uploadCsvModalId" />
|
||||
</template>
|
||||
<gl-button
|
||||
v-gl-modal="$options.uploadCsvModalId"
|
||||
variant="link"
|
||||
icon="media"
|
||||
data-testid="reassign-csv-button"
|
||||
>
|
||||
{{ s__('UserMapping|Reassign with CSV file') }}
|
||||
</gl-button>
|
||||
<csv-upload-modal :modal-id="$options.uploadCsvModalId" />
|
||||
<gl-disclosure-dropdown
|
||||
icon="ellipsis_v"
|
||||
placement="bottom-end"
|
||||
|
|
|
|||
|
|
@ -90,9 +90,6 @@ export const ALL_BRANCHES_WILDCARD = '*';
|
|||
export const REQUIRED_ICON = 'check-circle-filled';
|
||||
export const NOT_REQUIRED_ICON = 'status-failed';
|
||||
|
||||
export const REQUIRED_ICON_CLASS = 'gl-fill-green-500';
|
||||
export const NOT_REQUIRED_ICON_CLASS = 'gl-text-danger';
|
||||
|
||||
export const DELETE_RULE_MODAL_ID = 'delete-branch-rule-modal';
|
||||
|
||||
export const projectUsersOptions = { push_code: true, active: true };
|
||||
|
|
|
|||
|
|
@ -1,12 +1,7 @@
|
|||
<script>
|
||||
import { GlToggle, GlIcon, GlSprintf, GlLink } from '@gitlab/ui';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import {
|
||||
REQUIRED_ICON,
|
||||
NOT_REQUIRED_ICON,
|
||||
REQUIRED_ICON_CLASS,
|
||||
NOT_REQUIRED_ICON_CLASS,
|
||||
} from './constants';
|
||||
import { REQUIRED_ICON, NOT_REQUIRED_ICON } from './constants';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -60,8 +55,8 @@ export default {
|
|||
iconName() {
|
||||
return this.isProtected ? REQUIRED_ICON : NOT_REQUIRED_ICON;
|
||||
},
|
||||
iconClass() {
|
||||
return this.isProtected ? REQUIRED_ICON_CLASS : NOT_REQUIRED_ICON_CLASS;
|
||||
iconVariant() {
|
||||
return this.isProtected ? 'success' : 'danger';
|
||||
},
|
||||
iconDataTestId() {
|
||||
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||
|
|
@ -102,7 +97,7 @@ export default {
|
|||
</div>
|
||||
<div v-else class="gl-mb-5">
|
||||
<div class="gl-flex gl-items-center">
|
||||
<gl-icon :data-testid="iconDataTestId" :size="14" :name="iconName" :class="iconClass" />
|
||||
<gl-icon :data-testid="iconDataTestId" :size="14" :name="iconName" :variant="iconVariant" />
|
||||
<strong class="gl-ml-2">{{ iconTitle }}</strong>
|
||||
</div>
|
||||
<gl-sprintf v-if="hasDescription" :message="description" data-testid="protection-description">
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ module Groups
|
|||
feature_category :importers
|
||||
|
||||
def show
|
||||
return render_404 unless Feature.enabled?(:importer_user_mapping_reassignment_csv, current_user)
|
||||
|
||||
csv_response = Import::SourceUsers::GenerateCsvService.new(group, current_user: current_user).execute
|
||||
|
||||
if csv_response.success?
|
||||
|
|
@ -27,8 +25,6 @@ module Groups
|
|||
end
|
||||
|
||||
def create
|
||||
return render_404 unless Feature.enabled?(:importer_user_mapping_reassignment_csv, current_user)
|
||||
|
||||
unless file_type_is_valid?(file_params[:file])
|
||||
render_unprocessable_entity(s_('UserMapping|You must upload a CSV file with a .csv file extension.'))
|
||||
return
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ class Groups::GroupMembersController < Groups::ApplicationController
|
|||
|
||||
before_action only: [:index] do
|
||||
push_frontend_feature_flag(:importer_user_mapping, current_user)
|
||||
push_frontend_feature_flag(:importer_user_mapping_reassignment_csv, current_user)
|
||||
push_frontend_feature_flag(:importer_user_mapping_allow_bypass_of_confirmation, @group)
|
||||
push_frontend_feature_flag(:service_accounts_crud, @group)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -56,6 +56,12 @@ module Ci
|
|||
@subject.projects.visible_to_user_and_access_level(@user, Gitlab::Access::MAINTAINER).exists?
|
||||
end
|
||||
|
||||
with_options score: 6
|
||||
condition(:maintainer_in_owner_project) do
|
||||
# Check if user is a maintainer+ in the project owning the runner
|
||||
@user.authorized_projects(Gitlab::Access::MAINTAINER).id_in(@subject.owner).exists?
|
||||
end
|
||||
|
||||
with_options score: 8
|
||||
condition(:maintainer_in_any_associated_groups) do
|
||||
user_group_ids = @user.owned_or_maintainers_groups.select(:id)
|
||||
|
|
@ -79,7 +85,11 @@ module Ci
|
|||
|
||||
rule { admin | owned_runner }.policy do
|
||||
enable :read_builds
|
||||
|
||||
enable :read_runner
|
||||
enable :assign_runner
|
||||
enable :update_runner
|
||||
enable :delete_runner
|
||||
end
|
||||
|
||||
rule { is_instance_runner & any_maintainer_owned_groups_inheriting_shared_runners }.policy do
|
||||
|
|
@ -94,6 +104,10 @@ module Ci
|
|||
enable :read_runner
|
||||
end
|
||||
|
||||
rule { is_project_runner & maintainer_in_owner_project }.policy do
|
||||
enable :update_runner
|
||||
end
|
||||
|
||||
rule { is_group_runner & maintainer_in_any_associated_groups }.policy do
|
||||
enable :read_runner
|
||||
end
|
||||
|
|
@ -102,12 +116,6 @@ module Ci
|
|||
enable :read_runner
|
||||
end
|
||||
|
||||
rule { admin | owned_runner }.policy do
|
||||
enable :assign_runner
|
||||
enable :update_runner
|
||||
enable :delete_runner
|
||||
end
|
||||
|
||||
rule { ~admin & belongs_to_multiple_projects }.prevent :delete_runner
|
||||
|
||||
rule { ~admin & locked }.prevent :assign_runner
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@ module Groups # rubocop:disable Gitlab/BoundedContexts -- existing top-level mod
|
|||
private
|
||||
|
||||
def send_group_deletion_notification
|
||||
return unless ::Feature.enabled?(:group_deletion_notification_email, group) &&
|
||||
group.adjourned_deletion?
|
||||
return unless group.adjourned_deletion?
|
||||
|
||||
::NotificationService.new.group_scheduled_for_deletion(group)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
module MergeRequests
|
||||
class RefreshService < MergeRequests::BaseService
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
attr_reader :push
|
||||
|
||||
def execute(oldrev, newrev, ref)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,10 @@ module Snippets
|
|||
class DestroyService
|
||||
include Gitlab::Allowable
|
||||
|
||||
FAILED_TO_DELETE_ERROR = :failed_to_delete_error
|
||||
SNIPPET_NOT_FOUND_ERROR = :snippet_not_found_error
|
||||
SNIPPET_ACCESS_ERROR = :snippet_access_error
|
||||
|
||||
attr_reader :current_user, :snippet
|
||||
|
||||
DestroyError = Class.new(StandardError)
|
||||
|
|
@ -15,13 +19,13 @@ module Snippets
|
|||
|
||||
def execute
|
||||
if snippet.nil?
|
||||
return service_response_error('No snippet found.', 404)
|
||||
return service_response_error('No snippet found.', SNIPPET_NOT_FOUND_ERROR)
|
||||
end
|
||||
|
||||
unless user_can_delete_snippet?
|
||||
return service_response_error(
|
||||
"You don't have access to delete this snippet.",
|
||||
403
|
||||
SNIPPET_ACCESS_ERROR
|
||||
)
|
||||
end
|
||||
|
||||
|
|
@ -29,9 +33,9 @@ module Snippets
|
|||
|
||||
ServiceResponse.success(message: 'Snippet was deleted.')
|
||||
rescue DestroyError
|
||||
service_response_error('Failed to remove snippet repository.', 400)
|
||||
service_response_error('Failed to remove snippet repository.', FAILED_TO_DELETE_ERROR)
|
||||
rescue StandardError
|
||||
service_response_error('Failed to remove snippet.', 400)
|
||||
service_response_error('Failed to remove snippet.', FAILED_TO_DELETE_ERROR)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -8,18 +8,16 @@ module Import
|
|||
idempotent!
|
||||
feature_category :importers
|
||||
|
||||
def perform(source_user_id)
|
||||
source_user = Import::SourceUser.find_by_id(source_user_id)
|
||||
return if source_user.nil? || source_user.placeholder_user.nil?
|
||||
return unless source_user.placeholder_user.placeholder?
|
||||
def perform(source_user_or_placeholder_user_id, params = {})
|
||||
placeholder_user = find_placeholder_user(source_user_or_placeholder_user_id, params.symbolize_keys)
|
||||
return unless placeholder_user
|
||||
|
||||
if placeholder_user_referenced?(source_user)
|
||||
log_placeholder_user_not_deleted(source_user)
|
||||
placeholder_user_id = placeholder_user.id
|
||||
if placeholder_user_referenced?(placeholder_user_id)
|
||||
log_placeholder_user_not_deleted(placeholder_user_id)
|
||||
return
|
||||
end
|
||||
|
||||
placeholder_user = source_user.placeholder_user
|
||||
|
||||
placeholder_user.delete_async(
|
||||
deleted_by: placeholder_user,
|
||||
params: { "skip_authorization" => true }
|
||||
|
|
@ -28,18 +26,33 @@ module Import
|
|||
|
||||
private
|
||||
|
||||
def log_placeholder_user_not_deleted(source_user)
|
||||
def find_placeholder_user(id, params)
|
||||
if params[:type].blank?
|
||||
source_user = Import::SourceUser.find_by_id(id)
|
||||
return if source_user.nil? || source_user.placeholder_user.nil?
|
||||
return unless source_user.placeholder_user.placeholder?
|
||||
|
||||
source_user.placeholder_user
|
||||
else
|
||||
user = User.find_by_id(id)
|
||||
return if user.nil? || !user.placeholder?
|
||||
|
||||
user
|
||||
end
|
||||
end
|
||||
|
||||
def log_placeholder_user_not_deleted(placeholder_user_id)
|
||||
::Import::Framework::Logger.warn(
|
||||
message: 'Unable to delete placeholder user because it is still referenced in other tables',
|
||||
source_user_id: source_user.id
|
||||
placeholder_user_id: placeholder_user_id
|
||||
)
|
||||
end
|
||||
|
||||
def placeholder_user_referenced?(source_user)
|
||||
def placeholder_user_referenced?(placeholder_user_id)
|
||||
PlaceholderReferences::AliasResolver.models_with_data.any? do |model, data|
|
||||
columns = data[:columns].values - data[:columns_ignored_on_deletion].to_a
|
||||
(columns & ::Gitlab::ImportExport::Base::RelationFactory::USER_REFERENCES).any? do |user_reference_column|
|
||||
model.where(user_reference_column => source_user.placeholder_user_id).any? # rubocop:disable CodeReuse/ActiveRecord -- Adding a scope for all possible models would not be feasible here
|
||||
model.where(user_reference_column => placeholder_user_id).any? # rubocop:disable CodeReuse/ActiveRecord -- Adding a scope for all possible models would not be feasible here
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ module Import
|
|||
return self.class.perform_in(BACKOFF_PERIOD, import_source_user.id, params)
|
||||
end
|
||||
|
||||
Import::DeletePlaceholderUserWorker.perform_async(import_source_user.id)
|
||||
Import::DeletePlaceholderUserWorker.perform_async(import_source_user.placeholder_user_id,
|
||||
type: 'placeholder_user')
|
||||
end
|
||||
|
||||
def perform_failure(exception, import_source_user_id)
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
name: importer_user_mapping_reassignment_csv
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/455906
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/162267
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/478022
|
||||
milestone: '17.4'
|
||||
group: group::import and integrate
|
||||
type: beta
|
||||
default_enabled: true
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
name: group_deletion_notification_email
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/522883
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/185270
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/526037
|
||||
milestone: '17.11'
|
||||
group: group::authorization
|
||||
type: gitlab_com_derisk
|
||||
default_enabled: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
removal_milestone: "18.0"
|
||||
announcement_milestone: "17.5"
|
||||
breaking_change: true
|
||||
window: 1
|
||||
window: 2
|
||||
reporter: g.hickman
|
||||
stage: security risk management
|
||||
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/510897
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@ feature_category: runner
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/182527
|
||||
milestone: '17.10'
|
||||
queued_migration_version: 20250224182011
|
||||
finalized_by: # version of the migration that finalized this BBM
|
||||
finalized_by: 20250414181659
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FinalizeFixBadShardingKeyIdOnProjectCiRunners < Gitlab::Database::Migration[2.2]
|
||||
disable_ddl_transaction!
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_ci
|
||||
|
||||
milestone '18.0'
|
||||
|
||||
def up
|
||||
ensure_batched_background_migration_is_finished(
|
||||
job_class_name: 'FixBadShardingKeyIdOnProjectCiRunners',
|
||||
table_name: :ci_runners,
|
||||
column_name: :id,
|
||||
job_arguments: [],
|
||||
finalize: true
|
||||
)
|
||||
end
|
||||
|
||||
def down; end
|
||||
end
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AsyncRemoveIdxExpireAtJobIdOnCiJobArtifacts < Gitlab::Database::Migration[2.2]
|
||||
include Gitlab::Database::PartitioningMigrationHelpers
|
||||
|
||||
milestone '18.0'
|
||||
|
||||
TABLE_NAME = :p_ci_job_artifacts
|
||||
INDEX_DEFINITION = 'CREATE _ btree (expire_at, job_id)'
|
||||
COLUMNS = [:expire_at, :job_id]
|
||||
|
||||
# TODO: Index to be destroyed synchronously in https://gitlab.com/gitlab-org/gitlab/-/issues/532779
|
||||
def up
|
||||
return unless index_name
|
||||
|
||||
prepare_async_index_removal TABLE_NAME, COLUMNS, name: index_name
|
||||
end
|
||||
|
||||
def down
|
||||
return unless index_name
|
||||
|
||||
unprepare_async_index TABLE_NAME, COLUMNS, name: index_name
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# This index has a different name on Production DB and possibly on other instances.
|
||||
# So we must find the index by definition instead.
|
||||
# See https://gitlab.com/gitlab-org/gitlab/-/issues/520213#note_2450943371.
|
||||
def index_name
|
||||
indexes_by_definition = indexes_by_definition_for_table(TABLE_NAME)
|
||||
indexes_by_definition[INDEX_DEFINITION]
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
ec6c32dca920868ba6db982545710803bcb8fbbafb465430cb3cf5e102245b67
|
||||
|
|
@ -0,0 +1 @@
|
|||
ceaea792d4212c3768695a28ee0558ec2d5ea68b1a11198a4cf854e97e1ce587
|
||||
|
|
@ -526,6 +526,14 @@ Report any issues or feedback using [issue 525855](https://gitlab.com/gitlab-org
|
|||
|
||||
<!--- end_remove -->
|
||||
|
||||
The `s3_v2` driver (in Beta) uses AWS SDK v2 and only supports Signature Version 4 for authentication.
|
||||
This driver improves performance and reliability while ensuring compatibility with AWS authentication requirements,
|
||||
as support for older signature methods is deprecated. For more information, see [epic 16272](https://gitlab.com/groups/gitlab-org/-/epics/16272).
|
||||
|
||||
For a complete list of configuration parameters for each driver, see [`s3_v1`](https://gitlab.com/gitlab-org/container-registry/-/blob/f4ece8cdba4413b968c8a3fd20497a8186f23d26/docs/storage-drivers/s3_v1.md) and [`s3_v2`](https://gitlab.com/gitlab-org/container-registry/-/blob/f4ece8cdba4413b968c8a3fd20497a8186f23d26/docs/storage-drivers/s3_v2.md).
|
||||
|
||||
To configure the S3 storage driver, add one of the following configurations to your `/etc/gitlab/gitlab.rb` file:
|
||||
|
||||
```ruby
|
||||
# Deprecated: Will be removed in GitLab 19.0
|
||||
registry['storage'] = {
|
||||
|
|
@ -537,7 +545,11 @@ registry['storage'] = {
|
|||
'regionendpoint' => '<your-s3-regionendpoint>'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Or
|
||||
|
||||
```ruby
|
||||
# Beta: s3_v2 driver
|
||||
registry['storage'] = {
|
||||
's3_v2' => {
|
||||
|
|
@ -550,9 +562,33 @@ registry['storage'] = {
|
|||
}
|
||||
```
|
||||
|
||||
The `s3_v2` driver (in Beta) uses AWS SDK v2 and only supports Signature Version 4 for authentication. This driver improves performance and reliability while ensuring compatibility with AWS authentication requirements, as they are phasing out support for older signature methods. For more information, see [epic 16272](https://gitlab.com/groups/gitlab-org/-/epics/16272).
|
||||
For improved security, you can use an IAM role instead of static credentials by not including the `accesskey` and `secretkey` parameters.
|
||||
|
||||
For improved security, you can use an IAM role instead of static credentials by omitting the `accesskey` and `secretkey` parameters.
|
||||
To prevent storage cost increases, configure a lifecycle policy in your S3 bucket to purge incomplete multipart uploads.
|
||||
The container registry does not automatically clean these up.
|
||||
A three-day expiration policy for incomplete multipart uploads works well for most usage patterns.
|
||||
|
||||
{{< alert type="note" >}}
|
||||
|
||||
`loglevel` settings differ between the [`s3_v1`](https://gitlab.com/gitlab-org/container-registry/-/blob/f4ece8cdba4413b968c8a3fd20497a8186f23d26/docs/storage-drivers/s3_v1.md#configuration-parameters) and [`s3_v2`](https://gitlab.com/gitlab-org/container-registry/-/blob/f4ece8cdba4413b968c8a3fd20497a8186f23d26/docs/storage-drivers/s3_v2.md#configuration-parameters) drivers.
|
||||
If you set the `loglevel` for the wrong driver, it is ignored and a warning message is printed.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
When using MinIO with the `s3_v2` driver, add the `checksum_disabled` parameter to disable AWS checksums:
|
||||
|
||||
```ruby
|
||||
registry['storage'] = {
|
||||
's3_v2' => {
|
||||
'accesskey' => '<s3-access-key>',
|
||||
'secretkey' => '<s3-secret-key-for-access-key>',
|
||||
'bucket' => '<your-s3-bucket>',
|
||||
'region' => '<your-s3-region>',
|
||||
'regionendpoint' => '<your-s3-regionendpoint>',
|
||||
'checksum_disabled' => true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For S3 VPC endpoints:
|
||||
|
||||
|
|
@ -569,11 +605,13 @@ registry['storage'] = {
|
|||
}
|
||||
```
|
||||
|
||||
- `regionendpoint` is only required when configuring an S3 compatible service such as MinIO, or when using an AWS S3 VPC Endpoint.
|
||||
- `<your-s3-bucket>` should be the name of a bucket that exists, and can't include subdirectories.
|
||||
- `pathstyle` should be set to `true` to use host/bucket_name/object style paths instead of bucket_name.host/object. Set to `false` for AWS S3.
|
||||
S3 configuration parameters:
|
||||
|
||||
You can set a rate limit on connections to S3 to avoid 503 errors from the S3 API:
|
||||
- `<your-s3-bucket>`: The name of an existing bucket. Cannot include subdirectories.
|
||||
- `regionendpoint`: Required only when using an S3-compatible service like MinIO or an AWS S3 VPC Endpoint.
|
||||
- `pathstyle`: Controls URL formatting. Set to `true` for `host/bucket_name/object` (most S3-compatible services) or `false` for `bucket_name.host/object` (AWS S3).
|
||||
|
||||
To avoid 503 errors from the S3 API, add the `maxrequestspersecond` parameter to set a rate limit on connections:
|
||||
|
||||
```ruby
|
||||
registry['storage'] = {
|
||||
|
|
@ -606,6 +644,10 @@ Report any issues or feedback using [issue 525855](https://gitlab.com/gitlab-org
|
|||
|
||||
{{< /alert >}}
|
||||
|
||||
For a complete list of configuration parameters for each driver, see [`azure_v1`](https://gitlab.com/gitlab-org/container-registry/-/blob/7b1786d261481a3c69912ad3423225f47f7c8242/docs/storage-drivers/azure_v1.md) and [`azure_v2`](https://gitlab.com/gitlab-org/container-registry/-/blob/7b1786d261481a3c69912ad3423225f47f7c8242/docs/storage-drivers/azure_v2.md).
|
||||
|
||||
To configure the Azure storage driver, add one of the following configurations to your `/etc/gitlab/gitlab.rb` file:
|
||||
|
||||
```ruby
|
||||
# Deprecated: Will be removed in GitLab 19.0
|
||||
registry['storage'] = {
|
||||
|
|
@ -615,7 +657,11 @@ registry['storage'] = {
|
|||
'container' => '<container_name>'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Or
|
||||
|
||||
```ruby
|
||||
# Beta: azure_v2 driver
|
||||
registry['storage'] = {
|
||||
'azure_v2' => {
|
||||
|
|
|
|||
|
|
@ -336,7 +336,7 @@ Returns [`BlobSearch`](#blobsearch).
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="queryblobsearchchunkcount"></a>`chunkCount` {{< icon name="warning-solid" >}} | [`Int`](#int) | **Introduced** in GitLab 17.2. **Status**: Experiment. Maximum chunks per file. |
|
||||
| <a id="queryblobsearchexcludeforks"></a>`excludeForks` {{< icon name="warning-solid" >}} | [`Boolean`](#boolean) | **Introduced** in GitLab 17.11. **Status**: Experiment. Excludes forked projects in the search. Always false for project search. Not available for global search. |
|
||||
| <a id="queryblobsearchexcludeforks"></a>`excludeForks` {{< icon name="warning-solid" >}} | [`Boolean`](#boolean) | **Introduced** in GitLab 17.11. **Status**: Experiment. Excludes forked projects in the search. Always false for project search. |
|
||||
| <a id="queryblobsearchgroupid"></a>`groupId` {{< icon name="warning-solid" >}} | [`GroupID`](#groupid) | **Introduced** in GitLab 17.2. **Status**: Experiment. Group to search in. |
|
||||
| <a id="queryblobsearchincludearchived"></a>`includeArchived` {{< icon name="warning-solid" >}} | [`Boolean`](#boolean) | **Introduced** in GitLab 17.7. **Status**: Experiment. Includes archived projects in the search. Always true for project search. Default is false. |
|
||||
| <a id="queryblobsearchincludeforked"></a>`includeForked` {{< icon name="warning-solid" >}} | [`Boolean`](#boolean) | **Introduced** in GitLab 17.7. **Status**: Experiment. Includes forked projects in the search. Always true for project search. Not available for global search. |
|
||||
|
|
|
|||
|
|
@ -13,17 +13,11 @@ title: Group placeholder reassignments API
|
|||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/513794) in GitLab 17.10 [with a flag](../administration/feature_flags.md) named `importer_user_mapping_reassignment_csv`. [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/478022).
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/513794) in GitLab 17.10 [with a flag](../administration/feature_flags.md) named `importer_user_mapping_reassignment_csv`. Enabled by default.
|
||||
- [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/478022) in GitLab 18.0. Feature flag `importer_user_mapping_reassignment_csv` removed.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
{{< alert type="flag" >}}
|
||||
|
||||
The availability of this feature is controlled by a feature flag.
|
||||
For more information, see the history.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have the Owner role for the group.
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ title: Service account users API
|
|||
|
||||
{{< /details >}}
|
||||
|
||||
Use this API to interact with service accounts. For more information, see [Service accounts](../user/profile/service_accounts.md).
|
||||
Use this API to interact with service accounts. Service accounts are a specific type of user, and many attributes of a service account can also be managed through the
|
||||
[Users API](users.md) by administrators on GitLab Self Self-Managed instances.
|
||||
|
||||
## List all service account users
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ This window takes place on April 21 - 23, 2025 from 09:00 UTC to 22:00 UTC.
|
|||
| [CI/CD job token - **Authorized groups and projects** allowlist enforcement](deprecations.md#cicd-job-token---authorized-groups-and-projects-allowlist-enforcement) | High | Software supply chain security | Project | Refer to the [Understanding this change](https://gitlab.com/gitlab-org/gitlab/-/issues/383084#understanding-this-change) section for details. |
|
||||
| [Replace `add_on_purchase` GraphQL field with `add_on_purchases`](deprecations.md#replace-add_on_purchase-graphql-field-with-add_on_purchases) | Low | Fulfillment | Instance, group | |
|
||||
| [Replace namespace `add_on_purchase` GraphQL field with `add_on_purchases`](deprecations.md#replace-namespace-add_on_purchase-graphql-field-with-add_on_purchases) | Low | Fulfillment | Instance, group | |
|
||||
| [Limit number of scan execution policy actions allowed per policy](deprecations.md#limit-number-of-scan-execution-policy-actions-allowed-per-policy) | Low | Security risk management | Instance, group, project | |
|
||||
| [Deprecation of `name` field in `ProjectMonthlyUsageType` GraphQL API](deprecations.md#deprecation-of-name-field-in-projectmonthlyusagetype-graphql-api) | Low | Fulfillment | Project | |
|
||||
| [Deprecation of `STORAGE` enum in `NamespaceProjectSortEnum` GraphQL API](deprecations.md#deprecation-of-storage-enum-in-namespaceprojectsortenum-graphql-api) | Low | Fulfillment | Group | |
|
||||
| [DAST `dast_devtools_api_timeout` will have a lower default value](deprecations.md#dast-dast_devtools_api_timeout-will-have-a-lower-default-value) | Low | Application security testing | Project | |
|
||||
|
|
@ -42,6 +41,7 @@ This window takes place on April 28 - 30, 2025 from 09:00 UTC to 22:00 UTC.
|
|||
|
||||
| Deprecation | Impact | Stage | Scope | Check potential impact |
|
||||
|-------------|--------|-------|-------|------------------------|
|
||||
| [Limit number of scan execution policy actions allowed per policy](deprecations.md#limit-number-of-scan-execution-policy-actions-allowed-per-policy) | Low | Security risk management | Instance, group, project | |
|
||||
| [Behavior change for Upcoming and Started milestone filters](deprecations.md#behavior-change-for-upcoming-and-started-milestone-filters) | Low | Plan | Group, project | |
|
||||
|
||||
## Window 3
|
||||
|
|
|
|||
|
|
@ -456,7 +456,10 @@ Audit event types belong to the following product categories.
|
|||
| Type name | Event triggered when | Saved to database | Introduced in | Scope |
|
||||
|:----------|:---------------------|:------------------|:--------------|:------|
|
||||
| [`admin_role_assigned_to_user`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/186570) | A custom admin role is assigned to a user | {{< icon name="check-circle" >}} Yes | GitLab [18.0](https://gitlab.com/gitlab-org/gitlab/-/issues/507958) | User |
|
||||
| [`admin_role_created`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/188367) | A custom admin role is created | {{< icon name="check-circle" >}} Yes | GitLab [18.0](https://gitlab.com/gitlab-org/gitlab/-/issues/536131) | Instance |
|
||||
| [`admin_role_deleted`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/188367) | A custom admin role is deleted | {{< icon name="check-circle" >}} Yes | GitLab [18.0](https://gitlab.com/gitlab-org/gitlab/-/issues/536131) | Instance |
|
||||
| [`admin_role_unassigned_from_user`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/186570) | A custom admin role is unassigned from a user | {{< icon name="check-circle" >}} Yes | GitLab [18.0](https://gitlab.com/gitlab-org/gitlab/-/issues/507958) | User |
|
||||
| [`admin_role_updated`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/188367) | A custom admin role is updated | {{< icon name="check-circle" >}} Yes | GitLab [18.0](https://gitlab.com/gitlab-org/gitlab/-/issues/536131) | Instance |
|
||||
| [`member_role_created`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/137087) | A custom role is created | {{< icon name="check-circle" >}} Yes | GitLab [16.7](https://gitlab.com/gitlab-org/gitlab/-/issues/388934) | Group, Instance |
|
||||
| [`member_role_deleted`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141630) | A custom role is deleted | {{< icon name="check-circle" >}} Yes | GitLab [16.9](https://gitlab.com/gitlab-org/gitlab/-/issues/437672) | Group, Instance |
|
||||
| [`member_role_updated`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141630) | A custom role is updated | {{< icon name="check-circle" >}} Yes | GitLab [16.9](https://gitlab.com/gitlab-org/gitlab/-/issues/437672) | Group, Instance |
|
||||
|
|
|
|||
|
|
@ -416,17 +416,11 @@ Before a user accepts the reassignment, you can [cancel the request](#cancel-rea
|
|||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/455901) in GitLab 17.10 [with a flag](../../../administration/feature_flags.md) named `importer_user_mapping_reassignment_csv`. [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/478022).
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/455901) in GitLab 17.10 [with a flag](../../../administration/feature_flags.md) named `importer_user_mapping_reassignment_csv`. Enabled by default.
|
||||
- [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/478022) in GitLab 18.0. Feature flag `importer_user_mapping_reassignment_csv` removed.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
{{< alert type="flag" >}}
|
||||
|
||||
The availability of this feature is controlled by a feature flag.
|
||||
For more information, see the history.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have the Owner role for the group.
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ module API
|
|||
|
||||
before do
|
||||
authenticate!
|
||||
not_found! unless Feature.enabled?(:importer_user_mapping_reassignment_csv, current_user)
|
||||
forbidden! unless can?(current_user, :owner_access, user_group)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -174,9 +174,10 @@ module API
|
|||
destroy_conditionally!(snippet) do |snippet|
|
||||
service = ::Snippets::DestroyService.new(current_user, snippet)
|
||||
response = service.execute
|
||||
http_status = Helpers::Snippets::HttpResponseMap.status_for(response.reason)
|
||||
|
||||
if response.error?
|
||||
render_api_error!({ error: response.message }, response.reason)
|
||||
render_api_error!({ error: response.message }, http_status)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -225,9 +225,10 @@ module API
|
|||
destroy_conditionally!(snippet) do |snippet|
|
||||
service = ::Snippets::DestroyService.new(current_user, snippet)
|
||||
response = service.execute
|
||||
http_status = Helpers::Snippets::HttpResponseMap.status_for(response.reason)
|
||||
|
||||
if response.error?
|
||||
render_api_error!({ error: response.message }, response.reason)
|
||||
render_api_error!({ error: response.message }, http_status)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ module Gitlab
|
|||
SEARCH_CHAR_LIMIT = 4096
|
||||
SEARCH_TERM_LIMIT = 64
|
||||
MIN_TERM_LENGTH = 2
|
||||
BOOLEAN_PARAMS = %i[confidential exclude_forks include_archived include_forked].freeze
|
||||
|
||||
# Generic validation
|
||||
validates :query_string, length: { maximum: SEARCH_CHAR_LIMIT }
|
||||
|
|
@ -38,6 +39,10 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
def slice(*keys)
|
||||
keys.index_with { |key| self[key] }.with_indifferent_access
|
||||
end
|
||||
|
||||
def abusive?
|
||||
detect_abuse? && abuse_detection.errors.any?
|
||||
end
|
||||
|
|
@ -93,7 +98,8 @@ module Gitlab
|
|||
end
|
||||
|
||||
def process_params(params)
|
||||
processed_params = convert_all_boolean_params(params)
|
||||
processed_params = params.is_a?(Hash) ? params.with_indifferent_access : params.dup
|
||||
processed_params = convert_all_boolean_params(processed_params)
|
||||
convert_not_params(processed_params)
|
||||
end
|
||||
|
||||
|
|
@ -109,25 +115,11 @@ module Gitlab
|
|||
end
|
||||
|
||||
def convert_all_boolean_params(params)
|
||||
converted_params = params.is_a?(Hash) ? params.with_indifferent_access : params.dup
|
||||
|
||||
if converted_params.key?(:confidential)
|
||||
converted_params[:confidential] = Gitlab::Utils.to_boolean(converted_params[:confidential])
|
||||
BOOLEAN_PARAMS.each do |key|
|
||||
params[key] = Gitlab::Utils.to_boolean(params[key]) if params.key?(key)
|
||||
end
|
||||
|
||||
if converted_params.key?(:include_archived)
|
||||
converted_params[:include_archived] = Gitlab::Utils.to_boolean(converted_params[:include_archived])
|
||||
end
|
||||
|
||||
if converted_params.key?(:include_forked)
|
||||
converted_params[:include_forked] = Gitlab::Utils.to_boolean(converted_params[:include_forked])
|
||||
end
|
||||
|
||||
if converted_params.key?(:exclude_forks)
|
||||
converted_params[:exclude_forks] = Gitlab::Utils.to_boolean(converted_params[:exclude_forks])
|
||||
end
|
||||
|
||||
converted_params
|
||||
params
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -302,39 +302,21 @@ describe('PlaceholdersTabApp', () => {
|
|||
});
|
||||
|
||||
describe('reassign CSV button', () => {
|
||||
describe('when the feature flag is enabled', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
provide: {
|
||||
glFeatures: { importerUserMappingReassignmentCsv: true },
|
||||
},
|
||||
mountFn: mountExtended,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders the button and the modal', () => {
|
||||
expect(findReassignCsvButton().exists()).toBe(true);
|
||||
expect(findCsvModal().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('shows modal when button is clicked', async () => {
|
||||
findReassignCsvButton().trigger('click');
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(findCsvModal().findComponent(GlModal).isVisible()).toBe(true);
|
||||
});
|
||||
beforeEach(() => {
|
||||
createComponent({ mountFn: mountExtended });
|
||||
});
|
||||
|
||||
describe('when the feature flag is disabled', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ provide: { glFeatures: { importerUserMappingReassignmentCsv: false } } });
|
||||
});
|
||||
it('renders the button and the modal', () => {
|
||||
expect(findReassignCsvButton().exists()).toBe(true);
|
||||
expect(findCsvModal().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('does not render the button and the modal', () => {
|
||||
expect(findReassignCsvButton().exists()).toBe(false);
|
||||
expect(findCsvModal().exists()).toBe(false);
|
||||
});
|
||||
it('shows modal when button is clicked', async () => {
|
||||
findReassignCsvButton().trigger('click');
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(findCsvModal().findComponent(GlModal).isVisible()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,38 @@ RSpec.describe Gitlab::Search::Params, feature_category: :global_search do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#slice' do
|
||||
let(:controller_params) { ActionController::Parameters.new(group_id: 123, search: search, exclude_forks: true) }
|
||||
let(:params) { described_class.new(controller_params) }
|
||||
|
||||
it 'returns a new params object with only the specified keys' do
|
||||
sliced = params.slice(:exclude_forks, :group_id, :project_id)
|
||||
|
||||
expect(sliced).to be_a(Hash)
|
||||
expect(sliced[:exclude_forks]).to be(true)
|
||||
expect(sliced[:group_id]).to eq(123)
|
||||
expect(sliced[:project_id]).to be_nil
|
||||
end
|
||||
|
||||
it 'works with string keys' do
|
||||
sliced = params.slice('exclude_forks', 'group_id', 'project_id')
|
||||
|
||||
expect(sliced).to be_a(Hash)
|
||||
expect(sliced['exclude_forks']).to be(true)
|
||||
expect(sliced['group_id']).to eq(123)
|
||||
expect(sliced['project_id']).to be_nil
|
||||
end
|
||||
|
||||
it 'handles mixed string and symbol keys' do
|
||||
sliced = params.slice(:exclude_forks, 'group_id')
|
||||
|
||||
expect(sliced).to be_a(Hash)
|
||||
expect(sliced[:exclude_forks]).to be(true)
|
||||
expect(sliced[:group_id]).to eq(123)
|
||||
expect(sliced[:project_id]).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe '#query_string' do
|
||||
let(:term) { 'term' }
|
||||
|
||||
|
|
|
|||
|
|
@ -5,11 +5,14 @@ require 'spec_helper'
|
|||
RSpec.describe Ci::RunnerManagerPolicy, feature_category: :fleet_visibility do
|
||||
let_it_be(:owner) { create(:user) }
|
||||
|
||||
subject(:policy) { described_class.new(user, runner_manager) }
|
||||
|
||||
describe 'ability :read_runner_manager' do
|
||||
let(:runner_manager) { runner.runner_managers.first }
|
||||
|
||||
subject(:policy) { described_class.new(user, runner_manager) }
|
||||
include_context 'with runner policy environment'
|
||||
|
||||
it_behaves_like 'runner read policy', :read_runner_manager
|
||||
it_behaves_like 'runner policy not allowed for levels lower than maintainer', :read_runner_manager
|
||||
it_behaves_like 'runner policy', :read_runner_manager
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,15 +5,93 @@ require 'spec_helper'
|
|||
RSpec.describe Ci::RunnerPolicy, feature_category: :runner do
|
||||
let_it_be(:owner) { create(:user) }
|
||||
|
||||
describe 'ability :read_runner' do
|
||||
subject(:policy) { described_class.new(user, runner) }
|
||||
subject(:policy) { described_class.new(user, runner) }
|
||||
|
||||
it_behaves_like 'runner read policy', :read_runner
|
||||
include_context 'with runner policy environment'
|
||||
|
||||
describe 'ability :read_runner' do
|
||||
it_behaves_like 'runner policy not allowed for levels lower than maintainer', :read_runner
|
||||
it_behaves_like 'runner policy', :read_runner
|
||||
end
|
||||
|
||||
describe 'ability :update_runner' do
|
||||
it_behaves_like 'runner policy not allowed for levels lower than maintainer', :update_runner
|
||||
|
||||
context 'with maintainer access' do
|
||||
let(:user) { maintainer }
|
||||
|
||||
it_behaves_like 'a policy disallowing access to instance runner/runner manager', :update_runner
|
||||
|
||||
context 'with group runner' do
|
||||
let(:runner) { group_runner }
|
||||
|
||||
it { expect_disallowed :update_runner }
|
||||
end
|
||||
|
||||
context 'with project runner' do
|
||||
let(:runner) { project_runner }
|
||||
|
||||
it { expect_allowed :update_runner }
|
||||
|
||||
context 'when user is maintainer in an unrelated group' do
|
||||
let_it_be(:maintainers_group_maintainer) { create(:user) }
|
||||
let_it_be_with_reload(:maintainers_group) do
|
||||
create(:group, name: 'maintainers', path: 'maintainers', maintainers: maintainers_group_maintainer)
|
||||
end
|
||||
|
||||
let(:user) { maintainers_group_maintainer }
|
||||
|
||||
it { expect_disallowed :update_runner }
|
||||
|
||||
context 'when maintainers group is invited as maintainer to project' do
|
||||
before do
|
||||
create(:project_group_link, :maintainer, group: maintainers_group, project: project_invited_to)
|
||||
end
|
||||
|
||||
context 'and target project is owner project' do
|
||||
let(:project_invited_to) { owner_project }
|
||||
|
||||
it { expect_allowed :update_runner }
|
||||
end
|
||||
|
||||
context 'and target project is other project' do
|
||||
let(:project_invited_to) { other_project }
|
||||
|
||||
it { expect_disallowed :update_runner }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with owner access' do
|
||||
let(:user) { owner }
|
||||
|
||||
it_behaves_like 'a policy disallowing access to instance runner/runner manager', :update_runner
|
||||
|
||||
context 'with group runner' do
|
||||
let(:runner) { group_runner }
|
||||
|
||||
it { expect_allowed :update_runner }
|
||||
|
||||
context 'with sharing of group runners disabled' do
|
||||
before do
|
||||
owner_project.update!(group_runners_enabled: false)
|
||||
end
|
||||
|
||||
it { expect_allowed :update_runner }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with project runner' do
|
||||
let(:runner) { project_runner }
|
||||
|
||||
it { expect_allowed :update_runner }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'ability :read_ephemeral_token' do
|
||||
subject(:policy) { described_class.new(user, runner) }
|
||||
|
||||
let_it_be(:runner) { create(:ci_runner, creator: owner) }
|
||||
|
||||
let(:creator) { owner }
|
||||
|
|
|
|||
|
|
@ -30,18 +30,6 @@ RSpec.describe API::GroupPlaceholderReassignments, feature_category: :importers
|
|||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when importer_user_mapping_reassignment_csv flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(importer_user_mapping_reassignment_csv: false)
|
||||
end
|
||||
|
||||
it 'returns 404' do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /groups/:id/placeholder_reassignments' do
|
||||
|
|
|
|||
|
|
@ -398,7 +398,12 @@ RSpec.describe API::ProjectSnippets, :aggregate_failures, feature_category: :sou
|
|||
|
||||
context "when destruction fails" do
|
||||
let(:error_message) { "some service error message" }
|
||||
let(:error_response) { ServiceResponse.error(message: error_message, reason: :bad_request) }
|
||||
let(:error_response) do
|
||||
ServiceResponse.error(
|
||||
message: error_message,
|
||||
reason: ::Snippets::DestroyService::FAILED_TO_DELETE_ERROR
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
allow_next_instance_of(::Snippets::DestroyService) do |service|
|
||||
|
|
|
|||
|
|
@ -548,7 +548,13 @@ RSpec.describe API::Snippets, :aggregate_failures, factory_default: :keep, featu
|
|||
|
||||
context "when destruction fails" do
|
||||
let(:error_message) { "some service error message" }
|
||||
let(:error_response) { ServiceResponse.error(message: error_message, reason: :bad_request) }
|
||||
|
||||
let(:error_response) do
|
||||
ServiceResponse.error(
|
||||
message: error_message,
|
||||
reason: ::Snippets::DestroyService::FAILED_TO_DELETE_ERROR
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
allow_next_instance_of(::Snippets::DestroyService) do |service|
|
||||
|
|
|
|||
|
|
@ -58,18 +58,6 @@ RSpec.describe Groups::BulkPlaceholderAssignmentsController, feature_category: :
|
|||
expect(flash[:alert]).to eq('my error message')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when :importer_user_mapping_reassignment_csv is disabled' do
|
||||
before do
|
||||
stub_feature_flags(importer_user_mapping_reassignment_csv: false)
|
||||
end
|
||||
|
||||
it 'responds with 404' do
|
||||
request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -143,18 +131,6 @@ RSpec.describe Groups::BulkPlaceholderAssignmentsController, feature_category: :
|
|||
})
|
||||
end
|
||||
end
|
||||
|
||||
context 'when :importer_user_mapping_reassignment_csv is disabled' do
|
||||
before do
|
||||
stub_feature_flags(importer_user_mapping_reassignment_csv: false)
|
||||
end
|
||||
|
||||
it 'responds with 404' do
|
||||
request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when not signed in' do
|
||||
|
|
|
|||
|
|
@ -33,37 +33,8 @@ RSpec.describe Groups::MarkForDeletionService, feature_category: :groups_and_pro
|
|||
result
|
||||
end
|
||||
|
||||
context 'when notification feature flag is enabled and adjourned deletion is enabled' do
|
||||
context 'when adjourned deletion is enabled' do
|
||||
before do
|
||||
stub_feature_flags(group_deletion_notification_email: true)
|
||||
allow(group).to receive(:adjourned_deletion?).and_return(true)
|
||||
end
|
||||
|
||||
it 'sends a notification email' do
|
||||
expect_next_instance_of(NotificationService) do |service|
|
||||
expect(service).to receive(:group_scheduled_for_deletion).with(group)
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
context 'when notification feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(group_deletion_notification_email: false)
|
||||
allow(group).to receive(:adjourned_deletion?).and_return(true)
|
||||
end
|
||||
|
||||
it 'does not send a notification email' do
|
||||
expect(NotificationService).not_to receive(:new)
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
context 'when notification feature flag is enabled for specific group' do
|
||||
before do
|
||||
stub_feature_flags(group_deletion_notification_email: group)
|
||||
allow(group).to receive(:adjourned_deletion?).and_return(true)
|
||||
end
|
||||
|
||||
|
|
@ -78,7 +49,6 @@ RSpec.describe Groups::MarkForDeletionService, feature_category: :groups_and_pro
|
|||
|
||||
context 'when adjourned deletion is disabled' do
|
||||
before do
|
||||
stub_feature_flags(group_deletion_notification_email: true)
|
||||
allow(group).to receive(:adjourned_deletion?).and_return(false)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ RSpec.describe Snippets::DestroyService, feature_category: :source_code_manageme
|
|||
|
||||
it 'returns a ServiceResponse error' do
|
||||
expect(subject).to be_error
|
||||
expect(subject.reason).to eq(404)
|
||||
expect(subject.reason).to eq(described_class::SNIPPET_NOT_FOUND_ERROR)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ RSpec.describe Snippets::DestroyService, feature_category: :source_code_manageme
|
|||
|
||||
it 'returns ServiceResponse error' do
|
||||
expect(subject).to be_error
|
||||
expect(subject.reason).to eq(403)
|
||||
expect(subject.reason).to eq(described_class::SNIPPET_ACCESS_ERROR)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ RSpec.describe Snippets::DestroyService, feature_category: :source_code_manageme
|
|||
|
||||
it 'returns ServiceResponse error' do
|
||||
expect(subject).to be_error
|
||||
expect(subject.reason).to eq(400)
|
||||
expect(subject.reason).to eq(described_class::FAILED_TO_DELETE_ERROR)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'a policy allowing reading instance runner/runner manager depending on runner sharing' do
|
||||
RSpec.shared_examples 'a policy allowing accessing instance runner/runner manager depending on runner sharing' do
|
||||
|ability|
|
||||
context 'with instance runner' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:shared_runners_enabled_on_group, :shared_runners_enabled_on_project, :expect_can_read) do
|
||||
where(:shared_runners_enabled_on_group, :shared_runners_enabled_on_project, :expect_to_be_allowed) do
|
||||
false | false | false
|
||||
false | true | true
|
||||
true | false | true
|
||||
|
|
@ -17,11 +17,11 @@ RSpec.shared_examples 'a policy allowing reading instance runner/runner manager
|
|||
|
||||
before do
|
||||
group.update!(shared_runners_enabled: shared_runners_enabled_on_group)
|
||||
project.update!(shared_runners_enabled: shared_runners_enabled_on_project)
|
||||
owner_project.update!(shared_runners_enabled: shared_runners_enabled_on_project)
|
||||
end
|
||||
|
||||
specify do
|
||||
if expect_can_read
|
||||
if expect_to_be_allowed
|
||||
expect_allowed ability
|
||||
else
|
||||
expect_disallowed ability
|
||||
|
|
@ -31,18 +31,42 @@ RSpec.shared_examples 'a policy allowing reading instance runner/runner manager
|
|||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'a policy allowing reading group runner/runner manager depending on runner sharing' do
|
||||
RSpec.shared_examples 'a policy disallowing access to instance runner/runner manager' do |ability|
|
||||
context 'with instance runner' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:shared_runners_enabled_on_group, :shared_runners_enabled_on_project) do
|
||||
false | false
|
||||
false | true
|
||||
true | false
|
||||
true | true
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:runner) { instance_runner }
|
||||
|
||||
before do
|
||||
group.update!(shared_runners_enabled: shared_runners_enabled_on_group)
|
||||
owner_project.update!(shared_runners_enabled: shared_runners_enabled_on_project)
|
||||
end
|
||||
|
||||
specify { expect_disallowed ability }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'a policy allowing accessing group runner/runner manager depending on runner sharing' do
|
||||
|ability, user_role|
|
||||
let(:group_runners_enabled_on_project) { true }
|
||||
|
||||
before do
|
||||
project.update!(group_runners_enabled: group_runners_enabled_on_project)
|
||||
owner_project.update!(group_runners_enabled: group_runners_enabled_on_project)
|
||||
end
|
||||
|
||||
context 'with group runner' do
|
||||
let(:runner) { group_runner }
|
||||
|
||||
# NOTE: The user is allowed to read the runner/runner manager because:
|
||||
# NOTE: The user is allowed to access the runner/runner manager because:
|
||||
# - the user is a maintainer+ in the runner's group
|
||||
# - the user is a maintainer+ in `group/subgroup/project`, and the runner is shared to that project
|
||||
it { expect_allowed ability }
|
||||
|
|
@ -61,7 +85,7 @@ RSpec.shared_examples 'a policy allowing reading group runner/runner manager dep
|
|||
let(:user) { subgroup_member }
|
||||
|
||||
context 'with runner visible to group project' do
|
||||
# NOTE: The user is allowed to read the runner/runner manager because the user is a maintainer+
|
||||
# NOTE: The user is allowed to access the runner/runner manager because the user is a maintainer+
|
||||
# in `group/subgroup/project`, and the runner is shared to that project
|
||||
it { expect_allowed ability }
|
||||
|
||||
|
|
@ -114,7 +138,7 @@ RSpec.shared_examples 'a policy allowing reading group runner/runner manager dep
|
|||
context 'when runner is in subgroup' do
|
||||
let(:runner) { subgroup_runner }
|
||||
|
||||
# NOTE: The user is allowed to read the runner/runner manager because the user is a maintainer+ in
|
||||
# NOTE: The user is allowed to access the runner/runner manager because the user is a maintainer+ in
|
||||
# `group/subgroup/project`, and the runner is shared to that project
|
||||
it { expect_allowed ability }
|
||||
|
||||
|
|
@ -126,7 +150,7 @@ RSpec.shared_examples 'a policy allowing reading group runner/runner manager dep
|
|||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'does not allow reading runners/runner managers on any scope' do |ability|
|
||||
RSpec.shared_examples 'does not allow accessing runners/runner managers on any scope' do |ability|
|
||||
context 'with instance runner' do
|
||||
let(:runner) { instance_runner }
|
||||
|
||||
|
|
@ -135,7 +159,7 @@ RSpec.shared_examples 'does not allow reading runners/runner managers on any sco
|
|||
context 'with shared runners disabled for groups and projects' do
|
||||
before do
|
||||
group.update!(shared_runners_enabled: false)
|
||||
project.update!(shared_runners_enabled: false)
|
||||
owner_project.update!(shared_runners_enabled: false)
|
||||
end
|
||||
|
||||
it { expect_disallowed ability }
|
||||
|
|
@ -160,7 +184,7 @@ RSpec.shared_examples 'does not allow reading runners/runner managers on any sco
|
|||
|
||||
context 'with sharing of group runners disabled' do
|
||||
before do
|
||||
project.update!(group_runners_enabled: false)
|
||||
owner_project.update!(group_runners_enabled: false)
|
||||
end
|
||||
|
||||
it { expect_disallowed ability }
|
||||
|
|
@ -174,7 +198,7 @@ RSpec.shared_examples 'does not allow reading runners/runner managers on any sco
|
|||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'runner read policy' do |ability|
|
||||
RSpec.shared_context 'with runner policy environment' do
|
||||
let_it_be(:guest) { create(:user) }
|
||||
let_it_be(:reporter) { create(:user) }
|
||||
let_it_be(:developer) { create(:user) }
|
||||
|
|
@ -186,47 +210,79 @@ RSpec.shared_examples 'runner read policy' do |ability|
|
|||
end
|
||||
|
||||
let_it_be_with_reload(:subgroup) { create(:group, name: 'subgroup', path: 'subgroup', parent: group) }
|
||||
let_it_be_with_reload(:project) { create(:project, group: subgroup) }
|
||||
let_it_be_with_reload(:owner_project) { create(:project, group: subgroup) }
|
||||
let_it_be_with_reload(:other_project) { create(:project) }
|
||||
let_it_be_with_reload(:group_without_project) { create(:group, name: 'top-level2', path: 'top-level2') }
|
||||
|
||||
let_it_be(:instance_runner) { create(:ci_runner, :instance, :with_runner_manager) }
|
||||
let_it_be(:group_runner) { create(:ci_runner, :group, :with_runner_manager, groups: [group]) }
|
||||
let_it_be(:subgroup_runner) { create(:ci_runner, :group, :with_runner_manager, groups: [subgroup]) }
|
||||
let_it_be(:project_runner) { create(:ci_runner, :project, :with_runner_manager, projects: [project]) }
|
||||
let_it_be(:project_runner) do
|
||||
create(:ci_runner, :project, :with_runner_manager, projects: [owner_project, other_project])
|
||||
end
|
||||
|
||||
let_it_be(:runner_on_group_without_project) do
|
||||
create(:ci_runner, :group, :with_runner_manager, groups: [group_without_project])
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'runner policy not allowed for levels lower than maintainer' do |ability|
|
||||
context 'without access' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
it_behaves_like 'does not allow reading runners/runner managers on any scope', ability
|
||||
it_behaves_like 'does not allow accessing runners/runner managers on any scope', ability
|
||||
end
|
||||
|
||||
context 'with guest access' do
|
||||
let(:user) { guest }
|
||||
|
||||
it_behaves_like 'does not allow reading runners/runner managers on any scope', ability
|
||||
it_behaves_like 'does not allow accessing runners/runner managers on any scope', ability
|
||||
end
|
||||
|
||||
context 'with reporter access' do
|
||||
let(:user) { reporter }
|
||||
|
||||
it_behaves_like 'does not allow reading runners/runner managers on any scope', ability
|
||||
it_behaves_like 'does not allow accessing runners/runner managers on any scope', ability
|
||||
end
|
||||
|
||||
context 'with developer access' do
|
||||
let(:user) { developer }
|
||||
|
||||
it_behaves_like 'does not allow reading runners/runner managers on any scope', ability
|
||||
it_behaves_like 'does not allow accessing runners/runner managers on any scope', ability
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'runner policy' do |ability|
|
||||
context 'without access' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
it_behaves_like 'does not allow accessing runners/runner managers on any scope', ability
|
||||
end
|
||||
|
||||
context 'with guest access' do
|
||||
let(:user) { guest }
|
||||
|
||||
it_behaves_like 'does not allow accessing runners/runner managers on any scope', ability
|
||||
end
|
||||
|
||||
context 'with reporter access' do
|
||||
let(:user) { reporter }
|
||||
|
||||
it_behaves_like 'does not allow accessing runners/runner managers on any scope', ability
|
||||
end
|
||||
|
||||
context 'with developer access' do
|
||||
let(:user) { developer }
|
||||
|
||||
it_behaves_like 'does not allow accessing runners/runner managers on any scope', ability
|
||||
end
|
||||
|
||||
context 'with maintainer access' do
|
||||
let(:user) { maintainer }
|
||||
|
||||
it_behaves_like 'a policy allowing reading instance runner/runner manager depending on runner sharing', ability
|
||||
it_behaves_like 'a policy allowing accessing instance runner/runner manager depending on runner sharing', ability
|
||||
|
||||
it_behaves_like 'a policy allowing reading group runner/runner manager depending on runner sharing',
|
||||
it_behaves_like 'a policy allowing accessing group runner/runner manager depending on runner sharing',
|
||||
ability, :maintainer
|
||||
|
||||
context 'with project runner' do
|
||||
|
|
@ -234,25 +290,32 @@ RSpec.shared_examples 'runner read policy' do |ability|
|
|||
|
||||
it { expect_allowed ability }
|
||||
|
||||
context 'when user is not maintainer in parent group' do
|
||||
context 'when user is maintainer in an unrelated group' do
|
||||
let_it_be(:maintainers_group_maintainer) { create(:user) }
|
||||
let_it_be_with_reload(:maintainers_group) { create(:group, name: 'maintainers', path: 'maintainers') }
|
||||
let_it_be_with_reload(:maintainers_group) do
|
||||
create(:group, name: 'maintainers', path: 'maintainers', maintainers: maintainers_group_maintainer)
|
||||
end
|
||||
|
||||
let(:user) { maintainers_group_maintainer }
|
||||
|
||||
before_all do
|
||||
create(:project_group_link, :maintainer, group: maintainers_group, project: project)
|
||||
maintainers_group.add_reporter(maintainers_group_maintainer)
|
||||
end
|
||||
|
||||
it { expect_disallowed ability }
|
||||
|
||||
context 'when user is maintainer in a group invited to project as maintainer' do
|
||||
before_all do
|
||||
maintainers_group.add_maintainer(maintainers_group_maintainer)
|
||||
context 'when maintainers group is invited as maintainer to project' do
|
||||
before do
|
||||
create(:project_group_link, :maintainer, group: maintainers_group, project: project_invited_to)
|
||||
end
|
||||
|
||||
it { expect_allowed ability }
|
||||
context 'and target project is owner project' do
|
||||
let(:project_invited_to) { owner_project }
|
||||
|
||||
it { expect_allowed ability }
|
||||
end
|
||||
|
||||
context 'and target project is other project' do
|
||||
let(:project_invited_to) { other_project }
|
||||
|
||||
it { expect_allowed ability }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -261,7 +324,7 @@ RSpec.shared_examples 'runner read policy' do |ability|
|
|||
context 'with owner access' do
|
||||
let(:user) { owner }
|
||||
|
||||
it_behaves_like 'a policy allowing reading instance runner/runner manager depending on runner sharing', ability
|
||||
it_behaves_like 'a policy allowing accessing instance runner/runner manager depending on runner sharing', ability
|
||||
|
||||
context 'with group runner' do
|
||||
let(:runner) { group_runner }
|
||||
|
|
@ -270,7 +333,7 @@ RSpec.shared_examples 'runner read policy' do |ability|
|
|||
|
||||
context 'with sharing of group runners disabled' do
|
||||
before do
|
||||
project.update!(group_runners_enabled: false)
|
||||
owner_project.update!(group_runners_enabled: false)
|
||||
end
|
||||
|
||||
it { expect_allowed ability }
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ RSpec.describe Tooling::Danger::ProjectHelper, feature_category: :tooling do
|
|||
'lib/gitlab/sql/foo' | [:database, :backend]
|
||||
'rubocop/cop/migration/foo' | [:database]
|
||||
|
||||
'ee/db/seeds/data_seeder/foo_seed.db' | [:backend]
|
||||
'db/fixtures/foo.rb' | [:backend]
|
||||
'ee/db/fixtures/foo.rb' | [:backend]
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ RSpec.describe Import::DeletePlaceholderUserWorker, feature_category: :importers
|
|||
let_it_be(:placeholder_user) { create(:user, :placeholder) }
|
||||
let_it_be(:source_user) { create(:import_source_user, placeholder_user: placeholder_user) }
|
||||
|
||||
let(:job_args) { source_user.id }
|
||||
let(:job_args) { [placeholder_user.id, { type: 'placeholder_user' }] }
|
||||
|
||||
subject(:perform) { described_class.new.perform(*job_args) }
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ RSpec.describe Import::DeletePlaceholderUserWorker, feature_category: :importers
|
|||
it 'does not delete the placeholder_user and logs the issue' do
|
||||
expect(::Import::Framework::Logger).to receive(:warn).with(
|
||||
message: 'Unable to delete placeholder user because it is still referenced in other tables',
|
||||
source_user_id: source_user.id
|
||||
placeholder_user_id: placeholder_user.id
|
||||
)
|
||||
|
||||
expect(DeleteUserWorker).not_to receive(:perform_async)
|
||||
|
|
@ -68,7 +68,7 @@ RSpec.describe Import::DeletePlaceholderUserWorker, feature_category: :importers
|
|||
end
|
||||
|
||||
context 'when there is no placeholder user' do
|
||||
let_it_be(:source_user) { create(:import_source_user, :completed, placeholder_user: nil) }
|
||||
let(:job_args) { [-1, { type: 'placeholder_user' }] }
|
||||
|
||||
it 'does not delete the placeholder_user and does not log an issue' do
|
||||
expect(::Import::Framework::Logger).not_to receive(:warn)
|
||||
|
|
@ -80,7 +80,7 @@ RSpec.describe Import::DeletePlaceholderUserWorker, feature_category: :importers
|
|||
|
||||
context 'when attempting to delete a user who is not a placeholder' do
|
||||
let_it_be(:user) { create(:user, :import_user) }
|
||||
let_it_be(:source_user) { create(:import_source_user, placeholder_user: user) }
|
||||
let(:job_args) { [user.id, { type: 'placeholder_user' }] }
|
||||
|
||||
it 'does not delete the user' do
|
||||
expect(DeleteUserWorker).not_to receive(:perform_async)
|
||||
|
|
@ -88,4 +88,17 @@ RSpec.describe Import::DeletePlaceholderUserWorker, feature_category: :importers
|
|||
perform
|
||||
end
|
||||
end
|
||||
|
||||
context 'when called with legacy parameters (source_user_id only)' do
|
||||
let(:job_args) { [source_user.id] }
|
||||
|
||||
it_behaves_like 'deletes the placeholder user'
|
||||
|
||||
context 'when another table references the user from an author_id column' do
|
||||
let!(:note) { create(:note, author: placeholder_user) }
|
||||
let(:job_args) { [source_user.id] }
|
||||
|
||||
it_behaves_like 'does not delete the placeholder_user and logs the issue'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -51,9 +51,9 @@ RSpec.describe Import::ReassignPlaceholderUserRecordsWorker, feature_category: :
|
|||
it_behaves_like 'an invalid source user'
|
||||
end
|
||||
|
||||
it 'queues a DeletePlaceholderUserWorker with the source user ID' do
|
||||
it 'queues a DeletePlaceholderUserWorker with the placeholder user ID' do
|
||||
expect(Import::DeletePlaceholderUserWorker)
|
||||
.to receive(:perform_async).with(import_source_user.id)
|
||||
.to receive(:perform_async).with(import_source_user.placeholder_user_id, { type: 'placeholder_user' })
|
||||
|
||||
perform_multiple(job_args)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ module Tooling
|
|||
\.gitlab/ci/frontend\.gitlab-ci\.yml
|
||||
)\z}x => %i[frontend tooling],
|
||||
|
||||
%r{\Aee/db/seeds/data_seeder/} => [:backend],
|
||||
%r{\A((ee|jh)/)?db/(geo/)?(?!click_house|fixtures)[^/]+} => [:database],
|
||||
%r{\A((ee|jh)/)?db/[^/]+\z} => [:database], # db/ root files
|
||||
%r{\Adb/docs/.+\.yml\z} => [:database],
|
||||
|
|
|
|||
Loading…
Reference in New Issue