Commit cfa0e2dc authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents 5541e08b 2cf8a20b
......@@ -55,7 +55,7 @@ class ProjectsFinder < UnionFinder
collection = Project.wrap_with_cte(collection) if use_cte
collection = filter_projects(collection)
if params[:sort] == 'similarity' && params[:search] && Feature.enabled?(:project_finder_similarity_sort, current_user)
if params[:sort] == 'similarity' && params[:search]
collection.sorted_by_similarity_desc(params[:search])
else
sort(collection)
......
......@@ -172,10 +172,6 @@ module IntegrationsHelper
name: integration.to_param
}
end
def show_service_templates_nav_link?
Feature.disabled?(:disable_service_templates, type: :development, default_enabled: :yaml)
end
end
IntegrationsHelper.prepend_mod_with('IntegrationsHelper')
......
......@@ -18,7 +18,7 @@ module Ci
.joins('LEFT JOIN project_features ON ci_builds.project_id = project_features.project_id')
.where('project_features.builds_access_level IS NULL or project_features.builds_access_level > 0')
if Feature.enabled?(:ci_queueing_disaster_recovery, runner, type: :ops, default_enabled: :yaml)
if Feature.enabled?(:ci_queueing_disaster_recovery_disable_fair_scheduling, runner, type: :ops, default_enabled: :yaml)
# if disaster recovery is enabled, we fallback to FIFO scheduling
relation.order('ci_builds.id ASC')
else
......
......@@ -18,7 +18,7 @@ module Ci
.joins('LEFT JOIN project_features ON ci_pending_builds.project_id = project_features.project_id')
.where('project_features.builds_access_level IS NULL or project_features.builds_access_level > 0')
if Feature.enabled?(:ci_queueing_disaster_recovery, runner, type: :ops, default_enabled: :yaml)
if Feature.enabled?(:ci_queueing_disaster_recovery_disable_fair_scheduling, runner, type: :ops, default_enabled: :yaml)
# if disaster recovery is enabled, we fallback to FIFO scheduling
relation.order('ci_pending_builds.build_id ASC')
else
......
......@@ -209,19 +209,6 @@
= render_if_exists 'layouts/nav/sidebar/credentials_link'
- if show_service_templates_nav_link?
= nav_link(controller: :services) do
= link_to admin_application_settings_services_path do
.nav-icon-container
= sprite_icon('template')
%span.nav-item-name
= _('Service Templates')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :services, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_application_settings_services_path do
%strong.fly-out-top-item-name
= _('Service Templates')
= nav_link(controller: :labels) do
= link_to admin_labels_path do
.nav-icon-container
......
---
name: disable_service_templates
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59098
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/327436
milestone: '13.12'
type: development
group: group::ecosystem
default_enabled: true
---
name: project_finder_similarity_sort
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43136
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/263249
milestone: '13.5'
type: development
group: group::threat insights
name: ci_queueing_disaster_recovery_disable_fair_scheduling
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56658
rollout_issue_url:
milestone: "13.12"
type: ops
group: group::pipeline execution
default_enabled: false
---
name: ci_queueing_disaster_recovery
name: ci_queueing_disaster_recovery_disable_quota
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56658
rollout_issue_url:
milestone: "13.12"
......
......@@ -10,7 +10,7 @@ type: reference
This document describes a feature that allows you to disable some important but computationally
expensive parts of the application to relieve stress on the database during an ongoing downtime.
## `ci_queueing_disaster_recovery`
## `ci_queueing_disaster_recovery_disable_fair_scheduling`
This feature flag, if temporarily enabled, disables fair scheduling on shared runners.
This can help to reduce system resource usage on the `jobs/request` endpoint
......@@ -20,6 +20,16 @@ Side effects:
- In case of a large backlog of jobs, the jobs are processed in the order
they were put in the system, instead of balancing the jobs across many projects.
## `ci_queueing_disaster_recovery_disable_quota`
This feature flag, if temporarily enabled, disables enforcing CI minutes quota
on shared runners. This can help to reduce system resource usage on the
`jobs/request` endpoint by significantly reducing the computations being
performed.
Side effects:
- Projects which are out of quota will be run. This affects
only jobs created during the last hour, as prior jobs are canceled
by a periodic background worker (`StuckCiJobsWorker`).
......@@ -30,6 +30,12 @@ const createPolicyFetchError = ({ gqlError, networkError }) => {
});
};
const getPoliciesWithType = (policies, policyType) =>
policies.map((policy) => ({
...policy,
policyType,
}));
export default {
components: {
GlTable,
......@@ -110,7 +116,10 @@ export default {
return setUrlFragment(this.documentationPath, 'container-network-policy');
},
policies() {
return [...this.networkPolicies, ...this.scanExecutionPolicies];
return [
...getPoliciesWithType(this.networkPolicies, s__('SecurityPolicies|Network')),
...getPoliciesWithType(this.scanExecutionPolicies, s__('SecurityPolicies|Scan execution')),
];
},
isLoadingPolicies() {
return (
......@@ -156,9 +165,15 @@ export default {
label: s__('NetworkPolicies|Name'),
thClass: 'gl-w-half',
},
{
key: 'policyType',
label: s__('SecurityPolicies|Policy type'),
sortable: true,
},
{
key: 'updatedAt',
label: s__('NetworkPolicies|Last modified'),
sortable: true,
},
];
// Adds column 'namespace' only while 'all environments' option is selected
......@@ -239,6 +254,9 @@ export default {
:busy="isLoadingPolicies"
:items="policies"
:fields="fields"
sort-icon-left
sort-by="updatedAt"
sort-desc
head-variant="white"
stacked="md"
thead-class="gl-text-gray-900 border-bottom"
......
......@@ -10,7 +10,7 @@ module EE
override :builds_for_shared_runner
def builds_for_shared_runner
# if disaster recovery is enabled, we disable quota
if ::Feature.enabled?(:ci_queueing_disaster_recovery, runner, type: :ops, default_enabled: :yaml)
if ::Feature.enabled?(:ci_queueing_disaster_recovery_disable_quota, runner, type: :ops, default_enabled: :yaml)
super
else
enforce_minutes_based_on_cost_factors(super)
......
......@@ -146,18 +146,27 @@ describe('PolicyList component', () => {
rows = wrapper.findAll('tr');
});
it.each`
rowIndex | expectedPolicyName
${1} | ${mockNetworkPoliciesResponse[0].name}
${2} | ${'drop-outbound'}
${3} | ${'allow-inbound-http'}
${4} | ${mockScanExecutionPoliciesResponse[0].name}
`(
'renders "$expectedPolicyName" policy in row #$rowIndex',
({ expectedPolicyName, rowIndex }) => {
expect(rows.at(rowIndex).text()).toContain(expectedPolicyName);
},
);
describe.each`
rowIndex | expectedPolicyName | expectedPolicyType
${1} | ${mockScanExecutionPoliciesResponse[0].name} | ${'Scan execution'}
${2} | ${mockNetworkPoliciesResponse[0].name} | ${'Network'}
${3} | ${'drop-outbound'} | ${'Network'}
${4} | ${'allow-inbound-http'} | ${'Network'}
`('policy in row #$rowIndex', ({ rowIndex, expectedPolicyName, expectedPolicyType }) => {
let row;
beforeEach(() => {
row = rows.at(rowIndex);
});
it(`renders ${expectedPolicyName} in the name cell`, () => {
expect(row.findAll('td').at(1).text()).toBe(expectedPolicyName);
});
it(`renders ${expectedPolicyType} in the policy type cell`, () => {
expect(row.findAll('td').at(2).text()).toBe(expectedPolicyType);
});
});
});
describe('status column', () => {
......@@ -166,7 +175,7 @@ describe('PolicyList component', () => {
});
it('renders a checkmark icon for enabled policies', () => {
const icon = findPolicyStatusCells().at(0).find('svg');
const icon = findPolicyStatusCells().at(1).find('svg');
expect(icon.exists()).toBe(true);
expect(icon.props('name')).toBe('check-circle-filled');
......@@ -174,7 +183,7 @@ describe('PolicyList component', () => {
});
it('renders a "Disabled" label for screen readers for disabled policies', () => {
const span = findPolicyStatusCells().at(1).find('span');
const span = findPolicyStatusCells().at(2).find('span');
expect(span.exists()).toBe(true);
expect(span.attributes('class')).toBe('gl-sr-only');
......@@ -190,7 +199,7 @@ describe('PolicyList component', () => {
it('renders namespace column', () => {
const namespaceHeader = findPoliciesTable().findAll('[role="columnheader"]').at(2);
expect(namespaceHeader.text()).toBe('Namespace');
expect(namespaceHeader.text()).toContain('Namespace');
});
});
......
......@@ -37,7 +37,7 @@ RSpec.describe Ci::RegisterJobService, '#execute' do
end
it 'when in disaster recovery it ignores quota and returns anyway' do
stub_feature_flags(ci_queueing_disaster_recovery: true)
stub_feature_flags(ci_queueing_disaster_recovery_disable_quota: true)
is_expected.to be_kind_of(Ci::Build)
end
......@@ -67,7 +67,7 @@ RSpec.describe Ci::RegisterJobService, '#execute' do
end
it 'when in disaster recovery it ignores quota and returns anyway' do
stub_feature_flags(ci_queueing_disaster_recovery: true)
stub_feature_flags(ci_queueing_disaster_recovery_disable_quota: true)
is_expected.to be_kind_of(Ci::Build)
end
......
......@@ -28841,6 +28841,12 @@ msgstr ""
msgid "SecurityPolicies|Latest scan"
msgstr ""
msgid "SecurityPolicies|Network"
msgstr ""
msgid "SecurityPolicies|Policy type"
msgstr ""
msgid "SecurityPolicies|Scan execution"
msgstr ""
......
......@@ -309,65 +309,6 @@ RSpec.describe 'Admin updates settings' do
end
end
context 'when Service Templates are enabled' do
before do
stub_feature_flags(disable_service_templates: false)
visit general_admin_application_settings_path
end
it 'shows Service Templates link' do
expect(page).to have_link('Service Templates')
end
context 'when the Slack Notifications Service template is active' do
before do
create(:service, :template, type: 'SlackService', active: true)
visit general_admin_application_settings_path
end
it 'change Slack Notifications Service template settings', :js do
first(:link, 'Service Templates').click
click_link 'Slack notifications'
fill_in 'Webhook', with: 'http://localhost'
fill_in 'Username', with: 'test_user'
fill_in 'service[push_channel]', with: '#test_channel'
page.check('Notify only broken pipelines')
page.select 'All branches', from: 'Branches to be notified'
page.select 'Match any of the labels', from: 'Labels to be notified behavior'
check_all_events
click_button 'Save changes'
expect(page).to have_content 'Application settings saved successfully'
click_link 'Slack notifications'
expect(page.all('input[type=checkbox]')).to all(be_checked)
expect(find_field('Webhook').value).to eq 'http://localhost'
expect(find_field('Username').value).to eq 'test_user'
expect(find('[name="service[push_channel]"]').value).to eq '#test_channel'
end
it 'defaults Deployment events to false for chat notification template settings', :js do
first(:link, 'Service Templates').click
click_link 'Slack notifications'
expect(find_field('Deployment')).not_to be_checked
end
end
end
context 'When Service templates are disabled' do
before do
stub_feature_flags(disable_service_templates: true)
end
it 'does not show Service Templates link' do
expect(page).not_to have_link('Service Templates')
end
end
context 'Integration page', :js do
before do
visit integrations_admin_application_settings_path
......
......@@ -31,10 +31,6 @@ RSpec.describe ProjectsFinder do
let(:use_cte) { true }
let(:finder) { described_class.new(params: params.merge(use_cte: use_cte), current_user: current_user, project_ids_relation: project_ids_relation) }
before do
stub_feature_flags(project_finder_similarity_sort: false)
end
subject { finder.execute }
shared_examples 'ProjectFinder#execute examples' do
......@@ -368,32 +364,28 @@ RSpec.describe ProjectsFinder do
end
describe 'sorting' do
let_it_be(:more_projects) do
[
create(:project, :internal, group: group, name: 'projA', path: 'projA'),
create(:project, :internal, group: group, name: 'projABC', path: 'projABC'),
create(:project, :internal, group: group, name: 'projAB', path: 'projAB')
]
end
context 'when sorting by a field' do
let(:params) { { sort: 'name_asc' } }
it { is_expected.to eq([internal_project, public_project]) }
it { is_expected.to eq(([internal_project, public_project] + more_projects).sort_by { |p| p[:name] }) }
end
context 'when sorting by similarity' do
let(:params) { { sort: 'similarity', search: 'pro' } }
let_it_be(:internal_project2) do
create(:project, :internal, group: group, name: 'projA', path: 'projA')
end
let_it_be(:internal_project3) do
create(:project, :internal, group: group, name: 'projABC', path: 'projABC')
end
let_it_be(:internal_project4) do
create(:project, :internal, group: group, name: 'projAB', path: 'projAB')
end
before do
stub_feature_flags(project_finder_similarity_sort: current_user)
end
it { is_expected.to eq([more_projects[0], more_projects[2], more_projects[1]]) }
end
it { is_expected.to eq([internal_project2, internal_project4, internal_project3]) }
context 'when no sort is provided' do
it { is_expected.to eq(([internal_project, public_project] + more_projects).sort_by { |p| p[:id] }.reverse) }
end
end
......
......@@ -27,10 +27,6 @@ RSpec.describe Resolvers::ProjectsResolver do
private_group.add_developer(user)
end
before do
stub_feature_flags(project_finder_similarity_sort: false)
end
context 'when user is not logged in' do
let(:current_user) { nil }
......@@ -83,6 +79,7 @@ RSpec.describe Resolvers::ProjectsResolver do
context 'when user is logged in' do
let(:current_user) { user }
let(:visible_projecs) { [project, other_project, group_project, private_project, private_group_project] }
context 'when no filters are applied' do
it 'returns all visible projects for the user' do
......@@ -129,21 +126,24 @@ RSpec.describe Resolvers::ProjectsResolver do
end
end
context 'when sort is similarity' do
context 'when sorting' do
let_it_be(:named_project1) { create(:project, :public, name: 'projAB', path: 'projAB') }
let_it_be(:named_project2) { create(:project, :public, name: 'projABC', path: 'projABC') }
let_it_be(:named_project3) { create(:project, :public, name: 'projA', path: 'projA') }
let_it_be(:named_projects) { [named_project1, named_project2, named_project3] }
let(:filters) { { search: 'projA', sort: 'similarity' } }
it 'returns projects in order of similarity to search' do
stub_feature_flags(project_finder_similarity_sort: current_user)
context 'when sorting by similarity' do
let(:filters) { { search: 'projA', sort: 'similarity' } }
is_expected.to eq([named_project3, named_project1, named_project2])
it 'returns projects in order of similarity to search' do
is_expected.to eq([named_project3, named_project1, named_project2])
end
end
it 'returns projects in any order if flag is off' do
is_expected.to match_array([named_project3, named_project1, named_project2])
context 'when no sort is provided' do
it 'returns projects in descending order by id' do
is_expected.to match_array((visible_projecs + named_projects).sort_by { |p| p[:id]}.reverse )
end
end
end
......
......@@ -145,7 +145,7 @@ module Ci
context 'when using DEFCON mode that disables fair scheduling' do
before do
stub_feature_flags(ci_queueing_disaster_recovery: true)
stub_feature_flags(ci_queueing_disaster_recovery_disable_fair_scheduling: true)
end
context 'when all builds are pending' do
......
......@@ -260,8 +260,9 @@ RSpec.configure do |config|
# tests, until we introduce it in user settings
stub_feature_flags(forti_token_cloud: false)
# This feature flag is by default disabled and used in disaster recovery mode
stub_feature_flags(ci_queueing_disaster_recovery: false)
# These feature flag are by default disabled and used in disaster recovery mode
stub_feature_flags(ci_queueing_disaster_recovery_disable_fair_scheduling: false)
stub_feature_flags(ci_queueing_disaster_recovery_disable_quota: false)
enable_rugged = example.metadata[:enable_rugged].present?
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment