diff --git a/.gitlab/merge_request_templates/Stable Branch.md b/.gitlab/merge_request_templates/Stable Branch.md
index 28db9d4229f..6c923847f85 100644
--- a/.gitlab/merge_request_templates/Stable Branch.md
+++ b/.gitlab/merge_request_templates/Stable Branch.md
@@ -37,4 +37,5 @@ If you have questions about the patch release process, please:
[patch release runbook for engineers and maintainers]: https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/patch/engineers.md
[`#releases`]: https://gitlab.slack.com/archives/C0XM5UU6B
+/label ~backport
/assign me
diff --git a/.rubocop_todo/rspec/change_by_zero.yml b/.rubocop_todo/rspec/change_by_zero.yml
index 2dd412a1d8c..334e0f0e58c 100644
--- a/.rubocop_todo/rspec/change_by_zero.yml
+++ b/.rubocop_todo/rspec/change_by_zero.yml
@@ -16,27 +16,6 @@ RSpec/ChangeByZero:
- 'ee/spec/requests/api/graphql/mutations/work_items/create_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/work_items/linked_items/add_spec.rb'
- 'ee/spec/requests/api/merge_request_approvals_spec.rb'
- - 'ee/spec/services/app_sec/dast/profiles/create_service_spec.rb'
- - 'ee/spec/services/application_settings/update_service_spec.rb'
- - 'ee/spec/services/approval_rules/user_rules_destroy_service_spec.rb'
- - 'ee/spec/services/ci/delete_project_subscription_service_spec.rb'
- - 'ee/spec/services/ci/minutes/update_project_and_namespace_usage_service_spec.rb'
- - 'ee/spec/services/ee/ci/update_instance_variables_service_spec.rb'
- - 'ee/spec/services/ee/issues/create_service_spec.rb'
- - 'ee/spec/services/ee/members/destroy_service_spec.rb'
- - 'ee/spec/services/geo/container_repository_registry_removal_service_spec.rb'
- - 'ee/spec/services/geo/file_registry_removal_service_spec.rb'
- - 'ee/spec/services/geo/metrics_update_service_spec.rb'
- - 'ee/spec/services/gitlab_subscriptions/add_on_purchases/gitlab_com/provision_service_spec.rb'
- - 'ee/spec/services/push_rules/create_or_update_service_spec.rb'
- - 'ee/spec/services/registrations/import_namespace_create_service_spec.rb'
- - 'ee/spec/services/registrations/standard_namespace_create_service_spec.rb'
- - 'ee/spec/services/sbom/ingestion/tasks/ingest_sources_spec.rb'
- - 'ee/spec/services/security/ingestion/tasks/ingest_cvs_security_scanners_spec.rb'
- - 'ee/spec/services/security/orchestration/create_bot_service_spec.rb'
- - 'ee/spec/services/vulnerabilities/manually_create_service_spec.rb'
- - 'ee/spec/services/vulnerabilities/security_finding/create_merge_request_service_spec.rb'
- - 'ee/spec/services/work_items/legacy_epics/related_epic_links/create_service_spec.rb'
- 'spec/controllers/admin/clusters_controller_spec.rb'
- 'spec/controllers/groups/boards_controller_spec.rb'
- 'spec/controllers/groups/clusters_controller_spec.rb'
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index cbcee7d4b72..0fd231905a4 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-55f4fb94e39f60e1d4c76deac5d6f20c6202c68f
+3292fb4882db9208602f3cd2cc61ba56bce8e6a9
diff --git a/app/assets/javascripts/projects/new/components/new_project_push_tip_popover.vue b/app/assets/javascripts/projects/new/components/new_project_push_tip_popover.vue
index 1dcfd32e4ff..6bcdea78ac1 100644
--- a/app/assets/javascripts/projects/new/components/new_project_push_tip_popover.vue
+++ b/app/assets/javascripts/projects/new/components/new_project_push_tip_popover.vue
@@ -2,6 +2,7 @@
import { GlPopover, GlFormInputGroup } from '@gitlab/ui';
import { __ } from '~/locale';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import { helpPagePath } from '~/helpers/help_page_helper';
export default {
components: {
@@ -9,13 +10,14 @@ export default {
GlFormInputGroup,
ClipboardButton,
},
- inject: ['pushToCreateProjectCommand', 'projectHelpPath'],
+ inject: ['pushToCreateProjectCommand'],
props: {
target: {
type: [Function, HTMLElement],
required: true,
},
},
+ helpPath: helpPagePath('topics/git/project.md'),
i18n: {
clipboardButtonTitle: __('Copy command'),
commandInputAriaLabel: __('Push project from command line'),
@@ -55,12 +57,9 @@ export default {
- {{ $options.i18n.helpLinkText }}
+ {{
+ $options.i18n.helpLinkText
+ }}
diff --git a/app/assets/javascripts/projects/new/index.js b/app/assets/javascripts/projects/new/index.js
index 6e9cb7b3336..58bc46566d1 100644
--- a/app/assets/javascripts/projects/new/index.js
+++ b/app/assets/javascripts/projects/new/index.js
@@ -16,7 +16,6 @@ export function initNewProjectCreation() {
const {
pushToCreateProjectCommand,
- projectHelpPath,
newProjectGuidelines,
hasErrors,
isCiCdAvailable,
@@ -39,7 +38,6 @@ export function initNewProjectCreation() {
};
const provide = {
- projectHelpPath,
pushToCreateProjectCommand,
};
diff --git a/app/assets/javascripts/projects/new_v2/components/command_line.vue b/app/assets/javascripts/projects/new_v2/components/command_line.vue
index c66fa12464a..d85bd2644e6 100644
--- a/app/assets/javascripts/projects/new_v2/components/command_line.vue
+++ b/app/assets/javascripts/projects/new_v2/components/command_line.vue
@@ -2,6 +2,7 @@
import { GlFormGroup, GlLink, GlFormInputGroup } from '@gitlab/ui';
import SafeHtml from '~/vue_shared/directives/safe_html';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import { helpPagePath } from '~/helpers/help_page_helper';
export default {
components: {
@@ -13,7 +14,8 @@ export default {
directives: {
SafeHtml,
},
- inject: ['projectHelpPath', 'pushToCreateProjectCommand'],
+ helpPath: helpPagePath('topics/git/project.md'),
+ inject: ['pushToCreateProjectCommand'],
};
@@ -30,7 +32,7 @@ export default {
data-testid="new-project-with-command"
>
-
+
{{ s__('ProjectNew|What does this command do?') }}
diff --git a/app/assets/javascripts/projects/new_v2/index.js b/app/assets/javascripts/projects/new_v2/index.js
index fee9c87089e..e4de98776d5 100644
--- a/app/assets/javascripts/projects/new_v2/index.js
+++ b/app/assets/javascripts/projects/new_v2/index.js
@@ -22,7 +22,6 @@ export function initNewProjectForm() {
projectsUrl,
parentGroupUrl,
parentGroupName,
- projectHelpPath,
isCiCdAvailable,
canImportProjects,
importSourcesEnabled,
@@ -64,7 +63,6 @@ export function initNewProjectForm() {
projectsUrl,
parentGroupUrl,
parentGroupName,
- projectHelpPath,
trackLabel,
isCiCdAvailable: parseBoolean(isCiCdAvailable),
importSourcesEnabled: parseBoolean(importSourcesEnabled),
diff --git a/app/assets/javascripts/ref/format_refs.js b/app/assets/javascripts/ref/format_refs.js
index df10c54c13b..d9fa45e3807 100644
--- a/app/assets/javascripts/ref/format_refs.js
+++ b/app/assets/javascripts/ref/format_refs.js
@@ -23,9 +23,7 @@ export const formatListBoxItems = ({ branches, tags, commits, selectedRef }) =>
const addToFinalResult = (items, header, shouldFilter = true) => {
if (!items) return;
const filteredItems =
- shouldFilter && selectedRef
- ? items.filter((item) => item.value !== selectedRef.value)
- : items; // Filter out the selected
+ shouldFilter && selectedRef ? items.filter((item) => item.name !== selectedRef.name) : items; // Filter out the selected
if (!filteredItems?.length) return;
listBoxItems.push({
diff --git a/app/services/ci/register_job_service.rb b/app/services/ci/register_job_service.rb
index c10b1cb6ac4..f4aaece7f32 100644
--- a/app/services/ci/register_job_service.rb
+++ b/app/services/ci/register_job_service.rb
@@ -98,8 +98,7 @@ module Ci
next unless result
if result.valid?
- @metrics.register_success(result.build_presented)
- @metrics.observe_queue_depth(:found, depth)
+ track_success(result, depth)
return result # rubocop:disable Cop/AvoidReturnFromBlocks
else
@@ -109,10 +108,7 @@ module Ci
end
end
- @metrics.increment_queue_operation(:queue_conflict) unless valid
- @metrics.observe_queue_depth(:conflict, depth) unless valid
- @metrics.observe_queue_depth(:not_found, depth) if valid
- @metrics.register_failure
+ track_conflict(depth, valid)
Result.new(nil, nil, nil, valid)
end
@@ -308,14 +304,40 @@ module Ci
track_exception_for_build(ex, build)
end
+ def track_success(result, depth)
+ @metrics.register_success(result.build_presented)
+ @metrics.observe_queue_depth(:found, depth)
+ rescue StandardError => ex
+ # We should know about any errors during tracking but we don't want them to prevent
+ # reporting a result to the runner
+ Gitlab::ErrorTracking.track_and_raise_for_dev_exception(
+ ex, **build_tracking_data(result.build)
+ )
+ end
+
+ def track_conflict(depth, valid)
+ @metrics.increment_queue_operation(:queue_conflict) unless valid
+ @metrics.observe_queue_depth(:conflict, depth) unless valid
+ @metrics.observe_queue_depth(:not_found, depth) if valid
+ @metrics.register_failure
+ rescue StandardError => ex
+ # We should know about any errors during tracking but we don't want them to prevent
+ # reporting a result to the runner
+ Gitlab::ErrorTracking.track_and_raise_for_dev_exception(ex)
+ end
+
def track_exception_for_build(ex, build)
- Gitlab::ErrorTracking.track_exception(ex,
+ Gitlab::ErrorTracking.track_exception(ex, **build_tracking_data(build))
+ end
+
+ def build_tracking_data(build)
+ {
build_id: build.id,
build_name: build.name,
build_stage: build.stage_name,
pipeline_id: build.pipeline_id,
project_id: build.project_id
- )
+ }
end
def pre_assign_runner_checks
diff --git a/app/views/devise/sessions/_successful_verification.haml b/app/views/devise/sessions/_successful_verification.haml
new file mode 100644
index 00000000000..8a5a3f6c423
--- /dev/null
+++ b/app/views/devise/sessions/_successful_verification.haml
@@ -0,0 +1,12 @@
+= content_for :meta_tags do
+ %meta{ 'http-equiv': 'refresh', content: "3; url=#{@redirect_url}" }
+
+.gl-text-center.gl-max-w-62.gl-mx-auto{ data: local_assigns.fetch(:data, {}) }
+ .svg-content.svg-80
+ = image_tag 'illustrations/success-sm.svg'
+ %h2
+ = s_('IdentityVerification|Verification successful')
+ %p.gl-pt-2
+ - redirect_url_start = ''.html_safe % { url: @redirect_url }
+ - redirect_url_end = ''.html_safe
+ = html_escape(s_("IdentityVerification|Your account has been successfully verified. You'll be redirected to your account in just a moment. You can also %{redirect_url_start}refresh the page%{redirect_url_end}.")) % { redirect_url_start: redirect_url_start, redirect_url_end: redirect_url_end }
diff --git a/app/views/devise/sessions/_successful_verification_lightweight.haml b/app/views/devise/sessions/_successful_verification_lightweight.haml
new file mode 100644
index 00000000000..fd870267cab
--- /dev/null
+++ b/app/views/devise/sessions/_successful_verification_lightweight.haml
@@ -0,0 +1,13 @@
+- @html_class = 'gl-dark'
+= content_for :meta_tags do
+ %meta{ 'http-equiv': 'refresh', content: "3; url=#{@redirect_url}" }
+
+.gl-text-center.gl-max-w-xl.gl-mx-auto.gl-bg-subtle.gl-rounded-lg.gl-py-4{ data: local_assigns.fetch(:data, {}) }
+ .svg-content.svg-80
+ = image_tag 'illustrations/secure-sm.svg'
+ %h2
+ = s_('IdentityVerification|Verification successful')
+ %p.gl-pt-2.gl-px-6
+ - redirect_url_start = ''.html_safe % { url: @redirect_url }
+ - redirect_url_end = ''.html_safe
+ = html_escape(s_("IdentityVerification|Your account has been successfully verified. You'll be redirected to your account in just a moment. You can also %{redirect_url_start}refresh the page%{redirect_url_end}.")) % { redirect_url_start: redirect_url_start, redirect_url_end: redirect_url_end }
diff --git a/app/views/devise/sessions/successful_verification.haml b/app/views/devise/sessions/successful_verification.haml
index e9be028ad9c..50751b3a2d7 100644
--- a/app/views/devise/sessions/successful_verification.haml
+++ b/app/views/devise/sessions/successful_verification.haml
@@ -1,12 +1,8 @@
-= content_for :meta_tags do
- %meta{ 'http-equiv': 'refresh', content: "3; url=#{@redirect_url}" }
-
-.gl-text-center.gl-max-w-62.gl-mx-auto{ data: local_assigns.fetch(:data, {}) }
- .svg-content.svg-80
- = image_tag 'illustrations/success-sm.svg'
- %h2
- = s_('IdentityVerification|Verification successful')
- %p.gl-pt-2
- - redirect_url_start = ''.html_safe % { url: @redirect_url }
- - redirect_url_end = ''.html_safe
- = html_escape(s_("IdentityVerification|Your account has been successfully verified. You'll be redirected to your account in just a moment. You can also %{redirect_url_start}refresh the page%{redirect_url_end}.")) % { redirect_url_start: redirect_url_start, redirect_url_end: redirect_url_end }
+- if current_user.try(:onboarding_status_initial_registration_type) != "trial"
+ = render 'devise/sessions/successful_verification', local_assigns
+- else
+ - experiment(:lightweight_trial_registration_redesign, actor: current_user) do |e|
+ - e.control do
+ = render 'devise/sessions/successful_verification', local_assigns
+ - e.candidate do
+ = render 'devise/sessions/successful_verification_lightweight', local_assigns
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index ebfef15ee08..71207981fdd 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -17,7 +17,6 @@
projects_url: dashboard_projects_url,
parent_group_url: @project.parent && group_url(@project.parent),
parent_group_name: @project.parent&.name,
- project_help_path: help_page_path("user/project/_index.md"),
is_ci_cd_available: remote_mirror_setting_enabled?.to_s,
can_import_projects: params[:namespace_id].presence ? current_user.can?(:import_projects, @namespace).to_s : 'true',
import_sources_enabled: import_sources_enabled?.to_s,
@@ -56,7 +55,6 @@
has_errors: @project.errors.any?.to_s,
new_project_guidelines: brand_new_project_guidelines,
push_to_create_project_command: push_to_create_project_command,
- project_help_path: help_page_path("user/project/_index.md"),
root_path: root_path,
parent_group_url: @project.parent && group_url(@project.parent),
parent_group_name: @project.parent&.name,
diff --git a/app/workers/gitlab/counters/flush_stale_counter_increments_worker.rb b/app/workers/gitlab/counters/flush_stale_counter_increments_worker.rb
index f265312d936..38ba22f2a4b 100644
--- a/app/workers/gitlab/counters/flush_stale_counter_increments_worker.rb
+++ b/app/workers/gitlab/counters/flush_stale_counter_increments_worker.rb
@@ -28,17 +28,24 @@ module Gitlab
feature_category :continuous_integration
urgency :throttled
idempotent!
- deduplicate :until_executed
+ deduplicate :until_executing
sidekiq_options retry: true
def perform_work
return unless ::Gitlab.com_except_jh? # rubocop:disable Gitlab/AvoidGitlabInstanceChecks -- we need to check on which instance this happens
- ID_RANGES.each do |model, attributes|
- min_id = start_id(model)
- last_id = flush_stale_for_model(model, min_id, attributes[:end_id])
- # we need to add +1 here, because otherwise, we'd process the last record twice.
- update_start_id(model, last_id + 1)
+ # Process up to 100 batches per job execution as a compromise between
+ # performance (avoiding too many small jobs) and efficiency (preventing
+ # jobs from running too long and potentially timing out)
+ 100.times do
+ ID_RANGES.each do |model, attributes|
+ min_id = start_id(model)
+ remaining_work = [(attributes[:end_id] - min_id), 0].max
+ last_id = flush_stale_for_model(model, min_id, attributes[:end_id])
+ # we need to add +1 here, because otherwise, we'd process the last record twice.
+ update_start_id(model, last_id + 1)
+ return if remaining_work == 0 # rubocop:disable Lint/NonLocalExitFromIterator -- return if we don't have anymore work to do
+ end
end
end
diff --git a/config/feature_flags/beta/migrate_user_access_tokens_ui.yml b/config/feature_flags/beta/migrate_user_access_tokens_ui.yml
index 32d13fc0ca7..527032ded22 100644
--- a/config/feature_flags/beta/migrate_user_access_tokens_ui.yml
+++ b/config/feature_flags/beta/migrate_user_access_tokens_ui.yml
@@ -7,4 +7,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/538388
milestone: '18.0'
group: group::authentication
type: beta
-default_enabled: false
+default_enabled: true
diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb
index 198203ab208..38a960ba5dd 100644
--- a/config/initializers/doorkeeper.rb
+++ b/config/initializers/doorkeeper.rb
@@ -173,7 +173,9 @@ Doorkeeper.configure do
expires_in: configuration.device_code_expires_in,
scopes: scopes.to_s,
user_code: generate_user_code,
- organization_id: Organizations::Organization::DEFAULT_ORGANIZATION_ID
+ # This will result in a fallback to Default Organizzation
+ # OAuth device grant flow doesn't support other organizations yet
+ organization_id: Gitlab::Current::Organization.new.organization.id
}
end
end
diff --git a/lib/gitlab/tracking/ai_tracking.rb b/lib/gitlab/tracking/ai_tracking.rb
deleted file mode 100644
index 648347f5e4d..00000000000
--- a/lib/gitlab/tracking/ai_tracking.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Tracking
- class AiTracking
- def self.track_event(*args, **kwargs)
- new.track_event(*args, **kwargs)
- end
-
- def self.track_user_activity(*args)
- new.track_user_activity(*args)
- end
-
- def track_event(_event_name, **_context_hash)
- # no-op for CE
- end
-
- def track_user_activity(_user)
- # no-op for CE
- end
- end
- end
-end
-
-Gitlab::Tracking::AiTracking.prepend_mod
diff --git a/spec/frontend/projects/new/components/new_project_push_tip_popover_spec.js b/spec/frontend/projects/new/components/new_project_push_tip_popover_spec.js
index e4fe5678ebd..4e37e6c1683 100644
--- a/spec/frontend/projects/new/components/new_project_push_tip_popover_spec.js
+++ b/spec/frontend/projects/new/components/new_project_push_tip_popover_spec.js
@@ -8,7 +8,6 @@ describe('New project push tip popover', () => {
let wrapper;
const targetId = 'target';
const pushToCreateProjectCommand = 'command';
- const projectHelpPath = 'path';
const findPopover = () => wrapper.findComponent(GlPopover);
const findClipboardButton = () => wrapper.findComponent(ClipboardButton);
@@ -27,7 +26,6 @@ describe('New project push tip popover', () => {
},
provide: {
pushToCreateProjectCommand,
- projectHelpPath,
},
});
};
@@ -74,8 +72,6 @@ describe('New project push tip popover', () => {
});
it('displays a link to open the push command help page reference', () => {
- expect(findHelpLink().attributes().href).toBe(
- `${projectHelpPath}#create-a-new-project-with-git-push`,
- );
+ expect(findHelpLink().attributes().href).toBe('/help/topics/git/project.md');
});
});
diff --git a/spec/frontend/ref/format_refs_spec.js b/spec/frontend/ref/format_refs_spec.js
index 592978766b9..a2a94050674 100644
--- a/spec/frontend/ref/format_refs_spec.js
+++ b/spec/frontend/ref/format_refs_spec.js
@@ -13,9 +13,9 @@ import {
describe('formatListBoxItems', () => {
const FORMATTED_SELECTED = {
text: DEFAULT_I18N.selected,
- options: [{ text: 'main', value: 'main', default: undefined, protected: undefined }],
+ options: [{ text: 'selected', value: 'selected', default: undefined, protected: undefined }],
};
- const selected = { name: 'main', value: 'main' };
+ const selected = { name: 'selected', value: 'selected' };
it.each`
branches | tags | commits | selectedRef | expectedResult
diff --git a/spec/lib/gitlab/tracking/event_definition_spec.rb b/spec/lib/gitlab/tracking/event_definition_spec.rb
index 5ea2f5a3c77..7fcc6eec733 100644
--- a/spec/lib/gitlab/tracking/event_definition_spec.rb
+++ b/spec/lib/gitlab/tracking/event_definition_spec.rb
@@ -144,6 +144,12 @@ RSpec.describe Gitlab::Tracking::EventDefinition, feature_category: :service_pin
end
describe '.extra_trackers' do
+ let(:dummy_tracking_class) { Class.new }
+
+ before do
+ stub_const('Gitlab::Tracking::DummyTracking', dummy_tracking_class)
+ end
+
it 'returns an empty hash when no extra tracking classes are set' do
expect(described_class.new(nil, {}).extra_trackers).to eq([])
end
@@ -153,7 +159,7 @@ RSpec.describe Gitlab::Tracking::EventDefinition, feature_category: :service_pin
extra_trackers:
[
{
- tracking_class: 'Gitlab::Tracking::AiTracking',
+ tracking_class: 'Gitlab::Tracking::DummyTracking',
protected_properties: { prop: { description: 'description' } }
}
]
@@ -161,7 +167,7 @@ RSpec.describe Gitlab::Tracking::EventDefinition, feature_category: :service_pin
config = attributes.merge(extra_trackers)
expect(described_class.new(nil, config).extra_trackers)
- .to eq({ Gitlab::Tracking::AiTracking => { protected_properties: [:prop] } })
+ .to eq({ dummy_tracking_class => { protected_properties: [:prop] } })
end
it 'returns the hash with extra tracking class with empty array when props are not set' do
@@ -169,14 +175,14 @@ RSpec.describe Gitlab::Tracking::EventDefinition, feature_category: :service_pin
extra_trackers:
[
{
- tracking_class: 'Gitlab::Tracking::AiTracking'
+ tracking_class: 'Gitlab::Tracking::DummyTracking'
}
]
}
config = attributes.merge(extra_trackers)
expect(described_class.new(nil, config).extra_trackers)
- .to eq({ Gitlab::Tracking::AiTracking => { protected_properties: [] } })
+ .to eq({ dummy_tracking_class => { protected_properties: [] } })
end
end
diff --git a/spec/requests/api/ml_model_packages_spec.rb b/spec/requests/api/ml_model_packages_spec.rb
index 96434756e1e..f0748fddb2b 100644
--- a/spec/requests/api/ml_model_packages_spec.rb
+++ b/spec/requests/api/ml_model_packages_spec.rb
@@ -13,8 +13,10 @@ RSpec.describe ::API::MlModelPackages, feature_category: :mlops do
let_it_be(:project, reload: true) { create(:project) }
let_it_be(:personal_access_token) { create(:personal_access_token) }
let_it_be(:job) { create(:ci_build, :running, user: personal_access_token.user, project: project) }
- let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
- let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
+ let_it_be(:deploy_token) do
+ create(:deploy_token, read_package_registry: true, write_package_registry: true, projects: [project])
+ end
+
let_it_be(:another_project, reload: true) { create(:project) }
let_it_be(:model) { create(:ml_models, user: project.owner, project: project) }
let_it_be(:model_version) { create(:ml_model_versions, :with_package, model: model, version: '0.1.0') }
diff --git a/spec/requests/api/oauth_tokens_spec.rb b/spec/requests/api/oauth_tokens_spec.rb
index 139180d7873..8263bf4b81a 100644
--- a/spec/requests/api/oauth_tokens_spec.rb
+++ b/spec/requests/api/oauth_tokens_spec.rb
@@ -5,7 +5,11 @@ require 'spec_helper'
RSpec.describe 'OAuth tokens', feature_category: :system_access do
include HttpBasicAuthHelpers
- let_it_be(:organization) { create(:organization, :default) }
+ let_it_be(:organization) { create(:organization) }
+
+ before do
+ stub_current_organization(organization)
+ end
context 'Resource Owner Password Credentials' do
def request_oauth_token(user, headers = {}, password = user.password)
diff --git a/spec/requests/oauth/flows/device_grant_spec.rb b/spec/requests/oauth/flows/device_grant_spec.rb
index 2e91727d8d9..33ec7bb3019 100644
--- a/spec/requests/oauth/flows/device_grant_spec.rb
+++ b/spec/requests/oauth/flows/device_grant_spec.rb
@@ -2,8 +2,8 @@
require 'spec_helper'
-RSpec.describe 'Gitlab OAuth2 Device Authorization Grant', feature_category: :system_access do
- let_it_be(:organization) { create(:organization, :default) }
+RSpec.describe 'Gitlab OAuth2 Device Authorization Grant', :with_current_organization, feature_category: :system_access do
+ let_it_be(:organization) { current_organization }
let_it_be(:application) { create(:oauth_application, redirect_uri: 'urn:ietf:wg:oauth:2.0:oob', confidential: false) }
let_it_be(:user) { create(:user, :with_namespace, organizations: [organization]) }
let_it_be(:client_id) { application.uid }
diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb
index 18acc56ff7b..91c0e901493 100644
--- a/spec/services/ci/register_job_service_spec.rb
+++ b/spec/services/ci/register_job_service_spec.rb
@@ -9,8 +9,8 @@ module Ci
let_it_be_with_reload(:pipeline) { create(:ci_pipeline, project: project) }
let_it_be(:shared_runner) { create(:ci_runner, :instance) }
- let!(:project_runner) { create(:ci_runner, :project, projects: [project]) }
- let!(:group_runner) { create(:ci_runner, :group, groups: [group]) }
+ let_it_be_with_reload(:project_runner) { create(:ci_runner, :project, projects: [project]) }
+ let_it_be_with_reload(:group_runner) { create(:ci_runner, :group, groups: [group]) }
let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
describe '#execute' do
@@ -463,9 +463,11 @@ module Ci
context 'when first build is stalled' do
before do
- allow_any_instance_of(described_class).to receive(:assign_runner!).and_call_original
- allow_any_instance_of(described_class).to receive(:assign_runner!)
- .with(pending_job, anything).and_raise(ActiveRecord::StaleObjectError)
+ allow_next_instance_of(described_class) do |instance|
+ allow(instance).to receive(:assign_runner!).and_call_original
+ allow(instance).to receive(:assign_runner!)
+ .with(pending_job, anything).and_raise(ActiveRecord::StaleObjectError)
+ end
end
subject { described_class.new(project_runner, nil).execute }
@@ -474,9 +476,10 @@ module Ci
let!(:other_build) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
before do
- allow_any_instance_of(::Ci::Queue::BuildQueueService)
- .to receive(:execute)
- .and_return(Ci::Build.where(id: [pending_job, other_build]).pluck(:id, :partition_id))
+ allow_next_instance_of(::Ci::Queue::BuildQueueService) do |instance|
+ allow(instance).to receive(:execute)
+ .and_return(Ci::Build.where(id: [pending_job, other_build]).pluck(:id, :partition_id))
+ end
end
it "receives second build from the queue" do
@@ -487,9 +490,10 @@ module Ci
context 'when single build is in queue' do
before do
- allow_any_instance_of(::Ci::Queue::BuildQueueService)
- .to receive(:execute)
- .and_return(Ci::Build.where(id: pending_job).pluck(:id, :partition_id))
+ allow_next_instance_of(::Ci::Queue::BuildQueueService) do |instance|
+ allow(instance).to receive(:execute)
+ .and_return(Ci::Build.where(id: pending_job).pluck(:id, :partition_id))
+ end
end
it "does not receive any valid result" do
@@ -499,9 +503,10 @@ module Ci
context 'when there is no build in queue' do
before do
- allow_any_instance_of(::Ci::Queue::BuildQueueService)
- .to receive(:execute)
- .and_return([])
+ allow_next_instance_of(::Ci::Queue::BuildQueueService) do |instance|
+ allow(instance).to receive(:execute)
+ .and_return([])
+ end
end
it "does not receive builds but result is valid" do
@@ -893,6 +898,66 @@ module Ci
end
end
end
+
+ context 'when metrics recording fails' do
+ before do
+ project.update!(shared_runners_enabled: true)
+ pending_job.reload.create_queuing_entry!
+
+ allow_next_instance_of(::Gitlab::Ci::Queue::Metrics) do |metric|
+ allow(metric).to receive(:register_success).and_raise(StandardError, 'metrics failure')
+ end
+ end
+
+ it 'continues assignment when register_success fails' do
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
+ .with(
+ instance_of(StandardError),
+ hash_including(
+ build_id: pending_job.id,
+ build_name: pending_job.name,
+ build_stage: pending_job.stage_name,
+ pipeline_id: pending_job.pipeline_id,
+ project_id: pending_job.project_id
+ )
+ )
+
+ result = described_class.new(shared_runner, nil).execute
+
+ expect(result).to be_valid
+ expect(result.build).to eq(pending_job)
+ expect(result.build_json).to be_present
+ expect(pending_job.reload).to be_running
+ end
+
+ it 'continues assignment when observe_queue_depth fails' do
+ allow_next_instance_of(::Gitlab::Ci::Queue::Metrics) do |metric|
+ allow(metric).to receive(:register_success).and_call_original
+ allow(metric).to receive(:observe_queue_depth)
+ .with(:found, anything)
+ .and_raise(StandardError, 'queue depth metrics failure')
+ end
+
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
+ .with(
+ instance_of(StandardError),
+ hash_including(
+ build_id: pending_job.id,
+ build_name: pending_job.name,
+ build_stage: pending_job.stage_name,
+ pipeline_id: pending_job.pipeline_id,
+ project_id: pending_job.project_id
+ )
+ )
+
+ result = described_class.new(shared_runner, nil).execute
+
+ expect(result).to be_valid
+ expect(result.build).to eq(pending_job)
+ expect(result.build_json).to be_present
+ expect(pending_job.reload).to be_running
+ end
+ end
end
context 'when using pending builds table' do
@@ -1137,6 +1202,25 @@ module Ci
expect(result.build).to be_nil
expect(result.build_json).to be_nil
end
+
+ context 'when metrics tracking raises an error during conflict' do
+ let(:error) { StandardError.new('Metrics tracking failed') }
+
+ before do
+ allow_next_instance_of(Gitlab::Ci::Queue::Metrics) do |metric|
+ allow(metric).to receive(:observe_queue_depth).with(:conflict, any_args).and_raise(error)
+ end
+ end
+
+ it 'tracks and raises the exception for dev without affecting the result' do
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception).with(error)
+
+ result = described_class.new(project_runner, nil).execute
+
+ expect(result).not_to be_valid
+ expect(result.build).to be_nil
+ end
+ end
end
def build_on(runner, runner_manager: nil, params: {})
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 7ccdf9f166e..1b32198cb31 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -224,6 +224,7 @@ RSpec.configure do |config|
config.include_context 'when rendered has no HTML escapes', type: :view
config.include_context 'with STI disabled', type: :model
+ include StubCurrentOrganization
include StubFeatureFlags
include StubSnowplow
include StubMember
diff --git a/spec/support/helpers/current_organization_helper.rb b/spec/support/helpers/current_organization_helper.rb
new file mode 100644
index 00000000000..b87555f67e4
--- /dev/null
+++ b/spec/support/helpers/current_organization_helper.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module StubCurrentOrganization
+ def stub_current_organization(organization)
+ allow_next_instance_of(Gitlab::Current::Organization) do |instance|
+ allow(instance).to receive(:organization).and_return(organization)
+ end
+ end
+end
diff --git a/spec/support/shared_contexts/current_organization_context.rb b/spec/support/shared_contexts/current_organization_context.rb
index 227e6a97647..92381eaa5fd 100644
--- a/spec/support/shared_contexts/current_organization_context.rb
+++ b/spec/support/shared_contexts/current_organization_context.rb
@@ -8,9 +8,7 @@ RSpec.shared_context 'with current_organization setting' do
end
before do
- allow_next_instance_of(::Gitlab::Current::Organization) do |organization|
- allow(organization).to receive(:organization).and_return(current_organization)
- end
+ stub_current_organization(current_organization)
end
end
diff --git a/spec/support/shared_contexts/requests/api/conan_packages_shared_context.rb b/spec/support/shared_contexts/requests/api/conan_packages_shared_context.rb
index bf87671f591..16f0e28dff5 100644
--- a/spec/support/shared_contexts/requests/api/conan_packages_shared_context.rb
+++ b/spec/support/shared_contexts/requests/api/conan_packages_shared_context.rb
@@ -8,11 +8,7 @@ RSpec.shared_context 'with conan api setup' do
let_it_be(:user) { create(:user, developer_of: [project]) }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
let_it_be(:deploy_token) do
- create(:deploy_token, read_package_registry: true, write_package_registry: true)
- end
-
- let_it_be(:project_deploy_token, freeze: true) do
- create(:project_deploy_token, deploy_token: deploy_token, project: project)
+ create(:deploy_token, read_package_registry: true, write_package_registry: true, projects: [project])
end
let_it_be(:job, freeze: true) { create(:ci_build, :running, user: user, project: project) }
diff --git a/spec/workers/gitlab/counters/flush_stale_counter_increments_cron_worker_spec.rb b/spec/workers/gitlab/counters/flush_stale_counter_increments_cron_worker_spec.rb
index a478b51af74..42d44292a66 100644
--- a/spec/workers/gitlab/counters/flush_stale_counter_increments_cron_worker_spec.rb
+++ b/spec/workers/gitlab/counters/flush_stale_counter_increments_cron_worker_spec.rb
@@ -9,7 +9,6 @@ RSpec.describe ::Gitlab::Counters::FlushStaleCounterIncrementsCronWorker, featur
context 'when we are on gitlab.com' do
before do
allow(Gitlab).to receive(:com_except_jh?).and_return(true)
- allow(::Gitlab::Counters::FlushStaleCounterIncrementsWorker).to receive(:perform_with_capacity)
end
it 'calls FlushStaleCounterIncrementsWorker.perform_with_capacity' do
diff --git a/spec/workers/gitlab/counters/flush_stale_counter_increments_worker_spec.rb b/spec/workers/gitlab/counters/flush_stale_counter_increments_worker_spec.rb
index af42f475aa6..773aa1ac323 100644
--- a/spec/workers/gitlab/counters/flush_stale_counter_increments_worker_spec.rb
+++ b/spec/workers/gitlab/counters/flush_stale_counter_increments_worker_spec.rb
@@ -78,18 +78,26 @@ RSpec.describe ::Gitlab::Counters::FlushStaleCounterIncrementsWorker, :saas, :cl
before do
Gitlab::Redis::SharedState.with do |redis|
redis.set(redis_key, project_daily_statistic.id)
+ stub_const("#{described_class}::ID_RANGES", { ProjectDailyStatistic => {
+ end_id: project_daily_statistic_three.id
+ } })
+ stub_const("#{described_class}::BATCH_LIMIT", 1)
end
- allow(Gitlab::Saas).to receive(:feature_available?).with(:purchases_additional_minutes).and_return(true)
end
it "flushes stale counters and updates the redis start id" do
Gitlab::Redis::SharedState.with do |redis|
expect(redis.get(redis_key).to_i).to eq(project_daily_statistic.id)
end
+
+ # Test that the service is called multiple times (batching behavior)
+ # without running the full 100 iterations, and verify early termination
+ # when no more work is available
+
expect_next_instance_of(Gitlab::Counters::FlushStaleCounterIncrements) do |service|
expect(service).to receive(:execute)
.and_call_original
- end
+ end.thrice
expect_initial_counts
worker.perform_work