Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-05-22 15:12:03 +00:00
parent 40ac69b43f
commit 98b4d737cd
68 changed files with 1284 additions and 837 deletions

View File

@ -7,7 +7,7 @@ workflow:
include:
- local: .gitlab/ci/version.yml
- local: .gitlab/ci/global.gitlab-ci.yml
- component: "gitlab.com/gitlab-org/quality/pipeline-common/allure-report@9.14.0"
- component: "gitlab.com/gitlab-org/quality/pipeline-common/allure-report@11.3.0"
inputs:
job_name: "e2e-test-report"
job_stage: "report"
@ -17,7 +17,7 @@ include:
gitlab_auth_token_variable_name: "PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE"
allure_job_name: "${QA_RUN_TYPE}"
- project: gitlab-org/quality/pipeline-common
ref: 9.14.0
ref: 11.3.0
file:
- /ci/notify-slack.gitlab-ci.yml
- /ci/qa-report.gitlab-ci.yml

View File

@ -27,8 +27,6 @@ Layout/LineBreakAfterFinalMixin:
- 'ee/app/workers/active_user_count_threshold_worker.rb'
- 'ee/app/workers/analytics/value_stream_dashboard/count_worker.rb'
- 'ee/app/workers/arkose/blocked_users_report_worker.rb'
- 'ee/app/workers/geo/metrics_update_worker.rb'
- 'ee/app/workers/geo/sidekiq_cron_config_worker.rb'
- 'ee/app/workers/gitlab_subscriptions/notify_seats_exceeded_batch_worker.rb'
- 'ee/app/workers/historical_data_worker.rb'
- 'ee/app/workers/ldap_all_groups_sync_worker.rb'

View File

@ -262,7 +262,7 @@ gem 'asciidoctor-kroki', '~> 0.10.0', require: false, feature_category: :markdow
gem 'rouge', '~> 4.5.0', feature_category: :shared
gem 'truncato', '~> 0.7.13', feature_category: :team_planning
gem 'nokogiri', '~> 1.18', feature_category: :shared
gem 'gitlab-glfm-markdown', '~> 0.0.30', feature_category: :markdown
gem 'gitlab-glfm-markdown', '~> 0.0.31', feature_category: :markdown
gem 'tanuki_emoji', '~> 0.13', feature_category: :markdown
gem 'unicode-emoji', '~> 4.0', feature_category: :markdown

View File

@ -223,13 +223,13 @@
{"name":"gitlab-dangerfiles","version":"4.9.1","platform":"ruby","checksum":"296b19d8aca5e4da8d391234914a1c4dfedc29700ddbcd9c554b6ffaa7fdf1b2"},
{"name":"gitlab-experiment","version":"0.9.1","platform":"ruby","checksum":"f230ee742154805a755d5f2539dc44d93cdff08c5bbbb7656018d61f93d01f48"},
{"name":"gitlab-fog-azure-rm","version":"2.2.0","platform":"ruby","checksum":"31aa7c2170f57874053144e7f716ec9e15f32e71ffbd2c56753dce46e2e78ba9"},
{"name":"gitlab-glfm-markdown","version":"0.0.30","platform":"aarch64-linux-gnu","checksum":"faaa675d3934a066b0374a5ba4a1d97ec228195656814d5eb51c5db2356acad8"},
{"name":"gitlab-glfm-markdown","version":"0.0.30","platform":"aarch64-linux-musl","checksum":"06407c9ce6753b6e6219302c875e0d981c15bdcc98a2df4f064771e5e40859da"},
{"name":"gitlab-glfm-markdown","version":"0.0.30","platform":"arm64-darwin","checksum":"788065d211288ff60cf3c5d875f678678cf03824d79b5e2d269aaa83c5c4f411"},
{"name":"gitlab-glfm-markdown","version":"0.0.30","platform":"ruby","checksum":"f3dea33f9fc6d8991fd496631ef36b6e2406392e378d879f320c4c1b645c0066"},
{"name":"gitlab-glfm-markdown","version":"0.0.30","platform":"x86_64-darwin","checksum":"583057ac3223900759a2bbc0f7dfe11befba74127217f883cd8ed2de2b7e2251"},
{"name":"gitlab-glfm-markdown","version":"0.0.30","platform":"x86_64-linux-gnu","checksum":"d43b185f48577fbe850fa49a5ff28ce2d875a4dd23b1c5333fae2ef4c40bea40"},
{"name":"gitlab-glfm-markdown","version":"0.0.30","platform":"x86_64-linux-musl","checksum":"50ac59a1f9545387773fe0daa389ae146c73beb1acff4093011c2a9a1889879a"},
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"aarch64-linux-gnu","checksum":"21bd0d9bccaeb1fc9787bbe8b4cabc30688d6800ae2212b7972c9438f0b40f59"},
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"aarch64-linux-musl","checksum":"87b3b500dbab5dd003eff79d2909e8b23eb839fbfb49ab342cd173d6b9adb16d"},
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"arm64-darwin","checksum":"4f452db9f540ea1af0672042fe046b2b883d897f1325394894376da4e7acc1e8"},
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"ruby","checksum":"91c8e9c61c78d49f1e52dbb49e9fd2d790a494a254bc8ad54004dadf091e2d1b"},
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"x86_64-darwin","checksum":"3d9df3278add66356ce07c983b74f6f0bdefcdfb4110f43dd291c43fb69eb6a6"},
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"x86_64-linux-gnu","checksum":"c2c4c8f77d078f2afb1420289e32f444e91ece48d8f76a78e43f5b69f5d2248c"},
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"x86_64-linux-musl","checksum":"cc3e8529f8eaf6be9bfa71509a58396540bb7c2b025e5dd9615a73ad0cf2a6b3"},
{"name":"gitlab-kas-grpc","version":"17.11.2","platform":"ruby","checksum":"f2b9054dcf636346e89549e9478a684a38bf03bf853332e84154ec3a9856ae1c"},
{"name":"gitlab-labkit","version":"0.37.0","platform":"ruby","checksum":"d2dd0a60db2149a9a8eebf2975dc23f54ac3ceb01bdba732eb1b26b86dfffa70"},
{"name":"gitlab-license","version":"2.6.0","platform":"ruby","checksum":"2c1f8ae73835640ec77bf758c1d0c9730635043c01cf77902f7976e826d7d016"},

View File

@ -766,7 +766,7 @@ GEM
mime-types
net-http-persistent (~> 4.0)
nokogiri (~> 1, >= 1.10.8)
gitlab-glfm-markdown (0.0.30)
gitlab-glfm-markdown (0.0.31)
rb_sys (~> 0.9.109)
gitlab-kas-grpc (17.11.2)
grpc (~> 1.0)
@ -2163,7 +2163,7 @@ DEPENDENCIES
gitlab-duo-workflow-service-client (~> 0.1)!
gitlab-experiment (~> 0.9.1)
gitlab-fog-azure-rm (~> 2.2.0)
gitlab-glfm-markdown (~> 0.0.30)
gitlab-glfm-markdown (~> 0.0.31)
gitlab-housekeeper!
gitlab-http!
gitlab-kas-grpc (~> 17.11.0)

View File

@ -223,13 +223,13 @@
{"name":"gitlab-dangerfiles","version":"4.9.1","platform":"ruby","checksum":"296b19d8aca5e4da8d391234914a1c4dfedc29700ddbcd9c554b6ffaa7fdf1b2"},
{"name":"gitlab-experiment","version":"0.9.1","platform":"ruby","checksum":"f230ee742154805a755d5f2539dc44d93cdff08c5bbbb7656018d61f93d01f48"},
{"name":"gitlab-fog-azure-rm","version":"2.2.0","platform":"ruby","checksum":"31aa7c2170f57874053144e7f716ec9e15f32e71ffbd2c56753dce46e2e78ba9"},
{"name":"gitlab-glfm-markdown","version":"0.0.30","platform":"aarch64-linux-gnu","checksum":"faaa675d3934a066b0374a5ba4a1d97ec228195656814d5eb51c5db2356acad8"},
{"name":"gitlab-glfm-markdown","version":"0.0.30","platform":"aarch64-linux-musl","checksum":"06407c9ce6753b6e6219302c875e0d981c15bdcc98a2df4f064771e5e40859da"},
{"name":"gitlab-glfm-markdown","version":"0.0.30","platform":"arm64-darwin","checksum":"788065d211288ff60cf3c5d875f678678cf03824d79b5e2d269aaa83c5c4f411"},
{"name":"gitlab-glfm-markdown","version":"0.0.30","platform":"ruby","checksum":"f3dea33f9fc6d8991fd496631ef36b6e2406392e378d879f320c4c1b645c0066"},
{"name":"gitlab-glfm-markdown","version":"0.0.30","platform":"x86_64-darwin","checksum":"583057ac3223900759a2bbc0f7dfe11befba74127217f883cd8ed2de2b7e2251"},
{"name":"gitlab-glfm-markdown","version":"0.0.30","platform":"x86_64-linux-gnu","checksum":"d43b185f48577fbe850fa49a5ff28ce2d875a4dd23b1c5333fae2ef4c40bea40"},
{"name":"gitlab-glfm-markdown","version":"0.0.30","platform":"x86_64-linux-musl","checksum":"50ac59a1f9545387773fe0daa389ae146c73beb1acff4093011c2a9a1889879a"},
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"aarch64-linux-gnu","checksum":"21bd0d9bccaeb1fc9787bbe8b4cabc30688d6800ae2212b7972c9438f0b40f59"},
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"aarch64-linux-musl","checksum":"87b3b500dbab5dd003eff79d2909e8b23eb839fbfb49ab342cd173d6b9adb16d"},
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"arm64-darwin","checksum":"4f452db9f540ea1af0672042fe046b2b883d897f1325394894376da4e7acc1e8"},
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"ruby","checksum":"91c8e9c61c78d49f1e52dbb49e9fd2d790a494a254bc8ad54004dadf091e2d1b"},
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"x86_64-darwin","checksum":"3d9df3278add66356ce07c983b74f6f0bdefcdfb4110f43dd291c43fb69eb6a6"},
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"x86_64-linux-gnu","checksum":"c2c4c8f77d078f2afb1420289e32f444e91ece48d8f76a78e43f5b69f5d2248c"},
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"x86_64-linux-musl","checksum":"cc3e8529f8eaf6be9bfa71509a58396540bb7c2b025e5dd9615a73ad0cf2a6b3"},
{"name":"gitlab-kas-grpc","version":"17.11.2","platform":"ruby","checksum":"f2b9054dcf636346e89549e9478a684a38bf03bf853332e84154ec3a9856ae1c"},
{"name":"gitlab-labkit","version":"0.37.0","platform":"ruby","checksum":"d2dd0a60db2149a9a8eebf2975dc23f54ac3ceb01bdba732eb1b26b86dfffa70"},
{"name":"gitlab-license","version":"2.6.0","platform":"ruby","checksum":"2c1f8ae73835640ec77bf758c1d0c9730635043c01cf77902f7976e826d7d016"},

View File

@ -766,7 +766,7 @@ GEM
mime-types
net-http-persistent (~> 4.0)
nokogiri (~> 1, >= 1.10.8)
gitlab-glfm-markdown (0.0.30)
gitlab-glfm-markdown (0.0.31)
rb_sys (~> 0.9.109)
gitlab-kas-grpc (17.11.2)
grpc (~> 1.0)
@ -2163,7 +2163,7 @@ DEPENDENCIES
gitlab-duo-workflow-service-client (~> 0.1)!
gitlab-experiment (~> 0.9.1)
gitlab-fog-azure-rm (~> 2.2.0)
gitlab-glfm-markdown (~> 0.0.30)
gitlab-glfm-markdown (~> 0.0.31)
gitlab-housekeeper!
gitlab-http!
gitlab-kas-grpc (~> 17.11.0)

View File

@ -1,3 +1,7 @@
# @graphql-eslint/eslint-plugin@4.0.0 reports missing IDs in `FragmentDefinition`. For now, we are
# ignoring the newly uncovered error on this fragment. Please consider addressing the violation
# if you are modifying this file and it turns out selecting the ID makes sense here.
# eslint-disable-next-line @graphql-eslint/require-selections
fragment BaseCiGroupVariable on CiGroupVariable {
description
environmentScope

View File

@ -1,3 +1,7 @@
# @graphql-eslint/eslint-plugin@4.0.0 reports missing IDs in `FragmentDefinition`. For now, we are
# ignoring the newly uncovered error on this fragment. Please consider addressing the violation
# if you are modifying this file and it turns out selecting the ID makes sense here.
# eslint-disable-next-line @graphql-eslint/require-selections
fragment BaseCiInstanceVariable on CiInstanceVariable {
description
protected

View File

@ -1,3 +1,7 @@
# @graphql-eslint/eslint-plugin@4.0.0 reports missing IDs in `FragmentDefinition`. For now, we are
# ignoring the newly uncovered error on this fragment. Please consider addressing the violation
# if you are modifying this file and it turns out selecting the ID makes sense here.
# eslint-disable-next-line @graphql-eslint/require-selections
fragment BaseCiProjectVariable on CiProjectVariable {
description
environmentScope

View File

@ -27,7 +27,7 @@ query getJobs(
}
nodes {
artifacts {
# eslint-disable-next-line @graphql-eslint/require-id-when-available
# eslint-disable-next-line @graphql-eslint/require-selections
nodes {
downloadPath
fileType

View File

@ -11,7 +11,7 @@ query getPipelineJobs($fullPath: ID!, $iid: ID!, $after: String) {
}
nodes {
artifacts {
# eslint-disable-next-line @graphql-eslint/require-id-when-available
# eslint-disable-next-line @graphql-eslint/require-selections
nodes {
downloadPath
fileType

View File

@ -1,5 +1,9 @@
#import "./list_item_shared.fragment.graphql"
fragment ListItem on CiRunner {
# @graphql-eslint/eslint-plugin@4.0.0 reports missing IDs in `FragmentDefinition`. For now, we are
# ignoring the newly uncovered error on this fragment. Please consider addressing the violation
# if you are modifying this file and it turns out selecting the ID makes sense here.
# eslint-disable-next-line @graphql-eslint/require-selections
...ListItemShared
}

View File

@ -21,6 +21,10 @@ fragment ListItemShared on CiRunner {
}
managers(first: 1) {
count
# @graphql-eslint/eslint-plugin@4.0.0 reports missing IDs in `FragmentDefinition`. For now, we are
# ignoring the newly uncovered error on this fragment. Please consider addressing the violation
# if you are modifying this file and it turns out selecting the ID makes sense here.
# eslint-disable-next-line @graphql-eslint/require-selections
nodes {
version
ipAddress

View File

@ -1,3 +1,7 @@
# @graphql-eslint/eslint-plugin@4.0.0 reports missing IDs in `FragmentDefinition`. For now, we are
# ignoring the newly uncovered error on this fragment. Please consider addressing the violation
# if you are modifying this file and it turns out selecting the ID makes sense here.
# eslint-disable-next-line @graphql-eslint/require-selections
fragment ApprovalSummary on Deployment {
iid
}

View File

@ -1,3 +1,7 @@
# @graphql-eslint/eslint-plugin@4.0.0 reports missing IDs in `FragmentDefinition`. For now, we are
# ignoring the newly uncovered error on this fragment. Please consider addressing the violation
# if you are modifying this file and it turns out selecting the ID makes sense here.
# eslint-disable-next-line @graphql-eslint/require-selections
fragment UserAvailability on User {
status {
availability

View File

@ -1,3 +1,7 @@
# @graphql-eslint/eslint-plugin@4.0.0 reports missing IDs in `FragmentDefinition`. For now, we are
# ignoring the newly uncovered error on this fragment. Please consider addressing the violation
# if you are modifying this file and it turns out selecting the ID makes sense here.
# eslint-disable-next-line @graphql-eslint/require-selections
fragment IncidentFields on Issue {
severity
escalationStatus

View File

@ -1,3 +1,7 @@
# @graphql-eslint/eslint-plugin@4.0.0 reports missing IDs in `FragmentDefinition`. For now, we are
# ignoring the newly uncovered error on this fragment. Please consider addressing the violation
# if you are modifying this file and it turns out selecting the ID makes sense here.
# eslint-disable-next-line @graphql-eslint/require-selections
fragment MergeRequestApprovalFragment on MergeRequest {
approved
approvedBy {

View File

@ -14,7 +14,7 @@ query securityReportsDownloadPaths(
id
name
artifacts {
# eslint-disable-next-line @graphql-eslint/require-id-when-available
# eslint-disable-next-line @graphql-eslint/require-selections
nodes {
downloadPath
fileType

View File

@ -5,6 +5,10 @@ fragment JobArtifacts on Pipeline {
id
name
artifacts {
# @graphql-eslint/eslint-plugin@4.0.0 reports missing IDs in `FragmentDefinition`. For now, we are
# ignoring the newly uncovered error on this fragment. Please consider addressing the violation
# if you are modifying this file and it turns out selecting the ID makes sense here.
# eslint-disable-next-line @graphql-eslint/require-selections
nodes {
downloadPath
fileType

View File

@ -14,7 +14,7 @@ query securityReportDownloadPaths(
id
name
artifacts {
# eslint-disable-next-line @graphql-eslint/require-id-when-available
# eslint-disable-next-line @graphql-eslint/require-selections
nodes {
downloadPath
fileType

View File

@ -4,7 +4,7 @@ query getPipelineCorpuses($projectPath: ID!, $iid: ID, $reportTypes: [SecurityRe
project(fullPath: $projectPath) {
id
pipeline(iid: $iid) {
# eslint-disable-next-line @graphql-eslint/require-id-when-available
# eslint-disable-next-line @graphql-eslint/require-selections
...JobArtifacts
}
}

View File

@ -1,6 +1,10 @@
#import "ee_else_ce/work_items/graphql/work_item_metadata_widgets.fragment.graphql"
#import "ee_else_ce/work_items/graphql/work_item_metadata_widgets_extras.fragment.graphql"
# @graphql-eslint/eslint-plugin@4.0.0 reports missing IDs in `FragmentDefinition`. For now, we are
# ignoring the newly uncovered error on this fragment. Please consider addressing the violation
# if you are modifying this file and it turns out selecting the ID makes sense here.
# eslint-disable-next-line @graphql-eslint/require-selections
fragment WorkItemLinkedItemsFragment on WorkItem {
widgets {
... on WorkItemWidgetLinkedItems {

View File

@ -9,6 +9,10 @@ fragment WorkItemWidgets on WorkItemWidget {
description
descriptionHtml
lastEditedAt
# @graphql-eslint/eslint-plugin@4.0.0 reports missing IDs in `FragmentDefinition`. For now, we are
# ignoring the newly uncovered error on this fragment. Please consider addressing the violation
# if you are modifying this file and it turns out selecting the ID makes sense here.
# eslint-disable-next-line @graphql-eslint/require-selections
lastEditedBy {
name
webPath

View File

@ -16,6 +16,7 @@ module Mutations
type: GraphQL::Types::ID,
required: true,
description: 'Full path of the namespace on which the preference is set.'
argument :work_item_type_id,
type: ::Types::GlobalIDType[::WorkItems::Type],
required: false,
@ -27,6 +28,11 @@ module Mutations
required: false,
default_value: :created_asc
argument :display_settings,
type: GraphQL::Types::JSON,
description: 'Display settings for the work item lists.',
required: false
field :user_preferences,
type: ::Types::WorkItems::UserPreference,
description: 'User preferences.'

View File

@ -23,6 +23,10 @@ fragment LinkedPipelineData on Pipeline {
userPermissions {
updatePipeline
}
# @graphql-eslint/eslint-plugin@4.0.0 reports missing IDs in `FragmentDefinition`. For now, we are
# ignoring the newly uncovered error on this fragment. Please consider addressing the violation
# if you are modifying this file and it turns out selecting the ID makes sense here.
# eslint-disable-next-line @graphql-eslint/require-selections
status: detailedStatus {
__typename
group
@ -59,13 +63,13 @@ query getPipelineDetails($projectPath: ID!, $iid: ID!) {
downstream {
__typename
nodes {
# eslint-disable-next-line @graphql-eslint/require-id-when-available -- for detailedStatus.id
# eslint-disable-next-line @graphql-eslint/require-selections -- for detailedStatus.id
...LinkedPipelineData
name
}
}
upstream {
# eslint-disable-next-line @graphql-eslint/require-id-when-available -- for detailedStatus.id
# eslint-disable-next-line @graphql-eslint/require-selections -- for detailedStatus.id
...LinkedPipelineData
}
stages {
@ -74,7 +78,7 @@ query getPipelineDetails($projectPath: ID!, $iid: ID!) {
__typename
id
name
# eslint-disable-next-line @graphql-eslint/require-id-when-available
# eslint-disable-next-line @graphql-eslint/require-selections
status: detailedStatus {
__typename
action {
@ -91,7 +95,7 @@ query getPipelineDetails($projectPath: ID!, $iid: ID!) {
nodes {
__typename
id
# eslint-disable-next-line @graphql-eslint/require-id-when-available
# eslint-disable-next-line @graphql-eslint/require-selections
status: detailedStatus {
__typename
label
@ -122,7 +126,7 @@ query getPipelineDetails($projectPath: ID!, $iid: ID!) {
...CiNeeds
}
}
# eslint-disable-next-line @graphql-eslint/require-id-when-available
# eslint-disable-next-line @graphql-eslint/require-selections
status: detailedStatus {
__typename
icon

View File

@ -22,6 +22,11 @@ module Types
null: true,
description: 'Sort order for work item lists.'
field :display_settings,
type: GraphQL::Types::JSON,
null: true,
description: 'Display settings for the work item lists.'
def sort
object.sort&.to_sym
end

View File

@ -63,6 +63,10 @@ module Approvable
def eligible_for_unapproval_by?(user)
user && approved_by?(user) && user.can?(:approve_merge_request, self)
end
def approvals_for_user_ids(user_ids)
approvals.where(user_id: user_ids)
end
end
Approvable.prepend_mod

View File

@ -89,6 +89,7 @@ module MergeRequests
merge_request_activity_counter.track_reviewers_changed_action(user: current_user)
trigger_merge_request_reviewers_updated(merge_request)
set_reviewers_approved(merge_request, new_reviewers) if new_reviewers.any?
set_first_reviewer_assigned_at_metrics(merge_request) if new_reviewers.any?
trigger_user_merge_request_updated(merge_request)
end
@ -218,6 +219,13 @@ module MergeRequests
# Implemented in EE
end
def set_reviewers_approved(merge_request, new_reviewers)
approval_users = merge_request.approvals_for_user_ids(new_reviewers.map(&:id))
merge_request.merge_request_reviewers_with(approval_users.select(:user_id))
.update_all(state: :approved)
end
def merge_request_metrics_service(merge_request)
MergeRequestMetricsService.new(merge_request.metrics)
end

View File

@ -1,13 +1,16 @@
- if @project.pages_deployed?
- if can?(current_user, :remove_pages, @project)
.gl-bg-red-50.gl-shadow-inner-l-3-red-600.gl-py-5.gl-px-6.gl-mt-5
%h4.gl-text-lg.gl-mt-0= s_('GitLabPages|Remove pages')
%p= s_('GitLabPages|Removing pages will prevent them from being exposed to the public internet.')
= render Pajamas::ButtonComponent.new(href: project_pages_path(@project),
variant: :danger,
method: :delete,
button_options: { data: { confirm: s_('GitLabPages|Are you sure?'), 'confirm-btn-variant': 'danger' }, "aria-label": s_('GitLabPages|Remove pages') }) do
= s_('GitLabPages|Remove pages')
- else
.nothing-here-block
= s_('GitLabPages|Only project maintainers can remove pages')
= render ::Layouts::CrudComponent.new(s_('GitLabPages|Delete Pages'),
options: { class: 'gl-mt-5' },
body_options: { class: '!gl-m-0 gl-p-5 gl-bg-feedback-danger' }) do |c|
- c.with_body do
- if can?(current_user, :remove_pages, @project)
%p
= s_('GitLabPages|This action will permanently delete all Pages deployments.')
= s_('GitLabPages|This is permanent and cannot be undone. To deploy this Pages site again, run a new pipeline.')
= render Pajamas::ButtonComponent.new(href: project_pages_path(@project),
variant: :danger,
method: :delete,
button_options: { data: { confirm: s_('GitLabPages|Are you sure?'), 'confirm-btn-variant': 'danger' }, "aria-label": s_('GitLabPages|Remove pages') }) do
= s_('GitLabPages|Delete Pages')
- else
= s_('GitLabPages|Only project maintainers can remove pages.')

View File

@ -5,5 +5,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/178281
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/514208
milestone: '17.11'
group: group::source code
type: gitlab_com_derisk
default_enabled: false
type: beta
default_enabled: true

View File

@ -1119,8 +1119,8 @@ Settings.cell['enabled'] ||= false # All Cells Features are disabled by default
Settings.cell['id'] ||= nil
Settings.cell['database'] ||= {}
Settings.cell.database['skip_sequence_alteration'] ||= false
# Topology Service Client Settings
# NOTE: `topology_service_client` is the configuration to use going forward as per https://docs.gitlab.com/administration/cells/#configuration
# We continue to be backwards compatible and support `topology_service` as a top-level key.
Settings.cell['topology_service_client'] ||= Settings.respond_to?(:topology_service) ? Settings.topology_service || {} : {}
Settings.cell.topology_service_client['address'] ||= 'topology-service.gitlab.example.com:443'
Settings.cell.topology_service_client['ca_file'] ||= '/home/git/gitlab/config/topology-service-ca.pem'

View File

@ -20,7 +20,7 @@ if Gitlab.config.cell.enabled
Settings.required_topology_service_settings.each do |setting|
setting_value = Gitlab.config.cell.topology_service_client.send(setting)
print_error.call("Topology Service setting '#{setting}' is not set.") if setting_value.blank?
print_error.call("Topology Service Client setting '#{setting}' is not set.") if setting_value.blank?
end
elsif Gitlab.config.cell.id.present?
print_error.call("Cell ID is set but Cell is not enabled.")

View File

@ -0,0 +1,18 @@
---
key_path: counts.total_top_level_groups
description: Counts the number of top-level groups on the instance
product_group: organizations
product_categories:
- groups_and_projects
value_type: number
status: active
milestone: "18.1"
instrumentation_class: CountTopLevelGroupsMetric
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/190217
time_frame: all
data_source: database
data_category: optional
tiers:
- free
- premium
- ultimate

View File

@ -1,8 +1,9 @@
---
migration_job_name: BackfillStatusPagePublishedIncidentsNamespaceId
description: Backfills sharding key `status_page_published_incidents.namespace_id` from `issues`.
description: Backfills sharding key `status_page_published_incidents.namespace_id`
from `issues`.
feature_category: incident_management
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/174868
milestone: '17.7'
queued_migration_version: 20241205143060
finalized_by: # version of the migration that finalized this BBM
finalized_by: '20250521232727'

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class FinalizeHkBackfillStatusPagePublishedIncidentsNamespaceId < Gitlab::Database::Migration[2.3]
milestone '18.1'
disable_ddl_transaction!
restrict_gitlab_migration gitlab_schema: :gitlab_main_cell
def up
ensure_batched_background_migration_is_finished(
job_class_name: 'BackfillStatusPagePublishedIncidentsNamespaceId',
table_name: :status_page_published_incidents,
column_name: :id,
job_arguments: [:namespace_id, :issues, :namespace_id, :issue_id],
finalize: true
)
end
def down; end
end

View File

@ -0,0 +1 @@
790cec3f4a91a1db687211c1c6013683339e66d39ceb32fd486015b00069b294

View File

@ -13001,6 +13001,7 @@ Input type: `WorkItemUserPreferenceUpdateInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationworkitemuserpreferenceupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationworkitemuserpreferenceupdatedisplaysettings"></a>`displaySettings` | [`JSON`](#json) | Display settings for the work item lists. |
| <a id="mutationworkitemuserpreferenceupdatenamespacepath"></a>`namespacePath` | [`ID!`](#id) | Full path of the namespace on which the preference is set. |
| <a id="mutationworkitemuserpreferenceupdatesort"></a>`sort` | [`WorkItemSort`](#workitemsort) | Sort order for work item lists. |
| <a id="mutationworkitemuserpreferenceupdateworkitemtypeid"></a>`workItemTypeId` | [`WorkItemsTypeID`](#workitemstypeid) | Global ID of a work item type. |
@ -21551,6 +21552,7 @@ Counts for each analyzer status in the group and subgroups.
| <a id="analyzergroupstatustypefailure"></a>`failure` | [`Int!`](#int) | Number of analyzers failed. |
| <a id="analyzergroupstatustypenamespaceid"></a>`namespaceId` | [`Int!`](#int) | Namespace ID. |
| <a id="analyzergroupstatustypesuccess"></a>`success` | [`Int!`](#int) | Number of analyzers succeeded. |
| <a id="analyzergroupstatustypeupdatedat"></a>`updatedAt` | [`ISO8601DateTime!`](#iso8601datetime) | Timestamp of when the status was last updated. |
### `AnalyzerProjectStatusType`
@ -21565,6 +21567,7 @@ Analyzer status (success/fail) for projects.
| <a id="analyzerprojectstatustypelastcall"></a>`lastCall` | [`Time!`](#time) | Last time analyzer was called. |
| <a id="analyzerprojectstatustypeprojectid"></a>`projectId` | [`Int!`](#int) | Project ID. |
| <a id="analyzerprojectstatustypestatus"></a>`status` | [`AnalyzerStatusEnum!`](#analyzerstatusenum) | Analyzer status. |
| <a id="analyzerprojectstatustypeupdatedat"></a>`updatedAt` | [`ISO8601DateTime!`](#iso8601datetime) | Timestamp of when the status was last updated. |
### `AncestorType`
@ -42070,6 +42073,7 @@ Represents Depth limit reached for the allowed work item type.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="workitemtypesuserpreferencedisplaysettings"></a>`displaySettings` | [`JSON`](#json) | Display settings for the work item lists. |
| <a id="workitemtypesuserpreferencenamespace"></a>`namespace` | [`Namespace!`](#namespace) | Namespace for the user preference. |
| <a id="workitemtypesuserpreferencesort"></a>`sort` | [`WorkItemSort`](#workitemsort) | Sort order for work item lists. |
| <a id="workitemtypesuserpreferenceworkitemtype"></a>`workItemType` | [`WorkItemType`](#workitemtype) | Type assigned to the work item. |

View File

@ -839,10 +839,11 @@ space by truncating tables. This results in a smaller data set: For example,
the data in `users` table on CI database is no longer read and also no
longer updated. So this data can be removed by truncating the tables.
For this purpose, GitLab provides two Rake tasks, one for each database:
For this purpose, GitLab provides separate Rake tasks, one for each database:
- `gitlab:db:truncate_legacy_tables:main` will truncate the CI tables in Main database.
- `gitlab:db:truncate_legacy_tables:ci` will truncate the Main tables in CI database.
- `gitlab:db:truncate_legacy_tables:main` will truncate the legacy tables in Main database.
- `gitlab:db:truncate_legacy_tables:ci` will truncate the legacy tables in CI database.
- `gitlab:db:truncate_legacy_tables:sec` will truncate the legacy tables in Sec database.
{{< alert type="note" >}}

View File

@ -21,8 +21,9 @@ title: AI impact analytics
{{< /history >}}
The primary goal of AI impact analytics is to measure GitLab Duo's impact on software development lifecycle (SDLC) performance.
This dashboard provides visibility into key SDLC metrics in the context of AI adoption, helping you measure which metrics have improved as a result of AI investments.
AI impact analytics measure the impact of GitLab Duo on software development lifecycle (SDLC) performance.
This dashboard provides visibility into key SDLC metrics in the context of AI adoption for projects or groups.
You can use the dashboard to measure which metrics have improved from your AI investments.
Use AI impact analytics for:
@ -32,30 +33,32 @@ Use AI impact analytics for:
To learn how you can optimize your license utilization,
see [GitLab Duo add-ons](../../subscriptions/subscription-add-ons.md).
To learn more about AI impact analytics, see the blog post
[Developing GitLab Duo: AI impact analytics dashboard measures the ROI of AI](https://about.gitlab.com/blog/2024/05/15/developing-gitlab-duo-ai-impact-analytics-dashboard-measures-the-roi-of-ai/).
For a click-through demo, see the [AI impact analytics product tour](https://gitlab.navattic.com/ai-impact).
<i class="fa-youtube-play" aria-hidden="true"></i>
For an overview, see [GitLab Duo AI Impact Dashboard](https://youtu.be/FxSWX64aUOE?si=7Yfc6xHm63c3BRwn).
<!-- Video published on 2025-03-06 -->
## AI impact metrics
AI impact analytics displays key metrics and metric trends for a project or group.
### Key metrics
## Key metrics
- **Duo seats: Assigned and used**: Percentage of users that are assigned a Duo seat and used at least one AI feature in the last 30 days.
It is calculated as the number of users with Duo seats that use AI features divided by the total number of assigned Duo seats.
- **Code Suggestions: Unique users**: Percentage of users that engage with Code Suggestions every month. It is calculated as the number of monthly unique Code Suggestions users divided by total monthly [unique contributors](../profile/contributions_calendar.md#user-contribution-events). Only unique code contributors, meaning users with `pushed` events, are included in the calculation.
- **Code Suggestions: Unique users**: Percentage of users that engage with Code Suggestions every month.
It is calculated as the number of monthly unique Code Suggestions users divided by total monthly [unique contributors](../profile/contributions_calendar.md#user-contribution-events).
Only unique code contributors (users with `pushed` events) are included in the calculation.
- **Code Suggestions: Acceptance rate**: Percentage of code suggestions provided by GitLab Duo that have been accepted by code contributors in the last 30 days.
It is calculated as the number of accepted code suggestions divided by the total number of generated code suggestions.
- **Duo Chat: Unique users**: Percentage of users that engage with GitLab Duo Chat every month. It is calculated as the number of monthly unique GitLab Duo Chat users divided by the total GitLab Duo assigned users.
- **Duo Chat: Unique users**: Percentage of users that engage with GitLab Duo Chat every month.
It is calculated as the number of monthly unique GitLab Duo Chat users divided by the total GitLab Duo assigned users.
### Metric trends
## Metric trends
The **Metric trends** table displays metrics for the last six months, with monthly values, percentage changes in the past six months, and trend sparklines.
#### Lifecycle metrics
### Lifecycle metrics
- [**Cycle time**](../group/value_stream_analytics/_index.md#lifecycle-metrics)
- [**Lead time**](../group/value_stream_analytics/_index.md#lifecycle-metrics)
@ -63,13 +66,19 @@ The **Metric trends** table displays metrics for the last six months, with month
- [**Change failure rate**](dora_metrics.md#change-failure-rate)
- [**Critical vulnerabilities over time**](../application_security/vulnerability_report/_index.md)
#### AI usage metrics
### AI usage metrics
**Code Suggestions usage**: Monthly user engagement with AI Code Suggestions.
- The month-over-month comparison of the AI Usage unique users rate gives a more accurate indication of this metric, as it eliminates factors such as developer experience level and project type or complexity.
- The baseline for the AI Usage trend is the total number of code contributors, not just users with GitLab Duo seats. This baseline gives a more accurate representation of AI usage by team members. To learn more about AI impact analytics, see the blog post [Developing GitLab Duo: AI impact analytics dashboard measures the ROI of AI](https://about.gitlab.com/blog/2024/05/15/developing-gitlab-duo-ai-impact-analytics-dashboard-measures-the-roi-of-ai/).
- To analyze the performance of teams that use AI versus teams that don't, you can create a custom [Value Streams Dashboard Scheduled Report](https://gitlab.com/explore/catalog/components/vsd-reports-generator) based on the AI impact view of projects and groups with and without GitLab Duo.
The month-over-month comparison of the AI Usage unique users rate gives a more accurate indication of this metric,
because it eliminates factors such as developer experience level and project type or complexity.
The baseline for the AI Usage trend is the total number of code contributors, not just users with GitLab Duo seats.
This baseline gives a more accurate representation of AI usage by team members.
To analyze the performance of teams that use AI versus teams that don't, you can create a custom
[Value Streams Dashboard Scheduled Report](https://gitlab.com/explore/catalog/components/vsd-reports-generator)
based on the AI impact view of projects and groups with and without GitLab Duo.
{{< alert type="note" >}}

View File

@ -129,7 +129,7 @@ You can filter by:
- **Report Type**: For more details, see [Report Type filter](#report-type-filter)
- **Scanner**: For more details, see [Scanner filter](#scanner-filter)
- **Activity**: For more details, see [Activity filter](#activity-filter).
- **Identifier**: Filter by the vulnerability's identifier (available only for projects, support for groups is proposed in [issue 508713](https://gitlab.com/gitlab-org/gitlab/-/issues/508713)).
- **Identifier**: Filter by the vulnerability's identifier (requires [advanced vulnerability management](#advanced-vulnerability-management). Without advanced vulnerability management, availability is restricted to projects and groups with a maximum of 20,000 vulnerabilities).
- **Project**: Filter vulnerabilities in specific projects (available only for groups).
<!-- vale gitlab_base.SubstitutionWarning = YES -->
@ -244,6 +244,7 @@ The **GitLab Duo (AI)** filter is available when:
- Non-OWASP category in OWASP top 10 grouping [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/442526) in GitLab 17.1 [with a flag](../../../administration/feature_flags.md) named `owasp_top_10_null_filtering`. Disabled by default.
- Non-OWASP category in OWASP top 10 grouping [enabled on GitLab Self-Managed, and GitLab Dedicated](https://gitlab.com/gitlab-org/gitlab/-/issues/463783) in GitLab 17.5.
- Non-OWASP category in OWASP top 10 grouping [generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/463783) in GitLab 17.6. Feature flag `owasp_top_10_null_filtering` removed.
- OWASP 2021 top 10 grouping [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/466034) on GitLab.com and GitLab Dedicated in GitLab 18.1 [with a flag](../../../administration/feature_flags.md) named `vulnerability_report_owasp_2021`. Disabled by default. Feature also requires [advanced vulnerability management](#advanced-vulnerability-management).
{{< /history >}}
@ -256,6 +257,7 @@ You can group by:
- Report Type
- Scanner
- OWASP top 10 2017
- OWASP top 10 2021 (requires [advanced vulnerability management](#advanced-vulnerability-management))
### Group vulnerabilities
@ -530,6 +532,38 @@ To add a vulnerability manually:
The newly-created vulnerability's detail page is opened.
## Advanced vulnerability management
{{< history >}}
- Ingestion of vulnerability data into advanced search [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/536299) in GitLab 18.1 [with a flag](../../../administration/feature_flags.md) named `vulnerability_es_ingestion`. Available in GitLab.com and GitLab Dedicated. Disabled by default.
- Filters for OWASP 2021 grouping and identifiers in advanced search [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/537673) with the feature flag `advanced_vulnerability_management`. Available in GitLab.com and GitLab Dedicated. Disabled by default.
{{< /history >}}
{{< alert type="flag" >}}
Advanced vulnerability management is controlled by feature flags.
For more information, see the history.
{{< /alert >}}
GitLab primarily uses PostgreSQL for filtering in the vulnerability report. Due to database indexing limitations and performance challenges when applying multiple filters, GitLab uses [advanced search](../../search/advanced_search.md) for specific vulnerability management features.
Advanced search powers the following features:
1. Grouping data by OWASP 2021 categories in the vulnerability report for a project or group.
1. Filtering based on a vulnerability's identifier in the vulnerability report for a project or group.
Advanced search is used only for these specific features, including when they are combined with other [filters](#filter-vulnerabilities). Other filters, when used independently, continue to use the standard PostgreSQL filtering.
### Requirements
To use the filters in advanced vulnerability management:
- You must use GitLab.com or a GitLab Dedicated instance with [advanced search enabled](../../search/advanced_search.md#enable-advanced-search). This feature is not supported on GitLab Self-Managed, but support is proposed [issue 525484](https://gitlab.com/gitlab-org/gitlab/-/issues/525484).
- You must be in the vulnerability report for a project or group. This feature is not supported in the security dashboard, but support is proposed in [issue 537807](https://gitlab.com/gitlab-org/gitlab/-/issues/537807).
## Operational vulnerabilities
The **Operational vulnerabilities** tab lists vulnerabilities found by [Operational container scanning](../../clusters/agent/vulnerabilities.md).

View File

@ -69,13 +69,19 @@ If the case of `404.html`, there are different scenarios. For example:
You can configure redirects for your site using a `_redirects` file. For more information, see
[Create redirects for GitLab Pages](redirects.md).
## Remove your pages
## Delete a Pages site
To remove your pages:
Permanently delete all Pages deployments for a project.
This is permanent and cannot be undone.
To delete your pages:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Deploy > Pages**.
1. Select **Remove pages**.
1. Select **Delete pages**.
Your Pages site is no longer deployed.
To deploy this Pages site again, run a new pipeline.
## Subdomains of subdomains

View File

@ -55,7 +55,7 @@ To create a parallel deployment:
pages:
stage: deploy
script:
- echo "Pages accessible through ${CI_PAGES_URL}/${CI_COMMIT_BRANCH}"
- echo "Pages accessible through ${CI_PAGES_URL}"
pages: # specifies that this is a Pages job and publishes the default public directory
path_prefix: "$CI_COMMIT_BRANCH"
```

View File

@ -23,7 +23,7 @@ Use advanced search to find exactly what you need across your entire GitLab inst
With advanced search:
- Identify code patterns across all projects to refactor shared components more efficiently.
- Locate security vulnerabilities in dependencies across your entire organization at once.
- Locate security vulnerabilities across your entire organization's codebase and dependencies using [advanced vulnerability management](../application_security/vulnerability_report/_index.md#advanced-vulnerability-management).
- Track usage of deprecated functions or libraries throughout all repositories.
- Find discussions buried in issues, merge requests, or comments.
- Discover existing solutions instead of reinventing functionality that already exists.

View File

@ -4,7 +4,8 @@ import { existsSync } from 'node:fs';
import localRules from 'eslint-plugin-local-rules';
import js from '@eslint/js';
import { FlatCompat } from '@eslint/eslintrc';
import * as graphqlEslint from '@graphql-eslint/eslint-plugin';
// eslint-disable-next-line import/no-unresolved
import graphqlPlugin from '@graphql-eslint/eslint-plugin';
import * as todoLists from './.eslint_todo/index.mjs';
const { dirname } = import.meta;
@ -108,7 +109,7 @@ export default [
],
},
...compat.extends(...extendConfigs),
...compat.plugins('no-jquery', '@graphql-eslint'),
...compat.plugins('no-jquery'),
{
rules: {
'no-unused-vars': [
@ -589,11 +590,9 @@ export default [
files: ['**/*.graphql'],
languageOptions: {
ecmaVersion: 5,
sourceType: 'script',
parserOptions: {
parser: { ...graphqlEslint, meta: { name: '@graphql-eslint' } },
parser: graphqlPlugin.parser,
graphQLConfig: {
documents: '{,ee/,jh/}app/**/*.graphql',
schema: './tmp/tests/graphql/gitlab_schema_apollo.graphql',
@ -601,12 +600,16 @@ export default [
},
},
plugins: {
'@graphql-eslint': graphqlPlugin,
},
rules: {
'filenames/match-regex': 'off',
'spaced-comment': 'off',
'@graphql-eslint/no-anonymous-operations': 'error',
'@graphql-eslint/unique-operation-name': 'error',
'@graphql-eslint/require-id-when-available': 'error',
'@graphql-eslint/require-selections': 'error',
'@graphql-eslint/no-unused-variables': 'error',
'@graphql-eslint/no-unused-fragments': 'error',
'@graphql-eslint/no-duplicate-fields': 'error',
@ -622,7 +625,7 @@ export default [
],
rules: {
'@graphql-eslint/require-id-when-available': 'off',
'@graphql-eslint/require-selections': 'off',
},
},
{

View File

@ -2,9 +2,10 @@
module ActiveContext
class Embeddings
def self.generate_embeddings(content, model: nil, primitive: 'semantic_search_issue', user: nil)
def self.generate_embeddings(content, unit_primitive:, model: nil, user: nil)
action = 'embedding'
embeddings = Gitlab::Llm::VertexAi::Embeddings::Text
.new(content, user: user, tracking_context: { action: 'embedding' }, unit_primitive: primitive, model: model)
.new(content, user: user, tracking_context: { action: action }, unit_primitive: unit_primitive, model: model)
.execute
embeddings.all?(Array) ? embeddings : [embeddings]

View File

@ -14,6 +14,7 @@ module ActiveContext
class_methods do
def apply_embeddings(
refs:,
unit_primitive:,
content_field: :content,
content_method: nil,
remove_content: true
@ -44,7 +45,8 @@ module ActiveContext
versions = items.first[:versions]
contents = items.map { |item| item[:doc][content_field] }
embeddings_by_version = generate_embeddings_for_each_version(versions, contents)
embeddings_by_version = generate_embeddings_for_each_version(versions: versions, contents: contents,
unit_primitive: unit_primitive)
# Apply the generated embeddings back to each document
items.each.with_index do |item, index|
@ -75,9 +77,10 @@ module ActiveContext
end
end
def generate_embeddings_for_each_version(versions, contents)
def generate_embeddings_for_each_version(versions:, contents:, unit_primitive:)
versions.each_with_object({}) do |version, embeddings_by_version|
embedding = ActiveContext::Embeddings.generate_embeddings(contents, model: version[:model])
embedding = ActiveContext::Embeddings.generate_embeddings(contents, model: version[:model],
unit_primitive: unit_primitive)
embeddings_by_version[version[:field]] = embedding
end
end

View File

@ -6,7 +6,7 @@ RSpec.describe ActiveContext::Preprocessors::Embeddings do
include ::ActiveContext::Preprocessors::Embeddings
add_preprocessor :embeddings do |refs|
apply_embeddings(refs: refs, content_method: :embedding_content)
apply_embeddings(refs: refs, content_method: :embedding_content, unit_primitive: 'test_unit_primitive')
end
def embedding_content
@ -29,6 +29,7 @@ RSpec.describe ActiveContext::Preprocessors::Embeddings do
let(:object_id) { 5 }
let(:collection_name) { 'mock_collection' }
let(:vectors) { [1.0, 2.0] }
let(:unit_primitive) { 'test_unit_primitive' }
let(:vertex_blank_error) { StandardError.new('The text content is empty.') }
before do
@ -61,7 +62,7 @@ RSpec.describe ActiveContext::Preprocessors::Embeddings do
it 'generates and sets embeddings for each document' do
expect(ActiveContext::Embeddings).to receive(:generate_embeddings)
.once.with(['Some content'], model: nil).and_return([vectors])
.once.with(['Some content'], model: nil, unit_primitive: unit_primitive).and_return([vectors])
expect(preprocessed_reference.documents).to match_array([{ embedding: vectors }])
end
@ -86,7 +87,7 @@ RSpec.describe ActiveContext::Preprocessors::Embeddings do
it 'generates and sets embeddings for each document' do
expect(ActiveContext::Embeddings).to receive(:generate_embeddings)
.once.with(['Other content'], model: nil).and_return([vectors])
.once.with(['Other content'], model: nil, unit_primitive: unit_primitive).and_return([vectors])
expect(preprocessed_reference.documents).to match_array([{ embedding: vectors }])
end
@ -109,7 +110,7 @@ RSpec.describe ActiveContext::Preprocessors::Embeddings do
it 'generates and sets embeddings for each document' do
expect(ActiveContext::Embeddings).to receive(:generate_embeddings)
.once.with(['Some content'], model: nil).and_return([vectors])
.once.with(['Some content'], model: nil, unit_primitive: unit_primitive).and_return([vectors])
expect(preprocessed_reference.documents).to match_array([{ embedding: vectors }])
end
@ -121,7 +122,8 @@ RSpec.describe ActiveContext::Preprocessors::Embeddings do
include ::ActiveContext::Preprocessors::Embeddings
add_preprocessor :embeddings do |refs|
apply_embeddings(refs: refs, content_method: :embedding_content, remove_content: false)
apply_embeddings(refs: refs, content_method: :embedding_content, remove_content: false,
unit_primitive: 'test_unit_primitive')
end
def embedding_content
@ -146,7 +148,8 @@ RSpec.describe ActiveContext::Preprocessors::Embeddings do
include ::ActiveContext::Preprocessors::Embeddings
add_preprocessor :embeddings do |refs|
apply_embeddings(refs: refs, content_field: :other_field, content_method: :embedding_content)
apply_embeddings(refs: refs, content_field: :other_field, content_method: :embedding_content,
unit_primitive: 'test_unit_primitive')
end
def embedding_content
@ -172,7 +175,7 @@ RSpec.describe ActiveContext::Preprocessors::Embeddings do
it 'generates and sets embeddings for each document' do
expect(ActiveContext::Embeddings).to receive(:generate_embeddings)
.once.with(['Some other content'], model: nil).and_return([vectors])
.once.with(['Some other content'], model: nil, unit_primitive: unit_primitive).and_return([vectors])
expect(preprocessed_reference.documents).to match_array([{ embedding: vectors }])
end
@ -195,7 +198,7 @@ RSpec.describe ActiveContext::Preprocessors::Embeddings do
it 'generates and sets embeddings for each document' do
expect(ActiveContext::Embeddings).to receive(:generate_embeddings)
.once.with(['Some content'], model: nil).and_return([vectors])
.once.with(['Some content'], model: nil, unit_primitive: unit_primitive).and_return([vectors])
expect(preprocessed_reference.documents).to match_array([{ embedding: vectors }])
end
@ -207,8 +210,8 @@ RSpec.describe ActiveContext::Preprocessors::Embeddings do
include ::ActiveContext::Preprocessors::Embeddings
add_preprocessor :embeddings do |refs|
apply_embeddings(refs: refs, content_field: :other_field,
content_method: :embedding_content, remove_content: false)
apply_embeddings(refs: refs, content_field: :other_field, content_method: :embedding_content,
remove_content: false, unit_primitive: 'test_unit_primitive')
end
def embedding_content
@ -236,7 +239,8 @@ RSpec.describe ActiveContext::Preprocessors::Embeddings do
include ::ActiveContext::Preprocessors::Embeddings
add_preprocessor :embeddings do |refs|
apply_embeddings(refs: refs, content_method: :embedding_content)
apply_embeddings(refs: refs, content_method: :embedding_content,
unit_primitive: 'test_unit_primitive')
end
end
end
@ -258,7 +262,7 @@ RSpec.describe ActiveContext::Preprocessors::Embeddings do
include ::ActiveContext::Preprocessors::Embeddings
add_preprocessor :embeddings do |refs|
apply_embeddings(refs: refs)
apply_embeddings(refs: refs, unit_primitive: 'test_unit_primitive')
end
end
end
@ -288,7 +292,7 @@ RSpec.describe ActiveContext::Preprocessors::Embeddings do
it 'generates and sets embeddings for each document' do
expect(ActiveContext::Embeddings).to receive(:generate_embeddings)
.once.with(['Other content'], model: nil).and_return([vectors])
.once.with(['Other content'], model: nil, unit_primitive: unit_primitive).and_return([vectors])
expect(preprocessed_reference.documents).to match_array([{ embedding: vectors }])
end
@ -315,7 +319,8 @@ RSpec.describe ActiveContext::Preprocessors::Embeddings do
include ::ActiveContext::Preprocessors::Embeddings
add_preprocessor :embeddings do |refs|
apply_embeddings(refs: refs, content_field: :other_field)
apply_embeddings(refs: refs, content_field: :other_field,
unit_primitive: 'test_unit_primitive')
end
end
end
@ -331,7 +336,7 @@ RSpec.describe ActiveContext::Preprocessors::Embeddings do
it 'generates and sets embeddings for each document' do
expect(ActiveContext::Embeddings).to receive(:generate_embeddings)
.once.with(['Some other content'], model: nil).and_return([vectors])
.once.with(['Some other content'], model: nil, unit_primitive: unit_primitive).and_return([vectors])
expect(preprocessed_reference.documents).to match_array([{ embedding: vectors }])
end

View File

@ -1,5 +1,5 @@
variables:
DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.128.0'
DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.130.0'
.dast-auto-deploy:
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${DAST_AUTO_DEPLOY_IMAGE_VERSION}"

View File

@ -1,5 +1,5 @@
variables:
AUTO_DEPLOY_IMAGE_VERSION: 'v2.128.0'
AUTO_DEPLOY_IMAGE_VERSION: 'v2.130.0'
.auto-deploy:
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"

View File

@ -1,5 +1,5 @@
variables:
AUTO_DEPLOY_IMAGE_VERSION: 'v2.128.0'
AUTO_DEPLOY_IMAGE_VERSION: 'v2.130.0'
.auto-deploy:
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
module Gitlab
module Usage
module Metrics
module Instrumentations
class CountTopLevelGroupsMetric < DatabaseMetric
operation :count, column: :id
relation { Group.top_level }
end
end
end
end
end

View File

@ -3,7 +3,7 @@
namespace :gitlab do
namespace :db do
namespace :truncate_legacy_tables do
desc "GitLab | DB | Truncate CI Tables on Main"
desc "GitLab | DB | Truncate Legacy Tables on Main"
task :main, [:min_batch_size] => [:environment, 'gitlab:db:validate_config'] do |_t, args|
args.with_defaults(min_batch_size: 5)
Gitlab::Database::TablesTruncate.new(
@ -15,7 +15,7 @@ namespace :gitlab do
).execute
end
desc "GitLab | DB | Truncate Main Tables on CI"
desc "GitLab | DB | Truncate Legacy Tables on CI"
task :ci, [:min_batch_size] => [:environment, 'gitlab:db:validate_config'] do |_t, args|
args.with_defaults(min_batch_size: 5)
Gitlab::Database::TablesTruncate.new(
@ -26,6 +26,18 @@ namespace :gitlab do
until_table: ENV['UNTIL_TABLE']
).execute
end
desc "GitLab | DB | Truncate Legacy Tables on Sec"
task :sec, [:min_batch_size] => [:environment, 'gitlab:db:validate_config'] do |_t, args|
args.with_defaults(min_batch_size: 5)
Gitlab::Database::TablesTruncate.new(
database_name: 'sec',
min_batch_size: args.min_batch_size.to_i,
logger: Logger.new($stdout),
dry_run: ENV['DRY_RUN'] == 'true',
until_table: ENV['UNTIL_TABLE']
).execute
end
end
end
end

View File

@ -28375,6 +28375,9 @@ msgstr ""
msgid "GitLabPages|DNS check unsuccessful"
msgstr ""
msgid "GitLabPages|Delete Pages"
msgstr ""
msgid "GitLabPages|Domain ownership verification required. Add a TXT record to verify ownership at your domain provider."
msgstr ""
@ -28405,7 +28408,7 @@ msgstr ""
msgid "GitLabPages|New domain"
msgstr ""
msgid "GitLabPages|Only project maintainers can remove pages"
msgid "GitLabPages|Only project maintainers can remove pages."
msgstr ""
msgid "GitLabPages|Pages"
@ -28429,9 +28432,6 @@ msgstr ""
msgid "GitLabPages|Remove pages"
msgstr ""
msgid "GitLabPages|Removing pages will prevent them from being exposed to the public internet."
msgstr ""
msgid "GitLabPages|Restrict access to only project members on all group projects"
msgstr ""
@ -28447,6 +28447,12 @@ msgstr ""
msgid "GitLabPages|Support for domains and certificates is disabled. Ask your GitLab administrator to enable it."
msgstr ""
msgid "GitLabPages|This action will permanently delete all Pages deployments."
msgstr ""
msgid "GitLabPages|This is permanent and cannot be undone. To deploy this Pages site again, run a new pipeline."
msgstr ""
msgid "GitLabPages|Updating your Pages configuration…"
msgstr ""
@ -43224,7 +43230,10 @@ msgstr ""
msgid "Owasp|A9:2017 Using Components with Known Vulnerabilities"
msgstr ""
msgid "Owasp|Non-OWASP Top 10"
msgid "Owasp|Non-OWASP Top 10 2017"
msgstr ""
msgid "Owasp|Non-OWASP Top 10 2021"
msgstr ""
msgid "Owned by %{image_tag}"

View File

@ -56,7 +56,7 @@
"@babel/preset-env": "^7.23.7",
"@csstools/postcss-global-data": "^2.1.1",
"@cubejs-client/core": "^1.0.0",
"@floating-ui/dom": "^1.6.13",
"@floating-ui/dom": "^1.7.0",
"@gitlab/application-sdk-browser": "^0.3.4",
"@gitlab/at.js": "1.5.7",
"@gitlab/cluster-client": "^3.0.0",
@ -82,41 +82,41 @@
"@snowplow/browser-plugin-timezone": "^3.24.2",
"@snowplow/browser-tracker": "^3.24.2",
"@sourcegraph/code-host-integration": "0.0.95",
"@tiptap/core": "^2.11.7",
"@tiptap/extension-blockquote": "^2.11.7",
"@tiptap/extension-bold": "^2.11.7",
"@tiptap/extension-bubble-menu": "^2.11.7",
"@tiptap/extension-bullet-list": "^2.11.7",
"@tiptap/extension-code": "^2.11.7",
"@tiptap/extension-code-block": "^2.11.7",
"@tiptap/extension-code-block-lowlight": "^2.11.7",
"@tiptap/extension-document": "^2.11.7",
"@tiptap/extension-dropcursor": "^2.11.7",
"@tiptap/extension-gapcursor": "^2.11.7",
"@tiptap/extension-hard-break": "^2.11.7",
"@tiptap/extension-heading": "^2.11.7",
"@tiptap/extension-highlight": "^2.11.7",
"@tiptap/extension-history": "^2.11.7",
"@tiptap/extension-horizontal-rule": "^2.11.7",
"@tiptap/extension-image": "^2.11.7",
"@tiptap/extension-italic": "^2.11.7",
"@tiptap/extension-link": "^2.11.7",
"@tiptap/extension-list-item": "^2.11.7",
"@tiptap/extension-ordered-list": "^2.11.7",
"@tiptap/extension-paragraph": "^2.11.7",
"@tiptap/extension-strike": "^2.11.7",
"@tiptap/extension-subscript": "^2.11.7",
"@tiptap/extension-superscript": "^2.11.7",
"@tiptap/extension-table": "^2.11.7",
"@tiptap/extension-table-cell": "^2.11.7",
"@tiptap/extension-table-header": "^2.11.7",
"@tiptap/extension-table-row": "^2.11.7",
"@tiptap/extension-task-item": "^2.11.7",
"@tiptap/extension-task-list": "^2.11.7",
"@tiptap/extension-text": "^2.11.7",
"@tiptap/pm": "^2.11.7",
"@tiptap/suggestion": "^2.11.7",
"@tiptap/vue-2": "^2.11.7",
"@tiptap/core": "^2.12.0",
"@tiptap/extension-blockquote": "^2.12.0",
"@tiptap/extension-bold": "^2.12.0",
"@tiptap/extension-bubble-menu": "^2.12.0",
"@tiptap/extension-bullet-list": "^2.12.0",
"@tiptap/extension-code": "^2.12.0",
"@tiptap/extension-code-block": "^2.12.0",
"@tiptap/extension-code-block-lowlight": "^2.12.0",
"@tiptap/extension-document": "^2.12.0",
"@tiptap/extension-dropcursor": "^2.12.0",
"@tiptap/extension-gapcursor": "^2.12.0",
"@tiptap/extension-hard-break": "^2.12.0",
"@tiptap/extension-heading": "^2.12.0",
"@tiptap/extension-highlight": "^2.12.0",
"@tiptap/extension-history": "^2.12.0",
"@tiptap/extension-horizontal-rule": "^2.12.0",
"@tiptap/extension-image": "^2.12.0",
"@tiptap/extension-italic": "^2.12.0",
"@tiptap/extension-link": "^2.12.0",
"@tiptap/extension-list-item": "^2.12.0",
"@tiptap/extension-ordered-list": "^2.12.0",
"@tiptap/extension-paragraph": "^2.12.0",
"@tiptap/extension-strike": "^2.12.0",
"@tiptap/extension-subscript": "^2.12.0",
"@tiptap/extension-superscript": "^2.12.0",
"@tiptap/extension-table": "^2.12.0",
"@tiptap/extension-table-cell": "^2.12.0",
"@tiptap/extension-table-header": "^2.12.0",
"@tiptap/extension-table-row": "^2.12.0",
"@tiptap/extension-task-item": "^2.12.0",
"@tiptap/extension-task-list": "^2.12.0",
"@tiptap/extension-text": "^2.12.0",
"@tiptap/pm": "^2.12.0",
"@tiptap/suggestion": "^2.12.0",
"@tiptap/vue-2": "^2.12.0",
"@vue/apollo-components": "^4.0.0-beta.4",
"@vue/apollo-option": "^4.0.0-beta.4",
"apollo-upload-client": "15.0.0",
@ -251,7 +251,7 @@
"@gitlab/eslint-plugin": "20.7.1",
"@gitlab/noop": "^1.0.1",
"@gitlab/stylelint-config": "6.2.2",
"@graphql-eslint/eslint-plugin": "3.20.1",
"@graphql-eslint/eslint-plugin": "4.4.0",
"@originjs/vite-plugin-commonjs": "^1.0.3",
"@pinia/testing": "^0.1.5",
"@rollup/plugin-graphql": "^2.0.5",
@ -277,7 +277,7 @@
"custom-jquery-matchers": "^2.1.0",
"dependency-cruiser": "^16.9.0",
"eslint": "9.25.1",
"eslint-formatter-gitlab": "^5.1.0",
"eslint-formatter-gitlab": "^6.0.0",
"eslint-import-resolver-jest": "3.0.2",
"eslint-import-resolver-webpack": "0.13.10",
"eslint-plugin-import": "^2.31.0",

View File

@ -1,22 +0,0 @@
diff --git a/node_modules/@graphql-eslint/eslint-plugin/cjs/utils.js b/node_modules/@graphql-eslint/eslint-plugin/cjs/utils.js
index bd7f92a..1ee1ca1 100644
--- a/node_modules/@graphql-eslint/eslint-plugin/cjs/utils.js
+++ b/node_modules/@graphql-eslint/eslint-plugin/cjs/utils.js
@@ -52,7 +52,7 @@ var import_chalk = __toESM(require("chalk"));
var import_graphql = require("graphql");
var import_lodash = __toESM(require("lodash.lowercase"));
function requireSiblingsOperations(ruleId, context) {
- const { siblingOperations } = context.parserServices;
+ const { siblingOperations } = context.sourceCode.parserServices;
if (!siblingOperations.available) {
throw new Error(
`Rule \`${ruleId}\` requires \`parserOptions.operations\` to be set and loaded. See https://bit.ly/graphql-eslint-operations for more info`
@@ -61,7 +61,7 @@ function requireSiblingsOperations(ruleId, context) {
return siblingOperations;
}
function requireGraphQLSchemaFromContext(ruleId, context) {
- const { schema } = context.parserServices;
+ const { schema } = context.sourceCode.parserServices;
if (!schema) {
throw new Error(
`Rule \`${ruleId}\` requires \`parserOptions.schema\` to be set and loaded. See https://bit.ly/graphql-eslint-schema for more info`

View File

@ -85,7 +85,7 @@ RSpec.describe '1_settings', feature_category: :shared do
}
end
context 'when legacy topology service config is provided' do
context 'when legacy topology service client config is provided as a top-level key' do
before do
stub_config({ cell: { enabled: true, id: 1 }, topology_service: config })
load_settings
@ -96,6 +96,18 @@ RSpec.describe '1_settings', feature_category: :shared do
it { expect(Settings.cell.topology_service_client.certificate_file).to eq(config[:certificate_file]) }
it { expect(Settings.cell.topology_service_client.private_key_file).to eq(config[:private_key_file]) }
end
context 'when topology service client config is provided as a key nested' do
before do
stub_config({ cell: { enabled: true, id: 1, topology_service_client: config } })
load_settings
end
it { expect(Settings.cell.topology_service_client.address).to eq(config[:address]) }
it { expect(Settings.cell.topology_service_client.ca_file).to eq(config[:ca_file]) }
it { expect(Settings.cell.topology_service_client.certificate_file).to eq(config[:certificate_file]) }
it { expect(Settings.cell.topology_service_client.private_key_file).to eq(config[:private_key_file]) }
end
end
describe 'Pages custom domains settings' do

View File

@ -121,7 +121,7 @@ RSpec.describe 'validate database config', feature_category: :cell do
end
it 'raises exception about missing topology service client config' do
expect { validate_config }.to raise_error("Topology Service setting 'address' is not set.#{dev_message}")
expect { validate_config }.to raise_error("Topology Service Client setting 'address' is not set.#{dev_message}")
end
it_behaves_like 'with SKIP_CELL_CONFIG_VALIDATION=true'

View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountTopLevelGroupsMetric, feature_category: :groups_and_projects do
let_it_be(:top_level_group) { create(:group) }
let_it_be(:subgroup) { create(:group, :nested) }
let_it_be(:project_in_group_namespace) { create(:project, group: subgroup) }
let_it_be(:project_in_user_namespace) { create(:project) }
let(:expected_value) { 2 }
it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', data_source: 'database' }
end

View File

@ -106,6 +106,19 @@ RSpec.describe Approvable do
end
end
describe '#approvals_for_user_ids' do
let_it_be(:user) { create(:user) }
let_it_be(:merge_request) { create(:merge_request) }
let_it_be(:approval) { create(:approval, merge_request: merge_request, user: user) }
let_it_be(:approval2) { create(:approval, merge_request: merge_request, user: create(:user)) }
subject(:approvals) { merge_request.approvals_for_user_ids([user.id]) }
it 'returns approvals by user' do
is_expected.to contain_exactly(approval)
end
end
describe '.not_approved_by_users_with_usernames' do
subject { MergeRequest.not_approved_by_users_with_usernames([user.username, user2.username]) }

View File

@ -59,5 +59,41 @@ RSpec.describe WorkItems::UserPreference, type: :model, feature_category: :team_
MESSAGE
end
end
describe 'validate display_settings' do
before do
allow(WorkItems::SortingKeys).to receive(:available?).and_return(true)
end
it 'is valid with an empty display settings hash' do
preferences = described_class.new(namespace: namespace, display_settings: {})
expect(preferences).to be_valid
end
it 'is invalid with properties not defined in the schema' do
invalid_display_settings = { 'invalidProperty' => 'some_value' }
preferences = described_class.new(namespace: namespace, display_settings: invalid_display_settings)
expect(preferences).not_to be_valid
expect(preferences.errors[:display_settings]).to include('must be a valid json schema')
end
it 'is valid with a valid display_settings hash' do
valid_display_settings = { 'shouldOpenItemsInSidePanel' => true }
preferences = described_class.new(namespace: namespace, display_settings: valid_display_settings)
expect(preferences).to be_valid
expect(preferences.display_settings).to eq(valid_display_settings)
end
it 'is invalid with a wrong type as per schema validation' do
invalid_display_settings = { 'shouldOpenItemsInSidePanel' => 'string_type' }
preferences = described_class.new(namespace: namespace, display_settings: invalid_display_settings)
expect(preferences).not_to be_valid
expect(preferences.errors[:display_settings]).to include('must be a valid json schema')
end
end
end
end

View File

@ -31,5 +31,13 @@ RSpec.describe 'Updating an existing HTTP Integration', feature_category: :incid
let(:mutation_response) { graphql_mutation_response(:http_integration_update) }
before do
allow_unlimited_graphql_complexity
allow_unlimited_graphql_depth
allow_unlimited_validation_timeout
# Optional, if you suspect recursion issues, though less common for timeouts:
# allow_high_graphql_recursion
end
it_behaves_like 'updating an existing HTTP integration'
end

View File

@ -10,12 +10,14 @@ RSpec.describe 'Update work items user preferences', feature_category: :team_pla
let_it_be(:work_item_type) { WorkItems::Type.default_by_type(:incident) }
let(:sorting_value) { 'CREATED_ASC' }
let(:display_settings) { { 'shouldOpenItemsInSidePanel' => true } }
let(:input) do
{
namespacePath: namespace.full_path,
workItemTypeId: work_item_type&.to_gid,
sort: sorting_value
sort: sorting_value,
displaySettings: display_settings
}
end
@ -30,6 +32,7 @@ RSpec.describe 'Update work items user preferences', feature_category: :team_pla
name
}
sort
displaySettings
}
FIELDS
end
@ -66,7 +69,8 @@ RSpec.describe 'Update work items user preferences', feature_category: :team_pla
'workItemType' => {
'name' => work_item_type.name
},
'sort' => sorting_value
'sort' => sorting_value,
'displaySettings' => display_settings
)
end
@ -74,7 +78,8 @@ RSpec.describe 'Update work items user preferences', feature_category: :team_pla
let(:input) do
{
namespacePath: namespace.full_path,
sort: sorting_value
sort: sorting_value,
displaySettings: display_settings
}
end
@ -89,7 +94,8 @@ RSpec.describe 'Update work items user preferences', feature_category: :team_pla
'path' => namespace.path
},
'workItemType' => nil,
'sort' => sorting_value
'sort' => sorting_value,
'displaySettings' => display_settings
)
end
end
@ -109,6 +115,20 @@ RSpec.describe 'Update work items user preferences', feature_category: :team_pla
expect(mutation_response['userPreferences']).to be_nil
end
end
context 'when display settings are not valid' do
let_it_be(:display_settings) { { 'shouldOpenItemsInSidePanel' => 'test' } }
it 'updates the user preferences successfully' do
post_graphql_mutation(mutation, current_user: user)
expect(response).to have_gitlab_http_status(:success)
expect(graphql_errors).to be_blank
expect(mutation_response['errors']).to include(
'Display settings must be a valid json schema'
)
expect(mutation_response['userPreferences']).to be_nil
end
end
end
end

View File

@ -307,6 +307,14 @@ RSpec.describe MergeRequests::UpdateService, :mailer, feature_category: :code_re
update_merge_request(reviewer_ids: [user.id])
end
it 'sets reviewer state as approved if user has previously approved' do
create(:approval, merge_request: merge_request, user: user)
update_merge_request(reviewer_ids: [user.id])
expect(merge_request.find_reviewer(user)).to be_approved
end
end
it 'creates a resource label event' do

View File

@ -6,8 +6,18 @@ RSpec.describe 'gitlab:db:truncate_legacy_tables', :silence_stdout, :reestablish
:suppress_gitlab_schemas_validate_connection, feature_category: :cell do
let(:main_connection) { ApplicationRecord.connection }
let(:ci_connection) { Ci::ApplicationRecord.connection }
let(:sec_connection) { SecApplicationRecord.connection }
let(:test_gitlab_main_table) { '_test_gitlab_main_table' }
let(:test_gitlab_ci_table) { '_test_gitlab_ci_table' }
let(:test_gitlab_sec_table) { '_test_gitlab_sec_table' }
let(:databases) { %i[main ci] }
let(:tables_to_schema) do
{
test_gitlab_main_table => :gitlab_main,
test_gitlab_ci_table => :gitlab_ci,
test_gitlab_sec_table => :gitlab_main
}
end
before(:all) do
Rake.application.rake_require 'active_record/railties/databases'
@ -19,20 +29,21 @@ RSpec.describe 'gitlab:db:truncate_legacy_tables', :silence_stdout, :reestablish
before do
skip_if_shared_database(:ci)
execute_on_each_database(<<~SQL)
execute_on_each_database(<<~SQL, databases: databases)
CREATE TABLE #{test_gitlab_main_table} (id integer NOT NULL);
INSERT INTO #{test_gitlab_main_table} VALUES(generate_series(1, 50));
SQL
execute_on_each_database(<<~SQL)
execute_on_each_database(<<~SQL, databases: databases)
CREATE TABLE #{test_gitlab_ci_table} (id integer NOT NULL);
INSERT INTO #{test_gitlab_ci_table} VALUES(generate_series(1, 50));
SQL
execute_on_each_database(<<~SQL, databases: databases)
CREATE TABLE #{test_gitlab_sec_table} (id integer NOT NULL);
INSERT INTO #{test_gitlab_sec_table} VALUES(generate_series(1, 50));
SQL
allow(Gitlab::Database::GitlabSchema).to receive(:tables_to_schema).and_return(
{
test_gitlab_main_table => :gitlab_main,
test_gitlab_ci_table => :gitlab_ci
}
tables_to_schema
)
end
@ -61,6 +72,40 @@ RSpec.describe 'gitlab:db:truncate_legacy_tables', :silence_stdout, :reestablish
database_name: "ci",
with_retries: false
).lock_writes
# Locking sec table on the ci database
Gitlab::Database::LockWritesManager.new(
table_name: test_gitlab_sec_table,
connection: ci_connection,
database_name: "ci",
with_retries: false
).lock_writes
if database_exists?('sec')
# Locking sec table on the main database
Gitlab::Database::LockWritesManager.new(
table_name: test_gitlab_sec_table,
connection: main_connection,
database_name: "main",
with_retries: false
).lock_writes
# Locking ci table on the sec database
Gitlab::Database::LockWritesManager.new(
table_name: test_gitlab_ci_table,
connection: sec_connection,
database_name: "sec",
with_retries: false
).lock_writes
# Locking main table on the sec database
Gitlab::Database::LockWritesManager.new(
table_name: test_gitlab_main_table,
connection: sec_connection,
database_name: "sec",
with_retries: false
).lock_writes
end
end
it 'calls TablesTruncate with the correct parameters and default minimum batch size' do
@ -75,10 +120,20 @@ RSpec.describe 'gitlab:db:truncate_legacy_tables', :silence_stdout, :reestablish
truncate_legacy_tables
end
it 'truncates the legacy table' do
expect do
truncate_legacy_tables
end.to change { connection.select_value("SELECT count(*) from #{legacy_table}") }.from(50).to(0)
it 'truncates the legacy tables' do
legacy_tables.each do |legacy_table|
expect(
connection.select_value("SELECT count(*) from #{legacy_table}")
).to eq(50)
end
truncate_legacy_tables
legacy_tables.each do |legacy_table|
expect(
connection.select_value("SELECT count(*) from #{legacy_table}")
).to eq(0)
end
end
it 'does not truncate the table that belongs to the connection schema' do
@ -95,19 +150,23 @@ RSpec.describe 'gitlab:db:truncate_legacy_tables', :silence_stdout, :reestablish
it 'does not truncate any tables' do
expect do
truncate_legacy_tables
end.not_to change { connection.select_value("SELECT count(*) from #{legacy_table}") }
end.not_to change {
legacy_tables.map do |legacy_table|
connection.select_value("SELECT count(*) from #{legacy_table}")
end
}
end
it 'prints the truncation sql statement to the output' do
expect do
truncate_legacy_tables
end.to output(/TRUNCATE TABLE #{legacy_table} RESTRICT/).to_stdout
end.to output(/TRUNCATE TABLE #{legacy_tables.join(', ')} RESTRICT/).to_stdout
end
end
context 'when passing until_table parameter via environment variable' do
before do
stub_env('UNTIL_TABLE', legacy_table)
stub_env('UNTIL_TABLE', legacy_tables.first)
end
it 'sends the table name to TablesTruncate' do
@ -116,7 +175,7 @@ RSpec.describe 'gitlab:db:truncate_legacy_tables', :silence_stdout, :reestablish
min_batch_size: 5,
logger: anything,
dry_run: false,
until_table: legacy_table
until_table: legacy_tables.first
).and_call_original
truncate_legacy_tables
@ -131,18 +190,55 @@ RSpec.describe 'gitlab:db:truncate_legacy_tables', :silence_stdout, :reestablish
let(:connection) { ApplicationRecord.connection }
let(:database_name) { 'main' }
let(:active_table) { test_gitlab_main_table }
let(:legacy_table) { test_gitlab_ci_table }
let(:legacy_tables) { [test_gitlab_ci_table] }
it_behaves_like 'truncating legacy tables'
end
context 'when truncating main tables on the ci database' do
subject(:truncate_legacy_tables) { run_rake_task('gitlab:db:truncate_legacy_tables:ci') }
subject(:truncate_legacy_tables) do
# These are purposefully cross-DB to properly test multi-schema truncation
Gitlab::Database.allow_cross_joins_across_databases(
url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/189237'
) do
run_rake_task('gitlab:db:truncate_legacy_tables:ci')
end
end
let(:connection) { Ci::ApplicationRecord.connection }
let(:database_name) { 'ci' }
let(:active_table) { test_gitlab_ci_table }
let(:legacy_table) { test_gitlab_main_table }
let(:legacy_tables) { [test_gitlab_main_table, test_gitlab_sec_table] }
it_behaves_like 'truncating legacy tables'
end
context 'when truncating both ci and main tables on the sec database' do
subject(:truncate_legacy_tables) do
# These are purposefully cross-DB to properly test multi-schema truncation
Gitlab::Database.allow_cross_joins_across_databases(
url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/189237'
) do
run_rake_task('gitlab:db:truncate_legacy_tables:sec')
end
end
let(:connection) { SecApplicationRecord.connection }
let(:database_name) { 'sec' }
let(:active_table) { test_gitlab_sec_table }
let(:legacy_tables) { [test_gitlab_ci_table, test_gitlab_main_table] }
let(:databases) { %i[ci main sec] }
let(:tables_to_schema) do
{
test_gitlab_main_table => :gitlab_main,
test_gitlab_ci_table => :gitlab_ci,
test_gitlab_sec_table => :gitlab_sec
}
end
before do
skip unless database_exists?(:sec)
end
it_behaves_like 'truncating legacy tables'
end

View File

@ -72,7 +72,8 @@ RSpec.describe CI::ChangedFiles, feature_category: :tooling do
describe '#run_eslint_for_changed_files' do
let(:eslint_command) do
['yarn', 'run', 'lint:eslint', '--no-warn-ignored', '--format', 'gitlab', 'file1.js', 'file2.vue']
['yarn', 'run', 'lint:eslint', '--no-warn-ignored', '--no-error-on-unmatched-pattern', '--format', 'gitlab',
'file1.js', 'file2.vue']
end
let(:console_message) { /Running ESLint for changed files.../i }
@ -120,7 +121,7 @@ RSpec.describe CI::ChangedFiles, feature_category: :tooling do
context 'when a single todo file has been changed' do
let(:eslint_command) do
['yarn', 'run', 'lint:eslint', '--no-warn-ignored', '--format', 'gitlab',
['yarn', 'run', 'lint:eslint', '--no-warn-ignored', '--no-error-on-unmatched-pattern', '--format', 'gitlab',
'.eslint_todo/vue-no-unused-properties.mjs',
'app/assets/javascripts/add_context_commits_modal/components/add_context_commits_modal_wrapper.vue',
'app/assets/javascripts/admin/abuse_report/components/notes/abuse_report_comment_form.vue',
@ -174,7 +175,7 @@ RSpec.describe CI::ChangedFiles, feature_category: :tooling do
context 'when several todo files have been changed' do
let(:eslint_command) do
['yarn', 'run', 'lint:eslint', '--no-warn-ignored', '--format', 'gitlab',
['yarn', 'run', 'lint:eslint', '--no-warn-ignored', '--no-error-on-unmatched-pattern', '--format', 'gitlab',
'.eslint_todo/vue-no-unused-properties.mjs',
'app/assets/javascripts/projects/project_new.js',
'app/assets/javascripts/add_context_commits_modal/components/add_context_commits_modal_wrapper.vue',
@ -240,7 +241,7 @@ RSpec.describe CI::ChangedFiles, feature_category: :tooling do
context 'when todo files have been changed but no ignored file was removed from them' do
let(:eslint_command) do
['yarn', 'run', 'lint:eslint', '--no-warn-ignored', '--format', 'gitlab',
['yarn', 'run', 'lint:eslint', '--no-warn-ignored', '--no-error-on-unmatched-pattern', '--format', 'gitlab',
'.eslint_todo/vue-no-unused-properties.mjs']
end

View File

@ -45,7 +45,13 @@ module CI
return 0
end
command = ["yarn", "run", "lint:eslint", "--no-warn-ignored", "--format", "gitlab", *files]
command = [
"yarn", "run", "lint:eslint",
"--no-warn-ignored",
"--no-error-on-unmatched-pattern",
"--format", "gitlab",
*files
]
system(*command)
last_command_status.exitstatus

1309
yarn.lock

File diff suppressed because it is too large Load Diff