Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-04-12 09:09:09 +00:00
parent 4044a01bd7
commit ede2fbdc87
39 changed files with 279 additions and 121 deletions

View File

@ -442,7 +442,6 @@ RSpec/EmptyLineAfterFinalLetItBe:
- ee/spec/controllers/registrations/groups_controller_spec.rb
- ee/spec/controllers/registrations/projects_controller_spec.rb
- ee/spec/controllers/subscriptions_controller_spec.rb
- ee/spec/features/admin/admin_show_new_user_signups_cap_alert_spec.rb
- ee/spec/features/boards/group_boards/multiple_boards_spec.rb
- ee/spec/features/ci_shared_runner_warnings_spec.rb
- ee/spec/features/dashboards/todos_spec.rb
@ -1036,12 +1035,6 @@ RSpec/EmptyLineAfterFinalLetItBe:
- spec/services/markdown_content_rewriter_service_spec.rb
- spec/services/members/create_service_spec.rb
- spec/services/members/invite_service_spec.rb
- spec/services/merge_requests/base_service_spec.rb
- spec/services/merge_requests/create_pipeline_service_spec.rb
- spec/services/merge_requests/export_csv_service_spec.rb
- spec/services/merge_requests/merge_orchestration_service_spec.rb
- spec/services/merge_requests/merge_service_spec.rb
- spec/services/merge_requests/merge_to_ref_service_spec.rb
- spec/services/metrics/dashboard/annotations/create_service_spec.rb
- spec/services/metrics/dashboard/gitlab_alert_embed_service_spec.rb
- spec/services/metrics/users_starred_dashboards/create_service_spec.rb

View File

@ -1 +1 @@
2b9f2f35e178b8b56b5f657420aa72c6a77c62eb
ca2b1ea56e839a9bc4878abb1e9ecac8002b4b07

View File

@ -475,7 +475,7 @@ group :ed25519 do
end
# Gitaly GRPC protocol definitions
gem 'gitaly', '~> 13.9.0.pre.rc1'
gem 'gitaly', '~> 13.11.0.pre.rc1'
gem 'grpc', '~> 1.30.2'

View File

@ -440,7 +440,7 @@ GEM
rails (>= 3.2.0)
git (1.7.0)
rchardet (~> 1.8)
gitaly (13.9.0.pre.rc1)
gitaly (13.11.0.pre.rc1)
grpc (~> 1.0)
github-markup (1.7.0)
gitlab (4.16.1)
@ -1427,7 +1427,7 @@ DEPENDENCIES
gettext (~> 3.3)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
gitaly (~> 13.9.0.pre.rc1)
gitaly (~> 13.11.0.pre.rc1)
github-markup (~> 1.7.0)
gitlab-chronic (~> 0.10.5)
gitlab-dangerfiles (~> 1.1.1)

View File

