Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss19
-rw-r--r--app/controllers/admin/serverless/domains_controller.rb16
-rw-r--r--app/models/pages_domain.rb1
-rw-r--r--changelogs/unreleased/add-feature-flags-version.yml5
-rw-r--r--config/initializers/0_eager_load_http_cookie.rb10
-rw-r--r--config/routes/admin.rb2
-rw-r--r--db/migrate/20200224163804_add_version_to_feature_flags_table.rb23
-rw-r--r--db/schema.rb3
-rw-r--r--lib/gitlab/git/blob.rb4
-rw-r--r--lib/gitlab/import_export/after_export_strategies/move_file_strategy.rb19
-rw-r--r--lib/gitlab/profiler.rb32
-rw-r--r--lib/gitlab/sidekiq_config/cli_methods.rb2
-rw-r--r--lib/gitlab/sidekiq_middleware/request_store_middleware.rb10
-rw-r--r--lib/gitlab/utils/measuring.rb74
-rw-r--r--lib/gitlab/with_request_store.rb13
-rw-r--r--lib/tasks/gitlab/import_export/export.rake94
-rw-r--r--lib/tasks/gitlab/import_export/import.rake89
-rw-r--r--locale/gitlab.pot21
-rw-r--r--package.json2
-rw-r--r--spec/controllers/admin/serverless/domains_controller_spec.rb90
-rw-r--r--spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap9
-rw-r--r--spec/lib/gitlab/git/blob_spec.rb34
-rw-r--r--spec/lib/gitlab/sidekiq_config/cli_methods_spec.rb32
-rw-r--r--spec/models/pages_domain_spec.rb1
-rw-r--r--spec/support/shared_examples/tasks/gitlab/import_export/measurable_shared_examples.rb (renamed from spec/support/shared_examples/tasks/gitlab/import_export/import_measurement_shared_examples.rb)2
-rw-r--r--spec/tasks/gitlab/import_export/export_rake_spec.rb37
-rw-r--r--spec/tasks/gitlab/import_export/import_rake_spec.rb2
-rw-r--r--yarn.lock15
28 files changed, 511 insertions, 150 deletions
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 53a642d68ce..efcbd63626d 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -164,24 +164,11 @@
}
}
-// Temporary hack until `gitlab-ui` issue is fixed.
-// https://gitlab.com/gitlab-org/gitlab-ui/issues/164
.gl-dropdown .dropdown-menu-toggle {
- .gl-dropdown-caret {
- position: absolute;
- right: $gl-padding-8;
- top: $gl-padding-8;
- }
+ padding-right: $gl-padding-8;
- // Add some child to the button so that the default height kicks in
- // when there's no text (since the caret is now aboslute)
- &::after {
- border: 0;
- content: ' ';
- display: inline-block;
- margin: 0;
- padding: 0;
- position: relative;
+ .gl-dropdown-toggle-text {
+ min-height: $gl-line-height-20;
}
}
diff --git a/app/controllers/admin/serverless/domains_controller.rb b/app/controllers/admin/serverless/domains_controller.rb
index c37aec13105..9741a0716f2 100644
--- a/app/controllers/admin/serverless/domains_controller.rb
+++ b/app/controllers/admin/serverless/domains_controller.rb
@@ -2,7 +2,7 @@
class Admin::Serverless::DomainsController < Admin::ApplicationController
before_action :check_feature_flag
- before_action :domain, only: [:update, :verify]
+ before_action :domain, only: [:update, :verify, :destroy]
def index
@domain = PagesDomain.instance_serverless.first_or_initialize
@@ -30,6 +30,20 @@ class Admin::Serverless::DomainsController < Admin::ApplicationController
end
end
+ def destroy
+ if domain.serverless_domain_clusters.count > 0
+ return redirect_to admin_serverless_domains_path,
+ status: :conflict,
+ notice: _('Domain cannot be deleted while associated to one or more clusters.')
+ end
+
+ domain.destroy!
+
+ redirect_to admin_serverless_domains_path,
+ status: :found,
+ notice: _('Domain was successfully deleted.')
+ end
+
def verify
result = VerifyPagesDomainService.new(domain).execute
diff --git a/app/models/pages_domain.rb b/app/models/pages_domain.rb
index 05cf427184c..814c970f745 100644
--- a/app/models/pages_domain.rb
+++ b/app/models/pages_domain.rb
@@ -11,6 +11,7 @@ class PagesDomain < ApplicationRecord
belongs_to :project
has_many :acme_orders, class_name: "PagesDomainAcmeOrder"
+ has_many :serverless_domain_clusters, class_name: 'Serverless::DomainCluster', inverse_of: :pages_domain
validates :domain, hostname: { allow_numeric_hostname: true }
validates :domain, uniqueness: { case_sensitive: false }
diff --git a/changelogs/unreleased/add-feature-flags-version.yml b/changelogs/unreleased/add-feature-flags-version.yml
new file mode 100644
index 00000000000..580bd8da7e1
--- /dev/null
+++ b/changelogs/unreleased/add-feature-flags-version.yml
@@ -0,0 +1,5 @@
+---
+title: Add version column to operations_feature_flags table
+merge_request: 25552
+author:
+type: added
diff --git a/config/initializers/0_eager_load_http_cookie.rb b/config/initializers/0_eager_load_http_cookie.rb
new file mode 100644
index 00000000000..ed633fdb079
--- /dev/null
+++ b/config/initializers/0_eager_load_http_cookie.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+# https://gitlab.com/gitlab-org/gitlab/issues/207937
+# http-cookie is not thread-safe while loading it the first time, see:
+# https://github.com/sparklemotion/http-cookie/issues/6#issuecomment-543570876
+# If we're using it, we should eagerly load it.
+# For now, we have an implicit dependency on it via:
+# * http
+# * rest-client
+require 'http/cookie_jar/hash_store' if Gem.loaded_specs.key?('http-cookie')
diff --git a/config/routes/admin.rb b/config/routes/admin.rb
index 5210b84c8ba..54df15137d6 100644
--- a/config/routes/admin.rb
+++ b/config/routes/admin.rb
@@ -33,7 +33,7 @@ namespace :admin do
resources :gitaly_servers, only: [:index]
namespace :serverless do
- resources :domains, only: [:index, :create, :update] do
+ resources :domains, only: [:index, :create, :update, :destroy] do
member do
post '/verify', to: 'domains#verify'
end
diff --git a/db/migrate/20200224163804_add_version_to_feature_flags_table.rb b/db/migrate/20200224163804_add_version_to_feature_flags_table.rb
new file mode 100644
index 00000000000..e2ccefd8955
--- /dev/null
+++ b/db/migrate/20200224163804_add_version_to_feature_flags_table.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class AddVersionToFeatureFlagsTable < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ FEATURE_FLAG_LEGACY_VERSION = 1
+
+ def up
+ # The operations_feature_flags table is small enough that we can disable this cop.
+ # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25552#note_291202882
+ # rubocop: disable Migration/AddColumnWithDefault
+ add_column_with_default(:operations_feature_flags, :version, :smallint, default: FEATURE_FLAG_LEGACY_VERSION, allow_null: false)
+ # rubocop: enable Migration/AddColumnWithDefault
+ end
+
+ def down
+ remove_column(:operations_feature_flags, :version)
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index c3b1172c6dc..8052a93e841 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2020_02_21_144534) do
+ActiveRecord::Schema.define(version: 2020_02_24_163804) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm"
@@ -2916,6 +2916,7 @@ ActiveRecord::Schema.define(version: 2020_02_21_144534) do
t.string "name", null: false
t.text "description"
t.integer "iid", null: false
+ t.integer "version", limit: 2, default: 1, null: false
t.index ["project_id", "iid"], name: "index_operations_feature_flags_on_project_id_and_iid", unique: true
t.index ["project_id", "name"], name: "index_operations_feature_flags_on_project_id_and_name", unique: true
end
diff --git a/lib/gitlab/git/blob.rb b/lib/gitlab/git/blob.rb
index caa1314dd7f..5579449bf57 100644
--- a/lib/gitlab/git/blob.rb
+++ b/lib/gitlab/git/blob.rb
@@ -165,7 +165,9 @@ module Gitlab
end
def truncated?
- size && (size > loaded_size)
+ return false unless size && loaded_size
+
+ size > loaded_size
end
# Valid LFS object pointer is a text file consisting of
diff --git a/lib/gitlab/import_export/after_export_strategies/move_file_strategy.rb b/lib/gitlab/import_export/after_export_strategies/move_file_strategy.rb
new file mode 100644
index 00000000000..2e3136936f8
--- /dev/null
+++ b/lib/gitlab/import_export/after_export_strategies/move_file_strategy.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module ImportExport
+ module AfterExportStrategies
+ class MoveFileStrategy < BaseAfterExportStrategy
+ def initialize(archive_path:)
+ @archive_path = archive_path
+ end
+
+ private
+
+ def strategy_execute
+ FileUtils.mv(project.export_file.path, @archive_path)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/profiler.rb b/lib/gitlab/profiler.rb
index f47ccb8fed9..e10cdf0d8fb 100644
--- a/lib/gitlab/profiler.rb
+++ b/lib/gitlab/profiler.rb
@@ -2,6 +2,8 @@
module Gitlab
module Profiler
+ extend WithRequestStore
+
FILTERED_STRING = '[FILTERED]'
IGNORE_BACKTRACES = %w[
@@ -58,28 +60,26 @@ module Gitlab
logger = create_custom_logger(logger, private_token: private_token)
- RequestStore.begin!
-
- # Make an initial call for an asset path in development mode to avoid
- # sprockets dominating the profiler output.
- ActionController::Base.helpers.asset_path('katex.css') if Rails.env.development?
+ result = with_request_store do
+ # Make an initial call for an asset path in development mode to avoid
+ # sprockets dominating the profiler output.
+ ActionController::Base.helpers.asset_path('katex.css') if Rails.env.development?
- # Rails loads internationalization files lazily the first time a
- # translation is needed. Running this prevents this overhead from showing
- # up in profiles.
- ::I18n.t('.')[:test_string]
+ # Rails loads internationalization files lazily the first time a
+ # translation is needed. Running this prevents this overhead from showing
+ # up in profiles.
+ ::I18n.t('.')[:test_string]
- # Remove API route mounting from the profile.
- app.get('/api/v4/users')
+ # Remove API route mounting from the profile.
+ app.get('/api/v4/users')
- result = with_custom_logger(logger) do
- with_user(user) do
- RubyProf.profile { app.public_send(verb, url, params: post_data, headers: headers) } # rubocop:disable GitlabSecurity/PublicSend
+ with_custom_logger(logger) do
+ with_user(user) do
+ RubyProf.profile { app.public_send(verb, url, params: post_data, headers: headers) } # rubocop:disable GitlabSecurity/PublicSend
+ end
end
end
- RequestStore.end!
-
log_load_times_by_model(logger)
result
diff --git a/lib/gitlab/sidekiq_config/cli_methods.rb b/lib/gitlab/sidekiq_config/cli_methods.rb
index 8f19b557d24..c95ba6faf1e 100644
--- a/lib/gitlab/sidekiq_config/cli_methods.rb
+++ b/lib/gitlab/sidekiq_config/cli_methods.rb
@@ -21,7 +21,7 @@ module Gitlab
QUERY_OR_OPERATOR = '|'
QUERY_AND_OPERATOR = '&'
QUERY_CONCATENATE_OPERATOR = ','
- QUERY_TERM_REGEX = %r{^(\w+)(!?=)([\w#{QUERY_CONCATENATE_OPERATOR}]+)}.freeze
+ QUERY_TERM_REGEX = %r{^(\w+)(!?=)([\w:#{QUERY_CONCATENATE_OPERATOR}]+)}.freeze
QUERY_PREDICATES = {
feature_category: :to_sym,
diff --git a/lib/gitlab/sidekiq_middleware/request_store_middleware.rb b/lib/gitlab/sidekiq_middleware/request_store_middleware.rb
index 8824f81e8e3..f6142bd6ca5 100644
--- a/lib/gitlab/sidekiq_middleware/request_store_middleware.rb
+++ b/lib/gitlab/sidekiq_middleware/request_store_middleware.rb
@@ -3,12 +3,12 @@
module Gitlab
module SidekiqMiddleware
class RequestStoreMiddleware
+ include Gitlab::WithRequestStore
+
def call(worker, job, queue)
- RequestStore.begin!
- yield
- ensure
- RequestStore.end!
- RequestStore.clear!
+ with_request_store do
+ yield
+ end
end
end
end
diff --git a/lib/gitlab/utils/measuring.rb b/lib/gitlab/utils/measuring.rb
new file mode 100644
index 00000000000..20c57e777d8
--- /dev/null
+++ b/lib/gitlab/utils/measuring.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+require 'prometheus/pid_provider'
+
+module Gitlab
+ module Utils
+ class Measuring
+ def initialize(logger: Logger.new($stdout))
+ @logger = logger
+ end
+
+ def with_measuring
+ logger.info "Measuring enabled..."
+ with_gc_counter do
+ with_count_queries do
+ with_measure_time do
+ yield
+ end
+ end
+ end
+
+ logger.info "Memory usage: #{Gitlab::Metrics::System.memory_usage.to_f / 1024 / 1024} MiB"
+ logger.info "Label: #{::Prometheus::PidProvider.worker_id}"
+ end
+
+ private
+
+ attr_reader :logger
+
+ def with_count_queries(&block)
+ count = 0
+
+ counter_f = ->(_name, _started, _finished, _unique_id, payload) {
+ count += 1 unless payload[:name].in? %w[CACHE SCHEMA]
+ }
+
+ ActiveSupport::Notifications.subscribed(counter_f, "sql.active_record", &block)
+
+ logger.info "Number of sql calls: #{count}"
+ end
+
+ def with_gc_counter
+ gc_counts_before = GC.stat.select { |k, _v| k =~ /count/ }
+ yield
+ gc_counts_after = GC.stat.select { |k, _v| k =~ /count/ }
+ stats = gc_counts_before.merge(gc_counts_after) { |_k, vb, va| va - vb }
+
+ logger.info "Total GC count: #{stats[:count]}"
+ logger.info "Minor GC count: #{stats[:minor_gc_count]}"
+ logger.info "Major GC count: #{stats[:major_gc_count]}"
+ end
+
+ def with_measure_time
+ timing = Benchmark.realtime do
+ yield
+ end
+
+ logger.info "Time to finish: #{duration_in_numbers(timing)}"
+ end
+
+ def duration_in_numbers(duration_in_seconds)
+ seconds = duration_in_seconds % 1.minute
+ minutes = (duration_in_seconds / 1.minute) % (1.hour / 1.minute)
+ hours = duration_in_seconds / 1.hour
+
+ if hours == 0
+ "%02d:%02d" % [minutes, seconds]
+ else
+ "%02d:%02d:%02d" % [hours, minutes, seconds]
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/with_request_store.rb b/lib/gitlab/with_request_store.rb
new file mode 100644
index 00000000000..d6c05e1e256
--- /dev/null
+++ b/lib/gitlab/with_request_store.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module WithRequestStore
+ def with_request_store
+ RequestStore.begin!
+ yield
+ ensure
+ RequestStore.end!
+ RequestStore.clear!
+ end
+ end
+end
diff --git a/lib/tasks/gitlab/import_export/export.rake b/lib/tasks/gitlab/import_export/export.rake
new file mode 100644
index 00000000000..6cedf4e8cf1
--- /dev/null
+++ b/lib/tasks/gitlab/import_export/export.rake
@@ -0,0 +1,94 @@
+# frozen_string_literal: true
+
+require 'gitlab/with_request_store'
+
+# Export project to archive
+#
+# @example
+# bundle exec rake "gitlab:import_export:export[root, root, project_to_export, /path/to/file.tar.gz, true]"
+#
+namespace :gitlab do
+ namespace :import_export do
+ desc 'GitLab | Import/Export | EXPERIMENTAL | Export large project archives'
+ task :export, [:username, :namespace_path, :project_path, :archive_path, :measurement_enabled] => :gitlab_environment do |_t, args|
+ # Load it here to avoid polluting Rake tasks with Sidekiq test warnings
+ require 'sidekiq/testing'
+
+ warn_user_is_not_gitlab
+
+ if ENV['IMPORT_DEBUG'].present?
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
+ Gitlab::Metrics::Exporter::SidekiqExporter.instance.start
+ end
+
+ GitlabProjectExport.new(
+ namespace_path: args.namespace_path,
+ project_path: args.project_path,
+ username: args.username,
+ file_path: args.archive_path,
+ measurement_enabled: Gitlab::Utils.to_boolean(args.measurement_enabled)
+ ).export
+ end
+ end
+end
+
+class GitlabProjectExport
+ include Gitlab::WithRequestStore
+
+ def initialize(opts)
+ @project_path = opts.fetch(:project_path)
+ @file_path = opts.fetch(:file_path)
+ @current_user = User.find_by_username(opts.fetch(:username))
+ namespace = Namespace.find_by_full_path(opts.fetch(:namespace_path))
+ @project = namespace.projects.find_by_path(@project_path)
+ @measurement_enabled = opts.fetch(:measurement_enabled)
+ @measurable = Gitlab::Utils::Measuring.new if @measurement_enabled
+ end
+
+ def export
+ validate_project
+ validate_file_path
+
+ with_export do
+ ::Projects::ImportExport::ExportService.new(project, current_user)
+ .execute(Gitlab::ImportExport::AfterExportStrategies::MoveFileStrategy.new(archive_path: file_path))
+ end
+
+ puts 'Done!'
+ rescue StandardError => e
+ puts "Exception: #{e.message}"
+ puts e.backtrace
+ exit 1
+ end
+
+ private
+
+ attr_reader :measurable, :project, :current_user, :file_path, :project_path
+
+ def validate_project
+ unless project
+ puts "Error: Project with path: #{project_path} was not found. Please provide correct project path"
+ exit 1
+ end
+ end
+
+ def validate_file_path
+ directory = File.dirname(file_path)
+ unless Dir.exist?(directory)
+ puts "Error: Invalid file path: #{file_path}. Please provide correct file path"
+ exit 1
+ end
+ end
+
+ def with_export
+ with_request_store do
+ ::Gitlab::GitalyClient.allow_n_plus_1_calls do
+ measurement_enabled? ? measurable.with_measuring { yield } : yield
+ end
+ end
+ end
+
+ def measurement_enabled?
+ @measurement_enabled
+ end
+end
diff --git a/lib/tasks/gitlab/import_export/import.rake b/lib/tasks/gitlab/import_export/import.rake
index c832cba0287..4ed724a5c82 100644
--- a/lib/tasks/gitlab/import_export/import.rake
+++ b/lib/tasks/gitlab/import_export/import.rake
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require 'gitlab/with_request_store'
+
# Import large project archives
#
# This task:
@@ -27,19 +29,22 @@ namespace :gitlab do
project_path: args.project_path,
username: args.username,
file_path: args.archive_path,
- measurement_enabled: args.measurement_enabled == 'true'
+ measurement_enabled: Gitlab::Utils.to_boolean(args.measurement_enabled)
).import
end
end
end
class GitlabProjectImport
+ include Gitlab::WithRequestStore
+
def initialize(opts)
@project_path = opts.fetch(:project_path)
@file_path = opts.fetch(:file_path)
@namespace = Namespace.find_by_full_path(opts.fetch(:namespace_path))
@current_user = User.find_by_username(opts.fetch(:username))
@measurement_enabled = opts.fetch(:measurement_enabled)
+ @measurement = Gitlab::Utils::Measuring.new if @measurement_enabled
end
def import
@@ -49,11 +54,11 @@ class GitlabProjectImport
show_import_failures_count
- if @project&.import_state&.last_error
- puts "ERROR: #{@project.import_state.last_error}"
+ if project&.import_state&.last_error
+ puts "ERROR: #{project.import_state.last_error}"
exit 1
- elsif @project.errors.any?
- puts "ERROR: #{@project.errors.full_messages.join(', ')}"
+ elsif project.errors.any?
+ puts "ERROR: #{project.errors.full_messages.join(', ')}"
exit 1
else
puts 'Done!'
@@ -66,60 +71,10 @@ class GitlabProjectImport
private
- def with_request_store
- RequestStore.begin!
- yield
- ensure
- RequestStore.end!
- RequestStore.clear!
- end
-
- def with_count_queries(&block)
- count = 0
-
- counter_f = ->(name, started, finished, unique_id, payload) {
- unless payload[:name].in? %w[CACHE SCHEMA]
- count += 1
- end
- }
-
- ActiveSupport::Notifications.subscribed(counter_f, "sql.active_record", &block)
-
- puts "Number of sql calls: #{count}"
- end
-
- def with_gc_counter
- gc_counts_before = GC.stat.select { |k, v| k =~ /count/ }
- yield
- gc_counts_after = GC.stat.select { |k, v| k =~ /count/ }
- stats = gc_counts_before.merge(gc_counts_after) { |k, vb, va| va - vb }
- puts "Total GC count: #{stats[:count]}"
- puts "Minor GC count: #{stats[:minor_gc_count]}"
- puts "Major GC count: #{stats[:major_gc_count]}"
- end
-
- def with_measure_time
- timing = Benchmark.realtime do
- yield
- end
-
- time = Time.at(timing).utc.strftime("%H:%M:%S")
- puts "Time to finish: #{time}"
- end
-
- def with_measuring
- puts "Measuring enabled..."
- with_gc_counter do
- with_count_queries do
- with_measure_time do
- yield
- end
- end
- end
- end
+ attr_reader :measurement, :project, :namespace, :current_user, :file_path, :project_path
def measurement_enabled?
- @measurement_enabled != false
+ @measurement_enabled
end
# We want to ensure that all Sidekiq jobs are executed
@@ -135,7 +90,7 @@ class GitlabProjectImport
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24475#note_283090635
# For development setups, this code-path will be excluded from n+1 detection.
::Gitlab::GitalyClient.allow_n_plus_1_calls do
- measurement_enabled? ? with_measuring { yield } : yield
+ measurement_enabled? ? measurement.with_measuring { yield } : yield
end
end
@@ -158,11 +113,11 @@ class GitlabProjectImport
# 2. Download of archive before unpacking
disable_upload_object_storage do
service = Projects::GitlabProjectsImportService.new(
- @current_user,
+ current_user,
{
- namespace_id: @namespace.id,
- path: @project_path,
- file: File.open(@file_path)
+ namespace_id: namespace.id,
+ path: project_path,
+ file: File.open(file_path)
}
)
@@ -193,18 +148,18 @@ class GitlabProjectImport
end
def full_path
- "#{@namespace.full_path}/#{@project_path}"
+ "#{namespace.full_path}/#{project_path}"
end
def show_import_start_message
- puts "Importing GitLab export: #{@file_path} into GitLab" \
+ puts "Importing GitLab export: #{file_path} into GitLab" \
" #{full_path}" \
- " as #{@current_user.name}"
+ " as #{current_user.name}"
end
def show_import_failures_count
- return unless @project.import_failures.exists?
+ return unless project.import_failures.exists?
- puts "Total number of not imported relations: #{@project.import_failures.count}"
+ puts "Total number of not imported relations: #{project.import_failures.count}"
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 04fd7d3cc1a..ef30d868a01 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -3480,6 +3480,9 @@ msgstr ""
msgid "Checkout|Country"
msgstr ""
+msgid "Checkout|Create a new group"
+msgstr ""
+
msgid "Checkout|Credit card form failed to load. Please try again."
msgstr ""
@@ -3507,6 +3510,9 @@ msgstr ""
msgid "Checkout|Failed to register credit card. Please try again."
msgstr ""
+msgid "Checkout|GitLab group"
+msgstr ""
+
msgid "Checkout|GitLab plan"
msgstr ""
@@ -3531,6 +3537,9 @@ msgstr ""
msgid "Checkout|Please select a state"
msgstr ""
+msgid "Checkout|Select"
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -3555,9 +3564,15 @@ msgstr ""
msgid "Checkout|Users"
msgstr ""
+msgid "Checkout|You'll create your new group after checkout"
+msgstr ""
+
msgid "Checkout|Your organization"
msgstr ""
+msgid "Checkout|Your subscription will be applied to this group"
+msgstr ""
+
msgid "Checkout|Zip code"
msgstr ""
@@ -6865,12 +6880,18 @@ msgstr ""
msgid "Domain"
msgstr ""
+msgid "Domain cannot be deleted while associated to one or more clusters."
+msgstr ""
+
msgid "Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled"
msgstr ""
msgid "Domain was successfully created."
msgstr ""
+msgid "Domain was successfully deleted."
+msgstr ""
+
msgid "Domain was successfully updated."
msgstr ""
diff --git a/package.json b/package.json
index 4398ecc0bc4..ccd9c41cf8d 100644
--- a/package.json
+++ b/package.json
@@ -41,7 +41,7 @@
"@babel/preset-env": "^7.6.2",
"@gitlab/at.js": "^1.5.5",
"@gitlab/svgs": "^1.99.0",
- "@gitlab/ui": "^9.11.1",
+ "@gitlab/ui": "^9.11.2",
"@gitlab/visual-review-tools": "1.5.1",
"@sentry/browser": "^5.10.2",
"@sourcegraph/code-host-integration": "0.0.30",
diff --git a/spec/controllers/admin/serverless/domains_controller_spec.rb b/spec/controllers/admin/serverless/domains_controller_spec.rb
index aed83e190be..43c3f0117bc 100644
--- a/spec/controllers/admin/serverless/domains_controller_spec.rb
+++ b/spec/controllers/admin/serverless/domains_controller_spec.rb
@@ -15,7 +15,7 @@ describe Admin::Serverless::DomainsController do
it 'responds with 404' do
get :index
- expect(response.status).to eq(404)
+ expect(response).to have_gitlab_http_status(:not_found)
end
end
@@ -33,7 +33,7 @@ describe Admin::Serverless::DomainsController do
it 'responds with 404' do
get :index
- expect(response.status).to eq(404)
+ expect(response).to have_gitlab_http_status(:not_found)
end
end
@@ -81,7 +81,7 @@ describe Admin::Serverless::DomainsController do
it 'responds with 404' do
post :create, params: { pages_domain: create_params }
- expect(response.status).to eq(404)
+ expect(response).to have_gitlab_http_status(:not_found)
end
end
@@ -98,7 +98,7 @@ describe Admin::Serverless::DomainsController do
it 'responds with 404' do
post :create, params: { pages_domain: create_params }
- expect(response.status).to eq(404)
+ expect(response).to have_gitlab_http_status(:not_found)
end
end
@@ -169,7 +169,7 @@ describe Admin::Serverless::DomainsController do
it 'responds with 404' do
put :update, params: { id: domain.id, pages_domain: update_params }
- expect(response.status).to eq(404)
+ expect(response).to have_gitlab_http_status(:not_found)
end
end
@@ -186,7 +186,7 @@ describe Admin::Serverless::DomainsController do
it 'responds with 404' do
put :update, params: { id: domain.id, pages_domain: update_params }
- expect(response.status).to eq(404)
+ expect(response).to have_gitlab_http_status(:not_found)
end
end
@@ -221,7 +221,7 @@ describe Admin::Serverless::DomainsController do
it 'returns 404' do
put :update, params: { id: 0, pages_domain: update_params }
- expect(response.status).to eq(404)
+ expect(response).to have_gitlab_http_status(:not_found)
end
end
@@ -247,7 +247,7 @@ describe Admin::Serverless::DomainsController do
it 'responds with 404' do
post :verify, params: { id: domain.id }
- expect(response.status).to eq(404)
+ expect(response).to have_gitlab_http_status(:not_found)
end
end
@@ -272,7 +272,7 @@ describe Admin::Serverless::DomainsController do
it 'responds with 404' do
post :verify, params: { id: domain.id }
- expect(response.status).to eq(404)
+ expect(response).to have_gitlab_http_status(:not_found)
end
end
@@ -295,4 +295,76 @@ describe Admin::Serverless::DomainsController do
end
end
end
+
+ describe '#destroy' do
+ let!(:domain) { create(:pages_domain, :instance_serverless) }
+
+ context 'non-admin user' do
+ before do
+ sign_in(user)
+ end
+
+ it 'responds with 404' do
+ delete :destroy, params: { id: domain.id }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'admin user' do
+ before do
+ sign_in(admin)
+ end
+
+ context 'with serverless_domain feature disabled' do
+ before do
+ stub_feature_flags(serverless_domain: false)
+ end
+
+ it 'responds with 404' do
+ delete :destroy, params: { id: domain.id }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when domain exists' do
+ context 'and is not associated to any clusters' do
+ it 'deletes the domain' do
+ expect { delete :destroy, params: { id: domain.id } }
+ .to change { PagesDomain.count }.from(1).to(0)
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(flash[:notice]).to include('Domain was successfully deleted.')
+ end
+ end
+
+ context 'and is associated to any clusters' do
+ before do
+ create(:serverless_domain_cluster, pages_domain: domain)
+ end
+
+ it 'does not delete the domain' do
+ expect { delete :destroy, params: { id: domain.id } }
+ .not_to change { PagesDomain.count }
+
+ expect(response).to have_gitlab_http_status(:conflict)
+ expect(flash[:notice]).to include('Domain cannot be deleted while associated to one or more clusters.')
+ end
+ end
+ end
+
+ context 'when domain does not exist' do
+ before do
+ domain.destroy!
+ end
+
+ it 'responds with 404' do
+ delete :destroy, params: { id: domain.id }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+ end
end
diff --git a/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap b/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap
index a35348d86ea..d4269bf14ba 100644
--- a/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap
+++ b/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap
@@ -9,9 +9,12 @@ exports[`Remove cluster confirmation modal renders splitbutton with modal includ
class="btn btn-danger"
type="button"
>
-
- Remove integration and resources
-
+ <span
+ class="gl-dropdown-toggle-text"
+ >
+ Remove integration and resources
+ </span>
+
<!---->
</button>
<button
diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb
index 079f01c2c4e..9c2f0e910b1 100644
--- a/spec/lib/gitlab/git/blob_spec.rb
+++ b/spec/lib/gitlab/git/blob_spec.rb
@@ -613,6 +613,40 @@ describe Gitlab::Git::Blob, :seed_helper do
end
end
+ describe '#truncated?' do
+ context 'when blob.size is nil' do
+ let(:nil_size_blob) { Gitlab::Git::Blob.new(name: 'test', data: 'abcd') }
+
+ it 'returns false' do
+ expect(nil_size_blob.truncated?).to be_falsey
+ end
+ end
+
+ context 'when blob.data is missing' do
+ let(:nil_data_blob) { Gitlab::Git::Blob.new(name: 'test', size: 4) }
+
+ it 'returns false' do
+ expect(nil_data_blob.truncated?).to be_falsey
+ end
+ end
+
+ context 'when the blob is truncated' do
+ let(:truncated_blob) { Gitlab::Git::Blob.new(name: 'test', size: 40, data: 'abcd') }
+
+ it 'returns true' do
+ expect(truncated_blob.truncated?).to be_truthy
+ end
+ end
+
+ context 'when the blob is untruncated' do
+ let(:untruncated_blob) { Gitlab::Git::Blob.new(name: 'test', size: 4, data: 'abcd') }
+
+ it 'returns false' do
+ expect(untruncated_blob.truncated?).to be_falsey
+ end
+ end
+ end
+
describe 'metrics' do
it 'defines :gitlab_blob_truncated_true counter' do
expect(described_class).to respond_to(:gitlab_blob_truncated_true)
diff --git a/spec/lib/gitlab/sidekiq_config/cli_methods_spec.rb b/spec/lib/gitlab/sidekiq_config/cli_methods_spec.rb
index e6d0055df64..4ba5726732c 100644
--- a/spec/lib/gitlab/sidekiq_config/cli_methods_spec.rb
+++ b/spec/lib/gitlab/sidekiq_config/cli_methods_spec.rb
@@ -128,7 +128,7 @@ describe Gitlab::SidekiqConfig::CliMethods do
resource_boundary: :cpu
},
{
- name: 'a_2',
+ name: 'a:2',
feature_category: :category_a,
has_external_dependencies: false,
latency_sensitive: true,
@@ -154,40 +154,40 @@ describe Gitlab::SidekiqConfig::CliMethods do
context 'with valid input' do
where(:query, :selected_queues) do
# feature_category
- 'feature_category=category_a' | %w(a a_2)
- 'feature_category=category_a,category_c' | %w(a a_2 c)
- 'feature_category=category_a|feature_category=category_c' | %w(a a_2 c)
+ 'feature_category=category_a' | %w(a a:2)
+ 'feature_category=category_a,category_c' | %w(a a:2 c)
+ 'feature_category=category_a|feature_category=category_c' | %w(a a:2 c)
'feature_category!=category_a' | %w(b c)
# has_external_dependencies
'has_external_dependencies=true' | %w(b)
- 'has_external_dependencies=false' | %w(a a_2 c)
- 'has_external_dependencies=true,false' | %w(a a_2 b c)
- 'has_external_dependencies=true|has_external_dependencies=false' | %w(a a_2 b c)
- 'has_external_dependencies!=true' | %w(a a_2 c)
+ 'has_external_dependencies=false' | %w(a a:2 c)
+ 'has_external_dependencies=true,false' | %w(a a:2 b c)
+ 'has_external_dependencies=true|has_external_dependencies=false' | %w(a a:2 b c)
+ 'has_external_dependencies!=true' | %w(a a:2 c)
# latency_sensitive
- 'latency_sensitive=true' | %w(a_2 b)
+ 'latency_sensitive=true' | %w(a:2 b)
'latency_sensitive=false' | %w(a c)
- 'latency_sensitive=true,false' | %w(a a_2 b c)
- 'latency_sensitive=true|latency_sensitive=false' | %w(a a_2 b c)
+ 'latency_sensitive=true,false' | %w(a a:2 b c)
+ 'latency_sensitive=true|latency_sensitive=false' | %w(a a:2 b c)
'latency_sensitive!=true' | %w(a c)
# name
'name=a' | %w(a)
'name=a,b' | %w(a b)
- 'name=a,a_2|name=b' | %w(a a_2 b)
- 'name!=a,a_2' | %w(b c)
+ 'name=a,a:2|name=b' | %w(a a:2 b)
+ 'name!=a,a:2' | %w(b c)
# resource_boundary
'resource_boundary=memory' | %w(b c)
'resource_boundary=memory,cpu' | %w(a b c)
'resource_boundary=memory|resource_boundary=cpu' | %w(a b c)
- 'resource_boundary!=memory,cpu' | %w(a_2)
+ 'resource_boundary!=memory,cpu' | %w(a:2)
# combinations
- 'feature_category=category_a&latency_sensitive=true' | %w(a_2)
- 'feature_category=category_a&latency_sensitive=true|feature_category=category_c' | %w(a_2 c)
+ 'feature_category=category_a&latency_sensitive=true' | %w(a:2)
+ 'feature_category=category_a&latency_sensitive=true|feature_category=category_c' | %w(a:2 c)
end
with_them do
diff --git a/spec/models/pages_domain_spec.rb b/spec/models/pages_domain_spec.rb
index d2a54c3eea7..7b24ca5eb23 100644
--- a/spec/models/pages_domain_spec.rb
+++ b/spec/models/pages_domain_spec.rb
@@ -9,6 +9,7 @@ describe PagesDomain do
describe 'associations' do
it { is_expected.to belong_to(:project) }
+ it { is_expected.to have_many(:serverless_domain_clusters) }
end
describe 'validate domain' do
diff --git a/spec/support/shared_examples/tasks/gitlab/import_export/import_measurement_shared_examples.rb b/spec/support/shared_examples/tasks/gitlab/import_export/measurable_shared_examples.rb
index e232f237df9..4df81478639 100644
--- a/spec/support/shared_examples/tasks/gitlab/import_export/import_measurement_shared_examples.rb
+++ b/spec/support/shared_examples/tasks/gitlab/import_export/measurable_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.shared_examples 'import measurement' do
+RSpec.shared_examples 'measurable' do
context 'when measurement is enabled' do
let(:measurement_enabled) { true }
diff --git a/spec/tasks/gitlab/import_export/export_rake_spec.rb b/spec/tasks/gitlab/import_export/export_rake_spec.rb
new file mode 100644
index 00000000000..b665b46fe1c
--- /dev/null
+++ b/spec/tasks/gitlab/import_export/export_rake_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'rake_helper'
+
+describe 'gitlab:import_export:export rake task' do
+ let(:username) { 'root' }
+ let(:namespace_path) { username }
+ let!(:user) { create(:user, username: username) }
+ let(:measurement_enabled) { false }
+ let(:task_params) { [username, namespace_path, project_name, archive_path, measurement_enabled] }
+
+ before do
+ Rake.application.rake_require('tasks/gitlab/import_export/export')
+ end
+
+ subject { run_rake_task('gitlab:import_export:export', task_params) }
+
+ context 'when project is found' do
+ let(:project) { create(:project, creator: user, namespace: user.namespace) }
+ let(:project_name) { project.name }
+ let(:archive_path) { 'spec/fixtures/gitlab/import_export/test_project_export.tar.gz' }
+
+ around do |example|
+ example.run
+ ensure
+ File.delete(archive_path)
+ end
+
+ it 'performs project export successfully' do
+ expect { subject }.to output(/Done!/).to_stdout
+
+ expect(File).to exist(archive_path)
+ end
+
+ it_behaves_like 'measurable'
+ end
+end
diff --git a/spec/tasks/gitlab/import_export/import_rake_spec.rb b/spec/tasks/gitlab/import_export/import_rake_spec.rb
index 3a819d23299..3e0bf2d0832 100644
--- a/spec/tasks/gitlab/import_export/import_rake_spec.rb
+++ b/spec/tasks/gitlab/import_export/import_rake_spec.rb
@@ -70,7 +70,7 @@ describe 'gitlab:import_export:import rake task' do
subject
end
- it_behaves_like 'import measurement'
+ it_behaves_like 'measurable'
end
context 'when project import is invalid' do
diff --git a/yarn.lock b/yarn.lock
index bfd3cdea05d..94ac80c7061 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -745,10 +745,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.99.0.tgz#bcf971c3a14920218e86da71ca115244b23a4a3f"
integrity sha512-bxYFxnmuoWPBU9isL3/CYFlr+k2YWU47Pq0vfmSmL7uLnb/vYymfZZF5p3erlZ62WGwuT3kp4GnuoZBMfmannA==
-"@gitlab/ui@^9.11.1":
- version "9.11.1"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-9.11.1.tgz#f234687d2d1b555ebeaf05156e16b4fd97aef453"
- integrity sha512-3INIA2n9rxz+VCc0hO4EnmET00XCAMS25hHnIJ6ffKeJz40diCvEZ6Asusv4BiIPosmTyz8VufYGQRq+8v8rNQ==
+"@gitlab/ui@^9.11.2":
+ version "9.11.2"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-9.11.2.tgz#ffb58bb10c6a8cd503a622946ed78512e9c18c6d"
+ integrity sha512-9acsjQ9+hSaAIGpiARNF4XfQUhulWiausns9JUTrN9XEQpa1o/EsDYqwP0HfSOMZ8JhnjSI2NGYVf+LIH5oudg==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.3.0"
@@ -11626,16 +11626,11 @@ uuid@3.3.2, uuid@^3.0.1, uuid@^3.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
-v8-compile-cache@2.0.3:
+v8-compile-cache@2.0.3, v8-compile-cache@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe"
integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==
-v8-compile-cache@^2.0.3:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
- integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==
-
validate-npm-package-license@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"