Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-11-26 09:31:49 +00:00
parent c0a0cfa93a
commit 33c421eb90
54 changed files with 1117 additions and 548 deletions

View File

@ -227,7 +227,6 @@ Layout/ClassStructure:
- 'ee/app/models/work_items/widgets/rolledup_dates.rb'
- 'ee/app/replicators/geo/lfs_object_replicator.rb'
- 'ee/app/replicators/geo/terraform_state_version_replicator.rb'
- 'ee/app/services/ai/store_repository_xray_service.rb'
- 'ee/app/services/analytics/value_stream_dashboard/top_level_group_counter_service.rb'
- 'ee/app/services/app_sec/dast/scan_configs/build_service.rb'
- 'ee/app/services/click_house/data_ingestion/ci_finished_builds_sync_service.rb'

View File

@ -310,7 +310,6 @@ Layout/LineEndStringConcatenationIndentation:
- 'ee/spec/requests/groups/protected_environments_controller_spec.rb'
- 'ee/spec/requests/users/registrations_identity_verification_controller_spec.rb'
- 'ee/spec/serializers/integrations/field_entity_spec.rb'
- 'ee/spec/services/ai/store_repository_xray_service_spec.rb'
- 'ee/spec/services/boards/epic_lists/destroy_service_spec.rb'
- 'ee/spec/services/ci/destroy_pipeline_service_spec.rb'
- 'ee/spec/services/clusters/agent_tokens/create_service_audit_log_spec.rb'

View File

@ -80,7 +80,6 @@ Performance/StringIdentifierArgument:
- 'ee/spec/support/helpers/search_results_helpers.rb'
- 'ee/spec/support/shared_examples/features/protected_branches_access_control_shared_examples.rb'
- 'ee/spec/support/shared_examples/google_cloud_platform/artifact_registry/services_shared_examples.rb'
- 'ee/spec/support/shared_examples/lib/gitlab/elastic/search_results_shared_examples.rb'
- 'ee/spec/support/shared_examples/policies/monitor_feature_visibility_shared_examples.rb'
- 'ee/spec/workers/concerns/elastic/migration_options_spec.rb'
- 'ee/spec/workers/elastic_namespace_rollout_worker_spec.rb'

View File

@ -18,13 +18,11 @@ RSpec/ExampleWording:
- 'ee/spec/requests/api/graphql/project/product_analytics/product_analytics_spec.rb'
- 'ee/spec/requests/api/groups_spec.rb'
- 'ee/spec/requests/projects/security/scanned_resources_controller_spec.rb'
- 'ee/spec/services/ai/store_repository_xray_service_spec.rb'
- 'ee/spec/services/ci/minutes/update_project_and_namespace_usage_service_spec.rb'
- 'ee/spec/services/ci/sync_reports_to_approval_rules_service_spec.rb'
- 'ee/spec/services/merge_requests/reset_approvals_service_spec.rb'
- 'ee/spec/services/quick_actions/interpret_service_spec.rb'
- 'ee/spec/services/security/ingestion/schedule_mark_dropped_as_resolved_service_spec.rb'
- 'ee/spec/workers/ai/store_repository_xray_worker_spec.rb'
- 'qa/spec/specs/helpers/context_selector_spec.rb'
- 'spec/controllers/projects/milestones_controller_spec.rb'
- 'spec/features/groups/merge_requests_spec.rb'

View File

@ -594,7 +594,7 @@ group :test do
# Moved in `test` because https://gitlab.com/gitlab-org/gitlab/-/issues/217527
gem 'derailed_benchmarks', require: false # rubocop:todo Gemfile/MissingFeatureCategory
gem 'gitlab_quality-test_tooling', '~> 2.1.0', require: false, feature_category: :tooling
gem 'gitlab_quality-test_tooling', '~> 2.2.0', require: false, feature_category: :tooling
end
gem 'octokit', '~> 9.0', feature_category: :importers

View File

@ -239,7 +239,7 @@
{"name":"gitlab-styles","version":"13.0.1","platform":"ruby","checksum":"bf1840fe97b215ab76fe1f1a83af0aee30d33ded905415918462b832004b68bd"},
{"name":"gitlab_chronic_duration","version":"0.12.0","platform":"ruby","checksum":"0d766944d415b5c831f176871ee8625783fc0c5bfbef2d79a3a616f207ffc16d"},
{"name":"gitlab_omniauth-ldap","version":"2.2.0","platform":"ruby","checksum":"bb4d20acb3b123ed654a8f6a47d3fac673ece7ed0b6992edb92dca14bad2838c"},
{"name":"gitlab_quality-test_tooling","version":"2.1.0","platform":"ruby","checksum":"834bb046677926399170946004debc0e7da5f4354e08c316c2b7d3f98a74e47c"},
{"name":"gitlab_quality-test_tooling","version":"2.2.0","platform":"ruby","checksum":"d8fdaa7e5b529d0157485db4c81876a492303b53f30d9e8246f91f37f689295a"},
{"name":"globalid","version":"1.1.0","platform":"ruby","checksum":"b337e1746f0c8cb0a6c918234b03a1ddeb4966206ce288fbb57779f59b2d154f"},
{"name":"gon","version":"6.4.0","platform":"ruby","checksum":"e3a618d659392890f1aa7db420f17c75fd7d35aeb5f8fe003697d02c4b88d2f0"},
{"name":"google-apis-androidpublisher_v3","version":"0.34.0","platform":"ruby","checksum":"d7e1d7dd92f79c498fe2082222a1740d788e022e660c135564b3fd299cab5425"},
@ -397,7 +397,7 @@
{"name":"mixlib-shellout","version":"3.2.7","platform":"ruby","checksum":"46f6d1f9c77e689a443081c5cac336203343f0f2224db06b80d39ae4cd797c7e"},
{"name":"mixlib-shellout","version":"3.2.7","platform":"universal-mingw32","checksum":"4d7bea07e347cc8de2b4bc22f4d8f84d7bb8165cf900d26b532d0d9fa4928a19"},
{"name":"mixlib-shellout","version":"3.2.7","platform":"x64-mingw-ucrt","checksum":"de01743f678b66c275ea5f40749cde6c056651d1bb6d320711779394d2eec654"},
{"name":"mize","version":"0.6.0","platform":"ruby","checksum":"3f1a0f52cb5c158e43e93a6dd3be896d9c7dd345d76eb1bd9f26088681db2363"},
{"name":"mize","version":"0.6.1","platform":"ruby","checksum":"4031558979ff5426fda24c75a149b4e4c0faf4cacf2fae8938f83866ab94b780"},
{"name":"msgpack","version":"1.5.4","platform":"java","checksum":"05b3bd16a65dddc64c878634b7ecb9cd613569ca3dd6e480d7295626a0a3f562"},
{"name":"msgpack","version":"1.5.4","platform":"ruby","checksum":"a53db320fba40f58c07c5b66ed9fd4d73cbe8eba4cb28fe9e3218444341a4e09"},
{"name":"multi_json","version":"1.14.1","platform":"ruby","checksum":"d971296c0eacea289d31e4a7ab7ac5eda97262c62bbc8c110de4f5e36425c577"},

View File

