Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-12-14 09:09:56 +00:00
parent 671c8718a9
commit 3c0faf1c6b
26 changed files with 551 additions and 98 deletions

View File

@ -3,3 +3,20 @@ export default function initLogoAnimation() {
document.querySelector('.tanuki-logo')?.classList.add('animate');
});
}
export function initPortraitLogoDetection() {
const image = document.querySelector('.js-portrait-logo-detection');
image?.addEventListener(
'load',
({ currentTarget: img }) => {
const isPortrait = img.height > img.width;
if (isPortrait) {
// Limit the width when the logo has portrait format
img.classList.replace('gl-h-9', 'gl-w-10');
}
img.classList.remove('gl-visibility-hidden');
},
{ once: true },
);
}

View File

@ -22,7 +22,7 @@ import { getLocationHash, visitUrl, mergeUrlParams } from './lib/utils/url_utili
// everything else
import LazyLoader from './lazy_loader';
import initLogoAnimation from './logo';
import initLogoAnimation, { initPortraitLogoDetection } from './logo';
import initBreadcrumbs from './breadcrumb';
import initPersistentUserCallouts from './persistent_user_callouts';
import { initUserTracking, initDefaultTrackers } from './tracking';
@ -83,6 +83,7 @@ function deferredInitialisation() {
initBreadcrumbs();
initPrefetchLinks('.js-prefetch-document');
initLogoAnimation();
initPortraitLogoDetection();
initUserPopovers();
initBroadcastNotifications();
initPersistentUserCallouts();

View File

@ -44,7 +44,7 @@ module AppearancesHelper
end
def brand_image
image_tag(brand_image_path, alt: brand_title, class: 'gl-w-10')
image_tag(brand_image_path, alt: brand_title, class: 'gl-visibility-hidden gl-h-9 js-portrait-logo-detection')
end
def brand_image_path

View File

@ -16,10 +16,6 @@ class MergeRequestPolicy < IssuablePolicy
prevent :accept_merge_request
end
rule { can?(:read_merge_request) }.policy do
enable :generate_diff_summary
end
rule { can_approve }.policy do
enable :approve_merge_request
end
@ -47,10 +43,6 @@ class MergeRequestPolicy < IssuablePolicy
enable :set_merge_request_metadata
end
rule { llm_bot }.policy do
enable :generate_diff_summary
end
private
def can_approve?

View File

@ -65,7 +65,6 @@ module Groups
) do
Group.transaction do
update_group_attributes
remove_paid_features_for_projects(old_root_ancestor_id)
ensure_ownership
update_integrations
remove_issue_contacts(old_root_ancestor_id, was_root_group)
@ -74,6 +73,7 @@ module Groups
end
end
remove_paid_features_for_projects(old_root_ancestor_id)
post_update_hooks(@updated_project_ids, old_root_ancestor_id)
propagate_integrations
update_pending_builds

View File

@ -131,8 +131,6 @@ module Projects
update_integrations
remove_paid_features
project.old_path_with_namespace = @old_path
update_repository_configuration(@new_path)
@ -143,6 +141,7 @@ module Projects
end
end
remove_paid_features
update_pending_builds
post_update_hooks(project, @old_group)

View File

@ -0,0 +1,12 @@
---
table_name: audit_events_streaming_http_instance_namespace_filters
classes:
- AuditEvents::Streaming::HTTP::Instance::NamespaceFilter
feature_categories:
- audit_events
description: Represents a group or project filter for instance-level custom http external audit event destinations.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/136959
milestone: '16.7'
gitlab_schema: gitlab_main_cell
sharding_key:
namespace_id: namespaces

View File

