Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
7e89568aa1
commit
6666461136
|
|
@ -1,25 +0,0 @@
|
|||
---
|
||||
# Cop supports --autocorrect.
|
||||
Layout/FirstArrayElementIndentation:
|
||||
Exclude:
|
||||
- 'spec/lib/gitlab/github_import/importer/issues_importer_spec.rb'
|
||||
- 'spec/lib/gitlab/search/found_blob_spec.rb'
|
||||
- 'spec/models/ci/runner_version_spec.rb'
|
||||
- 'spec/models/repository_spec.rb'
|
||||
- 'spec/requests/api/task_completion_status_spec.rb'
|
||||
- 'spec/services/security/merge_reports_service_spec.rb'
|
||||
- 'spec/simplecov_env.rb'
|
||||
- 'spec/support/atlassian/jira_connect/schemata.rb'
|
||||
- 'spec/support/capybara.rb'
|
||||
- 'spec/support/helpers/project_template_test_helper.rb'
|
||||
- 'spec/support/helpers/test_env.rb'
|
||||
- 'spec/support/helpers/usage_data_helpers.rb'
|
||||
- 'spec/support/matchers/exceed_query_limit.rb'
|
||||
- 'spec/support/migrations_helpers/vulnerabilities_findings_helper.rb'
|
||||
- 'spec/support/prometheus/additional_metrics_shared_examples.rb'
|
||||
- 'spec/support/shared_contexts/policies/group_policy_shared_context.rb'
|
||||
- 'spec/support/shared_examples/graphql/label_fields.rb'
|
||||
- 'spec/support/shared_examples/lib/gitlab/middleware/multipart_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/repository_storage_moves_shared_examples.rb'
|
||||
- 'spec/views/projects/issues/_related_branches.html.haml_spec.rb'
|
||||
- 'tooling/lib/tooling/helm3_client.rb'
|
||||
|
|
@ -1 +1 @@
|
|||
22722e29aa21a554ed1e729f9b23a485929ac4cf
|
||||
434051eb74b0043267538213192a790095caf671
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ export default {
|
|||
return {
|
||||
'gl-text-gray-500!': this.canUpdate && this.isNoMilestone,
|
||||
'is-not-focused': !this.isFocused,
|
||||
'gl-min-w-20': true,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
|
@ -214,9 +215,10 @@ export default {
|
|||
|
||||
<template>
|
||||
<gl-form-group
|
||||
class="work-item-dropdown"
|
||||
class="work-item-dropdown gl-flex-nowrap"
|
||||
:label="$options.i18n.MILESTONE"
|
||||
label-class="gl-pb-0! gl-overflow-wrap-break gl-mt-3"
|
||||
label-for="milestone-value"
|
||||
label-class="gl-pb-0! gl-mt-3 gl-overflow-wrap-break"
|
||||
label-cols="3"
|
||||
label-cols-lg="2"
|
||||
>
|
||||
|
|
@ -229,6 +231,8 @@ export default {
|
|||
</span>
|
||||
<gl-dropdown
|
||||
v-else
|
||||
id="milestone-value"
|
||||
class="col-9 gl-pl-0"
|
||||
:toggle-class="dropdownClasses"
|
||||
:text="dropdownText"
|
||||
:loading="updateInProgress"
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ module Import
|
|||
def authorize_url
|
||||
state = SecureRandom.base64(64)
|
||||
session[auth_state_key] = state
|
||||
session[:auth_on_failure_path] = "#{new_project_path}#import_project"
|
||||
if Feature.enabled?(:remove_legacy_github_client)
|
||||
oauth_client.auth_code.authorize_url(
|
||||
redirect_uri: callback_import_url,
|
||||
|
|
|
|||
|
|
@ -7,5 +7,9 @@ module Postgresql
|
|||
def fully_qualified_table_name
|
||||
"#{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}.#{table_name}"
|
||||
end
|
||||
|
||||
def table_schema
|
||||
Gitlab::Database::GitlabSchema.table_schema(table_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78991
|
|||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/350972
|
||||
milestone: '14.8'
|
||||
type: development
|
||||
group: group::authentication and authorization
|
||||
group: group::workspace
|
||||
default_enabled: false
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/11209
|
|||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/321404
|
||||
milestone: '11.11'
|
||||
type: development
|
||||
group: group::authentication and authorization
|
||||
group: group::workspace
|
||||
default_enabled: false
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78542
|
|||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/350637
|
||||
milestone: '14.8'
|
||||
type: development
|
||||
group: group::authentication and authorization
|
||||
group: group::workspace
|
||||
default_enabled: true
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/25
|
|||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/321407
|
||||
milestone: '11.11'
|
||||
type: development
|
||||
group: group::authentication and authorization
|
||||
group: group::workspace
|
||||
default_enabled: false
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79855
|
|||
rollout_issue_url:
|
||||
milestone: '14.8'
|
||||
type: ops
|
||||
group: 'group::authentication and authorization'
|
||||
group: 'group::workspace'
|
||||
default_enabled: true
|
||||
|
|
|
|||
|
|
@ -55,6 +55,22 @@ devise_scope :user do
|
|||
get '/users/almost_there' => 'confirmations#almost_there'
|
||||
post '/users/resend_verification_code', to: 'sessions#resend_verification_code'
|
||||
get '/users/successful_verification', to: 'sessions#successful_verification'
|
||||
|
||||
# Redirect on GitHub authorization request errors. E.g. it could happen when user:
|
||||
# 1. cancel authorization the GitLab OAuth app via GitHub to import GitHub repos
|
||||
# (they'll be redirected to /projects/new#import_project)
|
||||
# 2. cancel signing in to GitLab using GitHub account
|
||||
# (they'll be redirected to /users/sign_in)
|
||||
# In these cases, GitHub redirects user to the GitLab OAuth app's
|
||||
# registered callback URL - /users/auth, which is the url to the auth user's profile page
|
||||
get '/users/auth',
|
||||
constraints: ->(req) {
|
||||
req.params[:error].present? && req.params[:state].present?
|
||||
},
|
||||
to: redirect { |_params, req|
|
||||
redirect_path = req.session.delete(:auth_on_failure_path)
|
||||
redirect_path || Rails.application.routes.url_helpers.new_user_session_path
|
||||
}
|
||||
end
|
||||
|
||||
scope '-/users', module: :users do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddIndexAuthorIdCreatedAtOnMergeRequests < Gitlab::Database::Migration[2.0]
|
||||
INDEX_NAME = 'index_merge_requests_on_author_id_and_created_at'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_concurrent_index :merge_requests, %i[author_id created_at], name: INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name :merge_requests, INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
52294ac9fd807fdff49d918d6b49c071b53e683a479af6beef9449302080e44f
|
||||
|
|
@ -29844,6 +29844,8 @@ CREATE INDEX index_merge_requests_on_assignee_id ON merge_requests USING btree (
|
|||
|
||||
CREATE INDEX index_merge_requests_on_author_id ON merge_requests USING btree (author_id);
|
||||
|
||||
CREATE INDEX index_merge_requests_on_author_id_and_created_at ON merge_requests USING btree (author_id, created_at);
|
||||
|
||||
CREATE INDEX index_merge_requests_on_author_id_and_id ON merge_requests USING btree (author_id, id);
|
||||
|
||||
CREATE INDEX index_merge_requests_on_author_id_and_target_project_id ON merge_requests USING btree (author_id, target_project_id);
|
||||
|
|
|
|||
|
|
@ -10,18 +10,34 @@ module Gitlab
|
|||
# See https://www.postgresql.org/message-id/16934.1568989957%40sss.pgh.pa.us
|
||||
EXPECTED_TRIGGER_RECORD_COUNT = 3
|
||||
|
||||
def self.tables_to_lock(connection)
|
||||
Gitlab::Database::GitlabSchema.tables_to_schema.each do |table_name, schema_name|
|
||||
yield table_name, schema_name
|
||||
end
|
||||
|
||||
Gitlab::Database::SharedModel.using_connection(connection) do
|
||||
Postgresql::DetachedPartition.find_each do |detached_partition|
|
||||
yield detached_partition.fully_qualified_table_name, detached_partition.table_schema
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(table_name:, connection:, database_name:, logger: nil, dry_run: false)
|
||||
@table_name = table_name
|
||||
@connection = connection
|
||||
@database_name = database_name
|
||||
@logger = logger
|
||||
@dry_run = dry_run
|
||||
|
||||
@table_name_without_schema = ActiveRecord::ConnectionAdapters::PostgreSQL::Utils
|
||||
.extract_schema_qualified_name(table_name)
|
||||
.identifier
|
||||
end
|
||||
|
||||
def table_locked_for_writes?(table_name)
|
||||
query = <<~SQL
|
||||
SELECT COUNT(*) from information_schema.triggers
|
||||
WHERE event_object_table = '#{table_name}'
|
||||
WHERE event_object_table = '#{table_name_without_schema}'
|
||||
AND trigger_name = '#{write_trigger_name(table_name)}'
|
||||
SQL
|
||||
|
||||
|
|
@ -56,7 +72,7 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
attr_reader :table_name, :connection, :database_name, :logger, :dry_run
|
||||
attr_reader :table_name, :connection, :database_name, :logger, :dry_run, :table_name_without_schema
|
||||
|
||||
def execute_sql_statement(sql)
|
||||
if dry_run
|
||||
|
|
@ -99,7 +115,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def write_trigger_name(table_name)
|
||||
"gitlab_schema_write_trigger_for_#{table_name}"
|
||||
"gitlab_schema_write_trigger_for_#{table_name_without_schema}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,14 +27,31 @@ module Gitlab
|
|||
# it maps the tables to the tables that depend on it
|
||||
def tables_dependencies
|
||||
@tables.to_h do |table_name|
|
||||
[table_name, all_foreign_keys[table_name]&.map(&:from_table).to_a]
|
||||
[table_name, all_foreign_keys[table_name]]
|
||||
end
|
||||
end
|
||||
|
||||
def all_foreign_keys
|
||||
@all_foreign_keys ||= @tables.flat_map do |table_name|
|
||||
@connection.foreign_keys(table_name)
|
||||
end.group_by(&:to_table)
|
||||
@all_foreign_keys ||= @tables.each_with_object(Hash.new { |h, k| h[k] = [] }) do |table, hash|
|
||||
foreign_keys_for(table).each do |fk|
|
||||
hash[fk.to_table] << table
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def foreign_keys_for(table)
|
||||
# Detached partitions like gitlab_partitions_dynamic._test_gitlab_partition_20220101
|
||||
# store their foreign keys in the public schema.
|
||||
#
|
||||
# See spec/lib/gitlab/database/tables_sorted_by_foreign_keys_spec.rb
|
||||
# for an example
|
||||
name = ActiveRecord::ConnectionAdapters::PostgreSQL::Utils.extract_schema_qualified_name(table)
|
||||
|
||||
if name.schema == ::Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA.to_s
|
||||
@connection.foreign_keys(name.identifier)
|
||||
else
|
||||
@connection.foreign_keys(table)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -24,6 +24,14 @@ module Gitlab
|
|||
GITLAB_SCHEMAS_TO_IGNORE.union(schemas_for_connection).include?(schema_name)
|
||||
end.keys
|
||||
|
||||
Gitlab::Database::SharedModel.using_connection(connection) do
|
||||
Postgresql::DetachedPartition.find_each do |detached_partition|
|
||||
next if GITLAB_SCHEMAS_TO_IGNORE.union(schemas_for_connection).include?(detached_partition.table_schema)
|
||||
|
||||
tables_to_truncate << detached_partition.fully_qualified_table_name
|
||||
end
|
||||
end
|
||||
|
||||
tables_sorted = Gitlab::Database::TablesSortedByForeignKeys.new(connection, tables_to_truncate).execute
|
||||
# Checking if all the tables have the write-lock triggers
|
||||
# to make sure we are deleting the right tables on the right database.
|
||||
|
|
@ -66,7 +74,11 @@ module Gitlab
|
|||
truncated_tables = []
|
||||
|
||||
tables_sorted.flatten.each do |table|
|
||||
sql_statement = "SELECT set_config('lock_writes.#{table}', 'false', false)"
|
||||
table_name_without_schema = ActiveRecord::ConnectionAdapters::PostgreSQL::Utils
|
||||
.extract_schema_qualified_name(table)
|
||||
.identifier
|
||||
|
||||
sql_statement = "SELECT set_config('lock_writes.#{table_name_without_schema}', 'false', false)"
|
||||
logger&.info(sql_statement)
|
||||
connection.execute(sql_statement) unless dry_run
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ namespace :gitlab do
|
|||
task lock_writes: [:environment, 'gitlab:db:validate_config'] do
|
||||
Gitlab::Database::EachDatabase.each_database_connection(include_shared: false) do |connection, database_name|
|
||||
schemas_for_connection = Gitlab::Database.gitlab_schemas_for_connection(connection)
|
||||
Gitlab::Database::GitlabSchema.tables_to_schema.each do |table_name, schema_name|
|
||||
|
||||
Gitlab::Database::LockWritesManager.tables_to_lock(connection) do |table_name, schema_name|
|
||||
# TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/366834
|
||||
next if schema_name == :gitlab_geo
|
||||
|
||||
|
|
@ -30,7 +31,7 @@ namespace :gitlab do
|
|||
desc "GitLab | DB | Remove all triggers that prevents writes from all databases"
|
||||
task unlock_writes: :environment do
|
||||
Gitlab::Database::EachDatabase.each_database_connection do |connection, database_name|
|
||||
Gitlab::Database::GitlabSchema.tables_to_schema.each do |table_name, schema_name|
|
||||
Gitlab::Database::LockWritesManager.tables_to_lock(connection) do |table_name, schema_name|
|
||||
# TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/366834
|
||||
next if schema_name == :gitlab_geo
|
||||
|
||||
|
|
|
|||
|
|
@ -69,17 +69,13 @@ class VersionCheck
|
|||
|
||||
case response&.code
|
||||
when 200
|
||||
Gitlab::Json.parse(response.body)
|
||||
else
|
||||
{ error: 'version check failed', status: response&.code }
|
||||
response.body
|
||||
end
|
||||
end
|
||||
|
||||
def response
|
||||
with_reactive_cache do |data|
|
||||
raise InvalidateReactiveCache if data[:error]
|
||||
|
||||
data
|
||||
Gitlab::Json.parse(data) if data
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -37,6 +37,14 @@ RSpec.describe Gitlab::Database::LockWritesManager do
|
|||
it 'returns true for a table that is locked for writes' do
|
||||
expect { subject.lock_writes }.to change { subject.table_locked_for_writes?(test_table) }.from(false).to(true)
|
||||
end
|
||||
|
||||
context 'for detached partition tables in another schema' do
|
||||
let(:test_table) { 'gitlab_partitions_dynamic._test_table_20220101' }
|
||||
|
||||
it 'returns true for a table that is locked for writes' do
|
||||
expect { subject.lock_writes }.to change { subject.table_locked_for_writes?(test_table) }.from(false).to(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#lock_writes' do
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe Gitlab::Database::TablesSortedByForeignKeys do
|
||||
let(:connection) { ApplicationRecord.connection }
|
||||
let(:tables) { %w[_test_gitlab_main_items _test_gitlab_main_references] }
|
||||
let(:tables) do
|
||||
%w[_test_gitlab_main_items _test_gitlab_main_references _test_gitlab_partition_parent
|
||||
gitlab_partitions_dynamic._test_gitlab_partition_20220101]
|
||||
end
|
||||
|
||||
subject do
|
||||
described_class.new(connection, tables).execute
|
||||
|
|
@ -19,13 +22,33 @@ RSpec.describe Gitlab::Database::TablesSortedByForeignKeys do
|
|||
item_id BIGINT NOT NULL,
|
||||
CONSTRAINT fk_constrained_1 FOREIGN KEY(item_id) REFERENCES _test_gitlab_main_items(id)
|
||||
);
|
||||
|
||||
CREATE TABLE _test_gitlab_partition_parent (
|
||||
id bigserial not null,
|
||||
created_at timestamptz not null,
|
||||
item_id BIGINT NOT NULL,
|
||||
primary key (id, created_at),
|
||||
CONSTRAINT fk_constrained_1 FOREIGN KEY(item_id) REFERENCES _test_gitlab_main_items(id)
|
||||
) PARTITION BY RANGE(created_at);
|
||||
|
||||
CREATE TABLE gitlab_partitions_dynamic._test_gitlab_partition_20220101
|
||||
PARTITION OF _test_gitlab_partition_parent
|
||||
FOR VALUES FROM ('20220101') TO ('20220131');
|
||||
|
||||
ALTER TABLE _test_gitlab_partition_parent DETACH PARTITION gitlab_partitions_dynamic._test_gitlab_partition_20220101;
|
||||
SQL
|
||||
connection.execute(statement)
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
it 'returns the tables sorted by the foreign keys dependency' do
|
||||
expect(subject).to eq([['_test_gitlab_main_references'], ['_test_gitlab_main_items']])
|
||||
expect(subject).to eq(
|
||||
[
|
||||
['_test_gitlab_main_references'],
|
||||
['_test_gitlab_partition_parent'],
|
||||
['gitlab_partitions_dynamic._test_gitlab_partition_20220101'],
|
||||
['_test_gitlab_main_items']
|
||||
])
|
||||
end
|
||||
|
||||
it 'returns both tables together if they are strongly connected' do
|
||||
|
|
@ -35,7 +58,12 @@ RSpec.describe Gitlab::Database::TablesSortedByForeignKeys do
|
|||
SQL
|
||||
connection.execute(statement)
|
||||
|
||||
expect(subject).to eq([tables])
|
||||
expect(subject).to eq(
|
||||
[
|
||||
['_test_gitlab_partition_parent'],
|
||||
['gitlab_partitions_dynamic._test_gitlab_partition_20220101'],
|
||||
%w[_test_gitlab_main_items _test_gitlab_main_references]
|
||||
])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,14 +6,9 @@ RSpec.describe Gitlab::Database::TablesTruncate, :reestablished_active_record_ba
|
|||
:suppress_gitlab_schemas_validate_connection do
|
||||
include MigrationsHelpers
|
||||
|
||||
let(:logger) { instance_double(Logger) }
|
||||
let(:dry_run) { false }
|
||||
let(:until_table) { nil }
|
||||
let(:min_batch_size) { 1 }
|
||||
let(:main_connection) { ApplicationRecord.connection }
|
||||
let(:ci_connection) { Ci::ApplicationRecord.connection }
|
||||
let(:test_gitlab_main_table) { '_test_gitlab_main_table' }
|
||||
let(:test_gitlab_ci_table) { '_test_gitlab_ci_table' }
|
||||
|
||||
# Main Database
|
||||
let(:main_db_main_item_model) { table("_test_gitlab_main_items", database: "main") }
|
||||
|
|
@ -21,24 +16,37 @@ RSpec.describe Gitlab::Database::TablesTruncate, :reestablished_active_record_ba
|
|||
let(:main_db_ci_item_model) { table("_test_gitlab_ci_items", database: "main") }
|
||||
let(:main_db_ci_reference_model) { table("_test_gitlab_ci_references", database: "main") }
|
||||
let(:main_db_shared_item_model) { table("_test_gitlab_shared_items", database: "main") }
|
||||
let(:main_db_partitioned_item) { table("_test_gitlab_hook_logs", database: "main") }
|
||||
let(:main_db_partitioned_item_detached) do
|
||||
table("gitlab_partitions_dynamic._test_gitlab_hook_logs_20220101", database: "main")
|
||||
end
|
||||
|
||||
# CI Database
|
||||
let(:ci_db_main_item_model) { table("_test_gitlab_main_items", database: "ci") }
|
||||
let(:ci_db_main_reference_model) { table("_test_gitlab_main_references", database: "ci") }
|
||||
let(:ci_db_ci_item_model) { table("_test_gitlab_ci_items", database: "ci") }
|
||||
let(:ci_db_ci_reference_model) { table("_test_gitlab_ci_references", database: "ci") }
|
||||
let(:ci_db_shared_item_model) { table("_test_gitlab_shared_items", database: "ci") }
|
||||
|
||||
subject(:truncate_legacy_tables) do
|
||||
described_class.new(
|
||||
database_name: database_name,
|
||||
min_batch_size: min_batch_size,
|
||||
logger: logger,
|
||||
dry_run: dry_run,
|
||||
until_table: until_table
|
||||
).execute
|
||||
let(:ci_db_partitioned_item) { table("_test_gitlab_hook_logs", database: "ci") }
|
||||
let(:ci_db_partitioned_item_detached) do
|
||||
table("gitlab_partitions_dynamic._test_gitlab_hook_logs_20220101", database: "ci")
|
||||
end
|
||||
|
||||
shared_examples 'truncating legacy tables on a database' do
|
||||
let(:logger) { instance_double(Logger) }
|
||||
let(:dry_run) { false }
|
||||
let(:until_table) { nil }
|
||||
|
||||
subject(:truncate_legacy_tables) do
|
||||
described_class.new(
|
||||
database_name: connection.pool.db_config.name,
|
||||
min_batch_size: min_batch_size,
|
||||
logger: logger,
|
||||
dry_run: dry_run,
|
||||
until_table: until_table
|
||||
).execute
|
||||
end
|
||||
|
||||
before do
|
||||
skip_if_multiple_databases_not_setup
|
||||
|
||||
|
|
@ -51,6 +59,24 @@ RSpec.describe Gitlab::Database::TablesTruncate, :reestablished_active_record_ba
|
|||
item_id BIGINT NOT NULL,
|
||||
CONSTRAINT fk_constrained_1 FOREIGN KEY(item_id) REFERENCES _test_gitlab_main_items(id)
|
||||
);
|
||||
|
||||
CREATE TABLE _test_gitlab_hook_logs (
|
||||
id bigserial not null,
|
||||
created_at timestamptz not null,
|
||||
item_id BIGINT NOT NULL,
|
||||
primary key (id, created_at),
|
||||
CONSTRAINT fk_constrained_1 FOREIGN KEY(item_id) REFERENCES _test_gitlab_main_items(id)
|
||||
) PARTITION BY RANGE(created_at);
|
||||
|
||||
CREATE TABLE gitlab_partitions_dynamic._test_gitlab_hook_logs_20220101
|
||||
PARTITION OF _test_gitlab_hook_logs
|
||||
FOR VALUES FROM ('20220101') TO ('20220131');
|
||||
|
||||
CREATE TABLE gitlab_partitions_dynamic._test_gitlab_hook_logs_20220201
|
||||
PARTITION OF _test_gitlab_hook_logs
|
||||
FOR VALUES FROM ('20220201') TO ('20220228');
|
||||
|
||||
ALTER TABLE _test_gitlab_hook_logs DETACH PARTITION gitlab_partitions_dynamic._test_gitlab_hook_logs_20220101;
|
||||
SQL
|
||||
|
||||
main_connection.execute(main_tables_sql)
|
||||
|
|
@ -84,18 +110,37 @@ RSpec.describe Gitlab::Database::TablesTruncate, :reestablished_active_record_ba
|
|||
main_db_ci_item_model.create!(id: i)
|
||||
main_db_ci_reference_model.create!(item_id: i)
|
||||
main_db_shared_item_model.create!(id: i)
|
||||
main_db_partitioned_item.create!(item_id: i, created_at: '2022-02-02 02:00')
|
||||
main_db_partitioned_item_detached.create!(item_id: i, created_at: '2022-01-01 01:00')
|
||||
# CI Database
|
||||
ci_db_main_item_model.create!(id: i)
|
||||
ci_db_main_reference_model.create!(item_id: i)
|
||||
ci_db_ci_item_model.create!(id: i)
|
||||
ci_db_ci_reference_model.create!(item_id: i)
|
||||
ci_db_shared_item_model.create!(id: i)
|
||||
ci_db_partitioned_item.create!(item_id: i, created_at: '2022-02-02 02:00')
|
||||
ci_db_partitioned_item_detached.create!(item_id: i, created_at: '2022-01-01 01:00')
|
||||
end
|
||||
|
||||
Gitlab::Database::SharedModel.using_connection(main_connection) do
|
||||
Postgresql::DetachedPartition.create!(
|
||||
table_name: '_test_gitlab_hook_logs_20220101',
|
||||
drop_after: Time.current
|
||||
)
|
||||
end
|
||||
|
||||
Gitlab::Database::SharedModel.using_connection(ci_connection) do
|
||||
Postgresql::DetachedPartition.create!(
|
||||
table_name: '_test_gitlab_hook_logs_20220101',
|
||||
drop_after: Time.current
|
||||
)
|
||||
end
|
||||
|
||||
allow(Gitlab::Database::GitlabSchema).to receive(:tables_to_schema).and_return(
|
||||
{
|
||||
"_test_gitlab_main_items" => :gitlab_main,
|
||||
"_test_gitlab_main_references" => :gitlab_main,
|
||||
"_test_gitlab_hook_logs" => :gitlab_main,
|
||||
"_test_gitlab_ci_items" => :gitlab_ci,
|
||||
"_test_gitlab_ci_references" => :gitlab_ci,
|
||||
"_test_gitlab_shared_items" => :gitlab_shared,
|
||||
|
|
@ -119,7 +164,7 @@ RSpec.describe Gitlab::Database::TablesTruncate, :reestablished_active_record_ba
|
|||
Gitlab::Database::LockWritesManager.new(
|
||||
table_name: table,
|
||||
connection: connection,
|
||||
database_name: database_name
|
||||
database_name: connection.pool.db_config.name
|
||||
).lock_writes
|
||||
end
|
||||
end
|
||||
|
|
@ -199,7 +244,6 @@ RSpec.describe Gitlab::Database::TablesTruncate, :reestablished_active_record_ba
|
|||
|
||||
context 'when truncating gitlab_ci tables on the main database' do
|
||||
let(:connection) { ApplicationRecord.connection }
|
||||
let(:database_name) { "main" }
|
||||
let(:legacy_tables_models) { [main_db_ci_item_model, main_db_ci_reference_model] }
|
||||
let(:referencing_table_model) { main_db_ci_reference_model }
|
||||
let(:referenced_table_model) { main_db_ci_item_model }
|
||||
|
|
@ -217,8 +261,10 @@ RSpec.describe Gitlab::Database::TablesTruncate, :reestablished_active_record_ba
|
|||
|
||||
context 'when truncating gitlab_main tables on the ci database' do
|
||||
let(:connection) { Ci::ApplicationRecord.connection }
|
||||
let(:database_name) { "ci" }
|
||||
let(:legacy_tables_models) { [ci_db_main_item_model, ci_db_main_reference_model] }
|
||||
let(:legacy_tables_models) do
|
||||
[ci_db_main_item_model, ci_db_main_reference_model, ci_db_partitioned_item, ci_db_partitioned_item_detached]
|
||||
end
|
||||
|
||||
let(:referencing_table_model) { ci_db_main_reference_model }
|
||||
let(:referenced_table_model) { ci_db_main_item_model }
|
||||
let(:other_tables_models) do
|
||||
|
|
|
|||
|
|
@ -90,9 +90,13 @@ RSpec.describe Gitlab::GithubImport::Importer::IssuesImporter do
|
|||
.to receive(:each_object_to_import)
|
||||
.and_yield(github_issue)
|
||||
|
||||
expect(Gitlab::GithubImport::ImportIssueWorker).to receive(:bulk_perform_in).with(1.second, [
|
||||
[project.id, an_instance_of(Hash), an_instance_of(String)]
|
||||
], batch_size: 1000, batch_delay: 1.minute)
|
||||
expect(Gitlab::GithubImport::ImportIssueWorker)
|
||||
.to receive(:bulk_perform_in)
|
||||
.with(1.second,
|
||||
[[project.id, an_instance_of(Hash), an_instance_of(String)]],
|
||||
batch_size: 1000,
|
||||
batch_delay: 1.minute
|
||||
)
|
||||
|
||||
waiter = importer.parallel_import
|
||||
|
||||
|
|
|
|||
|
|
@ -141,9 +141,8 @@ RSpec.describe Gitlab::Search::FoundBlob do
|
|||
subject { described_class.new(blob_path: path, project: project, ref: 'master') }
|
||||
|
||||
before do
|
||||
allow(Gitlab::Git::Blob).to receive(:batch).and_return([
|
||||
Gitlab::Git::Blob.new(path: path)
|
||||
])
|
||||
allow(Gitlab::Git::Blob)
|
||||
.to receive(:batch).and_return([Gitlab::Git::Blob.new(path: path)])
|
||||
end
|
||||
|
||||
it { expect(subject.path).to eq('a/b/c.md') }
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe VersionCheck, :use_clean_rails_memory_store_caching do
|
||||
include ReactiveCachingHelpers
|
||||
|
||||
RSpec.describe VersionCheck do
|
||||
describe '.url' do
|
||||
it 'returns the correct URL' do
|
||||
expect(described_class.url).to match(%r{\A#{Regexp.escape(described_class.host)}/check\.json\?gitlab_info=\w+})
|
||||
|
|
@ -32,7 +30,7 @@ RSpec.describe VersionCheck, :use_clean_rails_memory_store_caching do
|
|||
end
|
||||
|
||||
it 'returns the response object' do
|
||||
expect(described_class.new.calculate_reactive_cache).to eq({ "status" => "success" })
|
||||
expect(described_class.new.calculate_reactive_cache).to eq("{ \"status\": \"success\" }")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -41,31 +39,38 @@ RSpec.describe VersionCheck, :use_clean_rails_memory_store_caching do
|
|||
stub_request(:get, described_class.url).to_return(status: 500, body: nil, headers: {})
|
||||
end
|
||||
|
||||
it 'returns an error hash' do
|
||||
expect(described_class.new.calculate_reactive_cache).to eq({ error: 'version check failed', status: 500 })
|
||||
it 'returns nil' do
|
||||
expect(described_class.new.calculate_reactive_cache).to be(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#response' do
|
||||
context 'cache returns value' do
|
||||
it 'returns the response object' do
|
||||
version_check = described_class.new
|
||||
data = { status: 'success' }
|
||||
stub_reactive_cache(version_check, data)
|
||||
let(:response) { { "severity" => "success" }.to_json }
|
||||
|
||||
expect(version_check.response).to eq(data)
|
||||
before do
|
||||
allow_next_instance_of(described_class) do |instance|
|
||||
allow(instance).to receive(:with_reactive_cache).and_return(response)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns the response object' do
|
||||
expect(described_class.new.response).to be(response)
|
||||
end
|
||||
end
|
||||
|
||||
context 'cache returns error' do
|
||||
it 'returns nil and invalidates the reactive cache' do
|
||||
version_check = described_class.new
|
||||
stub_reactive_cache(version_check, error: 'version check failed')
|
||||
context 'cache returns nil' do
|
||||
let(:response) { nil }
|
||||
|
||||
expect(version_check).to receive(:refresh_reactive_cache!).and_call_original
|
||||
expect(version_check.response).to be_nil
|
||||
expect(read_reactive_cache(version_check)).to be_nil
|
||||
before do
|
||||
allow_next_instance_of(described_class) do |instance|
|
||||
allow(instance).to receive(:with_reactive_cache).and_return(response)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns nil' do
|
||||
expect(described_class.new.response).to be(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -28,11 +28,9 @@ RSpec.describe Ci::RunnerVersion, feature_category: :runner do
|
|||
end
|
||||
|
||||
it 'contains any valid or unprocessed runner version that is not already recommended' do
|
||||
is_expected.to match_array([
|
||||
runner_version_nil,
|
||||
runner_version_not_available,
|
||||
runner_version_available
|
||||
])
|
||||
is_expected.to match_array(
|
||||
[runner_version_nil, runner_version_not_available, runner_version_available]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -2224,32 +2224,34 @@ RSpec.describe Repository do
|
|||
|
||||
describe '#after_change_head' do
|
||||
it 'flushes the method caches' do
|
||||
expect(repository).to receive(:expire_method_caches).with([
|
||||
:size,
|
||||
:commit_count,
|
||||
:readme_path,
|
||||
:contribution_guide,
|
||||
:changelog,
|
||||
:license_blob,
|
||||
:license_licensee,
|
||||
:license_gitaly,
|
||||
:gitignore,
|
||||
:gitlab_ci_yml,
|
||||
:branch_names,
|
||||
:tag_names,
|
||||
:branch_count,
|
||||
:tag_count,
|
||||
:avatar,
|
||||
:exists?,
|
||||
:root_ref,
|
||||
:merged_branch_names,
|
||||
:has_visible_content?,
|
||||
:issue_template_names_hash,
|
||||
:merge_request_template_names_hash,
|
||||
:user_defined_metrics_dashboard_paths,
|
||||
:xcode_project?,
|
||||
:has_ambiguous_refs?
|
||||
])
|
||||
expect(repository).to receive(:expire_method_caches).with(
|
||||
[
|
||||
:size,
|
||||
:commit_count,
|
||||
:readme_path,
|
||||
:contribution_guide,
|
||||
:changelog,
|
||||
:license_blob,
|
||||
:license_licensee,
|
||||
:license_gitaly,
|
||||
:gitignore,
|
||||
:gitlab_ci_yml,
|
||||
:branch_names,
|
||||
:tag_names,
|
||||
:branch_count,
|
||||
:tag_count,
|
||||
:avatar,
|
||||
:exists?,
|
||||
:root_ref,
|
||||
:merged_branch_names,
|
||||
:has_visible_content?,
|
||||
:issue_template_names_hash,
|
||||
:merge_request_template_names_hash,
|
||||
:user_defined_metrics_dashboard_paths,
|
||||
:xcode_project?,
|
||||
:has_ambiguous_refs?
|
||||
]
|
||||
)
|
||||
|
||||
repository.after_change_head
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,44 +10,44 @@ RSpec.describe 'task completion status response' do
|
|||
|
||||
shared_examples 'taskable completion status provider' do |path|
|
||||
samples = [
|
||||
{
|
||||
description: '',
|
||||
expected_count: 0,
|
||||
expected_completed_count: 0
|
||||
},
|
||||
{
|
||||
description: 'Lorem ipsum',
|
||||
expected_count: 0,
|
||||
expected_completed_count: 0
|
||||
},
|
||||
{
|
||||
description: %{- [ ] task 1
|
||||
{
|
||||
description: '',
|
||||
expected_count: 0,
|
||||
expected_completed_count: 0
|
||||
},
|
||||
{
|
||||
description: 'Lorem ipsum',
|
||||
expected_count: 0,
|
||||
expected_completed_count: 0
|
||||
},
|
||||
{
|
||||
description: %{- [ ] task 1
|
||||
- [x] task 2 },
|
||||
expected_count: 2,
|
||||
expected_completed_count: 1
|
||||
},
|
||||
{
|
||||
description: %{- [ ] task 1
|
||||
expected_count: 2,
|
||||
expected_completed_count: 1
|
||||
},
|
||||
{
|
||||
description: %{- [ ] task 1
|
||||
- [ ] task 2 },
|
||||
expected_count: 2,
|
||||
expected_completed_count: 0
|
||||
},
|
||||
{
|
||||
description: %{- [x] task 1
|
||||
expected_count: 2,
|
||||
expected_completed_count: 0
|
||||
},
|
||||
{
|
||||
description: %{- [x] task 1
|
||||
- [x] task 2 },
|
||||
expected_count: 2,
|
||||
expected_completed_count: 2
|
||||
},
|
||||
{
|
||||
description: %{- [ ] task 1},
|
||||
expected_count: 1,
|
||||
expected_completed_count: 0
|
||||
},
|
||||
{
|
||||
description: %{- [x] task 1},
|
||||
expected_count: 1,
|
||||
expected_completed_count: 1
|
||||
}
|
||||
expected_count: 2,
|
||||
expected_completed_count: 2
|
||||
},
|
||||
{
|
||||
description: %{- [ ] task 1},
|
||||
expected_count: 1,
|
||||
expected_completed_count: 0
|
||||
},
|
||||
{
|
||||
description: %{- [x] task 1},
|
||||
expected_count: 1,
|
||||
expected_completed_count: 1
|
||||
}
|
||||
]
|
||||
samples.each do |sample_data|
|
||||
context "with a description of #{sample_data[:description].inspect}" do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'user routing', :clean_gitlab_redis_sessions, feature_category: :authentication_and_authorization do
|
||||
include SessionHelpers
|
||||
|
||||
context 'when GitHub OAuth on project import is cancelled' do
|
||||
it_behaves_like 'redirecting a legacy path', '/users/auth?error=access_denied&state=xyz', '/users/sign_in'
|
||||
end
|
||||
|
||||
context 'when GitHub OAuth on sign in is cancelled' do
|
||||
before do
|
||||
stub_session(auth_on_failure_path: '/projects/new#import_project')
|
||||
end
|
||||
|
||||
context 'when all required parameters are present' do
|
||||
it_behaves_like 'redirecting a legacy path',
|
||||
'/users/auth?error=access_denied&state=xyz',
|
||||
'/projects/new#import_project'
|
||||
end
|
||||
|
||||
context 'when one of the required parameters is missing' do
|
||||
it_behaves_like 'redirecting a legacy path',
|
||||
'/users/auth?error=access_denied&state=',
|
||||
'/auth'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -187,25 +187,25 @@ RSpec.describe Security::MergeReportsService, '#execute' do
|
|||
it 'deduplicates (except cwe and wasc) and sorts the vulnerabilities by severity (desc) then by compare key' do
|
||||
expect(merged_report.findings).to(
|
||||
eq([
|
||||
finding_cwe_2,
|
||||
finding_wasc_2,
|
||||
finding_cwe_1,
|
||||
finding_id_2_loc_2,
|
||||
finding_id_2_loc_1,
|
||||
finding_wasc_1,
|
||||
finding_id_1
|
||||
])
|
||||
finding_cwe_2,
|
||||
finding_wasc_2,
|
||||
finding_cwe_1,
|
||||
finding_id_2_loc_2,
|
||||
finding_id_2_loc_1,
|
||||
finding_wasc_1,
|
||||
finding_id_1
|
||||
])
|
||||
)
|
||||
end
|
||||
|
||||
it 'deduplicates scanned resources' do
|
||||
expect(merged_report.scanned_resources).to(
|
||||
eq([
|
||||
scanned_resource,
|
||||
scanned_resource_1,
|
||||
scanned_resource_2,
|
||||
scanned_resource_3
|
||||
])
|
||||
scanned_resource,
|
||||
scanned_resource_1,
|
||||
scanned_resource_2,
|
||||
scanned_resource_3
|
||||
])
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -21,12 +21,14 @@ module SimpleCovEnv
|
|||
def configure_formatter
|
||||
SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true
|
||||
|
||||
SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new([
|
||||
SimpleCov::Formatter::SimpleFormatter,
|
||||
SimpleCov::Formatter::HTMLFormatter,
|
||||
SimpleCov::Formatter::CoberturaFormatter,
|
||||
SimpleCov::Formatter::LcovFormatter
|
||||
])
|
||||
SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new(
|
||||
[
|
||||
SimpleCov::Formatter::SimpleFormatter,
|
||||
SimpleCov::Formatter::HTMLFormatter,
|
||||
SimpleCov::Formatter::CoberturaFormatter,
|
||||
SimpleCov::Formatter::LcovFormatter
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def configure_job
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ module Atlassian
|
|||
schemaVersion pipelineId buildNumber updateSequenceNumber
|
||||
displayName url state issueKeys testInfo references
|
||||
lastUpdated
|
||||
),
|
||||
),
|
||||
'properties' => {
|
||||
'schemaVersion' => schema_version_type,
|
||||
'pipelineId' => { 'type' => 'string' },
|
||||
|
|
|
|||
|
|
@ -16,15 +16,17 @@ Capybara.server_port = ENV['CAPYBARA_PORT'] if ENV['CAPYBARA_PORT']
|
|||
JSConsoleError = Class.new(StandardError)
|
||||
|
||||
# Filter out innocuous JS console messages
|
||||
JS_CONSOLE_FILTER = Regexp.union([
|
||||
'"[HMR] Waiting for update signal from WDS..."',
|
||||
'"[WDS] Hot Module Replacement enabled."',
|
||||
'"[WDS] Live Reloading enabled."',
|
||||
'Download the Vue Devtools extension',
|
||||
'Download the Apollo DevTools',
|
||||
"Unrecognized feature: 'interest-cohort'",
|
||||
'Does this page need fixes or improvements?'
|
||||
])
|
||||
JS_CONSOLE_FILTER = Regexp.union(
|
||||
[
|
||||
'"[HMR] Waiting for update signal from WDS..."',
|
||||
'"[WDS] Hot Module Replacement enabled."',
|
||||
'"[WDS] Live Reloading enabled."',
|
||||
'Download the Vue Devtools extension',
|
||||
'Download the Apollo DevTools',
|
||||
"Unrecognized feature: 'interest-cohort'",
|
||||
'Does this page need fixes or improvements?'
|
||||
]
|
||||
)
|
||||
|
||||
CAPYBARA_WINDOW_SIZE = [1366, 768].freeze
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
# Allow list for spec/support/finder_collection.rb
|
||||
|
||||
# Permenant excludes
|
||||
# Permanent excludes
|
||||
# For example:
|
||||
# FooFinder # Reason: It uses a memory backend
|
||||
- Namespaces::BilledUsersFinder # Reason: There is no need to have anything else besides the ids is current structure
|
||||
- Namespaces::FreeUserCap::UsersFinder # Reason: There is no need to have anything else besides the count
|
||||
|
||||
# Temporary excludes (aka TODOs)
|
||||
# For example:
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@
|
|||
module ProjectTemplateTestHelper
|
||||
def all_templates
|
||||
%w[
|
||||
rails spring express iosswift dotnetcore android
|
||||
gomicro gatsby hugo jekyll plainhtml gitbook
|
||||
hexo middleman gitpod_spring_petclinic nfhugo
|
||||
nfjekyll nfplainhtml nfgitbook nfhexo salesforcedx
|
||||
serverless_framework tencent_serverless_framework
|
||||
jsonnet cluster_management kotlin_native_linux
|
||||
pelican bridgetown
|
||||
]
|
||||
rails spring express iosswift dotnetcore android
|
||||
gomicro gatsby hugo jekyll plainhtml gitbook
|
||||
hexo middleman gitpod_spring_petclinic nfhugo
|
||||
nfjekyll nfplainhtml nfgitbook nfhexo salesforcedx
|
||||
serverless_framework tencent_serverless_framework
|
||||
jsonnet cluster_management kotlin_native_linux
|
||||
pelican bridgetown
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -490,12 +490,14 @@ module TestEnv
|
|||
# The HEAD of the component_folder will be used as heuristic for the version
|
||||
# of the binaries, allowing to use Git to determine if HEAD is later than
|
||||
# the expected version. Note: Git considers HEAD to be an anchestor of HEAD.
|
||||
_out, exit_status = Gitlab::Popen.popen(%W[
|
||||
#{Gitlab.config.git.bin_path}
|
||||
-C #{component_folder}
|
||||
merge-base --is-ancestor
|
||||
#{expected_version} HEAD
|
||||
])
|
||||
_out, exit_status = Gitlab::Popen.popen(
|
||||
%W[
|
||||
#{Gitlab.config.git.bin_path}
|
||||
-C #{component_folder}
|
||||
merge-base --is-ancestor
|
||||
#{expected_version} HEAD
|
||||
]
|
||||
)
|
||||
|
||||
exit_status == 0
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,118 +2,118 @@
|
|||
|
||||
module UsageDataHelpers
|
||||
COUNTS_KEYS = %i(
|
||||
assignee_lists
|
||||
ci_builds
|
||||
ci_internal_pipelines
|
||||
ci_external_pipelines
|
||||
ci_pipeline_config_auto_devops
|
||||
ci_pipeline_config_repository
|
||||
ci_runners
|
||||
ci_triggers
|
||||
ci_pipeline_schedules
|
||||
auto_devops_enabled
|
||||
auto_devops_disabled
|
||||
deploy_keys
|
||||
deployments
|
||||
successful_deployments
|
||||
failed_deployments
|
||||
environments
|
||||
clusters
|
||||
clusters_enabled
|
||||
project_clusters_enabled
|
||||
group_clusters_enabled
|
||||
instance_clusters_enabled
|
||||
clusters_disabled
|
||||
project_clusters_disabled
|
||||
group_clusters_disabled
|
||||
instance_clusters_disabled
|
||||
clusters_platforms_eks
|
||||
clusters_platforms_gke
|
||||
clusters_platforms_user
|
||||
clusters_integrations_prometheus
|
||||
clusters_management_project
|
||||
in_review_folder
|
||||
grafana_integrated_projects
|
||||
groups
|
||||
issues
|
||||
issues_created_from_gitlab_error_tracking_ui
|
||||
issues_with_associated_zoom_link
|
||||
issues_using_zoom_quick_actions
|
||||
issues_with_embedded_grafana_charts_approx
|
||||
incident_issues
|
||||
keys
|
||||
label_lists
|
||||
labels
|
||||
lfs_objects
|
||||
merge_requests
|
||||
milestone_lists
|
||||
milestones
|
||||
notes
|
||||
pool_repositories
|
||||
projects
|
||||
projects_imported_from_github
|
||||
projects_asana_active
|
||||
projects_jenkins_active
|
||||
projects_jira_active
|
||||
projects_jira_server_active
|
||||
projects_jira_cloud_active
|
||||
projects_jira_dvcs_cloud_active
|
||||
projects_jira_dvcs_server_active
|
||||
projects_slack_active
|
||||
projects_slack_slash_commands_active
|
||||
projects_custom_issue_tracker_active
|
||||
projects_mattermost_active
|
||||
projects_prometheus_active
|
||||
projects_with_repositories_enabled
|
||||
projects_with_error_tracking_enabled
|
||||
projects_with_enabled_alert_integrations
|
||||
projects_with_terraform_reports
|
||||
projects_with_terraform_states
|
||||
pages_domains
|
||||
protected_branches
|
||||
protected_branches_except_default
|
||||
releases
|
||||
remote_mirrors
|
||||
snippets
|
||||
personal_snippets
|
||||
project_snippets
|
||||
suggestions
|
||||
terraform_reports
|
||||
terraform_states
|
||||
todos
|
||||
uploads
|
||||
web_hooks
|
||||
user_preferences_user_gitpod_enabled
|
||||
).freeze
|
||||
assignee_lists
|
||||
ci_builds
|
||||
ci_internal_pipelines
|
||||
ci_external_pipelines
|
||||
ci_pipeline_config_auto_devops
|
||||
ci_pipeline_config_repository
|
||||
ci_runners
|
||||
ci_triggers
|
||||
ci_pipeline_schedules
|
||||
auto_devops_enabled
|
||||
auto_devops_disabled
|
||||
deploy_keys
|
||||
deployments
|
||||
successful_deployments
|
||||
failed_deployments
|
||||
environments
|
||||
clusters
|
||||
clusters_enabled
|
||||
project_clusters_enabled
|
||||
group_clusters_enabled
|
||||
instance_clusters_enabled
|
||||
clusters_disabled
|
||||
project_clusters_disabled
|
||||
group_clusters_disabled
|
||||
instance_clusters_disabled
|
||||
clusters_platforms_eks
|
||||
clusters_platforms_gke
|
||||
clusters_platforms_user
|
||||
clusters_integrations_prometheus
|
||||
clusters_management_project
|
||||
in_review_folder
|
||||
grafana_integrated_projects
|
||||
groups
|
||||
issues
|
||||
issues_created_from_gitlab_error_tracking_ui
|
||||
issues_with_associated_zoom_link
|
||||
issues_using_zoom_quick_actions
|
||||
issues_with_embedded_grafana_charts_approx
|
||||
incident_issues
|
||||
keys
|
||||
label_lists
|
||||
labels
|
||||
lfs_objects
|
||||
merge_requests
|
||||
milestone_lists
|
||||
milestones
|
||||
notes
|
||||
pool_repositories
|
||||
projects
|
||||
projects_imported_from_github
|
||||
projects_asana_active
|
||||
projects_jenkins_active
|
||||
projects_jira_active
|
||||
projects_jira_server_active
|
||||
projects_jira_cloud_active
|
||||
projects_jira_dvcs_cloud_active
|
||||
projects_jira_dvcs_server_active
|
||||
projects_slack_active
|
||||
projects_slack_slash_commands_active
|
||||
projects_custom_issue_tracker_active
|
||||
projects_mattermost_active
|
||||
projects_prometheus_active
|
||||
projects_with_repositories_enabled
|
||||
projects_with_error_tracking_enabled
|
||||
projects_with_enabled_alert_integrations
|
||||
projects_with_terraform_reports
|
||||
projects_with_terraform_states
|
||||
pages_domains
|
||||
protected_branches
|
||||
protected_branches_except_default
|
||||
releases
|
||||
remote_mirrors
|
||||
snippets
|
||||
personal_snippets
|
||||
project_snippets
|
||||
suggestions
|
||||
terraform_reports
|
||||
terraform_states
|
||||
todos
|
||||
uploads
|
||||
web_hooks
|
||||
user_preferences_user_gitpod_enabled
|
||||
).freeze
|
||||
|
||||
USAGE_DATA_KEYS = %i(
|
||||
active_user_count
|
||||
counts
|
||||
counts_monthly
|
||||
recorded_at
|
||||
edition
|
||||
version
|
||||
installation_type
|
||||
uuid
|
||||
hostname
|
||||
mattermost_enabled
|
||||
signup_enabled
|
||||
ldap_enabled
|
||||
gravatar_enabled
|
||||
omniauth_enabled
|
||||
reply_by_email_enabled
|
||||
container_registry_enabled
|
||||
dependency_proxy_enabled
|
||||
gitlab_shared_runners_enabled
|
||||
gitlab_pages
|
||||
git
|
||||
gitaly
|
||||
database
|
||||
prometheus_metrics_enabled
|
||||
web_ide_clientside_preview_enabled
|
||||
object_store
|
||||
topology
|
||||
).freeze
|
||||
active_user_count
|
||||
counts
|
||||
counts_monthly
|
||||
recorded_at
|
||||
edition
|
||||
version
|
||||
installation_type
|
||||
uuid
|
||||
hostname
|
||||
mattermost_enabled
|
||||
signup_enabled
|
||||
ldap_enabled
|
||||
gravatar_enabled
|
||||
omniauth_enabled
|
||||
reply_by_email_enabled
|
||||
container_registry_enabled
|
||||
dependency_proxy_enabled
|
||||
gitlab_shared_runners_enabled
|
||||
gitlab_pages
|
||||
git
|
||||
gitaly
|
||||
database
|
||||
prometheus_metrics_enabled
|
||||
web_ide_clientside_preview_enabled
|
||||
object_store
|
||||
topology
|
||||
).freeze
|
||||
|
||||
def stub_usage_data_connections
|
||||
allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false)
|
||||
|
|
|
|||
|
|
@ -65,12 +65,14 @@ module ExceedQueryLimitHelpers
|
|||
|
||||
MARGINALIA_ANNOTATION_REGEX = %r{\s*\/\*.*\*\/}.freeze
|
||||
|
||||
DB_QUERY_RE = Regexp.union([
|
||||
/^(?<prefix>SELECT .* FROM "?[a-z_]+"?) (?<suffix>.*)$/m,
|
||||
/^(?<prefix>UPDATE "?[a-z_]+"?) (?<suffix>.*)$/m,
|
||||
/^(?<prefix>INSERT INTO "[a-z_]+" \((?:"[a-z_]+",?\s?)+\)) (?<suffix>.*)$/m,
|
||||
/^(?<prefix>DELETE FROM "[a-z_]+") (?<suffix>.*)$/m
|
||||
]).freeze
|
||||
DB_QUERY_RE = Regexp.union(
|
||||
[
|
||||
/^(?<prefix>SELECT .* FROM "?[a-z_]+"?) (?<suffix>.*)$/m,
|
||||
/^(?<prefix>UPDATE "?[a-z_]+"?) (?<suffix>.*)$/m,
|
||||
/^(?<prefix>INSERT INTO "[a-z_]+" \((?:"[a-z_]+",?\s?)+\)) (?<suffix>.*)$/m,
|
||||
/^(?<prefix>DELETE FROM "[a-z_]+") (?<suffix>.*)$/m
|
||||
]
|
||||
).freeze
|
||||
|
||||
def with_threshold(threshold)
|
||||
@threshold = threshold
|
||||
|
|
|
|||
|
|
@ -92,10 +92,10 @@ module MigrationHelpers
|
|||
"url" => "http://goat:8080/WebGoat/logout",
|
||||
"body" => "",
|
||||
"headers" => [
|
||||
{
|
||||
"name" => "Accept",
|
||||
"value" => "*/*"
|
||||
}
|
||||
{
|
||||
"name" => "Accept",
|
||||
"value" => "*/*"
|
||||
}
|
||||
]
|
||||
},
|
||||
"response" => {
|
||||
|
|
|
|||
|
|
@ -92,9 +92,9 @@ RSpec.shared_examples 'additional metrics query' do
|
|||
metrics: [
|
||||
{
|
||||
title: 'title', weight: 1, y_label: 'Values', queries: [
|
||||
{ query_range: 'query_range_a', result: query_range_result },
|
||||
{ query_range: 'query_range_b', label: 'label', unit: 'unit', result: query_range_result }
|
||||
]
|
||||
{ query_range: 'query_range_a', result: query_range_result },
|
||||
{ query_range: 'query_range_b', label: 'label', unit: 'unit', result: query_range_result }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ RSpec.shared_context 'GroupPolicy context' do
|
|||
%i[
|
||||
read_group read_counts
|
||||
read_label read_issue_board_list read_milestone read_issue_board
|
||||
]
|
||||
]
|
||||
end
|
||||
|
||||
let(:guest_permissions) do
|
||||
|
|
@ -22,32 +22,32 @@ RSpec.shared_context 'GroupPolicy context' do
|
|||
read_label read_group upload_file read_namespace read_group_activity
|
||||
read_group_issues read_group_boards read_group_labels read_group_milestones
|
||||
read_group_merge_requests
|
||||
]
|
||||
]
|
||||
end
|
||||
|
||||
let(:reporter_permissions) do
|
||||
%i[
|
||||
admin_label
|
||||
admin_milestone
|
||||
admin_issue_board
|
||||
read_container_image
|
||||
read_harbor_registry
|
||||
read_metrics_dashboard_annotation
|
||||
read_prometheus
|
||||
read_crm_contact
|
||||
read_crm_organization
|
||||
]
|
||||
admin_label
|
||||
admin_milestone
|
||||
admin_issue_board
|
||||
read_container_image
|
||||
read_harbor_registry
|
||||
read_metrics_dashboard_annotation
|
||||
read_prometheus
|
||||
read_crm_contact
|
||||
read_crm_organization
|
||||
]
|
||||
end
|
||||
|
||||
let(:developer_permissions) do
|
||||
%i[
|
||||
create_metrics_dashboard_annotation
|
||||
delete_metrics_dashboard_annotation
|
||||
update_metrics_dashboard_annotation
|
||||
create_custom_emoji
|
||||
create_package
|
||||
read_cluster
|
||||
]
|
||||
create_metrics_dashboard_annotation
|
||||
delete_metrics_dashboard_annotation
|
||||
update_metrics_dashboard_annotation
|
||||
create_custom_emoji
|
||||
create_package
|
||||
read_cluster
|
||||
]
|
||||
end
|
||||
|
||||
let(:maintainer_permissions) do
|
||||
|
|
|
|||
|
|
@ -42,9 +42,7 @@ RSpec.shared_examples 'querying a GraphQL type with labels' do
|
|||
make_query(
|
||||
[
|
||||
query_graphql_field(:label, label_params, all_graphql_fields_for(Label)),
|
||||
query_graphql_field(:labels, labels_params, [
|
||||
query_graphql_field(:nodes, nil, all_graphql_fields_for(Label))
|
||||
])
|
||||
query_graphql_field(:labels, labels_params, [query_graphql_field(:nodes, nil, all_graphql_fields_for(Label))])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -25,10 +25,12 @@ RSpec.shared_examples 'handling all upload parameters conditions' do
|
|||
end
|
||||
|
||||
it 'builds UploadedFiles' do
|
||||
expect_uploaded_files([
|
||||
{ filepath: uploaded_filepath, original_filename: filename, remote_id: remote_id, size: uploaded_file.size, params_path: %w(file1) },
|
||||
{ filepath: uploaded_filepath2, original_filename: filename2, remote_id: remote_id2, size: uploaded_file2.size, params_path: %w(file2) }
|
||||
])
|
||||
expect_uploaded_files(
|
||||
[
|
||||
{ filepath: uploaded_filepath, original_filename: filename, remote_id: remote_id, size: uploaded_file.size, params_path: %w(file1) },
|
||||
{ filepath: uploaded_filepath2, original_filename: filename2, remote_id: remote_id2, size: uploaded_file2.size, params_path: %w(file2) }
|
||||
]
|
||||
)
|
||||
|
||||
subject
|
||||
end
|
||||
|
|
@ -61,10 +63,12 @@ RSpec.shared_examples 'handling all upload parameters conditions' do
|
|||
end
|
||||
|
||||
it 'builds UploadedFiles' do
|
||||
expect_uploaded_files([
|
||||
{ filepath: uploaded_filepath, original_filename: filename, remote_id: remote_id, size: uploaded_file.size, params_path: %w(user avatar) },
|
||||
{ filepath: uploaded_filepath2, original_filename: filename2, remote_id: remote_id2, size: uploaded_file2.size, params_path: %w(user screenshot) }
|
||||
])
|
||||
expect_uploaded_files(
|
||||
[
|
||||
{ filepath: uploaded_filepath, original_filename: filename, remote_id: remote_id, size: uploaded_file.size, params_path: %w(user avatar) },
|
||||
{ filepath: uploaded_filepath2, original_filename: filename2, remote_id: remote_id2, size: uploaded_file2.size, params_path: %w(user screenshot) }
|
||||
]
|
||||
)
|
||||
|
||||
subject
|
||||
end
|
||||
|
|
@ -101,10 +105,12 @@ RSpec.shared_examples 'handling all upload parameters conditions' do
|
|||
end
|
||||
|
||||
it 'builds UploadedFiles' do
|
||||
expect_uploaded_files([
|
||||
{ filepath: uploaded_file, original_filename: filename, remote_id: remote_id, size: uploaded_file.size, params_path: %w(user avatar bananas) },
|
||||
{ filepath: uploaded_file2, original_filename: filename2, remote_id: remote_id2, size: uploaded_file2.size, params_path: %w(user friend ananas) }
|
||||
])
|
||||
expect_uploaded_files(
|
||||
[
|
||||
{ filepath: uploaded_file, original_filename: filename, remote_id: remote_id, size: uploaded_file.size, params_path: %w(user avatar bananas) },
|
||||
{ filepath: uploaded_file2, original_filename: filename2, remote_id: remote_id2, size: uploaded_file2.size, params_path: %w(user friend ananas) }
|
||||
]
|
||||
)
|
||||
|
||||
subject
|
||||
end
|
||||
|
|
@ -133,11 +139,13 @@ RSpec.shared_examples 'handling all upload parameters conditions' do
|
|||
end
|
||||
|
||||
it 'builds UploadedFiles' do
|
||||
expect_uploaded_files([
|
||||
{ filepath: uploaded_filepath, original_filename: filename, remote_id: remote_id, size: uploaded_file.size, params_path: %w(file) },
|
||||
{ filepath: uploaded_filepath2, original_filename: filename2, remote_id: remote_id2, size: uploaded_file2.size, params_path: %w(user avatar) },
|
||||
{ filepath: uploaded_filepath3, original_filename: filename3, remote_id: remote_id3, size: uploaded_file3.size, params_path: %w(user friend avatar) }
|
||||
])
|
||||
expect_uploaded_files(
|
||||
[
|
||||
{ filepath: uploaded_filepath, original_filename: filename, remote_id: remote_id, size: uploaded_file.size, params_path: %w(file) },
|
||||
{ filepath: uploaded_filepath2, original_filename: filename2, remote_id: remote_id2, size: uploaded_file2.size, params_path: %w(user avatar) },
|
||||
{ filepath: uploaded_filepath3, original_filename: filename3, remote_id: remote_id3, size: uploaded_file3.size, params_path: %w(user friend avatar) }
|
||||
]
|
||||
)
|
||||
|
||||
subject
|
||||
end
|
||||
|
|
|
|||
|
|
@ -71,11 +71,7 @@ RSpec.shared_examples 'repository_storage_moves API' do |container_type|
|
|||
get_container_repository_storage_moves
|
||||
|
||||
json_ids = json_response.map { |storage_move| storage_move['id'] }
|
||||
expect(json_ids).to eq([
|
||||
storage_move.id,
|
||||
storage_move_middle.id,
|
||||
storage_move_oldest.id
|
||||
])
|
||||
expect(json_ids).to eq([storage_move.id, storage_move_middle.id, storage_move_oldest.id])
|
||||
end
|
||||
|
||||
describe 'permissions' do
|
||||
|
|
|
|||
|
|
@ -19,6 +19,30 @@ RSpec.describe 'gitlab:db:lock_writes', :silence_stdout, :reestablished_active_r
|
|||
let(:main_connection) { ApplicationRecord.connection }
|
||||
let(:ci_connection) { Ci::ApplicationRecord.connection }
|
||||
|
||||
let(:detached_partition_table) { '_test_gitlab_main_part_20220101' }
|
||||
|
||||
before do
|
||||
create_detached_partition_sql = <<~SQL
|
||||
CREATE TABLE IF NOT EXISTS gitlab_partitions_dynamic._test_gitlab_main_part_20220101 (
|
||||
id bigserial primary key not null
|
||||
)
|
||||
SQL
|
||||
|
||||
main_connection.execute(create_detached_partition_sql)
|
||||
ci_connection.execute(create_detached_partition_sql)
|
||||
|
||||
Gitlab::Database::SharedModel.using_connection(main_connection) do
|
||||
Postgresql::DetachedPartition.create!(
|
||||
table_name: detached_partition_table,
|
||||
drop_after: Time.current
|
||||
)
|
||||
end
|
||||
|
||||
allow(Gitlab::Database::GitlabSchema).to receive(:table_schema).and_call_original
|
||||
allow(Gitlab::Database::GitlabSchema).to receive(:table_schema)
|
||||
.with(detached_partition_table).and_return(:gitlab_main)
|
||||
end
|
||||
|
||||
context 'single database' do
|
||||
before do
|
||||
skip_if_multiple_databases_are_setup
|
||||
|
|
@ -46,6 +70,13 @@ RSpec.describe 'gitlab:db:lock_writes', :silence_stdout, :reestablished_active_r
|
|||
context 'multiple databases' do
|
||||
before do
|
||||
skip_if_multiple_databases_not_setup
|
||||
|
||||
Gitlab::Database::SharedModel.using_connection(ci_connection) do
|
||||
Postgresql::DetachedPartition.create!(
|
||||
table_name: detached_partition_table,
|
||||
drop_after: Time.current
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when locking writes' do
|
||||
|
|
@ -87,6 +118,13 @@ RSpec.describe 'gitlab:db:lock_writes', :silence_stdout, :reestablished_active_r
|
|||
main_connection.execute("truncate ci_build_needs")
|
||||
end.to raise_error(ActiveRecord::StatementInvalid, /Table: "ci_build_needs" is write protected/)
|
||||
end
|
||||
|
||||
it 'prevents writes to detached partitions' do
|
||||
run_rake_task('gitlab:db:lock_writes')
|
||||
expect do
|
||||
ci_connection.execute("INSERT INTO gitlab_partitions_dynamic.#{detached_partition_table} DEFAULT VALUES")
|
||||
end.to raise_error(ActiveRecord::StatementInvalid, /Table: "#{detached_partition_table}" is write protected/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when running in dry_run mode' do
|
||||
|
|
@ -138,6 +176,14 @@ RSpec.describe 'gitlab:db:lock_writes', :silence_stdout, :reestablished_active_r
|
|||
main_connection.execute("delete from ci_builds")
|
||||
end.not_to raise_error
|
||||
end
|
||||
|
||||
it 'allows writes again to detached partitions' do
|
||||
run_rake_task('gitlab:db:unlock_writes')
|
||||
|
||||
expect do
|
||||
ci_connection.execute("INSERT INTO gitlab_partitions_dynamic._test_gitlab_main_part_20220101 DEFAULT VALUES")
|
||||
end.not_to raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -9,10 +9,13 @@ RSpec.describe 'projects/issues/_related_branches' do
|
|||
let(:status) { pipeline.detailed_status(build(:user)) }
|
||||
|
||||
before do
|
||||
assign(:related_branches, [
|
||||
{ name: 'other', link: 'link-to-other', pipeline_status: nil },
|
||||
{ name: 'feature', link: 'link-to-feature', pipeline_status: status }
|
||||
])
|
||||
assign(:related_branches,
|
||||
[
|
||||
{ name: 'other', link: 'link-to-other', pipeline_status: nil },
|
||||
{ name: 'feature', link: 'link-to-feature', pipeline_status: status }
|
||||
|
||||
]
|
||||
)
|
||||
|
||||
render
|
||||
end
|
||||
|
|
|
|||
|
|
@ -35,10 +35,7 @@ module Tooling
|
|||
end
|
||||
|
||||
def delete(release_name:)
|
||||
run_command([
|
||||
'uninstall',
|
||||
release_name
|
||||
])
|
||||
run_command(['uninstall', release_name])
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
Loading…
Reference in New Issue