Add latest changes from gitlab-org/gitlab@master
@ -367,6 +367,7 @@ jest-with-fixtures vue3 mr:
|
|||||||
when: always
|
when: always
|
||||||
paths:
|
paths:
|
||||||
- junit_jest.xml
|
- junit_jest.xml
|
||||||
|
parallel: 1
|
||||||
script:
|
script:
|
||||||
- run_timed_command "yarn jest:ci:vue3-mr:with-fixtures"
|
- run_timed_command "yarn jest:ci:vue3-mr:with-fixtures"
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
14.38.0
|
14.39.0
|
||||||
|
@ -237,6 +237,7 @@ ul.related-merge-requests > li gl-emoji {
|
|||||||
right: var(--application-bar-right);
|
right: var(--application-bar-right);
|
||||||
width: auto;
|
width: auto;
|
||||||
top: $calc-application-header-height;
|
top: $calc-application-header-height;
|
||||||
|
max-width: calc(100vw - #{$super-sidebar-width});
|
||||||
}
|
}
|
||||||
|
|
||||||
.limit-container-width {
|
.limit-container-width {
|
||||||
|
@ -12,7 +12,7 @@ module LinkableItem
|
|||||||
include IssuableLink
|
include IssuableLink
|
||||||
|
|
||||||
included do
|
included do
|
||||||
validate :check_existing_parent_link
|
validate :check_existing_parent_link, on: :create
|
||||||
|
|
||||||
scope :for_source, ->(item) { where(source_id: item.id) }
|
scope :for_source, ->(item) { where(source_id: item.id) }
|
||||||
scope :for_target, ->(item) { where(target_id: item.id) }
|
scope :for_target, ->(item) { where(target_id: item.id) }
|
||||||
|
@ -17,7 +17,7 @@ module WorkItems
|
|||||||
validate :validate_cyclic_reference
|
validate :validate_cyclic_reference
|
||||||
validate :validate_max_children
|
validate :validate_max_children
|
||||||
validate :validate_confidentiality
|
validate :validate_confidentiality
|
||||||
validate :check_existing_related_link
|
validate :check_existing_related_link, on: :create
|
||||||
|
|
||||||
scope :for_parents, ->(parent_ids) { where(work_item_parent_id: parent_ids) }
|
scope :for_parents, ->(parent_ids) { where(work_item_parent_id: parent_ids) }
|
||||||
scope :for_children, ->(children_ids) { where(work_item: children_ids) }
|
scope :for_children, ->(children_ids) { where(work_item: children_ids) }
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# As discussed in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/148637#note_1850247875,
|
|
||||||
# Rails 7.1 introduces enqueue_all which is not covered in this patch.
|
|
||||||
# We deliver emails using the `deliver_later` method and it uses ActiveJob
|
# We deliver emails using the `deliver_later` method and it uses ActiveJob
|
||||||
# under the hood, which later processes the email via the defined ActiveJob adapter's `enqueue` method.
|
# under the hood, which later processes the email via the defined ActiveJob adapter's `enqueue` method.
|
||||||
# For GitLab, the ActiveJob adapter is Sidekiq (in development and production environments).
|
# For GitLab, the ActiveJob adapter is Sidekiq (in development and production environments).
|
||||||
|
#
|
||||||
# We need to set the following up to override the ActiveJob adapater
|
# We need to set the following up to override the ActiveJob adapater
|
||||||
# so as to ensure that mailer jobs are enqueued in a shard-aware manner.
|
# so as to ensure that mailer jobs are enqueued in a shard-aware manner.
|
||||||
|
|
||||||
@ -15,8 +14,18 @@ end
|
|||||||
module ActiveJob
|
module ActiveJob
|
||||||
module QueueAdapters
|
module QueueAdapters
|
||||||
module ActiveJobShardSupport
|
module ActiveJobShardSupport
|
||||||
|
if ::Gitlab.next_rails?
|
||||||
|
def enqueue_all(jobs)
|
||||||
|
Gitlab::SidekiqSharding::Router.route(ActionMailer::MailDeliveryJob) do
|
||||||
|
super(jobs)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
%i[enqueue enqueue_at].each do |name|
|
%i[enqueue enqueue_at].each do |name|
|
||||||
define_method(name) do |*args|
|
define_method(name) do |*args|
|
||||||
|
return super(*args) if ::Gitlab.next_rails?
|
||||||
|
|
||||||
Gitlab::SidekiqSharding::Router.route(ActionMailer::MailDeliveryJob) do
|
Gitlab::SidekiqSharding::Router.route(ActionMailer::MailDeliveryJob) do
|
||||||
super(*args)
|
super(*args)
|
||||||
end
|
end
|
||||||
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 18 KiB |
@ -11,7 +11,25 @@ module Gitlab
|
|||||||
# so we only need to patch 1 method.
|
# so we only need to patch 1 method.
|
||||||
def perform_async(*args)
|
def perform_async(*args)
|
||||||
# rubocop:disable Gitlab/ModuleWithInstanceVariables -- @klass is present in the class we are patching
|
# rubocop:disable Gitlab/ModuleWithInstanceVariables -- @klass is present in the class we are patching
|
||||||
Gitlab::SidekiqSharding::Router.route(@klass) do
|
|
||||||
|
route_with_klass = @klass
|
||||||
|
|
||||||
|
# If an ActiveJob JobWrapper is pushed, check the arg hash's job_class for routing decisions.
|
||||||
|
#
|
||||||
|
# See https://github.com/rails/rails/blob/v7.1.0/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb#L21
|
||||||
|
# `job.serialize` would return a hash containing `job_class` set in
|
||||||
|
# https://github.com/rails/rails/blob/v7.1.0/activejob/lib/active_job/core.rb#L110
|
||||||
|
#
|
||||||
|
# In the GitLab Rails application, this only applies to ActionMailer::MailDeliveryJob
|
||||||
|
# but routing using the `job_class` keeps the option of using ActiveJob available for us.
|
||||||
|
#
|
||||||
|
if @klass == ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper &&
|
||||||
|
args.first.is_a?(Hash) &&
|
||||||
|
args.first['job_class']
|
||||||
|
route_with_klass = args.first['job_class'].to_s.safe_constantize
|
||||||
|
end
|
||||||
|
|
||||||
|
Gitlab::SidekiqSharding::Router.route(route_with_klass) do
|
||||||
# rubocop:enable Gitlab/ModuleWithInstanceVariables
|
# rubocop:enable Gitlab/ModuleWithInstanceVariables
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
@ -30,8 +30,7 @@ namespace :gitlab do
|
|||||||
File.open("config.yml", "w+") { |f| f.puts config.to_yaml }
|
File.open("config.yml", "w+") { |f| f.puts config.to_yaml }
|
||||||
|
|
||||||
[
|
[
|
||||||
%w[bin/install],
|
%w[make make_necessary_dirs build]
|
||||||
%w[make build]
|
|
||||||
].each do |cmd|
|
].each do |cmd|
|
||||||
unless Kernel.system(*cmd)
|
unless Kernel.system(*cmd)
|
||||||
raise "command failed: #{cmd.join(' ')}"
|
raise "command failed: #{cmd.join(' ')}"
|
||||||
|
@ -249,7 +249,7 @@
|
|||||||
"yaml": "^2.0.0-10"
|
"yaml": "^2.0.0-10"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@gitlab/eslint-plugin": "19.6.1",
|
"@gitlab/eslint-plugin": "20.0.0",
|
||||||
"@gitlab/stylelint-config": "6.2.1",
|
"@gitlab/stylelint-config": "6.2.1",
|
||||||
"@graphql-eslint/eslint-plugin": "3.20.1",
|
"@graphql-eslint/eslint-plugin": "3.20.1",
|
||||||
"@originjs/vite-plugin-commonjs": "^1.0.3",
|
"@originjs/vite-plugin-commonjs": "^1.0.3",
|
||||||
|
@ -168,6 +168,66 @@ RSpec.describe WorkItems::ParentLink, feature_category: :portfolio_management do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when parent is already linked' do
|
||||||
|
shared_examples 'invalid link' do |link_factory|
|
||||||
|
let_it_be(:parent_link) { build(:parent_link, work_item_parent: issue, work_item: task1) }
|
||||||
|
let(:error_msg) { 'cannot assign a linked work item as a parent' }
|
||||||
|
|
||||||
|
context 'when creating new link' do
|
||||||
|
context 'when parent is the link target' do
|
||||||
|
before do
|
||||||
|
create(link_factory, source_id: task1.id, target_id: issue.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it do
|
||||||
|
expect(parent_link).not_to be_valid
|
||||||
|
expect(parent_link.errors[:work_item]).to include(error_msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when parent is the link source' do
|
||||||
|
before do
|
||||||
|
create(link_factory, source_id: issue.id, target_id: task1.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it do
|
||||||
|
expect(parent_link).not_to be_valid
|
||||||
|
expect(parent_link.errors[:work_item]).to include(error_msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when updating existing link' do
|
||||||
|
context 'when parent is the link target' do
|
||||||
|
before do
|
||||||
|
create(link_factory, source_id: task1.id, target_id: issue.id)
|
||||||
|
parent_link.save!(validate: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it do
|
||||||
|
expect(parent_link).to be_valid
|
||||||
|
expect(parent_link.errors[:work_item]).not_to include(error_msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when parent is the link source' do
|
||||||
|
before do
|
||||||
|
create(link_factory, source_id: issue.id, target_id: task1.id)
|
||||||
|
parent_link.save!(validate: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it do
|
||||||
|
expect(parent_link).to be_valid
|
||||||
|
expect(parent_link.errors[:work_item]).not_to include(error_msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'invalid link', :work_item_link
|
||||||
|
it_behaves_like 'invalid link', :issue_link
|
||||||
|
end
|
||||||
|
|
||||||
context 'when setting confidentiality' do
|
context 'when setting confidentiality' do
|
||||||
using RSpec::Parameterized::TableSyntax
|
using RSpec::Parameterized::TableSyntax
|
||||||
|
|
||||||
@ -191,38 +251,6 @@ RSpec.describe WorkItems::ParentLink, feature_category: :portfolio_management do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when parent is already linked' do
|
|
||||||
shared_examples 'invalid link' do |link_factory|
|
|
||||||
let_it_be(:parent_link) { build(:parent_link, work_item_parent: issue, work_item: task1) }
|
|
||||||
let(:error_msg) { 'cannot assign a linked work item as a parent' }
|
|
||||||
|
|
||||||
context 'when parent is the link target' do
|
|
||||||
before do
|
|
||||||
create(link_factory, source_id: task1.id, target_id: issue.id)
|
|
||||||
end
|
|
||||||
|
|
||||||
it do
|
|
||||||
expect(parent_link).not_to be_valid
|
|
||||||
expect(parent_link.errors[:work_item]).to include(error_msg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when parent is the link source' do
|
|
||||||
before do
|
|
||||||
create(link_factory, source_id: issue.id, target_id: task1.id)
|
|
||||||
end
|
|
||||||
|
|
||||||
it do
|
|
||||||
expect(parent_link).not_to be_valid
|
|
||||||
expect(parent_link.errors[:work_item]).to include(error_msg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it_behaves_like 'invalid link', :work_item_link
|
|
||||||
it_behaves_like 'invalid link', :issue_link
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -8,34 +8,65 @@ RSpec.shared_examples 'includes LinkableItem concern' do
|
|||||||
subject(:link) { build(link_factory, source_id: source.id, target_id: target.id) }
|
subject(:link) { build(link_factory, source_id: source.id, target_id: target.id) }
|
||||||
|
|
||||||
describe '#check_existing_parent_link' do
|
describe '#check_existing_parent_link' do
|
||||||
shared_examples 'invalid due to existing link' do
|
context 'for new issuable link' do
|
||||||
it do
|
shared_examples 'invalid due to existing link' do
|
||||||
is_expected.to be_invalid
|
it do
|
||||||
expect(link.errors.messages[:source]).to include("is a parent or child of this #{item_type}")
|
is_expected.to be_invalid
|
||||||
|
expect(link.errors.messages[:source]).to include("is a parent or child of this #{item_type}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
context 'without existing link parent' do
|
context 'without existing link parent' do
|
||||||
let(:source) { issue }
|
|
||||||
let(:target) { task }
|
|
||||||
|
|
||||||
it 'is valid' do
|
|
||||||
is_expected.to be_valid
|
|
||||||
expect(link.errors).to be_empty
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with existing link parent' do
|
|
||||||
let_it_be(:relationship) { create(:parent_link, work_item_parent: issue, work_item: task) }
|
|
||||||
|
|
||||||
it_behaves_like 'invalid due to existing link' do
|
|
||||||
let(:source) { issue }
|
let(:source) { issue }
|
||||||
let(:target) { task }
|
let(:target) { task }
|
||||||
|
|
||||||
|
it 'is valid' do
|
||||||
|
is_expected.to be_valid
|
||||||
|
expect(link.errors).to be_empty
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'invalid due to existing link' do
|
context 'with existing link parent' do
|
||||||
|
let_it_be(:relationship) { create(:parent_link, work_item_parent: issue, work_item: task) }
|
||||||
|
|
||||||
|
it_behaves_like 'invalid due to existing link' do
|
||||||
|
let(:source) { issue }
|
||||||
|
let(:target) { task }
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'invalid due to existing link' do
|
||||||
|
let(:source) { task }
|
||||||
|
let(:target) { issue }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for existing issuable link with existing parent link' do
|
||||||
|
let(:link) { build(link_factory, source_id: source.id, target_id: target.id) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
create(:parent_link, work_item_parent: issue, work_item: task)
|
||||||
|
link.save!(validate: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when source is issue' do
|
||||||
|
let(:source) { issue }
|
||||||
|
let(:target) { task }
|
||||||
|
|
||||||
|
it 'is valid' do
|
||||||
|
expect(link).to be_valid
|
||||||
|
expect(link.errors).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when source is task' do
|
||||||
let(:source) { task }
|
let(:source) { task }
|
||||||
let(:target) { issue }
|
let(:target) { issue }
|
||||||
|
|
||||||
|
it 'is valid' do
|
||||||
|
expect(link).to be_valid
|
||||||
|
expect(link.errors).to be_empty
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -12,8 +12,7 @@ RSpec.describe 'gitlab:shell rake tasks', :silence_stdout do
|
|||||||
describe 'install task' do
|
describe 'install task' do
|
||||||
it 'installs and compiles gitlab-shell' do
|
it 'installs and compiles gitlab-shell' do
|
||||||
expect_any_instance_of(Gitlab::TaskHelpers).to receive(:checkout_or_clone_version)
|
expect_any_instance_of(Gitlab::TaskHelpers).to receive(:checkout_or_clone_version)
|
||||||
allow(Kernel).to receive(:system).with('bin/install').and_return(true)
|
allow(Kernel).to receive(:system).with('make', 'make_necessary_dirs', 'build').and_return(true)
|
||||||
allow(Kernel).to receive(:system).with('make', 'build').and_return(true)
|
|
||||||
|
|
||||||
run_rake_task('gitlab:shell:install')
|
run_rake_task('gitlab:shell:install')
|
||||||
end
|
end
|
||||||
|
@ -652,6 +652,46 @@ RSpec.describe ApplicationWorker, feature_category: :shared do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper' do
|
||||||
|
let(:worker) { ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper }
|
||||||
|
|
||||||
|
context 'when calling perform_async with setter' do
|
||||||
|
subject(:operation) { worker.set(testing: true).perform_async({ 'job_class' => ActionMailer::MailDeliveryJob }) }
|
||||||
|
|
||||||
|
it_behaves_like 'uses shard router'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when calling perform_async with setter without job_class' do
|
||||||
|
subject(:operation) { worker.set(testing: true).perform_async }
|
||||||
|
|
||||||
|
it_behaves_like 'uses shard router'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when calling perform_in with setter' do
|
||||||
|
subject(:operation) { worker.set(testing: true).perform_in(1, { 'job_class' => ActionMailer::MailDeliveryJob }) }
|
||||||
|
|
||||||
|
it_behaves_like 'uses shard router'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when calling perform_in with setter without job_class' do
|
||||||
|
subject(:operation) { worker.set(testing: true).perform_in(1) }
|
||||||
|
|
||||||
|
it_behaves_like 'uses shard router'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when calling perform_at with setter' do
|
||||||
|
subject(:operation) { worker.set(testing: true).perform_at(1, { 'job_class' => ActionMailer::MailDeliveryJob }) }
|
||||||
|
|
||||||
|
it_behaves_like 'uses shard router'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when calling perform_at with setter without job_class' do
|
||||||
|
subject(:operation) { worker.set(testing: true).perform_at(1) }
|
||||||
|
|
||||||
|
it_behaves_like 'uses shard router'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when calling perform_async with setter' do
|
context 'when calling perform_async with setter' do
|
||||||
subject(:operation) { worker.set(testing: true).perform_async }
|
subject(:operation) { worker.set(testing: true).perform_async }
|
||||||
|
|
||||||
|
@ -1310,10 +1310,10 @@
|
|||||||
core-js "^3.29.1"
|
core-js "^3.29.1"
|
||||||
mitt "^3.0.1"
|
mitt "^3.0.1"
|
||||||
|
|
||||||
"@gitlab/eslint-plugin@19.6.1":
|
"@gitlab/eslint-plugin@20.0.0":
|
||||||
version "19.6.1"
|
version "20.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-19.6.1.tgz#1e59cb0d83e2f8522945b1b5f01d1fc284b7e729"
|
resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-20.0.0.tgz#d451169692b3ee51e7e946f6b9cead3de5132a51"
|
||||||
integrity sha512-VA5eH9U6qr3PH24/hhwNKS4AF3jPB78ZaBmuQipGsn0DlyOqOdg2JnuX7C5tR4yM1D7uK2FcAdrW4AGovEQ7Xw==
|
integrity sha512-D/nScJCBqR5TMJkg5jpanhTIvrRVsWPohPUUhkHmCrjyXDjjZdZ3hkLZBF66tst0yENFDh6l5mtRVCzCIU5xdA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/eslint-plugin" "^7.14.1"
|
"@typescript-eslint/eslint-plugin" "^7.14.1"
|
||||||
eslint-config-airbnb-base "^15.0.0"
|
eslint-config-airbnb-base "^15.0.0"
|
||||||
|