@ -0,0 +1,9 @@
---
migration_job_name: BackfillBranchProtectionNamespaceSetting
description: This migration back fills column default_branch_protection_defaults of namespace settings table
feature_category: source_code_management
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/136181
milestone: '16.7'
queued_migration_version: 20231107092912
finalize_after: '2024-01-23'
finalized_by: # version of the migration that ensured this bbm

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class CreateAuditEventsStreamingHttpInstanceNamespaceFilters < Gitlab::Database::Migration[2.2]
milestone '16.7'
enable_lock_retries!
UNIQ_DESTINATION_INDEX_NAME = 'unique_audit_events_instance_namespace_filters_destination_id'
NAMESPACE_INDEX_NAME = 'index_audit_events_instance_namespace_filters_on_namespace_id'
def change
create_table :audit_events_streaming_http_instance_namespace_filters do |t|
t.timestamps_with_timezone null: false
t.bigint :audit_events_instance_external_audit_event_destination_id,
null: false,
index: { unique: true, name: UNIQ_DESTINATION_INDEX_NAME }
t.bigint :namespace_id,
null: false,
index: { name: NAMESPACE_INDEX_NAME }
end
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class AddDestinationFkToAuditEventsHttpInstanceNamespaceFilters < Gitlab::Database::Migration[2.2]
milestone '16.7'
disable_ddl_transaction!
def up
add_concurrent_foreign_key :audit_events_streaming_http_instance_namespace_filters,
:audit_events_instance_external_audit_event_destinations,
column: :audit_events_instance_external_audit_event_destination_id,
on_delete: :cascade
end
def down
with_lock_retries do
remove_foreign_key_if_exists :audit_events_streaming_http_instance_namespace_filters,
column: :audit_events_instance_external_audit_event_destination_id
end
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class AddNamespaceFkToAuditEventsHttpInstanceNamespaceFilters < Gitlab::Database::Migration[2.2]
milestone '16.7'
disable_ddl_transaction!
def up
add_concurrent_foreign_key :audit_events_streaming_http_instance_namespace_filters,
:namespaces,
column: :namespace_id,
on_delete: :cascade
end
def down
with_lock_retries do
remove_foreign_key_if_exists :audit_events_streaming_http_instance_namespace_filters,
column: :namespace_id
end
end
end

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
class QueueBackfillBranchProtectionNamespaceSetting < Gitlab::Database::Migration[2.2]
milestone "16.7"
MIGRATION = "BackfillBranchProtectionNamespaceSetting"
DELAY_INTERVAL = 2.minutes
BATCH_SIZE = 10_000
SUB_BATCH_SIZE = 100
disable_ddl_transaction!
restrict_gitlab_migration gitlab_schema: :gitlab_main
def up
queue_batched_background_migration(
MIGRATION,
:namespace_settings,
:namespace_id,
job_interval: DELAY_INTERVAL,
batch_size: BATCH_SIZE,
sub_batch_size: SUB_BATCH_SIZE
)
end
def down
delete_batched_background_migration(MIGRATION, :namespace_settings, :namespace_id, [])
end
end

View File

@ -0,0 +1 @@
f5bd273a05caa2cc662dc430cb2661321602e608054d6ef3f45dfc8cfacec152

View File

@ -0,0 +1 @@
3f8ea307440353cc193662c9c552609d09f7a58dd1d6acccb7208803f394329c

View File

@ -0,0 +1 @@
fce9aa43da310dbbcd7d0175f531ab069548d5cc782104ab8c83f20874cc3644

View File

@ -0,0 +1 @@
d5d599b967346e13f0cbdd909c33669d8a3268efc7744ca5749fab69e60ff606

View File