@ -117,7 +117,12 @@ export default {
<div class="table-section section-50" role="rowheader">{{ s__('CiVariables|Value') }}</div>
</div>
<div v-for="variable in variables" :key="variable.id" class="gl-responsive-table-row">
<div
v-for="variable in variables"
:key="variable.id"
class="gl-responsive-table-row"
data-testid="ci-variable-row"
>
<div class="table-section section-50">
<div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Key') }}</div>
<div class="table-mobile-content gl-mr-3">
@ -126,6 +131,7 @@ export default {
v-model="variable.key"
:placeholder="$options.i18n.keyPlaceholder"
class="ci-variable-body-item form-control"
data-testid="ci-variable-key"
/>
</div>
</div>
@ -138,6 +144,7 @@ export default {
v-model="variable.secret_value"
:placeholder="$options.i18n.valuePlaceholder"
class="ci-variable-body-item form-control"
data-testid="ci-variable-value"
/>
</div>
</div>
@ -149,6 +156,7 @@ export default {
category="tertiary"
icon="clear"
:aria-label="__('Delete variable')"
data-testid="delete-variable-btn"
@click="deleteVariable(variable.id)"
/>
</div>
@ -181,7 +189,7 @@ export default {
</div>
</div>
<div class="d-flex gl-mt-3 justify-content-center">
<p class="text-muted" v-html="helpText"></p>
<p class="text-muted" data-testid="form-help-text" v-html="helpText"></p>
</div>
<div class="d-flex justify-content-center">
<gl-button

View File

@ -5,11 +5,17 @@ module Clusters
module ApplicationVersion
extend ActiveSupport::Concern
EXTERNAL_VERSION = 'EXTERNALLY_INSTALLED'
included do
state_machine :status do
before_transition any => [:installed, :updated] do |application|
application.version = application.class.const_get(:VERSION, false)
end
before_transition any => [:externally_installed] do |application|
application.version = EXTERNAL_VERSION
end
end
end

View File

@ -0,0 +1,5 @@
---
title: Move to btn-confirm from btn-success in push_rules directory
merge_request: 58033
author: Yogi (@yo)
type: changed

View File

@ -0,0 +1,5 @@
---
title: Fix EmptyLineAfterFinalLetItBe offenses in spec/services/merge_requests
merge_request: 58429
author: Huzaifa Iftikhar @huzaifaiftikhar
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Use object quarantine directory to enumerate new LFS pointers
merge_request: 58634
author:
type: performance

View File

@ -0,0 +1,5 @@
---
title: Fix cop offenses for Style/HashTransformation in ee directory
merge_request: 56581
author: Karthik Sivadas @karthik.sivadas
type: other

View File

@ -0,0 +1,5 @@
---
title: Fix cop offenses for Style/HashTransformation in spec directory
merge_request: 56586
author: Karthik Sivadas @karthik.sivadas
type: other

View File

@ -0,0 +1,8 @@
---
name: lfs_integrity_inspect_quarantined_objects
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58634
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/327440
milestone: '13.11'
type: development
group: group::gitaly
default_enabled: false

View File

@ -762,6 +762,21 @@ end
Gitlab::CurrentSettings.current_application_settings.runners_registration_token
```
### Run pipeline schedules manually
You can run pipeline schedules manually through the Rails console to reveal any errors that are usually not visible.
```ruby
# schedule_id can be obtained from Edit Pipeline Schedule page
schedule = Ci::PipelineSchedule.find_by(id: <schedule_id>)
# Select the user that you want to run the schedule for
user = User.find_by_username('<username>')
# Run the schedule
ps = Ci::CreatePipelineService.new(schedule.project, user, ref: schedule.ref).execute!(:schedule, ignore_skip_ci: true, save_on_errors: false, schedule: schedule)
```
## License
### See current license information

View File

@ -78,17 +78,7 @@ module Gitlab
end
def get_new_lfs_pointers(revision, limit, not_in, dynamic_timeout = nil)
request = Gitaly::GetNewLFSPointersRequest.new(
repository: @gitaly_repo,
revision: encode_binary(revision),
limit: limit || 0
)
if not_in.nil? || not_in == :all
request.not_in_all = true
else
request.not_in_refs += not_in
end
request, rpc = create_new_lfs_pointers_request(revision, limit, not_in)
timeout =
if dynamic_timeout
@ -100,7 +90,7 @@ module Gitlab
response = GitalyClient.call(
@gitaly_repo.storage_name,
:blob_service,
:get_new_lfs_pointers,
rpc,
request,
timeout: timeout
)
@ -118,6 +108,39 @@ module Gitlab
private
def create_new_lfs_pointers_request(revision, limit, not_in)
# If the check happens for a change which is using a quarantine
# environment for incoming objects, then we can avoid doing the
# necessary graph walk to detect only new LFS pointers and instead scan
# through all quarantined objects.
git_env = ::Gitlab::Git::HookEnv.all(@gitaly_repo.gl_repository)
if Feature.enabled?(:lfs_integrity_inspect_quarantined_objects, @project, default_enabled: :yaml) && git_env['GIT_OBJECT_DIRECTORY_RELATIVE'].present?
repository = @gitaly_repo.dup
repository.git_alternate_object_directories = Google::Protobuf::RepeatedField.new(:string)
request = Gitaly::ListAllLFSPointersRequest.new(
repository: repository,
limit: limit || 0
)
[request, :list_all_lfs_pointers]
else
request = Gitaly::GetNewLFSPointersRequest.new(
repository: @gitaly_repo,
revision: encode_binary(revision),
limit: limit || 0
)
if not_in.nil? || not_in == :all
request.not_in_all = true
else
request.not_in_refs += not_in
end
[request, :get_new_lfs_pointers]
end
end
def consume_blob_response(response)
data = []
blob = nil

View File

@ -1,7 +1,7 @@
import { GlButton } from '@gitlab/ui';
import { createLocalVue, mount, shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import Form from '~/jobs/components/manual_variables_form.vue';
const localVue = createLocalVue();
@ -21,49 +21,48 @@ describe('Manual Variables Form', () => {
variablesSettingsUrl: '/settings',
};
const createComponent = (props = {}, mountFn = shallowMount) => {
const createComponent = ({ props = {}, mountFn = shallowMount } = {}) => {
store = new Vuex.Store({
actions: {
triggerManualJob: jest.fn(),
},
});
wrapper = mountFn(localVue.extend(Form), {
propsData: props,
localVue,
store,
});
wrapper = extendedWrapper(
mountFn(localVue.extend(Form), {
propsData: { ...requiredProps, ...props },
localVue,
store,
}),
);
};
const findTriggerBtn = () => wrapper.find('[data-testid="trigger-manual-job-btn"]');
const findInputKey = () => wrapper.findComponent({ ref: 'inputKey' });
const findInputValue = () => wrapper.findComponent({ ref: 'inputSecretValue' });
afterEach((done) => {
// The component has a `nextTick` callback after some events so we need
// to wait for those to finish before destroying.
setImmediate(() => {
wrapper.destroy();
wrapper = null;
const findTriggerBtn = () => wrapper.findByTestId('trigger-manual-job-btn');
const findHelpText = () => wrapper.findByTestId('form-help-text');
const findDeleteVarBtn = () => wrapper.findByTestId('delete-variable-btn');
const findCiVariableKey = () => wrapper.findByTestId('ci-variable-key');
const findCiVariableValue = () => wrapper.findByTestId('ci-variable-value');
const findAllVariables = () => wrapper.findAllByTestId('ci-variable-row');
done();
});
afterEach(() => {
wrapper.destroy();
});
describe('shallowMount', () => {
beforeEach(() => {
createComponent(requiredProps);
createComponent();
});
it('renders empty form with correct placeholders', () => {
expect(wrapper.find({ ref: 'inputKey' }).attributes('placeholder')).toBe(
'Input variable key',
);
expect(wrapper.find({ ref: 'inputSecretValue' }).attributes('placeholder')).toBe(
'Input variable value',
);
expect(findInputKey().attributes('placeholder')).toBe('Input variable key');
expect(findInputValue().attributes('placeholder')).toBe('Input variable value');
});
it('renders help text with provided link', () => {
expect(wrapper.find('p').text()).toBe(
expect(findHelpText().text()).toBe(
'Specify variable values to be used in this run. The values specified in CI/CD settings will be used as default',
);
@ -71,57 +70,47 @@ describe('Manual Variables Form', () => {
});
describe('when adding a new variable', () => {
it('creates a new variable when user types a new key and resets the form', (done) => {
wrapper.vm
.$nextTick()
.then(() => wrapper.find({ ref: 'inputKey' }).setValue('new key'))
.then(() => {
expect(wrapper.vm.variables.length).toBe(1);
expect(wrapper.vm.variables[0].key).toBe('new key');
expect(wrapper.find({ ref: 'inputKey' }).attributes('value')).toBe(undefined);
})
.then(done)
.catch(done.fail);
it('creates a new variable when user types a new key and resets the form', async () => {
await findInputKey().setValue('new key');
expect(findAllVariables()).toHaveLength(1);
expect(findCiVariableKey().element.value).toBe('new key');
expect(findInputKey().attributes('value')).toBe(undefined);
});
it('creates a new variable when user types a new value and resets the form', (done) => {
wrapper.vm
.$nextTick()
.then(() => wrapper.find({ ref: 'inputSecretValue' }).setValue('new value'))
.then(() => {
expect(wrapper.vm.variables.length).toBe(1);
expect(wrapper.vm.variables[0].secret_value).toBe('new value');
expect(wrapper.find({ ref: 'inputSecretValue' }).attributes('value')).toBe(undefined);
})
.then(done)
.catch(done.fail);
});
});
it('creates a new variable when user types a new value and resets the form', async () => {
await findInputValue().setValue('new value');
describe('when deleting a variable', () => {
beforeEach((done) => {
wrapper.vm.variables = [
{
key: 'new key',
secret_value: 'value',
id: '1',
},
];
wrapper.vm.$nextTick(done);
});
it('removes the variable row', () => {
wrapper.find(GlButton).vm.$emit('click');
expect(wrapper.vm.variables.length).toBe(0);
expect(findAllVariables()).toHaveLength(1);
expect(findCiVariableValue().element.value).toBe('new value');
expect(findInputValue().attributes('value')).toBe(undefined);
});
});
});
describe('mount', () => {
beforeEach(() => {
createComponent(requiredProps, mount);
createComponent({ mountFn: mount });
});
describe('when deleting a variable', () => {
it('removes the variable row', async () => {
await wrapper.setData({
variables: [
{
key: 'new key',
secret_value: 'value',
id: '1',
},
],
});
findDeleteVarBtn().trigger('click');
await wrapper.vm.$nextTick();
expect(findAllVariables()).toHaveLength(0);
});
});
it('trigger button is disabled after trigger action', async () => {

46
spec/knapsack_env.rb Normal file
View File

@ -0,0 +1,46 @@
# frozen_string_literal: true
require 'knapsack'
module KnapsackEnv
class RSpecContextAdapter < Knapsack::Adapters::RSpecAdapter
def bind_time_tracker
::RSpec.configure do |config|
# Original version starts timer in `config.prepend_before(:each) do`
# https://github.com/KnapsackPro/knapsack/blob/v1.17.0/lib/knapsack/adapters/rspec_adapter.rb#L9
config.prepend_before(:context) do
Knapsack.tracker.start_timer
end
# Original version is `config.prepend_before(:each) do`
# https://github.com/KnapsackPro/knapsack/blob/v1.17.0/lib/knapsack/adapters/rspec_adapter.rb#L9
config.prepend_before(:each) do # rubocop:disable RSpec/HookArgument
current_example_group =
if ::RSpec.respond_to?(:current_example)
::RSpec.current_example.metadata[:example_group]
else
example.metadata
end
Knapsack.tracker.test_path = Knapsack::Adapters::RSpecAdapter.test_path(current_example_group)
end
# Original version stops timer in `config.append_after(:each) do`
# https://github.com/KnapsackPro/knapsack/blob/v1.17.0/lib/knapsack/adapters/rspec_adapter.rb#L20
config.append_after(:context) do
Knapsack.tracker.stop_timer
end
config.after(:suite) do
Knapsack.logger.info(Knapsack::Presenter.global_time)
end
end
end
end
def self.configure!
return unless ENV['CI'] && ENV['KNAPSACK_GENERATE_REPORT'] && !ENV['NO_KNAPSACK']
RSpecContextAdapter.bind
end
end

View File

@ -14,7 +14,7 @@ RSpec.describe Atlassian::JiraConnect::Serializers::PullRequestEntity do
end
context 'with user_notes_count option' do
let(:user_notes_count) { merge_requests.map { |merge_request| [merge_request.id, 1] }.to_h }
let(:user_notes_count) { merge_requests.to_h { |merge_request| [merge_request.id, 1] } }
subject { described_class.represent(merge_requests, user_notes_count: user_notes_count).as_json }

View File

@ -6,13 +6,13 @@ RSpec.describe Gitlab::Ci::Status::Composite do
let_it_be(:pipeline) { create(:ci_pipeline) }
before_all do
@statuses = Ci::HasStatus::STATUSES_ENUM.map do |status, idx|
@statuses = Ci::HasStatus::STATUSES_ENUM.to_h do |status, idx|
[status, create(:ci_build, pipeline: pipeline, status: status, importing: true)]
end.to_h
end
@statuses_with_allow_failure = Ci::HasStatus::STATUSES_ENUM.map do |status, idx|
@statuses_with_allow_failure = Ci::HasStatus::STATUSES_ENUM.to_h do |status, idx|
[status, create(:ci_build, pipeline: pipeline, status: status, allow_failure: true, importing: true)]
end.to_h
end
end
describe '#status' do

View File

@ -21,7 +21,7 @@ RSpec.describe Gitlab::Conflict::File do
let(:section_keys) { conflict_file.sections.map { |section| section[:id] }.compact }
context 'when resolving everything to the same side' do
let(:resolution_hash) { section_keys.map { |key| [key, 'head'] }.to_h }
let(:resolution_hash) { section_keys.to_h { |key| [key, 'head'] } }
let(:resolved_lines) { conflict_file.resolve_lines(resolution_hash) }
let(:expected_lines) { conflict_file.lines.reject { |line| line.type == 'old' } }
@ -54,8 +54,8 @@ RSpec.describe Gitlab::Conflict::File do
end
it 'raises ResolutionError when passed a hash without resolutions for all sections' do
empty_hash = section_keys.map { |key| [key, nil] }.to_h
invalid_hash = section_keys.map { |key| [key, 'invalid'] }.to_h
empty_hash = section_keys.to_h { |key| [key, nil] }
invalid_hash = section_keys.to_h { |key| [key, 'invalid'] }
expect { conflict_file.resolve_lines({}) }
.to raise_error(Gitlab::Git::Conflict::Resolver::ResolutionError)

View File

@ -43,6 +43,33 @@ RSpec.describe Gitlab::GitalyClient::BlobService do
subject
end
end
context 'with hook environment' do
let(:git_env) do
{
'GIT_OBJECT_DIRECTORY_RELATIVE' => '.git/objects',
'GIT_ALTERNATE_OBJECT_DIRECTORIES_RELATIVE' => ['/dir/one', '/dir/two']
}
end
let(:expected_params) do
expected_repository = repository.gitaly_repository
expected_repository.git_alternate_object_directories = Google::Protobuf::RepeatedField.new(:string)
{ limit: limit, repository: expected_repository }
end
it 'sends a list_all_lfs_pointers message' do
allow(Gitlab::Git::HookEnv).to receive(:all).with(repository.gl_repository).and_return(git_env)
expect_any_instance_of(Gitaly::BlobService::Stub)
.to receive(:list_all_lfs_pointers)
.with(gitaly_request_with_params(expected_params), kind_of(Hash))
.and_return([])
subject
end
end
end
describe '#get_all_lfs_pointers' do

View File

@ -684,7 +684,7 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer do
it 'overrides project feature access levels' do
access_level_keys = ProjectFeature.available_features.map { |feature| ProjectFeature.access_level_attribute(feature) }
disabled_access_levels = Hash[access_level_keys.collect { |item| [item, 'disabled'] }]
disabled_access_levels = access_level_keys.to_h { |item| [item, 'disabled'] }
project.create_import_data(data: { override_params: disabled_access_levels })

View File

@ -164,7 +164,7 @@ RSpec.describe Featurable do
end
def update_all_project_features(project, features, value)
project_feature_attributes = features.map { |f| ["#{f}_access_level", value] }.to_h
project_feature_attributes = features.to_h { |f| ["#{f}_access_level", value] }
project.project_feature.update!(project_feature_attributes)
end
end

View File

@ -299,11 +299,11 @@ RSpec.describe Event do
end
def visible_to_none_except(*roles)
visible_to_none.merge(roles.map { |role| [role, true] }.to_h)
visible_to_none.merge(roles.to_h { |role| [role, true] })
end
def visible_to_all_except(*roles)
visible_to_all.merge(roles.map { |role| [role, false] }.to_h)
visible_to_all.merge(roles.to_h { |role| [role, false] })
end
shared_examples 'visibility examples' do
@ -723,7 +723,7 @@ RSpec.describe Event do
note_on_design: true,
note_on_commit: true
}
valid_target_factories.map do |kind, needs_project|
valid_target_factories.to_h do |kind, needs_project|
extra_data = if kind == :merge_request
{ source_project: project }
elsif needs_project
@ -735,7 +735,7 @@ RSpec.describe Event do
target = kind == :project ? nil : build(kind, **extra_data)
[kind, build(:event, :created, author: project.owner, project: project, target: target)]
end.to_h
end
end
it 'passes a sanity check', :aggregate_failures do

View File

@ -54,7 +54,7 @@ RSpec.describe Packages::Dependency, type: :model do
context 'with too big parameter' do
let(:size) { (Packages::Dependency::MAX_CHUNKED_QUERIES_COUNT * chunk_size) + 1 }
let(:names_and_version_patterns) { Hash[(1..size).map { |v| [v, v] }] }
let(:names_and_version_patterns) { (1..size).to_h { |v| [v, v] } }
it { expect { subject }.to raise_error(ArgumentError, 'Too many names_and_version_patterns') }
end

View File

@ -34,7 +34,7 @@ RSpec.describe 'getting Alert Management Alert Assignees' do
end
let(:alerts) { graphql_data.dig('project', 'alertManagementAlerts', 'nodes') }
let(:assignees) { alerts.map { |alert| [alert['iid'], alert['assignees']['nodes']] }.to_h }
let(:assignees) { alerts.to_h { |alert| [alert['iid'], alert['assignees']['nodes']] } }
let(:first_assignees) { assignees[first_alert.iid.to_s] }
let(:second_assignees) { assignees[second_alert.iid.to_s] }

View File

@ -38,7 +38,7 @@ RSpec.describe 'getting Alert Management Alert Notes' do
end
let(:alerts_result) { graphql_data.dig('project', 'alertManagementAlerts', 'nodes') }
let(:notes_result) { alerts_result.map { |alert| [alert['iid'], alert['notes']['nodes']] }.to_h }
let(:notes_result) { alerts_result.to_h { |alert| [alert['iid'], alert['notes']['nodes']] } }
let(:first_notes_result) { notes_result[first_alert.iid.to_s] }
let(:second_notes_result) { notes_result[second_alert.iid.to_s] }

View File

@ -34,7 +34,7 @@ RSpec.describe 'getting Alert Management Alert Assignees' do
end
let(:gql_alerts) { graphql_data.dig('project', 'alertManagementAlerts', 'nodes') }
let(:gql_todos) { gql_alerts.map { |gql_alert| [gql_alert['iid'], gql_alert['todos']['nodes']] }.to_h }
let(:gql_todos) { gql_alerts.to_h { |gql_alert| [gql_alert['iid'], gql_alert['todos']['nodes']] } }
let(:gql_alert_todo) { gql_todos[alert.iid.to_s].first }
let(:gql_other_alert_todo) { gql_todos[other_alert.iid.to_s].first }

View File

@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.shared_examples 'languages and percentages JSON response' do
let(:expected_languages) { project.repository.languages.map { |language| language.values_at(:label, :value)}.to_h }
let(:expected_languages) { project.repository.languages.to_h { |language| language.values_at(:label, :value) } }
before do
allow(project.repository).to receive(:languages).and_return(

View File

@ -6,6 +6,7 @@ RSpec.describe MergeRequests::BaseService do
include ProjectForksHelper
let_it_be(:project) { create(:project, :repository) }
let(:title) { 'Awesome merge_request' }
let(:params) do
{

View File

@ -7,6 +7,7 @@ RSpec.describe MergeRequests::CreatePipelineService do
let_it_be(:project, reload: true) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
let(:service) { described_class.new(project, actor, params) }
let(:actor) { user }
let(:params) { {} }
@ -50,6 +51,7 @@ RSpec.describe MergeRequests::CreatePipelineService do
context 'with fork merge request' do
let_it_be(:forked_project) { fork_project(project, nil, repository: true, target_project: create(:project, :private, :repository)) }
let(:source_project) { forked_project }
context 'when actor has permission to create pipelines in target project' do

View File

@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe MergeRequests::ExportCsvService do
let_it_be(:merge_request) { create(:merge_request) }
let(:csv) { CSV.parse(subject.csv_data, headers: true).first }
subject { described_class.new(MergeRequest.where(id: merge_request.id), merge_request.project) }
@ -46,6 +47,7 @@ RSpec.describe MergeRequests::ExportCsvService do
describe 'approvers' do
context 'when approved' do
let_it_be(:merge_request) { create(:merge_request) }
let(:approvers) { create_list(:user, 2) }
before do

View File

@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe MergeRequests::MergeOrchestrationService do
let_it_be(:maintainer) { create(:user) }
let(:merge_params) { { sha: merge_request.diff_head_sha } }
let(:user) { maintainer }
let(:service) { described_class.new(project, user, merge_params) }

View File

@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe MergeRequests::MergeService do
let_it_be(:user) { create(:user) }
let_it_be(:user2) { create(:user) }
let(:merge_request) { create(:merge_request, :simple, author: user2, assignees: [user2]) }
let(:project) { merge_request.project }

View File

@ -68,6 +68,7 @@ RSpec.describe MergeRequests::MergeToRefService do
end
let_it_be(:user) { create(:user) }
let(:merge_request) { create(:merge_request, :simple) }
let(:project) { merge_request.project }
@ -226,6 +227,7 @@ RSpec.describe MergeRequests::MergeToRefService do
describe 'cascading merge refs' do
let_it_be(:project) { create(:project, :repository) }
let(:params) { { commit_message: 'Cascading merge', first_parent_ref: first_parent_ref, target_ref: target_ref, sha: merge_request.diff_head_sha } }
context 'when first merge happens' do

View File

@ -15,6 +15,9 @@ Warning[:deprecated] = true unless ENV.key?('SILENCE_DEPRECATIONS')
require './spec/deprecation_toolkit_env'
DeprecationToolkitEnv.configure!
require './spec/knapsack_env'
KnapsackEnv.configure!
require './spec/simplecov_env'
SimpleCovEnv.start!
@ -47,11 +50,6 @@ if rspec_profiling_is_configured && (!ENV.key?('CI') || branch_can_be_profiled)
require 'rspec_profiling/rspec'
end
if ENV['CI'] && ENV['KNAPSACK_GENERATE_REPORT'] && !ENV['NO_KNAPSACK']
require 'knapsack'
Knapsack::Adapters::RSpecAdapter.bind
end
# require rainbow gem String monkeypatch, so we can test SystemChecks
require 'rainbow/ext/string'
Rainbow.enabled = false
@ -81,7 +79,7 @@ RSpec.configure do |config|
config.run_all_when_everything_filtered = true
config.use_transactional_fixtures = true
config.use_instantiated_fixtures = false
config.use_instantiated_fixtures = false
config.fixture_path = Rails.root
config.verbose_retry = true

View File

@ -277,11 +277,11 @@ module GraphqlHelpers
# prepare_input_for_mutation({ 'my_key' => 1 })
# => { 'myKey' => 1}
def prepare_input_for_mutation(input)
input.map do |name, value|
input.to_h do |name, value|
value = prepare_input_for_mutation(value) if value.is_a?(Hash)
[GraphqlHelpers.fieldnamerize(name), value]
end.to_h
end
end
def input_variable_name_for_mutation(mutation_name)

View File

@ -97,13 +97,13 @@ module ImportExport
def normalize_elements(elem)
case elem
when Hash
elem.map do |key, value|
elem.to_h do |key, value|
if ignore_key?(key, value)
[key, :ignored]
else
[key, normalize_elements(value)]
end
end.to_h
end
when Array
elem.map { |a| normalize_elements(a) }
else

View File

@ -23,7 +23,7 @@ RSpec.shared_context 'container repository delete tags service shared context' d
end
def stub_delete_reference_requests(tags)
tags = Hash[Array.wrap(tags).map { |tag| [tag, 200] }] unless tags.is_a?(Hash)
tags = Array.wrap(tags).to_h { |tag| [tag, 200] } unless tags.is_a?(Hash)
tags.each do |tag, status|
stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/tags/reference/#{tag}")

View File

@ -47,4 +47,15 @@ RSpec.shared_examples 'cluster application version specs' do |application_name|
end
end
end
describe '#make_externally_installed' do
subject { build(application_name) }
it 'sets to a special version' do
subject.make_externally_installed!
expect(subject).to be_persisted
expect(subject.version).to eq('EXTERNALLY_INSTALLED')
end
end
end