@ -789,7 +789,7 @@ GEM
omniauth (>= 1.3, < 3)
pyu-ruby-sasl (>= 0.0.3.3, < 0.1)
rubyntlm (~> 0.5)
gitlab_quality-test_tooling (2.1.0)
gitlab_quality-test_tooling (2.2.0)
activesupport (>= 7.0, < 7.2)
amatch (~> 0.4.1)
fog-google (~> 1.24, >= 1.24.1)
@ -1160,7 +1160,7 @@ GEM
mixlib-log (3.0.9)
mixlib-shellout (3.2.7)
chef-utils
mize (0.6.0)
mize (0.6.1)
msgpack (1.5.4)
multi_json (1.14.1)
multi_xml (0.6.0)
@ -2093,7 +2093,7 @@ DEPENDENCIES
gitlab-utils!
gitlab_chronic_duration (~> 0.12)
gitlab_omniauth-ldap (~> 2.2.0)
gitlab_quality-test_tooling (~> 2.1.0)
gitlab_quality-test_tooling (~> 2.2.0)
gon (~> 6.4.0)
google-apis-androidpublisher_v3 (~> 0.34.0)
google-apis-cloudbilling_v1 (~> 0.21.0)

View File

@ -240,7 +240,7 @@
{"name":"gitlab-styles","version":"13.0.1","platform":"ruby","checksum":"bf1840fe97b215ab76fe1f1a83af0aee30d33ded905415918462b832004b68bd"},
{"name":"gitlab_chronic_duration","version":"0.12.0","platform":"ruby","checksum":"0d766944d415b5c831f176871ee8625783fc0c5bfbef2d79a3a616f207ffc16d"},
{"name":"gitlab_omniauth-ldap","version":"2.2.0","platform":"ruby","checksum":"bb4d20acb3b123ed654a8f6a47d3fac673ece7ed0b6992edb92dca14bad2838c"},
{"name":"gitlab_quality-test_tooling","version":"2.1.0","platform":"ruby","checksum":"834bb046677926399170946004debc0e7da5f4354e08c316c2b7d3f98a74e47c"},
{"name":"gitlab_quality-test_tooling","version":"2.2.0","platform":"ruby","checksum":"d8fdaa7e5b529d0157485db4c81876a492303b53f30d9e8246f91f37f689295a"},
{"name":"globalid","version":"1.1.0","platform":"ruby","checksum":"b337e1746f0c8cb0a6c918234b03a1ddeb4966206ce288fbb57779f59b2d154f"},
{"name":"gon","version":"6.4.0","platform":"ruby","checksum":"e3a618d659392890f1aa7db420f17c75fd7d35aeb5f8fe003697d02c4b88d2f0"},
{"name":"google-apis-androidpublisher_v3","version":"0.34.0","platform":"ruby","checksum":"d7e1d7dd92f79c498fe2082222a1740d788e022e660c135564b3fd299cab5425"},
@ -401,7 +401,7 @@
{"name":"mixlib-shellout","version":"3.2.7","platform":"ruby","checksum":"46f6d1f9c77e689a443081c5cac336203343f0f2224db06b80d39ae4cd797c7e"},
{"name":"mixlib-shellout","version":"3.2.7","platform":"universal-mingw32","checksum":"4d7bea07e347cc8de2b4bc22f4d8f84d7bb8165cf900d26b532d0d9fa4928a19"},
{"name":"mixlib-shellout","version":"3.2.7","platform":"x64-mingw-ucrt","checksum":"de01743f678b66c275ea5f40749cde6c056651d1bb6d320711779394d2eec654"},
{"name":"mize","version":"0.6.0","platform":"ruby","checksum":"3f1a0f52cb5c158e43e93a6dd3be896d9c7dd345d76eb1bd9f26088681db2363"},
{"name":"mize","version":"0.6.1","platform":"ruby","checksum":"4031558979ff5426fda24c75a149b4e4c0faf4cacf2fae8938f83866ab94b780"},
{"name":"msgpack","version":"1.5.4","platform":"java","checksum":"05b3bd16a65dddc64c878634b7ecb9cd613569ca3dd6e480d7295626a0a3f562"},
{"name":"msgpack","version":"1.5.4","platform":"ruby","checksum":"a53db320fba40f58c07c5b66ed9fd4d73cbe8eba4cb28fe9e3218444341a4e09"},
{"name":"multi_json","version":"1.14.1","platform":"ruby","checksum":"d971296c0eacea289d31e4a7ab7ac5eda97262c62bbc8c110de4f5e36425c577"},

View File

@ -799,7 +799,7 @@ GEM
omniauth (>= 1.3, < 3)
pyu-ruby-sasl (>= 0.0.3.3, < 0.1)
rubyntlm (~> 0.5)
gitlab_quality-test_tooling (2.1.0)
gitlab_quality-test_tooling (2.2.0)
activesupport (>= 7.0, < 7.2)
amatch (~> 0.4.1)
fog-google (~> 1.24, >= 1.24.1)
@ -1174,7 +1174,7 @@ GEM
mixlib-log (3.0.9)
mixlib-shellout (3.2.7)
chef-utils
mize (0.6.0)
mize (0.6.1)
msgpack (1.5.4)
multi_json (1.14.1)
multi_xml (0.6.0)
@ -2120,7 +2120,7 @@ DEPENDENCIES
gitlab-utils!
gitlab_chronic_duration (~> 0.12)
gitlab_omniauth-ldap (~> 2.2.0)
gitlab_quality-test_tooling (~> 2.1.0)
gitlab_quality-test_tooling (~> 2.2.0)
gon (~> 6.4.0)
google-apis-androidpublisher_v3 (~> 0.34.0)
google-apis-cloudbilling_v1 (~> 0.21.0)

View File

@ -1,9 +1,8 @@
import InputValidator from '~/validators/input_validator';
// It checks if email contains at least one character, number or whatever except
// another "@" or whitespace before "@", at least two characters except
// another "@" or whitespace after "@" and one dot in between
const emailRegexPattern = /[^@\s]+@[^@\s]+\.[^@\s]+/;
// The format of the email is validated by the default `type="email"` input field.
// In addition, the email should contain a top-level domain of at least two alphabetical characters.
const emailRegexPattern = /.+\.[a-zA-Z]{2,}/;
const hintMessageSelector = '.validation-hint';
const warningMessageSelector = '.validation-warning';

View File

@ -402,7 +402,7 @@ export default {
/>
</div>
<ai-genie
v-if="explainCodeAvailable"
v-if="explainCodeAvailable && activeViewerType === 'simple'"
container-selector=".file-content"
:file-path="path"
class="gl-ml-7"

View File

@ -88,6 +88,9 @@ export default {
featureFlags() {
return this.workItemDevelopment?.featureFlags?.nodes || [];
},
relatedBranches() {
return this.workItemDevelopment?.relatedBranches?.nodes || [];
},
shouldShowEmptyState() {
return this.isRelatedDevelopmentListEmpty ? this.workItemsAlphaEnabled : true;
},
@ -95,7 +98,12 @@ export default {
return this.workItemDevelopment && this.shouldShowEmptyState;
},
isRelatedDevelopmentListEmpty() {
return !this.error && this.linkedMergeRequests.length === 0 && this.featureFlags.length === 0;
return (
!this.error &&
this.linkedMergeRequests.length === 0 &&
this.featureFlags.length === 0 &&
this.relatedBranches.length === 0
);
},
showAutoCloseInformation() {
return (

View File

@ -0,0 +1,36 @@
<script>
import { GlIcon, GlTooltip, GlLink } from '@gitlab/ui';
export default {
components: {
GlIcon,
GlTooltip,
GlLink,
},
props: {
itemContent: {
type: Object,
required: true,
},
},
};
</script>
<template>
<div
ref="branchInfo"
class="gl-grid-cols-[auto, 1fr] gl-grid gl-w-fit gl-gap-2 gl-gap-5 gl-p-2 gl-pl-0 gl-pr-3"
>
<gl-link
:href="itemContent.comparePath"
class="gl-truncate gl-text-primary hover:gl-text-primary hover:gl-underline"
>
<gl-icon name="branch" class="gl-text-gray-500" />
{{ itemContent.name }}
</gl-link>
<gl-tooltip :target="() => $refs.branchInfo" placement="top">
<div class="gl-font-bold">{{ __('Branch') }}</div>
<div>{{ itemContent.name }}</div>
</gl-tooltip>
</div>
</template>

View File

@ -1,10 +1,12 @@
<script>
import { GlButton } from '@gitlab/ui';
import { uniqueId } from 'lodash';
import { sprintf, __ } from '~/locale';
import { renderGFM } from '~/behaviors/markdown/render_gfm';
import { TYPENAME_FEATURE_FLAG } from '~/graphql_shared/constants';
import WorkItemDevelopmentMrItem from './work_item_development_mr_item.vue';
import WorkItemDevelopmentBranchItem from './work_item_development_branch_item.vue';
const DEFAULT_RENDER_COUNT = 3;
@ -30,8 +32,10 @@ export default {
},
computed: {
list() {
// keeping as a separate prop, will be appending with branches
return [...this.sortedFeatureFlags, ...this.mergeRequests];
return [...this.sortedFeatureFlags, ...this.mergeRequests, ...this.relatedBranches];
},
relatedBranches() {
return this.workItemDevWidget.relatedBranches?.nodes || [];
},
mergeRequests() {
return this.workItemDevWidget.closingMergeRequests?.nodes || [];
@ -74,6 +78,8 @@ export default {
component = WorkItemDevelopmentMrItem;
} else if (this.isFeatureFlag(item)) {
component = 'work-item-development-ff-item';
} else if (this.isBranch(item)) {
component = WorkItemDevelopmentBranchItem;
} else {
component = 'li';
}
@ -86,13 +92,17 @@ export default {
// eslint-disable-next-line no-underscore-dangle
return item.__typename === TYPENAME_FEATURE_FLAG;
},
isBranch(item) {
// eslint-disable-next-line no-underscore-dangle
return item.__typename === 'WorkItemRelatedBranch';
},
async toggleShowLess() {
this.showLess = !this.showLess;
await this.$nextTick();
renderGFM(this.$refs['list-body']);
},
itemId(item) {
return item.id || item.mergeRequest.id;
return item?.id || item?.mergeRequest?.id || uniqueId('branch-id-');
},
itemObject(item) {
return this.isMergeRequest(item) ? item.mergeRequest : item;

View File

@ -96,6 +96,12 @@ fragment WorkItemWidgets on WorkItemWidget {
... on WorkItemWidgetDevelopment {
type
willAutoCloseByMergeRequest
relatedBranches {
nodes {
name
comparePath
}
}
closingMergeRequests {
nodes {
fromMrDescription

View File

@ -81,3 +81,5 @@ module Mutations
end
end
end
Mutations::Ci::Runner::Create.prepend_mod

View File

@ -78,4 +78,4 @@ module Mutations
end
end
Mutations::Ci::Runner::Update.prepend_mod_with('Mutations::Ci::Runner::Update')
Mutations::Ci::Runner::Update.prepend_mod

View File

@ -13,7 +13,10 @@ module VirtualRegistries
class_name: 'VirtualRegistries::Packages::Maven::CachedResponse',
inverse_of: :upstream
attr_encrypted :credentials,
ignore_column :encrypted_credentials, remove_with: '17.9', remove_after: '2025-01-23'
ignore_column :encrypted_credentials_iv, remove_with: '17.9', remove_after: '2025-01-23'
attr_encrypted_options.merge!(
mode: :per_attribute_iv,
key: Settings.attr_encrypted_db_key_base_32,
algorithm: 'aes-256-gcm',
@ -21,8 +24,10 @@ module VirtualRegistries
marshaler: ::Gitlab::Json,
encode: false,
encode_iv: false
attribute :username, :string, default: nil
attribute :password, :string, default: nil
)
attr_encrypted :username
attr_encrypted :password
validates :group, top_level_group: true, presence: true
validates :url, addressable_url: { allow_localhost: false, allow_local_network: false }, presence: true
@ -30,10 +35,9 @@ module VirtualRegistries
validates :password, presence: true, if: :username?
validates :url, :username, :password, length: { maximum: 255 }
validates :cache_validity_hours, numericality: { greater_than_or_equal_to: 0, only_integer: true }
validates :encrypted_username_iv, :encrypted_password_iv, uniqueness: true
after_initialize :read_credentials
after_validation :reset_credentials, if: -> { persisted? && url_changed? }
before_save :write_credentials
prevent_from_serialization(:username, :password) if respond_to?(:prevent_from_serialization)
@ -52,27 +56,11 @@ module VirtualRegistries
private
def read_credentials
self.credentials ||= {}
# if credentials are blank we might have a username + password from initializer. Don't reset them.
return if credentials.blank?
self.username, self.password = (credentials || {}).values_at('username', 'password')
clear_username_change
clear_password_change
end
def write_credentials
self.credentials = (credentials || {}).merge('username' => username, 'password' => password)
end
def reset_credentials
return if username_changed? && password_changed?
self.username = nil
self.password = nil
self.credentials = {}
end
end
end

View File

@ -64,8 +64,8 @@
title: _('Please provide a valid email address.')
%p.validation-hint.text-secondary
= _('We recommend a work email address.')
%p.validation-warning.gl-field-error-ignore.text-secondary.hide
= _('This email address does not look right, are you sure you typed it correctly?')
%p.validation-warning.gl-field-error-ignore.gl-text-red-500.hide
= _('Email address without top-level domain. Make sure that you have entered the correct email address.')
-# This is used for providing entry to Jihu on email verification
= render_if_exists 'devise/shared/signup_email_additional_info'
.form-group.gl-mb-5

View File

@ -6,14 +6,40 @@ module Gitlab
class FinishImportWorker # rubocop:disable Scalability/IdempotentWorker
include StageMethods
PLACEHOLDER_WAIT_INTERVAL = 30.seconds
private
# project - An instance of Project.
# @param project [Project]
def import(project)
placeholder_reference_store = project.placeholder_reference_store
if placeholder_reference_store&.any?
info(
project.id,
message: 'Delaying finalization as placeholder references are pending',
placeholder_store_count: placeholder_reference_store.count
)
reschedule(project)
return
end
project.after_import
Gitlab::Import::Metrics.new(:bitbucket_server_importer, project).track_finished_import
end
def reschedule(project)
::Import::LoadPlaceholderReferencesWorker.perform_async(
project.import_type,
project.import_state.id,
{ current_user_id: project.creator_id }
)
self.class.perform_in(PLACEHOLDER_WAIT_INTERVAL.seconds, project.id)
end
end
end
end

View File

@ -25,8 +25,11 @@ module Import
end
def perform_failure(exception, import_source, import_uid)
fail_import(import_source, import_uid)
log_failure(exception, import_source, import_uid)
clear_placeholder_reference_store(import_source, import_uid)
end
def log_failure(exception, import_source, import_uid)
::Import::Framework::Logger.error(
message: 'Failed to load all references to placeholder user contributions',
error: exception.message,
@ -35,21 +38,9 @@ module Import
)
end
private
def fail_import(import_source, import_uid)
import_state = nil
case import_source
when 'gitlab'
import_state = BulkImport.find_by_id(import_uid)
when 'github', 'bitbucket', 'bitbucket_server', 'fogbugz', 'gitea', 'gitlab_project'
import_state = ProjectImportState.find_by_id(import_uid)
when 'import_group_from_file'
import_state = GroupImportState.find_by_group_id(import_uid)
end
import_state&.fail_op
def clear_placeholder_reference_store(import_source, import_uid)
store = PlaceholderReferences::Store.new(import_source: import_source, import_uid: import_uid)
store.clear!
end
end
end

View File

@ -0,0 +1,24 @@
---
key_path: redis_hll_counters.count_distinct_namespace_id_from_pull_ml_model_monthly
description: Monthly count of unique namespaces with ML model pulled
product_group: package_registry
performance_indicator_type: []
value_type: number
status: active
milestone: '17.7'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/173261
time_frame: 28d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tiers:
- free
- premium
- ultimate
events:
- name: pull_package_from_registry
unique: namespace.id
filter:
label: ml_model

View File

@ -0,0 +1,24 @@
---
key_path: redis_hll_counters.count_distinct_namespace_id_from_push_ml_model_monthly
description: Monthly count of unique namespaces with ML model pushed
product_group: package_registry
performance_indicator_type: []
value_type: number
status: active
milestone: '17.7'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/173261
time_frame: 28d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tiers:
- free
- premium
- ultimate
events:
- name: push_package_to_registry
unique: namespace.id
filter:
label: ml_model

View File

@ -0,0 +1,24 @@
---
key_path: redis_hll_counters.count_distinct_project_id_from_pull_ml_model_monthly
description: Monthly count of unique projects with ML model pulled last 28 days
product_group: package_registry
performance_indicator_type: []
value_type: number
status: active
milestone: '17.7'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/173261
time_frame: 28d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tiers:
- free
- premium
- ultimate
events:
- name: pull_package_from_registry
unique: project.id
filter:
label: ml_model

View File

@ -0,0 +1,24 @@
---
key_path: redis_hll_counters.count_distinct_project_id_from_push_ml_model_monthly
description: Monthly count of unique projects with ML model package pushed
product_group: package_registry
performance_indicator_type: []
value_type: number
status: active
milestone: '17.7'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/173261
time_frame: 28d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tiers:
- free
- premium
- ultimate
events:
- name: push_package_to_registry
unique: project.id
filter:
label: ml_model

View File

@ -0,0 +1,24 @@
---
key_path: redis_hll_counters.count_distinct_namespace_id_from_pull_ml_model_weekly
description: Weekly count of unique namespaces with ML model pulled
product_group: package_registry
performance_indicator_type: []
value_type: number
status: active
milestone: '17.7'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/173261
time_frame: 7d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tiers:
- free
- premium
- ultimate
events:
- name: pull_package_from_registry
unique: namespace.id
filter:
label: ml_model

View File

@ -0,0 +1,24 @@
---
key_path: redis_hll_counters.count_distinct_namespace_id_from_push_ml_model_weekly
description: Weekly count of unique namespaces with ML model pushed
product_group: package_registry
performance_indicator_type: []
value_type: number
status: active
milestone: '17.7'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/173261
time_frame: 7d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tiers:
- free
- premium
- ultimate
events:
- name: push_package_to_registry
unique: namespace.id
filter:
label: ml_model

View File

@ -0,0 +1,24 @@
---
key_path: redis_hll_counters.count_distinct_project_id_from_pull_ml_model_weekly
description: Weekly count of unique projects with ML model pulled last 7 days
product_group: package_registry
performance_indicator_type: []
value_type: number
status: active
milestone: '17.7'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/173261
time_frame: 7d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tiers:
- free
- premium
- ultimate
events:
- name: pull_package_from_registry
unique: project.id
filter:
label: ml_model

View File

@ -0,0 +1,24 @@
---
key_path: redis_hll_counters.count_distinct_project_id_from_push_ml_model_weekly
description: Weekly count of unique projects with ML model package pushed
product_group: package_registry
performance_indicator_type: []
value_type: number
status: active
milestone: '17.7'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/173261
time_frame: 7d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tiers:
- free
- premium
- ultimate
events:
- name: push_package_to_registry
unique: project.id
filter:
label: ml_model

View File

@ -0,0 +1,48 @@
# frozen_string_literal: true
class AddUsernamePasswordToVirtualRegistriesPackagesMavenUpstream < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '17.7'
TABLE_NAME = :virtual_registries_packages_maven_upstreams
COLUMNS = %i[encrypted_username encrypted_username_iv encrypted_password encrypted_password_iv]
def up
with_lock_retries do
# can't use COLUMNS.each here
unless column_exists?(TABLE_NAME, :encrypted_username)
add_column TABLE_NAME, :encrypted_username, :binary, null: true
end
unless column_exists?(TABLE_NAME, :encrypted_username_iv)
add_column TABLE_NAME, :encrypted_username_iv, :binary, null: true
end
unless column_exists?(TABLE_NAME, :encrypted_password)
add_column TABLE_NAME, :encrypted_password, :binary, null: true
end
unless column_exists?(TABLE_NAME, :encrypted_password_iv)
add_column TABLE_NAME, :encrypted_password_iv, :binary, null: true
end
end
add_concurrent_index TABLE_NAME,
:encrypted_username_iv,
unique: true,
name: 'index_virtual_reg_pkgs_maven_upstreams_on_uniq_enc_username_iv'
add_concurrent_index TABLE_NAME,
:encrypted_password_iv,
unique: true,
name: 'index_virtual_reg_pkgs_maven_upstreams_on_uniq_enc_password_iv'
COLUMNS.each do |col|
constraint = check_constraint_name(TABLE_NAME.to_s, col.to_s, 'max_length')
add_check_constraint(TABLE_NAME, "octet_length(#{col}) <= 1020", constraint)
end
end
def down
COLUMNS.each { |col| remove_column(TABLE_NAME, col, if_exists: true) }
end
end

View File

@ -0,0 +1 @@
b515de4fe506d99953b6026f16f27881df6cfb8234bd173dfcb40b3db3b7c365

View File

@ -21061,10 +21061,18 @@ CREATE TABLE virtual_registries_packages_maven_upstreams (
encrypted_credentials bytea,
encrypted_credentials_iv bytea,
cache_validity_hours smallint DEFAULT 24 NOT NULL,
encrypted_username bytea,
encrypted_username_iv bytea,
encrypted_password bytea,
encrypted_password_iv bytea,
CONSTRAINT check_2366658457 CHECK ((octet_length(encrypted_username) <= 1020)),
CONSTRAINT check_26c0572777 CHECK ((char_length(url) <= 255)),
CONSTRAINT check_4af2999ab8 CHECK ((octet_length(encrypted_credentials_iv) <= 1020)),
CONSTRAINT check_a3593dca3a CHECK ((cache_validity_hours >= 0)),
CONSTRAINT check_b9e3bfa31a CHECK ((octet_length(encrypted_credentials) <= 1020))
CONSTRAINT check_b9e3bfa31a CHECK ((octet_length(encrypted_credentials) <= 1020)),
CONSTRAINT check_c3977cdb0c CHECK ((octet_length(encrypted_username_iv) <= 1020)),
CONSTRAINT check_e4b6e651bf CHECK ((octet_length(encrypted_password_iv) <= 1020)),
CONSTRAINT check_e57d1f3005 CHECK ((octet_length(encrypted_password) <= 1020))
);
CREATE SEQUENCE virtual_registries_packages_maven_upstreams_id_seq
@ -32557,6 +32565,10 @@ CREATE INDEX index_virtual_reg_pkgs_maven_reg_upstreams_on_group_id ON virtual_r
CREATE INDEX index_virtual_reg_pkgs_maven_upstreams_on_group_id ON virtual_registries_packages_maven_upstreams USING btree (group_id);
CREATE UNIQUE INDEX index_virtual_reg_pkgs_maven_upstreams_on_uniq_enc_password_iv ON virtual_registries_packages_maven_upstreams USING btree (encrypted_password_iv);
CREATE UNIQUE INDEX index_virtual_reg_pkgs_maven_upstreams_on_uniq_enc_username_iv ON virtual_registries_packages_maven_upstreams USING btree (encrypted_username_iv);
CREATE UNIQUE INDEX index_vuln_findings_on_uuid_including_vuln_id_1 ON vulnerability_occurrences USING btree (uuid) INCLUDE (vulnerability_id);
CREATE UNIQUE INDEX index_vuln_historical_statistics_on_project_id_and_date ON vulnerability_historical_statistics USING btree (project_id, date);

View File

@ -9062,7 +9062,9 @@ Input type: `RunnerCreateInput`
| <a id="mutationrunnercreatemaintenancenote"></a>`maintenanceNote` | [`String`](#string) | Runner's maintenance notes. |
| <a id="mutationrunnercreatemaximumtimeout"></a>`maximumTimeout` | [`Int`](#int) | Maximum timeout (in seconds) for jobs processed by the runner. |
| <a id="mutationrunnercreatepaused"></a>`paused` | [`Boolean`](#boolean) | Indicates the runner is not allowed to receive jobs. |
| <a id="mutationrunnercreateprivateprojectsminutescostfactor"></a>`privateProjectsMinutesCostFactor` **{warning-solid}** | [`Float`](#float) | **Deprecated:** **Status**: Experiment. Introduced in GitLab 17.7. |
| <a id="mutationrunnercreateprojectid"></a>`projectId` | [`ProjectID`](#projectid) | Global ID of the project that the runner is created in (valid only for project runner). |
| <a id="mutationrunnercreatepublicprojectsminutescostfactor"></a>`publicProjectsMinutesCostFactor` **{warning-solid}** | [`Float`](#float) | **Deprecated:** **Status**: Experiment. Introduced in GitLab 17.7. |
| <a id="mutationrunnercreaterununtagged"></a>`runUntagged` | [`Boolean`](#boolean) | Indicates the runner is able to run untagged jobs. |
| <a id="mutationrunnercreaterunnertype"></a>`runnerType` | [`CiRunnerType!`](#cirunnertype) | Type of the runner to create. |
| <a id="mutationrunnercreatetaglist"></a>`tagList` | [`[String!]`](#string) | Tags associated with the runner. |
@ -9111,8 +9113,8 @@ Input type: `RunnerUpdateInput`
| <a id="mutationrunnerupdatemaintenancenote"></a>`maintenanceNote` | [`String`](#string) | Runner's maintenance notes. |
| <a id="mutationrunnerupdatemaximumtimeout"></a>`maximumTimeout` | [`Int`](#int) | Maximum timeout (in seconds) for jobs processed by the runner. |
| <a id="mutationrunnerupdatepaused"></a>`paused` | [`Boolean`](#boolean) | Indicates the runner is not allowed to receive jobs. |
| <a id="mutationrunnerupdateprivateprojectsminutescostfactor"></a>`privateProjectsMinutesCostFactor` | [`Float`](#float) | Private projects' "compute cost factor" associated with the runner (GitLab.com only). |
| <a id="mutationrunnerupdatepublicprojectsminutescostfactor"></a>`publicProjectsMinutesCostFactor` | [`Float`](#float) | Public projects' "compute cost factor" associated with the runner (GitLab.com only). |
| <a id="mutationrunnerupdateprivateprojectsminutescostfactor"></a>`privateProjectsMinutesCostFactor` **{warning-solid}** | [`Float`](#float) | **Deprecated:** **Status**: Experiment. Introduced in GitLab 17.7. |
| <a id="mutationrunnerupdatepublicprojectsminutescostfactor"></a>`publicProjectsMinutesCostFactor` **{warning-solid}** | [`Float`](#float) | **Deprecated:** **Status**: Experiment. Introduced in GitLab 17.7. |
| <a id="mutationrunnerupdaterununtagged"></a>`runUntagged` | [`Boolean`](#boolean) | Indicates the runner is able to run untagged jobs. |
| <a id="mutationrunnerupdatetaglist"></a>`tagList` | [`[String!]`](#string) | Tags associated with the runner. |

View File

@ -176,6 +176,19 @@ track_event(
)
```
#### Batching
When multiple events are emitted at once, use `with_batched_redis_writes` to batch all of them
in a single Redis call.
```ruby
Gitlab::InternalEvents.with_batched_redis_writes do
incr.times { Gitlab::InternalEvents.track_event(event) }
end
```
Notice that only updates to total counters are batched. If `n` unique metrics and `m` total counter metrics are defined, it will result in `incr * n + m` Redis writes.
### Backend testing
When testing code that simply triggers an internal event and make sure it increments all the related metrics,

File diff suppressed because it is too large Load Diff

View File

@ -115,7 +115,6 @@ If you need to copy a group to a different GitLab instance,
When transferring groups, note:
- Changing a group's parent can have unintended side effects. See [what happens when a repository path changes](../project/repository/index.md#repository-path-changes).
- You must have the Owner role for the source and target group.
- You must update your local repositories to point to the new location.
- If the immediate parent group's visibility is lower than the group's current visibility, visibility levels for subgroups and projects change to match the new parent group's visibility.
- Only explicit group membership is transferred, not inherited membership. If the group's Owners have only inherited membership, this leaves the group without an Owner. In this case, the user transferring the group becomes the group's Owner.
@ -125,6 +124,10 @@ When transferring groups, note:
- Existing package names need to be updated if the package uses an instance-level endpoint ([Maven](../packages/maven_repository/index.md#naming-convention), [npm](../packages/npm_registry/index.md#naming-convention), [Conan](../packages/conan_repository/index.md#package-recipe-naming-convention-for-instance-remotes)) and the group was moved to another top-level group.
- Top-level groups that have a subscription on GitLab.com cannot be transferred. To make the transfer possible, the top-level group's subscription must be removed first. Then the top-level group can be transferred as a subgroup to another top-level group.
Prerequisites:
- You must have the Owner role for the source and target group.
To transfer a group:
1. On the left sidebar, select **Search or go to** and find your group.

View File

@ -161,7 +161,7 @@ user_viewed_custom_dashboard-user: user_viewed_custom_dashboard
user_viewed_dashboard_designer-user: user_viewed_dashboard_designer
user_viewed_dashboard_list-user: user_viewed_dashboard_list
user_viewed_instrumentation_directions-user: user_viewed_instrumentation_directions
user_viewed_visualization_designer-user: user_viewed_visualization_designer
user_viewed_data_explorer-user: user_viewed_data_explorer
user_visited_dashboard-user: user_visited_dashboard
'view_merge_request_widget-filter:[label:accessibility]-user': i_code_review_merge_request_widget_accessibility_view
'view_merge_request_widget-filter:[label:code_quality]-user': i_code_review_merge_request_widget_code_quality_view

View File

@ -34,6 +34,10 @@ module Import
!empty?
end
def clear!
cache.del(cache_key)
end
private
attr_reader :import_source, :import_uid

View File

@ -20928,6 +20928,9 @@ msgstr ""
msgid "Email address to use for Service Desk"
msgstr ""
msgid "Email address without top-level domain. Make sure that you have entered the correct email address."
msgstr ""
msgid "Email could not be sent"
msgstr ""
@ -56382,9 +56385,6 @@ msgstr ""
msgid "This domain is not verified. You will need to verify ownership before access is enabled."
msgstr ""
msgid "This email address does not look right, are you sure you typed it correctly?"
msgstr ""
msgid "This email supersedes any previous emails about scheduled deletion you may have received for %{project_link}."
msgstr ""

View File

@ -42,6 +42,7 @@ end
RSpec.describe 'Signup', :with_current_organization, :js, feature_category: :user_management do
include TermsHelper
using RSpec::Parameterized::TableSyntax
let(:new_user) { build_stubbed(:user) }
@ -365,5 +366,82 @@ RSpec.describe 'Signup', :with_current_organization, :js, feature_category: :use
it_behaves_like 'user email validation' do
let(:path) { new_user_registration_path }
end
where(:email, :reason) do
'"A"@b.co' | 'quoted emails'
'a @b.co' | 'space in the local-part'
'ab.co' | 'no @ symbol'
'a@b@c.co' | 'several @ symbol'
'a@-b.co' | 'domain starting with hyphen'
'a@b-.co' | 'domain finishing with hyphen'
'a@example_me.co' | 'domain with underscore'
'a@example .com' | 'space in the domain'
'a@[123.123.123.123]' | 'IP addresses'
'a@b.' | 'invalid domain'
end
with_them do
cause = params[:reason]
it "doesn't accept emails with #{cause}" do
new_user.email = email
visit new_user_registration_path
fill_in_sign_up_form(new_user)
expect(page).to have_current_path new_user_registration_path
expect(page).to have_content(_("Please provide a valid email address."))
end
end
end
context 'with valid email with top-level-domain singularities' do
it_behaves_like 'user email validation' do
let(:path) { new_user_registration_path }
end
where(:email, :reason) do
'a@b' | 'no TLD'
'a@b.c' | 'TLD less than two characters'
end
with_them do
cause = params[:reason]
it "accept emails with #{cause} but displays a warning" do
new_user_password_ori = new_user.password
new_user.email = email
new_user.password = ''
visit new_user_registration_path
fill_in_sign_up_form(new_user)
expect(page).to have_current_path new_user_registration_path
expect(page).to have_content(
_('Email address without top-level domain. Make sure that you have entered the correct email address.')
)
new_user.password = new_user_password_ori
expect { fill_in_sign_up_form(new_user) }.to change { User.count }.by(1)
end
end
end
context 'with valid email' do
where(:email, :reason) do
'6@b.co' | 'alphanumerical first character in the local-part'
'012345678901234567890123456789@b.co' | 'long local-part'
'a@wwww.internal-site.co.uk' | 'several subdomains'
'a@3w.internal-site.co.uk' | 'several subdomains'
'a@b.example' | 'valid TLD'
end
with_them do
cause = params[:reason]
it "accepts emails with #{cause}" do
new_user.email = email
visit new_user_registration_path
expect { fill_in_sign_up_form(new_user) }.to change { User.count }.by(1)
end
end
end
end

View File

@ -0,0 +1,36 @@
import { GlLink, GlIcon, GlTooltip } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { workItemRelatedBranchNodes } from 'jest/work_items/mock_data';
import WorkItemDevelopmentBranchItem from '~/work_items/components/work_item_development/work_item_development_branch_item.vue';
describe('WorkItemDevelopmentBranchItem', () => {
let wrapper;
const branchNode = workItemRelatedBranchNodes[0];
const createComponent = ({ branch = branchNode } = {}) => {
wrapper = shallowMount(WorkItemDevelopmentBranchItem, {
propsData: {
itemContent: branch,
},
});
};
const findIcon = () => wrapper.findComponent(GlIcon);
const findLink = () => wrapper.findComponent(GlLink);
const findTooltip = () => wrapper.findComponent(GlTooltip);
it('should render the comparePath and name with icon', () => {
createComponent();
expect(findIcon().exists()).toBe(true);
expect(findIcon().props('name')).toBe('branch');
expect(findLink().attributes('href')).toBe(branchNode.comparePath);
expect(findLink().text()).toBe(branchNode.name);
});
it('should render the tooltip with name', () => {
createComponent();
expect(findTooltip().exists()).toBe(true);
expect(findTooltip().text()).toContain(`Branch ${branchNode.name}`);
});
});

View File

@ -12,6 +12,10 @@ describe('WorkItemDevelopmentRelationshipList', () => {
nodes: [workItemDevelopmentFragmentResponse().closingMergeRequests.nodes[0]],
__typename: 'WorkItemClosingMergeRequestConnection',
},
relatedBranches: {
nodes: [],
__typename: 'WorkItemRelatedBranchConnection',
},
featureFlags: {
nodes: [workItemDevelopmentFragmentResponse().featureFlags.nodes[0]],
__typename: 'FeatureFlagConnection',
@ -24,6 +28,10 @@ describe('WorkItemDevelopmentRelationshipList', () => {
nodes: [workItemDevelopmentFragmentResponse().closingMergeRequests.nodes[0]],
__typename: 'WorkItemClosingMergeRequestConnection',
},
relatedBranches: {
nodes: [],
__typename: 'WorkItemRelatedBranchConnection',
},
featureFlags: {
nodes: [
workItemDevelopmentFragmentResponse().featureFlags.nodes[0],

View File

@ -30,15 +30,21 @@ describe('WorkItemDevelopment CE', () => {
});
const workItemWithOneMR = workItemResponseFactory({
developmentWidgetPresent: true,
developmentItems: workItemDevelopmentFragmentResponse(
[workItemDevelopmentMRNodes[0]],
true,
null,
),
developmentItems: workItemDevelopmentFragmentResponse({
mrNodes: [workItemDevelopmentMRNodes[0]],
willAutoCloseByMergeRequest: true,
featureFlagNodes: null,
branchNodes: [],
}),
});
const workItemWithMRList = workItemResponseFactory({
developmentWidgetPresent: true,
developmentItems: workItemDevelopmentFragmentResponse(workItemDevelopmentMRNodes, true, null),
developmentItems: workItemDevelopmentFragmentResponse({
mrNodes: workItemDevelopmentMRNodes,
willAutoCloseByMergeRequest: true,
featureFlagNodes: null,
branchNodes: [],
}),
});
const projectWorkItemResponseWithMRList = {
@ -95,22 +101,33 @@ describe('WorkItemDevelopment CE', () => {
};
const successQueryHandler = jest.fn().mockResolvedValue(projectWorkItemResponseWithMRList);
const workItemWithEmptyMRList = workItemResponseFactory({
const workItemWithNoDevItems = workItemResponseFactory({
canUpdate: true,
developmentWidgetPresent: true,
developmentItems: workItemDevelopmentFragmentResponse([], false, null),
});
const workItemWithAutoCloseFlagEnabled = workItemResponseFactory({
developmentWidgetPresent: true,
developmentItems: workItemDevelopmentFragmentResponse(workItemDevelopmentMRNodes, true, null),
developmentItems: workItemDevelopmentFragmentResponse({
mrNodes: [],
willAutoCloseByMergeRequest: false,
featureFlagNodes: null,
branchNodes: [],
}),
});
const successQueryHandlerWithEmptyMRList = jest.fn().mockResolvedValue({
const workItemWithAutoCloseFlagEnabled = workItemResponseFactory({
developmentWidgetPresent: true,
developmentItems: workItemDevelopmentFragmentResponse({
mrNodes: workItemDevelopmentMRNodes,
willAutoCloseByMergeRequest: true,
featureFlagNodes: null,
branchNodes: [],
}),
});
const successQueryHandlerWithNoDevItems = jest.fn().mockResolvedValue({
data: {
workspace: {
__typename: 'Project',
id: 'gid://gitlab/Project/1',
workItem: workItemWithEmptyMRList.data.workItem,
workItem: workItemWithNoDevItems.data.workItem,
},
},
});
@ -217,11 +234,11 @@ describe('WorkItemDevelopment CE', () => {
${true} | ${true}
${false} | ${false}
`(
'when the list of MRs is empty and workItemsAlpha is `$workItemsAlphaFFEnabled`',
'when the list of dev items is empty and workItemsAlpha is `$workItemsAlphaFFEnabled`',
({ workItemsAlphaFFEnabled, shouldShowActionCtaButtons }) => {
beforeEach(async () => {
createComponent({
workItemQueryHandler: successQueryHandlerWithEmptyMRList,
workItemQueryHandler: successQueryHandlerWithNoDevItems,
workItemsAlphaEnabled: workItemsAlphaFFEnabled,
});
await waitForPromises();

View File

@ -1136,11 +1136,25 @@ export const workItemDevelopmentFeatureFlagNodes = [
},
];
export const workItemDevelopmentFragmentResponse = (
export const workItemRelatedBranchNodes = [
{
name: '178-issue',
comparePath: '/flightjs/Flight/-/compare/master...178-issue',
__typename: 'WorkItemRelatedBranch',
},
{
name: '178-issue-10',
comparePath: '/flightjs/Flight/-/compare/master...178-issue-10',
__typename: 'WorkItemRelatedBranch',
},
];
export const workItemDevelopmentFragmentResponse = ({
mrNodes = workItemDevelopmentMRNodes,
willAutoCloseByMergeRequest = false,
featureFlagNodes = workItemDevelopmentFeatureFlagNodes,
) => {
branchNodes = workItemRelatedBranchNodes,
} = {}) => {
return {
type: 'DEVELOPMENT',
willAutoCloseByMergeRequest,
@ -1148,6 +1162,10 @@ export const workItemDevelopmentFragmentResponse = (
nodes: featureFlagNodes,
__typename: 'FeatureFlagConnection',
},
relatedBranches: {
nodes: branchNodes,
__typename: 'WorkItemRelatedBranchConnection',
},
closingMergeRequests: {
nodes: mrNodes,
__typename: 'WorkItemClosingMergeRequestConnection',

View File

@ -72,6 +72,14 @@ RSpec.describe Import::PlaceholderReferences::Store, :clean_gitlab_redis_shared_
end
end
describe '#clear!' do
it 'removes the values from the cache' do
store.add('foo')
expect { store.clear! }.to change { store.count }.from(1).to(0)
end
end
def cache
Gitlab::Cache::Import::Caching
end

View File

@ -36,6 +36,8 @@ RSpec.describe VirtualRegistries::Packages::Maven::Upstream, type: :model, featu
it { is_expected.to validate_presence_of(:url) }
it { is_expected.to validate_presence_of(:username) }
it { is_expected.to validate_presence_of(:password) }
it { is_expected.to validate_uniqueness_of(:encrypted_username_iv).ignoring_case_sensitivity }
it { is_expected.to validate_uniqueness_of(:encrypted_password_iv).ignoring_case_sensitivity }
it { is_expected.to validate_length_of(:url).is_at_most(255) }
it { is_expected.to validate_length_of(:username).is_at_most(255) }
it { is_expected.to validate_length_of(:password).is_at_most(255) }
@ -101,12 +103,12 @@ RSpec.describe VirtualRegistries::Packages::Maven::Upstream, type: :model, featu
end
context 'when url is updated' do
where(:new_url, :new_user, :new_pwd, :expected_user, :expected_pwd, :expected_credentials) do
'http://original_url.test' | 'test' | 'test' | 'test' | 'test' | { 'username' => 'test', 'password' => 'test' }
'http://update_url.test' | 'test' | 'test' | 'test' | 'test' | { 'username' => 'test', 'password' => 'test' }
'http://update_url.test' | :none | :none | nil | nil | { 'username' => nil, 'password' => nil }
'http://update_url.test' | 'test' | :none | nil | nil | { 'username' => nil, 'password' => nil }
'http://update_url.test' | :none | 'test' | nil | nil | { 'username' => nil, 'password' => nil }
where(:new_url, :new_user, :new_pwd, :expected_user, :expected_pwd) do
'http://original_url.test' | 'test' | 'test' | 'test' | 'test'
'http://update_url.test' | 'test' | 'test' | 'test' | 'test'
'http://update_url.test' | :none | :none | nil | nil
'http://update_url.test' | 'test' | :none | nil | nil
'http://update_url.test' | :none | 'test' | nil | nil
end
with_them do
@ -121,7 +123,6 @@ RSpec.describe VirtualRegistries::Packages::Maven::Upstream, type: :model, featu
expect(upstream.reload.url).to eq(new_url)
expect(upstream.username).to eq(expected_user)
expect(upstream.password).to eq(expected_pwd)
expect(upstream.credentials).to eq(expected_credentials)
end
end
end

View File

@ -362,7 +362,6 @@
- './ee/spec/graphql/api/vulnerabilities_spec.rb'
- './ee/spec/graphql/ee/mutations/boards/issues/issue_move_list_spec.rb'
- './ee/spec/graphql/ee/mutations/boards/lists/create_spec.rb'
- './ee/spec/graphql/ee/mutations/ci/runner/update_spec.rb'
- './ee/spec/graphql/ee/mutations/concerns/mutations/resolves_issuable_spec.rb'
- './ee/spec/graphql/ee/resolvers/board_list_issues_resolver_spec.rb'
- './ee/spec/graphql/ee/resolvers/board_lists_resolver_spec.rb'
@ -981,7 +980,6 @@
- './ee/spec/lib/gitlab/elastic/bulk_indexer_spec.rb'
- './ee/spec/lib/gitlab/elastic/group_search_results_spec.rb'
- './ee/spec/lib/gitlab/elastic/project_search_results_spec.rb'
- './ee/spec/lib/gitlab/elastic/search_results_spec.rb'
- './ee/spec/lib/gitlab/elastic/snippet_search_results_spec.rb'
- './ee/spec/lib/gitlab/email/handler/create_note_handler_spec.rb'
- './ee/spec/lib/gitlab/exclusive_lease_spec.rb'

View File

@ -5,7 +5,7 @@ RSpec.shared_examples 'user email validation' do
let(:email_error_message) { _('Please provide a valid email address.') }
let(:email_warning_message) do
_('This email address does not look right, are you sure you typed it correctly?')
_('Email address without top-level domain. Make sure that you have entered the correct email address.')
end
it 'shows an error message until a correct email is entered' do

View File

@ -37,7 +37,7 @@ RSpec.describe Tasks::Gitlab::AuditEventTypes::CheckDocsTask, feature_category:
let(:removed_definition) { Gitlab::Audit::Type::Definition.definitions.except(:feature_flag_created) }
let(:updated_definition) do
definitions = Gitlab::Audit::Type::Definition.definitions
definitions[:feature_flag_created].attributes[:streamed] = false
definitions[:feature_flag_created].attributes[:saved_to_database] = false
definitions
end

View File

@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Gitlab::BitbucketServerImport::Stage::FinishImportWorker, feature_category: :importers do
let_it_be(:project) { create(:project, :import_started) }
let_it_be(:project) { create(:project, :import_started, import_type: :bitbucket_server) }
subject(:worker) { described_class.new }
@ -19,5 +19,66 @@ RSpec.describe Gitlab::BitbucketServerImport::Stage::FinishImportWorker, feature
expect(project.import_state.reload).to be_finished
end
context 'when there are no unloaded placeholder references' do
before do
allow_next_instance_of(::Import::PlaceholderReferences::Store) do |store|
allow(store).to receive(:any?).and_return(false)
end
end
it 'does not queue LoadPlaceholderReferencesWorker' do
expect(Import::LoadPlaceholderReferencesWorker).not_to receive(:perform_async)
worker.perform(project.id)
end
it 'does not re-enqueue itself' do
expect(described_class).not_to receive(:perform_in)
worker.perform(project.id)
end
end
context 'when there are unloaded placeholder references' do
before do
allow_next_instance_of(::Import::PlaceholderReferences::Store) do |store|
allow(store).to receive_messages(any?: true, count: 5)
end
end
it 'queues LoadPlaceholderReferencesWorker' do
expect(Import::LoadPlaceholderReferencesWorker).to receive(:perform_async).with(
project.import_type,
project.import_state.id,
{ current_user_id: project.creator.id }
)
worker.perform(project.id)
end
it 'schedules itself to run again after 30 seconds' do
expect(described_class).to receive(:perform_in).with(30.seconds, project.id)
worker.perform(project.id)
end
it 'writes a log entry' do
allow(Gitlab::BitbucketServerImport::Logger).to receive(:info)
expect(Gitlab::BitbucketServerImport::Logger)
.to receive(:info)
.with(
a_hash_including(
message: 'Delaying finalization as placeholder references are pending',
import_stage: 'Gitlab::BitbucketServerImport::Stage::FinishImportWorker',
placeholder_store_count: 5,
project_id: project.id
)
).once
worker.perform(project.id)
end
end
end
end

View File

@ -54,7 +54,7 @@ RSpec.describe Import::LoadPlaceholderReferencesWorker, feature_category: :impor
let_it_be(:project) { create(:project) }
shared_examples 'failed user contribution mapping' do
it 'logs the failure and fails the import status record', :aggregate_failures do
it 'logs the failure and clears the placeholder cache', :aggregate_failures do
exception = StandardError.new('Some error')
expect(::Import::Framework::Logger).to receive(:error).with({
@ -64,9 +64,11 @@ RSpec.describe Import::LoadPlaceholderReferencesWorker, feature_category: :impor
import_uid: uid
})
described_class.sidekiq_retries_exhausted_block.call({ 'args' => [import_source, uid] }, exception)
expect_next_instance_of(Import::PlaceholderReferences::Store) do |store|
expect(store).to receive(:clear!)
end
expect(import_status_record.reload).to be_failed
described_class.sidekiq_retries_exhausted_block.call({ 'args' => [import_source, uid] }, exception)
end
# This case should not happen, but in case it does, there should still be a relevant error log anyway

View File

@ -4017,9 +4017,9 @@ create-hmac@^1.1.4, create-hmac@^1.1.7:
sha.js "^2.4.8"
cross-spawn@^6.0.0:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
version "6.0.6"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.6.tgz#30d0efa0712ddb7eb5a76e1e8721bffafa6b5d57"
integrity sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==
dependencies:
nice-try "^1.0.4"
path-key "^2.0.1"
@ -4028,9 +4028,9 @@ cross-spawn@^6.0.0:
which "^1.2.9"
cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
version "7.0.6"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
dependencies:
path-key "^3.1.0"
shebang-command "^2.0.0"

View File

@ -38,17 +38,20 @@ DETAILS:
**Tier:** Premium, Ultimate
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/172757) in GitLab 17.7, all audit events can be streamed.
Audit event types are used to filter streamed audit events:
- [For instances](../../administration/audit_event_streaming/index.md#update-event-filters).
- [For top-level groups](audit_event_streaming.md#update-event-filters)
Every audit event is associated with an event type. Audit event types can allow audit events to be:
Every audit event is associated with an event type. Audit event types can allow:
- Saved to the database. Available in the Premium and Ultimate tier. You can retrieve audit events associated with these
types by using the audit events dashboard or the [audit events API](../../api/audit_events.md).
- Streamed to external destinations. Available in the Ultimate tier. You can stream audit events associated with these
types to external destinations if a destination is set.
- Most audit events to be saved to the database. Available in the Premium and Ultimate tier. You can retrieve
audit events associated with these types by using the audit events dashboard or the
[audit events API](../../api/audit_events.md).
- All audit events to be streamed to external destinations. Available in the Ultimate tier. You can stream audit events
associated with these types to external destinations if a destination is set.
Some audit event types don't allow saving audit events to the database. Other audit event types don't allow streaming
audit events to external destinations.
@ -65,8 +68,8 @@ Audit event types belong to the following product categories.
### <%= "#{humanize(category)}" %>
| Name | Description | Saved to database | Streamed | Introduced in | Scope |
| Name | Description | Saved to database | Introduced in | Scope |
|:------------|:------------|:------------------|:---------|:--------------|:--------------|
<% audit_event_types.each do |event_type| %>| <%= "[`#{event_type.name}`](#{event_type.introduced_by_mr})" %> | <%= event_type.description %> | <%= boolean_to_docs(event_type.saved_to_database) %> | <%= boolean_to_docs(event_type.streamed) %> | GitLab <%= "[#{event_type.milestone}](#{event_type.introduced_by_issue})" %> | <%= event_type.scope&.join(", ") %> |
<% audit_event_types.each do |event_type| %>| <%= "[`#{event_type.name}`](#{event_type.introduced_by_mr})" %> | <%= event_type.description %> | <%= boolean_to_docs(event_type.saved_to_database) %> | GitLab <%= "[#{event_type.milestone}](#{event_type.introduced_by_issue})" %> | <%= event_type.scope&.join(", ") %> |
<% end %>
<% end %>

View File

@ -5696,9 +5696,9 @@ cross-fetch@^3.0.2:
node-fetch "^2.6.12"
cross-spawn@^6.0.5:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
version "6.0.6"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.6.tgz#30d0efa0712ddb7eb5a76e1e8721bffafa6b5d57"
integrity sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==
dependencies:
nice-try "^1.0.4"
path-key "^2.0.1"