@ -12913,6 +12913,23 @@ CREATE SEQUENCE audit_events_streaming_http_group_namespace_filters_id_seq
ALTER SEQUENCE audit_events_streaming_http_group_namespace_filters_id_seq OWNED BY audit_events_streaming_http_group_namespace_filters.id;
CREATE TABLE audit_events_streaming_http_instance_namespace_filters (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
audit_events_instance_external_audit_event_destination_id bigint NOT NULL,
namespace_id bigint NOT NULL
);
CREATE SEQUENCE audit_events_streaming_http_instance_namespace_filters_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE audit_events_streaming_http_instance_namespace_filters_id_seq OWNED BY audit_events_streaming_http_instance_namespace_filters.id;
CREATE TABLE audit_events_streaming_instance_event_type_filters (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
@ -26354,6 +26371,8 @@ ALTER TABLE ONLY audit_events_streaming_headers ALTER COLUMN id SET DEFAULT next
ALTER TABLE ONLY audit_events_streaming_http_group_namespace_filters ALTER COLUMN id SET DEFAULT nextval('audit_events_streaming_http_group_namespace_filters_id_seq'::regclass);
ALTER TABLE ONLY audit_events_streaming_http_instance_namespace_filters ALTER COLUMN id SET DEFAULT nextval('audit_events_streaming_http_instance_namespace_filters_id_seq'::regclass);
ALTER TABLE ONLY audit_events_streaming_instance_event_type_filters ALTER COLUMN id SET DEFAULT nextval('audit_events_streaming_instance_event_type_filters_id_seq'::regclass);
ALTER TABLE ONLY authentication_events ALTER COLUMN id SET DEFAULT nextval('authentication_events_id_seq'::regclass);
@ -28212,6 +28231,9 @@ ALTER TABLE ONLY audit_events_streaming_headers
ALTER TABLE ONLY audit_events_streaming_http_group_namespace_filters
ADD CONSTRAINT audit_events_streaming_http_group_namespace_filters_pkey PRIMARY KEY (id);
ALTER TABLE ONLY audit_events_streaming_http_instance_namespace_filters
ADD CONSTRAINT audit_events_streaming_http_instance_namespace_filters_pkey PRIMARY KEY (id);
ALTER TABLE ONLY audit_events_streaming_instance_event_type_filters
ADD CONSTRAINT audit_events_streaming_instance_event_type_filters_pkey PRIMARY KEY (id);
@ -31867,6 +31889,8 @@ CREATE UNIQUE INDEX index_atlassian_identities_on_extern_uid ON atlassian_identi
CREATE UNIQUE INDEX index_audit_events_external_audit_on_verification_token ON audit_events_external_audit_event_destinations USING btree (verification_token);
CREATE INDEX index_audit_events_instance_namespace_filters_on_namespace_id ON audit_events_streaming_http_instance_namespace_filters USING btree (namespace_id);
CREATE INDEX index_audit_events_on_entity_id_and_entity_type_and_created_at ON ONLY audit_events USING btree (entity_id, entity_type, created_at, id);
CREATE INDEX index_authentication_events_on_provider ON authentication_events USING btree (provider);
@ -35421,6 +35445,8 @@ CREATE UNIQUE INDEX unique_audit_events_group_namespace_filters_destination_id O
CREATE UNIQUE INDEX unique_audit_events_group_namespace_filters_namespace_id ON audit_events_streaming_http_group_namespace_filters USING btree (namespace_id);
CREATE UNIQUE INDEX unique_audit_events_instance_namespace_filters_destination_id ON audit_events_streaming_http_instance_namespace_filters USING btree (audit_events_instance_external_audit_event_destination_id);
CREATE UNIQUE INDEX unique_batched_background_migrations_queued_migration_version ON batched_background_migrations USING btree (queued_migration_version);
CREATE UNIQUE INDEX unique_ci_builds_token_encrypted_and_partition_id ON ci_builds USING btree (token_encrypted, partition_id) WHERE (token_encrypted IS NOT NULL);
@ -37321,6 +37347,9 @@ ALTER TABLE ONLY users_star_projects
ALTER TABLE ONLY alert_management_alerts
ADD CONSTRAINT fk_2358b75436 FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE SET NULL;
ALTER TABLE ONLY audit_events_streaming_http_instance_namespace_filters
ADD CONSTRAINT fk_23f3ab7df0 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY import_failures
ADD CONSTRAINT fk_24b824da43 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
@ -37906,6 +37935,9 @@ ALTER TABLE ONLY identities
ALTER TABLE ONLY boards
ADD CONSTRAINT fk_ab0a250ff6 FOREIGN KEY (iteration_cadence_id) REFERENCES iterations_cadences(id) ON DELETE CASCADE;
ALTER TABLE ONLY audit_events_streaming_http_instance_namespace_filters
ADD CONSTRAINT fk_abe44125bc FOREIGN KEY (audit_events_instance_external_audit_event_destination_id) REFERENCES audit_events_instance_external_audit_event_destinations(id) ON DELETE CASCADE;
ALTER TABLE ONLY merge_requests
ADD CONSTRAINT fk_ad525e1f87 FOREIGN KEY (merge_user_id) REFERENCES users(id) ON DELETE SET NULL;

View File

@ -78,10 +78,10 @@ module CsvBuilder
def row(object)
attributes.map do |attribute|
if object.is_a?(Hash)
excel_sanitize(object[attribute])
elsif attribute.respond_to?(:call)
if attribute.respond_to?(:call)
excel_sanitize(attribute.call(object))
elsif object.is_a?(Hash)
excel_sanitize(object[attribute])
else
excel_sanitize(object.public_send(attribute)) # rubocop:disable GitlabSecurity/PublicSend
end

View File

@ -1,18 +1,19 @@
# frozen_string_literal: true
RSpec.describe CsvBuilder do
let(:object) { double(question: :answer) }
let(:csv_data) { subject.render }
let(:header_to_value_hash) do
{ 'Q & A' => :question, 'Reversed' => ->(o) { o.question.to_s.reverse } }
end
let(:subject) do
described_class.new(
enumerable, 'Q & A' => :question, 'Reversed' => ->(o) { o.question.to_s.reverse })
described_class.new(enumerable, **header_to_value_hash)
end
shared_examples 'csv builder examples' do
let(:items) { [object] }
it "has a version number" do
it 'has a version number' do
expect(CsvBuilder::Version::VERSION).not_to be nil
end
@ -45,30 +46,6 @@ RSpec.describe CsvBuilder do
end
end
describe 'truncation' do
let(:big_object) { double(question: 'Long' * 1024) }
let(:row_size) { big_object.question.length * 2 }
let(:items) { [big_object, big_object, big_object] }
it 'occurs after given number of bytes' do
expect(subject.render(row_size * 2).length).to be_between(row_size * 2, row_size * 3)
expect(subject).to be_truncated
expect(subject.rows_written).to eq 2
end
it 'is ignored by default' do
expect(subject.render.length).to be > row_size * 3
expect(subject.rows_written).to eq 3
end
it 'causes rows_expected to fall back to .count' do
subject.render(0)
expect(enumerable).to receive(:count).and_call_original
expect(subject.rows_expected).to eq 3
end
end
it 'avoids loading all data in a single query' do
expect(enumerable).to receive(:find_each)
@ -83,42 +60,61 @@ RSpec.describe CsvBuilder do
expect(csv_data).to include 'answer'
end
it 'allows lamdas to look up more complicated data' do
it 'allows lambdas to look up more complicated data' do
expect(csv_data).to include 'rewsna'
end
end
describe 'excel sanitization' do
let(:dangerous_title) { double(title: "=cmd|' /C calc'!A0 title", description: "*safe_desc") }
let(:dangerous_desc) { double(title: "*safe_title", description: "=cmd|' /C calc'!A0 desc") }
let(:items) { [dangerous_title, dangerous_desc] }
let(:subject) { described_class.new(enumerable, 'Title' => 'title', 'Description' => 'description') }
let(:csv_data) { subject.render }
shared_examples 'csv builder with truncation ability' do
let(:items) { [big_object, big_object, big_object] }
let(:row_size) { question_value.length * 2 }
it 'sanitizes dangerous characters at the beginning of a column' do
expect(csv_data).to include "'=cmd|' /C calc'!A0 title"
expect(csv_data).to include "'=cmd|' /C calc'!A0 desc"
end
it 'occurs after given number of bytes' do
expect(subject.render(row_size * 2).length).to be_between(row_size * 2, row_size * 3)
expect(subject).to be_truncated
expect(subject.rows_written).to eq 2
end
it 'does not sanitize safe symbols at the beginning of a column' do
expect(csv_data).not_to include "'*safe_desc"
expect(csv_data).not_to include "'*safe_title"
end
it 'is ignored by default' do
expect(subject.render.length).to be > row_size * 3
expect(subject.rows_written).to eq 3
end
context 'when dangerous characters are after a line break' do
let(:items) { [double(title: "Safe title", description: "With task list\n-[x] todo 1")] }
it 'causes rows_expected to fall back to .count' do
subject.render(0)
it 'does not append single quote to description' do
builder = described_class.new(enumerable, 'Title' => 'title', 'Description' => 'description')
expect(enumerable).to receive(:count).and_call_original
expect(subject.rows_expected).to eq 3
end
end
csv_data = builder.render
shared_examples 'excel sanitization' do
let(:dangerous_title) { double(title: "=cmd|' /C calc'!A0 title", description: "*safe_desc") }
let(:dangerous_desc) { double(title: "*safe_title", description: "=cmd|' /C calc'!A0 desc") }
let(:header_to_value_hash) { { 'Title' => 'title', 'Description' => 'description' } }
let(:items) { [dangerous_title, dangerous_desc] }
expect(csv_data).to eq("Title,Description\nSafe title,\"With task list\n-[x] todo 1\"\n")
end
it 'sanitizes dangerous characters at the beginning of a column' do
expect(csv_data).to include "'=cmd|' /C calc'!A0 title"
expect(csv_data).to include "'=cmd|' /C calc'!A0 desc"
end
it 'does not sanitize safe symbols at the beginning of a column' do
expect(csv_data).not_to include "'*safe_desc"
expect(csv_data).not_to include "'*safe_title"
end
context 'when dangerous characters are after a line break' do
let(:items) { [double(title: "Safe title", description: "With task list\n-[x] todo 1")] }
it 'does not append single quote to description' do
expect(csv_data).to eq("Title,Description\nSafe title,\"With task list\n-[x] todo 1\"\n")
end
end
end
context 'when ActiveRecord::Relation like object is given' do
let(:object) { double(question: :answer) }
let(:enumerable) { described_class::FakeRelation.new(items) }
before do
@ -132,11 +128,43 @@ RSpec.describe CsvBuilder do
end
it_behaves_like 'csv builder examples'
it_behaves_like 'excel sanitization'
it_behaves_like 'csv builder with truncation ability' do
let(:big_object) { double(question: 'Long' * 1024) }
let(:question_value) { big_object.question }
end
end
context 'when Enumerable like object is given' do
let(:object) { double(question: :answer) }
let(:enumerable) { items }
it_behaves_like 'csv builder examples'
it_behaves_like 'excel sanitization'
it_behaves_like 'csv builder with truncation ability' do
let(:big_object) { double(question: 'Long' * 1024) }
let(:question_value) { big_object.question }
end
end
context 'when Hash object is given' do
let(:object) { { question: :answer } }
let(:enumerable) { items }
let(:header_to_value_hash) do
{ 'Q & A' => :question, 'Reversed' => ->(o) { o[:question].to_s.reverse } }
end
it_behaves_like 'csv builder examples'
it_behaves_like 'excel sanitization' do
let(:dangerous_title) { { title: "=cmd|' /C calc'!A0 title", description: "*safe_desc" } }
let(:dangerous_desc) { { title: "*safe_title", description: "=cmd|' /C calc'!A0 desc" } }
let(:header_to_value_hash) { { 'Title' => :title, 'Description' => :description } }
end
it_behaves_like 'csv builder with truncation ability' do
let(:big_object) { { question: 'Long' * 1024 } }
let(:question_value) { big_object[:question] }
end
end
end

View File

@ -0,0 +1,135 @@
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# This class is used to update the default_branch_protection_defaults column
# for user namespaces of the namespace_settings table.
class BackfillBranchProtectionNamespaceSetting < BatchedMigrationJob
operation_name :set_default_branch_protection_defaults
feature_category :source_code_management
# Migration only version of `namespaces` table
class Namespace < ::ApplicationRecord
self.table_name = 'namespaces'
self.inheritance_column = :_type_disabled
has_one :namespace_setting,
class_name: '::Gitlab::BackgroundMigration::BackfillDefaultBranchProtectionNamespaceSetting::NamespaceSetting'
end
# Migration only version of `namespace_settings` table
class NamespaceSetting < ::ApplicationRecord
self.table_name = 'namespace_settings'
belongs_to :namespace,
class_name: '::Gitlab::BackgroundMigration::BackfillDefaultBranchProtectionNamespaceSetting::Namespace'
end
# Migration only version of Gitlab::Access:BranchProtection application code.
class BranchProtection
attr_reader :level
def initialize(level)
@level = level
end
PROTECTION_NONE = 0
PROTECTION_DEV_CAN_PUSH = 1
PROTECTION_FULL = 2
PROTECTION_DEV_CAN_MERGE = 3
PROTECTION_DEV_CAN_INITIAL_PUSH = 4
DEVELOPER = 30
MAINTAINER = 40
def to_hash
case level
when PROTECTION_NONE
self.class.protection_none
when PROTECTION_DEV_CAN_PUSH
self.class.protection_partial
when PROTECTION_FULL
self.class.protected_fully
when PROTECTION_DEV_CAN_MERGE
self.class.protected_against_developer_pushes
when PROTECTION_DEV_CAN_INITIAL_PUSH
self.class.protected_after_initial_push
end
end
class << self
def protection_none
{
allowed_to_push: [{ 'access_level' => Gitlab::Access::DEVELOPER }],
allowed_to_merge: [{ 'access_level' => Gitlab::Access::DEVELOPER }],
allow_force_push: true
}
end
def protection_partial
{
allowed_to_push: [{ 'access_level' => Gitlab::Access::DEVELOPER }],
allowed_to_merge: [{ 'access_level' => Gitlab::Access::MAINTAINER }],
allow_force_push: false
}
end
def protected_fully
{
allowed_to_push: [{ 'access_level' => Gitlab::Access::MAINTAINER }],
allowed_to_merge: [{ 'access_level' => Gitlab::Access::MAINTAINER }],
allow_force_push: false
}
end
def protected_against_developer_pushes
{
allowed_to_push: [{ 'access_level' => Gitlab::Access::MAINTAINER }],
allowed_to_merge: [{ 'access_level' => Gitlab::Access::DEVELOPER }],
allow_force_push: false
}
end
def protected_after_initial_push
{
allowed_to_push: [{ 'access_level' => Gitlab::Access::MAINTAINER }],
allowed_to_merge: [{ 'access_level' => Gitlab::Access::MAINTAINER }],
allow_force_push: false,
developer_can_initial_push: true
}
end
end
end
def perform
each_sub_batch do |sub_batch|
update_default_protection_branch_defaults(sub_batch)
end
end
private
def update_default_protection_branch_defaults(batch)
namespace_settings = NamespaceSetting.where(namespace_id: batch.pluck(:namespace_id)).includes(:namespace)
values_list = namespace_settings.map do |namespace_setting|
level = namespace_setting.namespace.default_branch_protection.to_i
value = BranchProtection.new(level).to_hash.to_json
"(#{namespace_setting.namespace_id}, '#{value}'::jsonb)"
end.join(", ")
sql = <<~SQL
WITH new_values (namespace_id, default_branch_protection_defaults) AS (
VALUES
#{values_list}
)
UPDATE namespace_settings
SET default_branch_protection_defaults = new_values.default_branch_protection_defaults
FROM new_values
WHERE namespace_settings.namespace_id = new_values.namespace_id;
SQL
connection.execute(sql)
end
end
end
end

View File

@ -646,7 +646,8 @@ module QA
def events(comments, label_events, state_events, milestone_events)
mapped_label_events = label_events.map { |event| event_mapping["label_#{event[:action]}"] }
mapped_milestone_events = milestone_events.map { |event| event_mapping["milestone_#{event[:action]}"] }
mapped_state_event = state_events.map { |event| event[:state] }
# merged events are fetched through comments so duplicates need to be removed
mapped_state_event = state_events.map { |event| event[:state] }.reject { |state| state == "merged" }
mapped_comment_events = comments.map do |c|
event_mapping[c[:body].match(event_pattern)&.named_captures&.fetch("event", nil)]
end

View File

@ -785,6 +785,13 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
ensure_no_tabs
end
it 'renders logo', :js do
visit new_user_session_path
image = find('img.js-portrait-logo-detection')
expect(image['class']).to include('gl-h-9')
end
it 'renders link to sign up path' do
visit new_user_session_path

View File

@ -0,0 +1,55 @@
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import { initPortraitLogoDetection } from '~/logo';
describe('initPortraitLogoDetection', () => {
let img;
const loadImage = () => {
const loadEvent = new Event('load');
img.dispatchEvent(loadEvent);
};
beforeEach(() => {
setHTMLFixture('<img class="gl-visibility-hidden gl-h-9 js-portrait-logo-detection" />');
initPortraitLogoDetection();
img = document.querySelector('img');
});
afterEach(() => {
resetHTMLFixture();
});
describe('when logo does not have portrait format', () => {
beforeEach(() => {
img.height = 10;
img.width = 10;
});
it('removes gl-visibility-hidden', () => {
expect(img.classList).toContain('gl-visibility-hidden');
expect(img.classList).toContain('gl-h-9');
loadImage();
expect(img.classList).not.toContain('gl-visibility-hidden');
expect(img.classList).toContain('gl-h-9');
});
});
describe('when logo has portrait format', () => {
beforeEach(() => {
img.height = 11;
img.width = 10;
});
it('removes gl-visibility-hidden', () => {
expect(img.classList).toContain('gl-visibility-hidden');
expect(img.classList).toContain('gl-h-9');
loadImage();
expect(img.classList).not.toContain('gl-visibility-hidden');
expect(img.classList).toContain('gl-w-10');
});
});
});

View File

@ -0,0 +1,76 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::BackfillBranchProtectionNamespaceSetting,
feature_category: :source_code_management do
let(:namespaces_table) { table(:namespaces) }
let(:namespace_settings_table) { table(:namespace_settings) }
let(:group_namespace) do
namespaces_table.create!(name: 'group_namespace', path: 'path-1', type: 'Group', default_branch_protection: 0)
end
let(:user_namespace) do
namespaces_table.create!(name: 'user_namespace', path: 'path-2', type: 'User', default_branch_protection: 1)
end
let(:user_three_namespace) do
namespaces_table.create!(name: 'user_three_namespace', path: 'path-3', type: 'User', default_branch_protection: 2)
end
let(:group_four_namespace) do
namespaces_table.create!(name: 'group_four_namespace', path: 'path-4', type: 'Group', default_branch_protection: 3)
end
let(:group_five_namespace) do
namespaces_table.create!(name: 'group_five_namespace', path: 'path-5', type: 'Group', default_branch_protection: 4)
end
let(:start_id) { group_namespace.id }
let(:end_id) { group_five_namespace.id }
subject(:perform_migration) do
described_class.new(
start_id: start_id,
end_id: end_id,
batch_table: :namespace_settings,
batch_column: :namespace_id,
sub_batch_size: 2,
pause_ms: 0,
connection: ActiveRecord::Base.connection
).perform
end
before do
namespace_settings_table.create!(namespace_id: group_namespace.id, default_branch_protection_defaults: {})
namespace_settings_table.create!(namespace_id: user_namespace.id, default_branch_protection_defaults: {})
namespace_settings_table.create!(namespace_id: user_three_namespace.id, default_branch_protection_defaults: {})
namespace_settings_table.create!(namespace_id: group_four_namespace.id, default_branch_protection_defaults: {})
namespace_settings_table.create!(namespace_id: group_five_namespace.id, default_branch_protection_defaults: {})
end
it 'updates default_branch_protection_defaults to a correct value', :aggregate_failures do
expect(ActiveRecord::QueryRecorder.new { perform_migration }.count).to eq(16)
expect(migrated_attribute(group_namespace.id)).to eq({ "allow_force_push" => true,
"allowed_to_merge" => [{ "access_level" => 30 }],
"allowed_to_push" => [{ "access_level" => 30 }] })
expect(migrated_attribute(user_namespace.id)).to eq({ "allow_force_push" => false,
"allowed_to_merge" => [{ "access_level" => 40 }],
"allowed_to_push" => [{ "access_level" => 30 }] })
expect(migrated_attribute(user_three_namespace.id)).to eq({ "allow_force_push" => false,
"allowed_to_merge" => [{ "access_level" => 40 }],
"allowed_to_push" => [{ "access_level" => 40 }] })
expect(migrated_attribute(group_four_namespace.id)).to eq({ "allow_force_push" => false,
"allowed_to_merge" => [{ "access_level" => 30 }],
"allowed_to_push" => [{ "access_level" => 40 }] })
expect(migrated_attribute(group_five_namespace.id)).to eq({ "allow_force_push" => false,
"allowed_to_merge" => [{ "access_level" => 40 }],
"allowed_to_push" => [{ "access_level" => 40 }],
"developer_can_initial_push" => true })
end
def migrated_attribute(namespace_id)
namespace_settings_table.find(namespace_id).default_branch_protection_defaults
end
end

View File

@ -0,0 +1,26 @@
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe QueueBackfillBranchProtectionNamespaceSetting, feature_category: :database do
let!(:batched_migration) { described_class::MIGRATION }
it 'schedules a new batched migration' do
reversible_migration do |migration|
migration.before -> {
expect(batched_migration).not_to have_scheduled_batched_migration
}
migration.after -> {
expect(batched_migration).to have_scheduled_batched_migration(
table_name: :namespace_settings,
column_name: :namespace_id,
interval: described_class::DELAY_INTERVAL,
batch_size: described_class::BATCH_SIZE,
sub_batch_size: described_class::SUB_BATCH_SIZE
)
}
end
end
end

View File

@ -462,37 +462,6 @@ RSpec.describe MergeRequestPolicy do
end
end
context 'when enabling generate diff summary permission' do
let_it_be(:project) { create(:project) }
let_it_be(:mr) { create(:merge_request, target_project: project, source_project: project) }
let_it_be(:user) { create(:user) }
let(:policy) { permissions(user, mr) }
context 'when can read_merge_request' do
before do
project.add_developer(user)
end
it 'allows to generate_diff_summary' do
expect(policy).to be_allowed(:generate_diff_summary)
end
end
context 'when can not read_merge_request' do
it 'does not allow to generate_diff_summary' do
expect(policy).not_to be_allowed(:generate_diff_summary)
end
context 'and when is the LLM bot' do
let(:user) { create(:user, :llm_bot) }
it 'allows to generate_diff_summary' do
expect(policy).to be_allowed(:generate_diff_summary)
end
end
end
end
context 'when the author of the merge request is banned', feature_category: :insider_threat do
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create(:user, :admin) }