Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-11-13 06:09:02 +00:00
parent a7364a0474
commit 254f79fb35
41 changed files with 463 additions and 43 deletions

View file

@ -28,7 +28,6 @@ import initUserPopovers from '~/user_popovers';
import { mergeUrlParams } from '~/lib/utils/url_utility';
import IssueAssignees from '~/vue_shared/components/issue/issue_assignees.vue';
import { isScopedLabel } from '~/lib/utils/common_utils';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { convertToCamelCase } from '~/lib/utils/text_utility';
@ -37,6 +36,7 @@ export default {
openedAgo: __('opened %{timeAgoString} by %{user}'),
openedAgoJira: __('opened %{timeAgoString} by %{user} in Jira'),
},
inject: ['scopedLabelsAvailable'],
components: {
IssueAssignees,
GlLink,
@ -50,7 +50,6 @@ export default {
GlTooltip,
SafeHtml,
},
mixins: [glFeatureFlagsMixin()],
props: {
issuable: {
type: Object,
@ -85,9 +84,6 @@ export default {
return this.issuableLink({ milestone_title: title });
},
scopedLabelsAvailable() {
return this.glFeatures.scopedLabels;
},
hasWeight() {
return isNumber(this.issuable.weight);
},

View file

@ -41,10 +41,13 @@ function mountIssuablesListApp() {
}
document.querySelectorAll('.js-issuables-list').forEach(el => {
const { canBulkEdit, emptyStateMeta = {}, ...data } = el.dataset;
const { canBulkEdit, emptyStateMeta = {}, scopedLabelsAvailable, ...data } = el.dataset;
return new Vue({
el,
provide: {
scopedLabelsAvailable: parseBoolean(scopedLabelsAvailable),
},
render(createElement) {
return createElement(IssuablesListApp, {
props: {

View file

@ -8,9 +8,6 @@ module IssuableActions
before_action :authorize_destroy_issuable!, only: :destroy
before_action :check_destroy_confirmation!, only: :destroy
before_action :authorize_admin_issuable!, only: :bulk_update
before_action only: :show do
push_frontend_feature_flag(:scoped_labels, type: :licensed, default_enabled: true)
end
before_action do
push_frontend_feature_flag(:not_issuable_queries, @project, default_enabled: true)
end

View file

@ -57,10 +57,6 @@ class Projects::IssuesController < Projects::ApplicationController
record_experiment_user(:invite_members_version_b)
end
before_action only: :index do
push_frontend_feature_flag(:scoped_labels, @project, type: :licensed)
end
around_action :allow_gitaly_ref_name_caching, only: [:discussions]
respond_to :html

View file

@ -214,7 +214,7 @@ class Projects::PipelinesController < Projects::ApplicationController
def config_variables
respond_to do |format|
format.json do
render json: Ci::ListConfigVariablesService.new(@project).execute(params[:sha])
render json: Ci::ListConfigVariablesService.new(@project, current_user).execute(params[:sha])
end
end
end

View file

@ -13,6 +13,8 @@ class Projects::ServicesController < Projects::ApplicationController
before_action :redirect_deprecated_prometheus_service, only: [:update]
before_action only: :edit do
push_frontend_feature_flag(:jira_issues_integration, @project, type: :licensed, default_enabled: true)
push_frontend_feature_flag(:jira_vulnerabilities_integration, @project, type: :licensed, default_enabled: true)
push_frontend_feature_flag(:jira_for_vulnerabilities, @project, type: :development, default_enabled: false)
end
respond_to :html

View file

@ -170,6 +170,11 @@ module IssuesHelper
submit_as_spam_path: mark_as_spam_project_issue_path(project, issuable)
}
end
# Overridden in EE
def scoped_labels_available?(parent)
false
end
end
IssuesHelper.prepend_if_ee('EE::IssuesHelper')

View file

@ -416,6 +416,7 @@ class ApplicationSetting < ApplicationRecord
attr_encrypted :slack_app_verification_token, encryption_options_base_truncated_aes_256_gcm
attr_encrypted :ci_jwt_signing_key, encryption_options_base_truncated_aes_256_gcm
attr_encrypted :secret_detection_token_revocation_token, encryption_options_base_truncated_aes_256_gcm
attr_encrypted :cloud_license_auth_token, encryption_options_base_truncated_aes_256_gcm
before_validation :ensure_uuid!

View file

@ -30,7 +30,7 @@ class JiraService < IssueTrackerService
# TODO: we can probably just delegate as part of
# https://gitlab.com/gitlab-org/gitlab/issues/29404
data_field :username, :password, :url, :api_url, :jira_issue_transition_id, :project_key, :issues_enabled
data_field :username, :password, :url, :api_url, :jira_issue_transition_id, :project_key, :issues_enabled, :vulnerabilities_enabled, :vulnerabilities_issuetype
before_update :reset_password
after_commit :update_deployment_type, on: [:create, :update], if: :update_deployment_type?

View file

@ -6,7 +6,10 @@ module Ci
config = project.ci_config_for(sha)
return {} unless config
result = Gitlab::Ci::YamlProcessor.new(config).execute
result = Gitlab::Ci::YamlProcessor.new(config, project: project,
user: current_user,
sha: sha).execute
result.valid? ? result.variables_with_data : {}
end
end

View file

@ -26,11 +26,27 @@ module Projects
project.set_repository_writable!
end
if result && block_given?
yield
end
result
rescue Gitlab::Git::CommandError => e
logger.error("Repository #{project.full_path} failed to upgrade (PROJECT_ID=#{project.id}). Git operation failed: #{e.inspect}")
rollback_migration!
false
rescue OpenSSL::Cipher::CipherError => e
logger.error("Repository #{project.full_path} failed to upgrade (PROJECT_ID=#{project.id}). There is a problem with encrypted attributes: #{e.inspect}")
rollback_migration!
false
end
private
def rollback_migration!
rollback_folder_move
project.storage_version = nil
project.set_repository_writable!
end
end
end

View file

@ -21,14 +21,32 @@ module Projects
project.storage_version = ::Project::HASHED_STORAGE_FEATURES[:repository]
end
project.repository_read_only = false
project.save!(validate: false)
if result && block_given?
yield
project.transaction do
project.save!(validate: false)
project.set_repository_writable!
end
result
rescue Gitlab::Git::CommandError => e
logger.error("Repository #{project.full_path} failed to rollback (PROJECT_ID=#{project.id}). Git operation failed: #{e.inspect}")
rollback_migration!
false
rescue OpenSSL::Cipher::CipherError => e
logger.error("Repository #{project.full_path} failed to rollback (PROJECT_ID=#{project.id}). There is a problem with encrypted attributes: #{e.inspect}")
rollback_migration!
false
end
private
def rollback_migration!
rollback_folder_move
project.storage_version = ::Project::HASHED_STORAGE_FEATURES[:repository]
project.set_repository_writable!
end
end
end

View file

@ -30,6 +30,7 @@
'can-bulk-edit': @can_bulk_update.to_json,
'empty-state-meta': { svg_path: image_path('illustrations/issues.svg') },
'sort-key': @sort,
type: 'issues' } }
type: 'issues',
'scoped-labels-available': scoped_labels_available?(@group).to_json } }
- else
= render 'shared/issues'

View file

@ -11,7 +11,8 @@
'empty-state-meta': data_empty_state_meta.to_json,
'can-bulk-edit': @can_bulk_update.to_json,
'sort-key': @sort,
type: type } }
type: type,
'scoped-labels-available': scoped_labels_available?(@project).to_json } }
- else
- empty_state_path = local_assigns.fetch(:empty_state_path, 'shared/empty_states/issues')
%ul.content-list.issues-list.issuable-list{ class: ("manual-ordering" if @sort == 'relative_position') }

View file

@ -0,0 +1,5 @@
---
title: Fix pipeline security tab filters not showing
merge_request: 47294
author:
type: fixed

View file

@ -0,0 +1,5 @@
---
title: "Hashed Storage: make migration and rollback resilient to exceptions"
merge_request: 46178
author:
type: fixed

View file

@ -0,0 +1,5 @@
---
title: Fix config variables when having includes
merge_request: 47189
author:
type: fixed

View file

@ -0,0 +1,5 @@
---
title: Fix duplicate epic iids and add uniqueness constraint
merge_request: 47081
author:
type: fixed

View file

@ -0,0 +1,5 @@
---
title: Add cloud_license_auth_token column to application_settings
merge_request: 47396
author:
type: added

View file

@ -0,0 +1,7 @@
---
name: jira_for_vulnerabilities
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46982
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/276893
type: development
group: group::threat insights
default_enabled: false

View file

@ -0,0 +1,13 @@
# frozen_string_literal: true
class AddVulnerabilitiesEnabledAndIssuetypeToJiraTrackerData < ActiveRecord::Migration[6.0]
DOWNTIME = false
# rubocop:disable Migration/AddLimitToTextColumns
# limit is added in 20201105143312_add_text_limit_to_jira_tracker_data_issuetype.rb
def change
add_column :jira_tracker_data, :vulnerabilities_issuetype, :text
add_column :jira_tracker_data, :vulnerabilities_enabled, :boolean, default: false, null: false
end
# rubocop:enable Migration/AddLimitToTextColumns
end

View file

@ -0,0 +1,17 @@
# frozen_string_literal: true
class AddTextLimitToJiraTrackerDataIssuetype < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_text_limit :jira_tracker_data, :vulnerabilities_issuetype, 255
end
def down
remove_text_limit :jira_tracker_data, :vulnerabilities_issuetype
end
end

View file

@ -0,0 +1,13 @@
# frozen_string_literal: true
class AddCloudLicenseAuthTokenToSettings < ActiveRecord::Migration[6.0]
DOWNTIME = false
# rubocop:disable Migration/AddLimitToTextColumns
# limit is added in 20201111110918_add_cloud_license_auth_token_application_settings_text_limit
def change
add_column :application_settings, :encrypted_cloud_license_auth_token, :text
add_column :application_settings, :encrypted_cloud_license_auth_token_iv, :text
end
# rubocop:enable Migration/AddLimitToTextColumns
end

View file

@ -0,0 +1,17 @@
# frozen_string_literal: true
class AddCloudLicenseAuthTokenApplicationSettingsTextLimit < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_text_limit :application_settings, :encrypted_cloud_license_auth_token_iv, 255
end
def down
remove_text_limit :application_settings, :encrypted_cloud_license_auth_token_iv
end
end

View file

@ -0,0 +1,121 @@
# frozen_string_literal: true
class DeduplicateEpicIids < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
INDEX_NAME = 'index_epics_on_group_id_and_iid'
disable_ddl_transaction!
class Epic < ActiveRecord::Base
end
class InternalId < ActiveRecord::Base
class << self
def generate_next(subject, scope, usage, init)
InternalIdGenerator.new(subject, scope, usage, init).generate
end
end
# Increments #last_value and saves the record
#
# The operation locks the record and gathers a `ROW SHARE` lock (in PostgreSQL).
# As such, the increment is atomic and safe to be called concurrently.
def increment_and_save!
update_and_save { self.last_value = (last_value || 0) + 1 }
end
private
def update_and_save(&block)
lock!
yield
save!
last_value
end
end
# See app/models/internal_id
class InternalIdGenerator
attr_reader :subject, :scope, :scope_attrs, :usage, :init
def initialize(subject, scope, usage, init = nil)
@subject = subject
@scope = scope
@usage = usage
@init = init
raise ArgumentError, 'Scope is not well-defined, need at least one column for scope (given: 0)' if scope.empty? || usage.to_s != 'epics'
end
# Generates next internal id and returns it
# init: Block that gets called to initialize InternalId record if not present
# Make sure to not throw exceptions in the absence of records (if this is expected).
def generate
subject.transaction do
# Create a record in internal_ids if one does not yet exist
# and increment its last value
#
# Note this will acquire a ROW SHARE lock on the InternalId record
record.increment_and_save!
end
end
def record
@record ||= (lookup || create_record)
end
def lookup
InternalId.find_by(**scope, usage: usage_value)
end
def usage_value
4 # see Enums::InternalId - this is the value for epics
end
# Create InternalId record for (scope, usage) combination, if it doesn't exist
#
# We blindly insert without synchronization. If another process
# was faster in doing this, we'll realize once we hit the unique key constraint
# violation. We can safely roll-back the nested transaction and perform
# a lookup instead to retrieve the record.
def create_record
raise ArgumentError, 'Cannot initialize without init!' unless init
instance = subject.is_a?(::Class) ? nil : subject
subject.transaction(requires_new: true) do
InternalId.create!(
**scope,
usage: usage_value,
last_value: init.call(instance, scope) || 0
)
end
rescue ActiveRecord::RecordNotUnique
lookup
end
end
def up
duplicate_epic_ids = ApplicationRecord.connection.execute('SELECT iid, group_id, COUNT(*) FROM epics GROUP BY iid, group_id HAVING COUNT(*) > 1;')
duplicate_epic_ids.each do |dup|
Epic.where(iid: dup['iid'], group_id: dup['group_id']).last(dup['count'] - 1).each do |epic|
new_iid = InternalId.generate_next(epic,
{ namespace_id: epic.group_id },
:epics, ->(instance, _) { instance.class.where(group_id: epic.group_id).maximum(:iid) }
)
epic.update!(iid: new_iid)
end
end
add_concurrent_index :epics, [:group_id, :iid], unique: true, name: INDEX_NAME
end
def down
# only remove the index, as we do not want to create the duplicates back
remove_concurrent_index :epics, [:group_id, :iid], name: INDEX_NAME
end
end

View file

@ -0,0 +1 @@
b614435cdb654ebbd11bcc5ac0ed69352219e51b368d8f10c0b2998c5258caf9

View file

@ -0,0 +1 @@
decdc314dbcf6b8ac2ce140f81f9d342efca0d98bbeff10c7a041568a67b63f3

View file

@ -0,0 +1 @@
f6e4e62dbd992fc8283f3d7872bb33f1b6bea1b366806caf8f7a65140584c0c1

View file

@ -0,0 +1 @@
4168c39fe93b1c11d8080e07167f79c8234c74a7b274332174d9e861f2084ada

View file

@ -0,0 +1 @@
f5705da7bce46d98ca798c85f08d8a6a0577839aabacd0ba9b50e0b7351a4e96

View file

@ -9342,6 +9342,8 @@ CREATE TABLE application_settings (
domain_denylist text,
domain_allowlist text,
new_user_signups_cap integer,
encrypted_cloud_license_auth_token text,
encrypted_cloud_license_auth_token_iv text,
CONSTRAINT app_settings_registry_exp_policies_worker_capacity_positive CHECK ((container_registry_expiration_policies_worker_capacity >= 0)),
CONSTRAINT check_2dba05b802 CHECK ((char_length(gitpod_url) <= 255)),
CONSTRAINT check_51700b31b5 CHECK ((char_length(default_branch_name) <= 255)),
@ -9351,7 +9353,8 @@ CREATE TABLE application_settings (
CONSTRAINT check_9c6c447a13 CHECK ((char_length(maintenance_mode_message) <= 255)),
CONSTRAINT check_d03919528d CHECK ((char_length(container_registry_vendor) <= 255)),
CONSTRAINT check_d820146492 CHECK ((char_length(spam_check_endpoint_url) <= 255)),
CONSTRAINT check_e5aba18f02 CHECK ((char_length(container_registry_version) <= 255))
CONSTRAINT check_e5aba18f02 CHECK ((char_length(container_registry_version) <= 255)),
CONSTRAINT check_ef6176834f CHECK ((char_length(encrypted_cloud_license_auth_token_iv) <= 255))
);
CREATE SEQUENCE application_settings_id_seq
@ -13192,6 +13195,9 @@ CREATE TABLE jira_tracker_data (
project_key text,
issues_enabled boolean DEFAULT false NOT NULL,
deployment_type smallint DEFAULT 0 NOT NULL,
vulnerabilities_issuetype text,
vulnerabilities_enabled boolean DEFAULT false NOT NULL,
CONSTRAINT check_0bf84b76e9 CHECK ((char_length(vulnerabilities_issuetype) <= 255)),
CONSTRAINT check_214cf6a48b CHECK ((char_length(project_key) <= 255))
);
@ -20735,6 +20741,8 @@ CREATE INDEX index_epics_on_group_id ON epics USING btree (group_id);
CREATE UNIQUE INDEX index_epics_on_group_id_and_external_key ON epics USING btree (group_id, external_key) WHERE (external_key IS NOT NULL);
CREATE UNIQUE INDEX index_epics_on_group_id_and_iid ON epics USING btree (group_id, iid);
CREATE INDEX index_epics_on_group_id_and_iid_varchar_pattern ON epics USING btree (group_id, ((iid)::character varying) varchar_pattern_ops);
CREATE INDEX index_epics_on_iid ON epics USING btree (iid);

View file

@ -24036,9 +24036,6 @@ msgstr ""
msgid "SecurityReports|Scan details"
msgstr ""
msgid "SecurityReports|Scanner"
msgstr ""
msgid "SecurityReports|Security Dashboard"
msgstr ""

View file

@ -83,6 +83,8 @@ FactoryBot.define do
jira_issue_transition_id { '56-1' }
issues_enabled { false }
project_key { nil }
vulnerabilities_enabled { false }
vulnerabilities_issuetype { nil }
end
before(:create) do |service, evaluator|
@ -90,7 +92,8 @@ FactoryBot.define do
create(:jira_tracker_data, service: service,
url: evaluator.url, api_url: evaluator.api_url, jira_issue_transition_id: evaluator.jira_issue_transition_id,
username: evaluator.username, password: evaluator.password, issues_enabled: evaluator.issues_enabled,
project_key: evaluator.project_key
project_key: evaluator.project_key, vulnerabilities_enabled: evaluator.vulnerabilities_enabled,
vulnerabilities_issuetype: evaluator.vulnerabilities_issuetype
)
end
end

View file

@ -38,7 +38,7 @@ describe('Issuable component', () => {
let DateOrig;
let wrapper;
const factory = (props = {}, scopedLabels = false) => {
const factory = (props = {}, scopedLabelsAvailable = false) => {
wrapper = shallowMount(Issuable, {
propsData: {
issuable: simpleIssue,
@ -46,9 +46,7 @@ describe('Issuable component', () => {
...props,
},
provide: {
glFeatures: {
scopedLabels,
},
scopedLabelsAvailable,
},
stubs: {
'gl-sprintf': GlSprintf,

View file

@ -34,13 +34,13 @@ RSpec.describe Resolvers::MergeRequestsResolver do
context 'no arguments' do
it 'returns all merge requests' do
result = resolve_mr(project, {})
result = resolve_mr(project)
expect(result).to contain_exactly(merge_request_1, merge_request_2, merge_request_3, merge_request_4, merge_request_5, merge_request_6, merge_request_with_milestone)
end
it 'returns only merge requests that the current user can see' do
result = resolve_mr(project, {}, user: build(:user))
result = resolve_mr(project, user: build(:user))
expect(result).to be_empty
end
@ -236,10 +236,10 @@ RSpec.describe Resolvers::MergeRequestsResolver do
end
def resolve_mr_single(project, iid)
resolve_mr(project, { iids: iid }, resolver: described_class.single)
resolve_mr(project, resolver: described_class.single, iids: iid)
end
def resolve_mr(project, args, resolver: described_class, user: current_user)
def resolve_mr(project, resolver: described_class, user: current_user, **args)
resolve(resolver, obj: project, args: args, ctx: { current_user: user })
end
end

View file

@ -0,0 +1,36 @@
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20201106134950_deduplicate_epic_iids.rb')
RSpec.describe DeduplicateEpicIids, :migration, schema: 20201106082723 do
let(:routes) { table(:routes) }
let(:epics) { table(:epics) }
let(:users) { table(:users) }
let(:namespaces) { table(:namespaces) }
let!(:group) { create_group('foo') }
let!(:user) { users.create!(email: 'test@example.com', projects_limit: 100, username: 'test') }
let!(:dup_epic1) { epics.create!(iid: 1, title: 'epic 1', group_id: group.id, author_id: user.id, created_at: Time.now, updated_at: Time.now, title_html: 'any') }
let!(:dup_epic2) { epics.create!(iid: 1, title: 'epic 2', group_id: group.id, author_id: user.id, created_at: Time.now, updated_at: Time.now, title_html: 'any') }
let!(:dup_epic3) { epics.create!(iid: 1, title: 'epic 3', group_id: group.id, author_id: user.id, created_at: Time.now, updated_at: Time.now, title_html: 'any') }
it 'deduplicates epic iids', :aggregate_failures do
duplicate_epics_count = epics.where(iid: 1, group_id: group.id).count
expect(duplicate_epics_count).to eq 3
migrate!
duplicate_epics_count = epics.where(iid: 1, group_id: group.id).count
expect(duplicate_epics_count).to eq 1
expect(dup_epic1.reload.iid).to eq 1
expect(dup_epic2.reload.iid).to eq 2
expect(dup_epic3.reload.iid).to eq 3
end
def create_group(path)
namespaces.create!(name: path, path: path, type: 'Group').tap do |namespace|
routes.create!(path: namespace.path, name: namespace.name, source_id: namespace.id, source_type: 'Namespace')
end
end
end

View file

@ -25,7 +25,7 @@ RSpec.describe MigrateDiscussionIdOnPromotedEpics do
end
def create_epic
epics.create!(author_id: user.id, iid: 1,
epics.create!(author_id: user.id, iid: epics.maximum(:iid).to_i + 1,
group_id: namespace.id,
title: 'Epic with discussion',
title_html: 'Epic with discussion')

View file

@ -665,6 +665,20 @@ RSpec.describe ApplicationSetting do
end
end
end
describe '#cloud_license_auth_token' do
it { is_expected.to allow_value(nil).for(:cloud_license_auth_token) }
it 'is encrypted' do
subject.cloud_license_auth_token = 'token-from-customers-dot'
aggregate_failures do
expect(subject.encrypted_cloud_license_auth_token).to be_present
expect(subject.encrypted_cloud_license_auth_token_iv).to be_present
expect(subject.encrypted_cloud_license_auth_token).not_to eq(subject.cloud_license_auth_token)
end
end
end
end
context 'static objects external storage' do

View file

@ -3,8 +3,9 @@
require 'spec_helper'
RSpec.describe Ci::ListConfigVariablesService do
let_it_be(:project) { create(:project, :repository) }
let(:service) { described_class.new(project) }
let(:project) { create(:project, :repository) }
let(:user) { project.creator }
let(:service) { described_class.new(project, user) }
let(:result) { YAML.dump(ci_config) }
subject { service.execute(sha) }
@ -38,6 +39,40 @@ RSpec.describe Ci::ListConfigVariablesService do
end
end
context 'when config has includes' do
let(:sha) { 'master' }
let(:ci_config) do
{
include: [{ local: 'other_file.yml' }],
variables: {
KEY1: { value: 'val 1', description: 'description 1' }
},
test: {
stage: 'test',
script: 'echo'
}
}
end
before do
allow_next_instance_of(Repository) do |repository|
allow(repository).to receive(:blob_data_at).with(sha, 'other_file.yml') do
<<~HEREDOC
variables:
KEY2:
value: 'val 2'
description: 'description 2'
HEREDOC
end
end
end
it 'returns variable list' do
expect(subject['KEY1']).to eq({ value: 'val 1', description: 'description 1' })
expect(subject['KEY2']).to eq({ value: 'val 2', description: 'description 2' })
end
end
context 'when sending an invalid sha' do
let(:sha) { 'invalid-sha' }
let(:ci_config) { nil }

View file

@ -77,6 +77,42 @@ RSpec.describe Projects::HashedStorage::MigrateRepositoryService do
end
end
context 'when exception happens' do
it 'handles OpenSSL::Cipher::CipherError' do
expect(project).to receive(:ensure_runners_token).and_raise(OpenSSL::Cipher::CipherError)
expect { service.execute }.not_to raise_exception
end
it 'ensures rollback when OpenSSL::Cipher::CipherError' do
expect(project).to receive(:ensure_runners_token).and_raise(OpenSSL::Cipher::CipherError)
expect(service).to receive(:rollback_folder_move).and_call_original
service.execute
project.reload
expect(project.legacy_storage?).to be_truthy
expect(project.repository_read_only?).to be_falsey
end
it 'handles Gitlab::Git::CommandError' do
expect(project).to receive(:write_repository_config).and_raise(Gitlab::Git::CommandError)
expect { service.execute }.not_to raise_exception
end
it 'ensures rollback when Gitlab::Git::CommandError' do
expect(project).to receive(:write_repository_config).and_raise(Gitlab::Git::CommandError)
expect(service).to receive(:rollback_folder_move).and_call_original
service.execute
project.reload
expect(project.legacy_storage?).to be_truthy
expect(project.repository_read_only?).to be_falsey
end
end
context 'when one move fails' do
it 'rollsback repositories to original name' do
allow(service).to receive(:move_repository).and_call_original

View file

@ -77,6 +77,42 @@ RSpec.describe Projects::HashedStorage::RollbackRepositoryService, :clean_gitlab
end
end
context 'when exception happens' do
it 'handles OpenSSL::Cipher::CipherError' do
expect(project).to receive(:ensure_runners_token).and_raise(OpenSSL::Cipher::CipherError)
expect { service.execute }.not_to raise_exception
end
it 'ensures rollback when OpenSSL::Cipher::CipherError' do
expect(project).to receive(:ensure_runners_token).and_raise(OpenSSL::Cipher::CipherError)
expect(service).to receive(:rollback_folder_move).and_call_original
service.execute
project.reload
expect(project.hashed_storage?(:repository)).to be_truthy
expect(project.repository_read_only?).to be_falsey
end
it 'handles Gitlab::Git::CommandError' do
expect(project).to receive(:write_repository_config).and_raise(Gitlab::Git::CommandError)
expect { service.execute }.not_to raise_exception
end
it 'ensures rollback when Gitlab::Git::CommandError' do
expect(project).to receive(:write_repository_config).and_raise(Gitlab::Git::CommandError)
expect(service).to receive(:rollback_folder_move).and_call_original
service.execute
project.reload
expect(project.hashed_storage?(:repository)).to be_truthy
expect(project.repository_read_only?).to be_falsey
end
end
context 'when one move fails' do
it 'rolls repositories back to original name' do
allow(service).to receive(:move_repository).and_call_original