Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
e83b20c4f3
commit
f71f0f5307
25 changed files with 108 additions and 161 deletions
|
@ -1 +1 @@
|
|||
5aa9d4d29c49ebe427a4a895158e195725cda2da
|
||||
47335e9fa13b0185b9d479a9e8bffc535eed6a7c
|
||||
|
|
|
@ -1 +1 @@
|
|||
14.7.0
|
||||
14.7.1
|
||||
|
|
|
@ -12,6 +12,6 @@ export default class EditorExtension {
|
|||
}
|
||||
|
||||
get api() {
|
||||
return this.obj.provides?.();
|
||||
return this.obj.provides?.() || {};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -417,6 +417,7 @@ export default {
|
|||
}
|
||||
|
||||
this.isMakingRequest = true;
|
||||
this.editCommitMessage = false;
|
||||
|
||||
if (!useAutoMerge) {
|
||||
this.mr.transitionStateMachine({ transition: MERGE });
|
||||
|
@ -663,7 +664,11 @@ export default {
|
|||
<gl-sprintf v-else :message="mergeDisabledText" />
|
||||
</div>
|
||||
<template v-if="glFeatures.restructuredMrWidget">
|
||||
<div v-show="editCommitMessage" class="gl-w-full gl-order-n1">
|
||||
<div
|
||||
v-if="editCommitMessage"
|
||||
class="gl-w-full gl-order-n1"
|
||||
data-testid="edit_commit_message"
|
||||
>
|
||||
<ul
|
||||
:class="{
|
||||
'content-list': !glFeatures.restructuredMrWidget,
|
||||
|
|
|
@ -743,3 +743,14 @@ $tabs-holder-z-index: 250;
|
|||
grid-gap: 5%;
|
||||
}
|
||||
}
|
||||
|
||||
.container-fluid:not(.container-limited) {
|
||||
.detail-page-header,
|
||||
.detail-page-description,
|
||||
.merge-request-tabs-container {
|
||||
&.is-merge-request {
|
||||
@include gl-mx-auto;
|
||||
max-width: $fixed-layout-width - ($gl-padding * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ class ApplicationController < ActionController::Base
|
|||
include FlocOptOut
|
||||
include CheckRateLimit
|
||||
|
||||
before_action :limit_session_time, if: -> { !current_user }
|
||||
before_action :authenticate_user!, except: [:route_not_found]
|
||||
before_action :enforce_terms!, if: :should_enforce_terms?
|
||||
before_action :validate_user_service_ticket!
|
||||
|
@ -43,7 +44,6 @@ class ApplicationController < ActionController::Base
|
|||
# Make sure the `auth_user` is memoized so it can be logged, we do this after
|
||||
# all other before filters that could have set the user.
|
||||
before_action :auth_user
|
||||
before_action :limit_session_time, if: -> { !current_user }
|
||||
|
||||
prepend_around_action :set_current_context
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
.detail-page-description.py-2
|
||||
- if Feature.enabled?(:updated_mr_header, @project)
|
||||
- updated_mr_header = Feature.enabled?(:updated_mr_header, @project)
|
||||
|
||||
.detail-page-description.py-2{ class: "#{'is-merge-request' if updated_mr_header && !fluid_layout}" }
|
||||
- if updated_mr_header
|
||||
= render 'shared/issuable/status_box', issuable: @merge_request
|
||||
= merge_request_header(@project, @merge_request)
|
||||
- else
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
- can_reopen_merge_request = can?(current_user, :reopen_merge_request, @merge_request)
|
||||
- are_close_and_open_buttons_hidden = merge_request_button_hidden?(@merge_request, true) && merge_request_button_hidden?(@merge_request, false)
|
||||
- updated_mr_header_enabled = Feature.enabled?(:updated_mr_header, @project)
|
||||
- cache_key = [@project, @merge_request, can_update_merge_request, can_reopen_merge_request, are_close_and_open_buttons_hidden, current_user&.preferred_language, updated_mr_header_enabled]
|
||||
- cache_key = [@project, @merge_request, can_update_merge_request, can_reopen_merge_request, are_close_and_open_buttons_hidden, current_user&.preferred_language, "1.1-#{updated_mr_header_enabled}"]
|
||||
|
||||
= cache(cache_key, expires_in: 1.day) do
|
||||
- if @merge_request.closed_or_merged_without_fork?
|
||||
|
@ -13,7 +13,7 @@
|
|||
= c.body do
|
||||
= _('The source project of this merge request has been removed.')
|
||||
|
||||
.detail-page-header.border-bottom-0.pt-0.pb-0{ class: "#{'gl-display-block gl-md-display-flex!' if updated_mr_header_enabled}" }
|
||||
.detail-page-header.border-bottom-0.pt-0.pb-0{ class: "#{'gl-display-block gl-md-display-flex!' if updated_mr_header_enabled} #{'is-merge-request' if updated_mr_header_enabled && !fluid_layout}" }
|
||||
.detail-page-header-body
|
||||
- unless updated_mr_header_enabled
|
||||
= render "shared/issuable/status_box", issuable: @merge_request
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
.merge-request-details.issuable-details{ data: { id: @merge_request.project.id } }
|
||||
= render "projects/merge_requests/mr_box"
|
||||
.merge-request-tabs-holder{ class: ("js-tabs-affix" unless ENV['RAILS_ENV'] == 'test') }
|
||||
.merge-request-tabs-container
|
||||
.merge-request-tabs-container{ class: "#{'is-merge-request' if Feature.enabled?(:updated_mr_header, @project) && !fluid_layout}" }
|
||||
%ul.merge-request-tabs.nav-tabs.nav.nav-links
|
||||
= render "projects/merge_requests/tabs/tab", class: "notes-tab", qa_selector: "notes_tab" do
|
||||
= tab_link_for @merge_request, :show, force_link: @commit.present? do
|
||||
|
|
|
@ -1614,24 +1614,6 @@
|
|||
:weight: 1
|
||||
:idempotent: true
|
||||
:tags: []
|
||||
- :name: pipeline_cache:expire_job_cache
|
||||
:worker_name: ExpireJobCacheWorker
|
||||
:feature_category: :continuous_integration
|
||||
:has_external_dependencies:
|
||||
:urgency: :high
|
||||
:resource_boundary: :unknown
|
||||
:weight: 3
|
||||
:idempotent: true
|
||||
:tags: []
|
||||
- :name: pipeline_cache:expire_pipeline_cache
|
||||
:worker_name: ExpirePipelineCacheWorker
|
||||
:feature_category: :continuous_integration
|
||||
:has_external_dependencies:
|
||||
:urgency: :high
|
||||
:resource_boundary: :cpu
|
||||
:weight: 3
|
||||
:idempotent:
|
||||
:tags: []
|
||||
- :name: pipeline_creation:ci_external_pull_requests_create_pipeline
|
||||
:worker_name: Ci::ExternalPullRequests::CreatePipelineWorker
|
||||
:feature_category: :continuous_integration
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ExpireJobCacheWorker # rubocop:disable Scalability/IdempotentWorker
|
||||
include ApplicationWorker
|
||||
|
||||
data_consistency :delayed
|
||||
|
||||
sidekiq_options retry: 3
|
||||
include PipelineQueue
|
||||
|
||||
queue_namespace :pipeline_cache
|
||||
urgency :high
|
||||
idempotent!
|
||||
|
||||
def perform(job_id)
|
||||
job = CommitStatus.find_by_id(job_id)
|
||||
return unless job
|
||||
|
||||
job.expire_etag_cache!
|
||||
ExpirePipelineCacheWorker.perform_async(job.pipeline_id)
|
||||
end
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# rubocop: disable Scalability/IdempotentWorker
|
||||
class ExpirePipelineCacheWorker
|
||||
include ApplicationWorker
|
||||
|
||||
sidekiq_options retry: 3
|
||||
include PipelineQueue
|
||||
|
||||
queue_namespace :pipeline_cache
|
||||
urgency :high
|
||||
worker_resource_boundary :cpu
|
||||
data_consistency :delayed
|
||||
|
||||
# This worker _should_ be idempotent, but due to us moving this to data_consistency :delayed
|
||||
# and an ongoing incompatibility between the two switches, we need to disable this.
|
||||
# Uncomment once https://gitlab.com/gitlab-org/gitlab/-/issues/325291 is resolved
|
||||
# idempotent!
|
||||
|
||||
def perform(pipeline_id)
|
||||
pipeline = Ci::Pipeline.find_by_id(pipeline_id)
|
||||
return unless pipeline
|
||||
|
||||
Ci::ExpirePipelineCacheService.new.execute(pipeline)
|
||||
end
|
||||
end
|
||||
# rubocop:enable Scalability/IdempotentWorker
|
|
@ -329,8 +329,6 @@
|
|||
- 1
|
||||
- - pipeline_background
|
||||
- 1
|
||||
- - pipeline_cache
|
||||
- 3
|
||||
- - pipeline_creation
|
||||
- 4
|
||||
- - pipeline_default
|
||||
|
|
|
@ -357,7 +357,10 @@ To add seats to a subscription:
|
|||
|
||||
A payment receipt is emailed to you, which you can also access in the Customers Portal under [**View invoices**](https://customers.gitlab.com/receipts).
|
||||
|
||||
For subscriptions that use cloud licensing, the additional seats are reflected on your instance immediately and no further action is needed. If you're using a legacy license, you receive an updated license file. [Add this license](../../user/admin_area/license.md) to your instance to use it.
|
||||
If your subscription was activated with an activation code, the additional seats are reflected in
|
||||
your instance immediately. If you're using a license file, you receive an updated file.
|
||||
To add the seats, [add the license file](../../user/admin_area/license_file.md)
|
||||
to your instance.
|
||||
|
||||
### Renew a subscription
|
||||
|
||||
|
|
|
@ -6,6 +6,9 @@ module Gitlab
|
|||
class BaseDoorkeeperController < ActionController::Base
|
||||
include Gitlab::Allowable
|
||||
include EnforcesTwoFactorAuthentication
|
||||
include SessionsHelper
|
||||
|
||||
before_action :limit_session_time, if: -> { !current_user }
|
||||
|
||||
helper_method :can?
|
||||
end
|
||||
|
|
|
@ -9,3 +9,5 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
Gitlab::DeviseFailure.prepend_mod
|
||||
|
|
|
@ -195,22 +195,22 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
|||
},
|
||||
'high urgency CI queues' => {
|
||||
query: 'feature_category=continuous_integration&urgency=high',
|
||||
included_queues: %w(pipeline_cache:expire_job_cache pipeline_cache:expire_pipeline_cache),
|
||||
included_queues: %w(pipeline_default:ci_drop_pipeline),
|
||||
excluded_queues: %w(merge)
|
||||
},
|
||||
'CPU-bound high urgency CI queues' => {
|
||||
query: 'feature_category=continuous_integration&urgency=high&resource_boundary=cpu',
|
||||
included_queues: %w(pipeline_cache:expire_pipeline_cache),
|
||||
excluded_queues: %w(pipeline_cache:expire_job_cache merge)
|
||||
included_queues: %w(pipeline_default:ci_create_downstream_pipeline),
|
||||
excluded_queues: %w(pipeline_default:ci_drop_pipeline merge)
|
||||
},
|
||||
'CPU-bound high urgency non-CI queues' => {
|
||||
query: 'feature_category!=continuous_integration&urgency=high&resource_boundary=cpu',
|
||||
included_queues: %w(new_issue),
|
||||
excluded_queues: %w(pipeline_cache:expire_pipeline_cache)
|
||||
excluded_queues: %w(pipeline_default:ci_create_downstream_pipeline)
|
||||
},
|
||||
'CI and SCM queues' => {
|
||||
query: 'feature_category=continuous_integration|feature_category=source_code_management',
|
||||
included_queues: %w(pipeline_cache:expire_job_cache merge),
|
||||
included_queues: %w(pipeline_default:ci_drop_pipeline merge),
|
||||
excluded_queues: %w(mailers)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,10 +105,6 @@ RSpec.describe ApplicationController do
|
|||
|
||||
describe 'session expiration' do
|
||||
controller(described_class) do
|
||||
# The anonymous controller will report 401 and fail to run any actions.
|
||||
# Normally, GitLab will just redirect you to sign in.
|
||||
skip_before_action :authenticate_user!, only: :index
|
||||
|
||||
def index
|
||||
render html: 'authenticated'
|
||||
end
|
||||
|
|
|
@ -195,6 +195,24 @@ RSpec.describe Oauth::AuthorizationsController do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user is not signed in' do
|
||||
before do
|
||||
sign_out(user)
|
||||
end
|
||||
|
||||
it 'sets a lower session expiry and redirects to the sign in page' do
|
||||
subject
|
||||
|
||||
expect(request.env['rack.session.options'][:expire_after]).to eq(
|
||||
Settings.gitlab['unauthenticated_session_expire_delay']
|
||||
)
|
||||
|
||||
expect(request.session['user_return_to']).to eq("/oauth/authorize?#{params.to_query}")
|
||||
expect(response).to have_gitlab_http_status(:found)
|
||||
expect(response).to redirect_to(new_user_session_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
|
|
|
@ -49,6 +49,12 @@ export const SEConstExt = () => {
|
|||
};
|
||||
};
|
||||
|
||||
export const SEExtWithoutAPI = () => {
|
||||
return {
|
||||
extensionName: 'SEExtWithoutAPI',
|
||||
};
|
||||
};
|
||||
|
||||
export class SEWithSetupExt {
|
||||
static get extensionName() {
|
||||
return 'SEWithSetupExt';
|
||||
|
|
|
@ -54,6 +54,7 @@ describe('Editor Extension', () => {
|
|||
${helpers.SEClassExtension} | ${['shared', 'classExtMethod']}
|
||||
${helpers.SEFnExtension} | ${['fnExtMethod']}
|
||||
${helpers.SEConstExt} | ${['constExtMethod']}
|
||||
${helpers.SEExtWithoutAPI} | ${[]}
|
||||
`('correctly returns API for $definition', ({ definition, expectedKeys }) => {
|
||||
const extension = new EditorExtension({ definition });
|
||||
const expectedApi = Object.fromEntries(
|
||||
|
|
|
@ -87,7 +87,11 @@ const createReadyToMergeResponse = (customMr) => {
|
|||
});
|
||||
};
|
||||
|
||||
const createComponent = (customConfig = {}, mergeRequestWidgetGraphql = false) => {
|
||||
const createComponent = (
|
||||
customConfig = {},
|
||||
mergeRequestWidgetGraphql = false,
|
||||
restructuredMrWidget = false,
|
||||
) => {
|
||||
wrapper = shallowMount(ReadyToMerge, {
|
||||
localVue,
|
||||
propsData: {
|
||||
|
@ -97,6 +101,7 @@ const createComponent = (customConfig = {}, mergeRequestWidgetGraphql = false) =
|
|||
provide: {
|
||||
glFeatures: {
|
||||
mergeRequestWidgetGraphql,
|
||||
restructuredMrWidget,
|
||||
},
|
||||
},
|
||||
stubs: {
|
||||
|
@ -307,6 +312,20 @@ describe('ReadyToMerge', () => {
|
|||
},
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
readyToMergeResponseSpy = jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce(createReadyToMergeResponse({ squash: true, squashOnMerge: true }))
|
||||
.mockResolvedValue(
|
||||
createReadyToMergeResponse({
|
||||
squash: true,
|
||||
squashOnMerge: true,
|
||||
defaultMergeCommitMessage: '',
|
||||
defaultSquashCommitMessage: '',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle merge when pipeline succeeds', async () => {
|
||||
createComponent();
|
||||
|
||||
|
@ -379,6 +398,27 @@ describe('ReadyToMerge', () => {
|
|||
expect(params.should_remove_source_branch).toBeTruthy();
|
||||
expect(params.auto_merge_strategy).toBeUndefined();
|
||||
});
|
||||
|
||||
it('hides edit commit message', async () => {
|
||||
createComponent({}, true, true);
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
|
||||
jest.spyOn(wrapper.vm.service, 'merge').mockResolvedValue(response('success'));
|
||||
|
||||
await wrapper
|
||||
.findComponent('[data-testid="widget_edit_commit_message"]')
|
||||
.vm.$emit('input', true);
|
||||
|
||||
expect(wrapper.findComponent('[data-testid="edit_commit_message"]').exists()).toBe(true);
|
||||
|
||||
wrapper.vm.handleMergeButtonClick();
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(wrapper.findComponent('[data-testid="edit_commit_message"]').exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('initiateRemoveSourceBranchPolling', () => {
|
||||
|
|
|
@ -227,8 +227,6 @@ RSpec.describe 'Every Sidekiq worker' do
|
|||
'Epics::UpdateEpicsDatesWorker' => 3,
|
||||
'ErrorTrackingIssueLinkWorker' => 3,
|
||||
'Experiments::RecordConversionEventWorker' => 3,
|
||||
'ExpireJobCacheWorker' => 3,
|
||||
'ExpirePipelineCacheWorker' => 3,
|
||||
'ExportCsvWorker' => 3,
|
||||
'ExternalServiceReactiveCachingWorker' => 3,
|
||||
'FileHookWorker' => false,
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe ExpireJobCacheWorker do
|
||||
let_it_be(:pipeline) { create(:ci_empty_pipeline) }
|
||||
|
||||
let(:project) { pipeline.project }
|
||||
|
||||
describe '#perform' do
|
||||
context 'with a job in the pipeline' do
|
||||
let_it_be(:job) { create(:ci_build, pipeline: pipeline) }
|
||||
|
||||
let(:job_args) { job.id }
|
||||
|
||||
it_behaves_like 'an idempotent worker'
|
||||
|
||||
it_behaves_like 'worker with data consistency',
|
||||
described_class,
|
||||
data_consistency: :delayed
|
||||
end
|
||||
|
||||
context 'when there is no job in the pipeline' do
|
||||
it 'does not change the etag store' do
|
||||
expect(Gitlab::EtagCaching::Store).not_to receive(:new)
|
||||
|
||||
perform_multiple(non_existing_record_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,38 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe ExpirePipelineCacheWorker do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
|
||||
|
||||
subject { described_class.new }
|
||||
|
||||
describe '#perform' do
|
||||
it 'executes the service' do
|
||||
expect_next_instance_of(Ci::ExpirePipelineCacheService) do |instance|
|
||||
expect(instance).to receive(:execute).with(pipeline).and_call_original
|
||||
end
|
||||
|
||||
subject.perform(pipeline.id)
|
||||
end
|
||||
|
||||
it "doesn't do anything if the pipeline not exist" do
|
||||
expect_any_instance_of(Ci::ExpirePipelineCacheService).not_to receive(:execute)
|
||||
expect_any_instance_of(Gitlab::EtagCaching::Store).not_to receive(:touch)
|
||||
|
||||
subject.perform(617748)
|
||||
end
|
||||
|
||||
skip "with https://gitlab.com/gitlab-org/gitlab/-/issues/325291 resolved" do
|
||||
it_behaves_like 'an idempotent worker' do
|
||||
let(:job_args) { [pipeline.id] }
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'worker with data consistency',
|
||||
described_class,
|
||||
data_consistency: :delayed
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue