Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-10-05 09:09:10 +00:00
parent b4d76c5ac7
commit 187727e248
40 changed files with 480 additions and 113 deletions

View File

@ -1,9 +1,10 @@
<script>
import { GlDropdownItem } from '@gitlab/ui';
import { GlDropdownItem, GlAvatarLabeled } from '@gitlab/ui';
export default {
components: {
GlDropdownItem,
GlAvatarLabeled,
},
props: {
@ -144,6 +145,10 @@ export default {
});
}
},
avatarSubLabel(item) {
return item.count ? `${item.name} (${item.count})` : item.name;
},
},
};
</script>
@ -161,18 +166,27 @@ export default {
:class="{ 'gl-bg-gray-50': index === selectedIndex }"
@click="selectItem(index)"
>
<span v-if="isUser">
{{ item.username }}
<small>{{ item.name }}</small>
</span>
<span v-if="isIssue || isMergeRequest || isMilestone">
<gl-avatar-labeled
v-if="isUser"
:label="item.username"
:sub-label="avatarSubLabel(item)"
:src="item.avatar_url"
:entity-name="item.username"
:shape="item.type === 'Group' ? 'rect' : 'circle'"
:size="32"
/>
<span v-if="isIssue || isMergeRequest">
<small>{{ item.iid }}</small>
{{ item.title }}
</span>
<span v-if="isMilestone">
{{ item.title }}
</span>
<div v-if="isEmoji" class="gl-display-flex gl-flex gl-align-items-center">
<div class="gl-pr-4 gl-font-lg">{{ item.e }}</div>
<div class="gl-flex-grow-1">
{{ item.name }}<br /><small>{{ item.d }}</small>
{{ item.name }}<br />
<small>{{ item.d }}</small>
</div>
</div>
</gl-dropdown-item>

View File

@ -161,7 +161,7 @@ class BulkImports::Entity < ApplicationRecord
end
def validate_imported_entity_type
if project_entity? && !BulkImports::Features.project_migration_enabled?(destination_name)
if project_entity? && !BulkImports::Features.project_migration_enabled?(destination_namespace)
errors.add(
:base,
s_('BulkImport|invalid entity source type')

View File

@ -58,7 +58,7 @@ module MergeRequests
new_reviewers = merge_request.reviewers - old_reviewers
merge_request_activity_counter.track_users_review_requested(users: new_reviewers)
merge_request_activity_counter.track_reviewers_changed_action(user: current_user)
GraphqlTriggers.merge_request_reviewers_updated(merge_request)
trigger_merge_request_reviewers_updated(merge_request)
end
def cleanup_environments(merge_request)
@ -245,6 +245,10 @@ module MergeRequests
Milestones::MergeRequestsCountService.new(milestone).delete_cache
end
def trigger_merge_request_reviewers_updated(merge_request)
GraphqlTriggers.merge_request_reviewers_updated(merge_request)
end
end
end

View File

@ -10,6 +10,8 @@ module MergeRequests
if reviewer
return error("Failed to update reviewer") unless reviewer.update(state: :reviewed)
trigger_merge_request_reviewers_updated(merge_request)
success
else
error("Reviewer not found")

View File

@ -11,6 +11,7 @@ module MergeRequests
return error("Failed to update reviewer") unless reviewer.update(state: :unreviewed)
notify_reviewer(merge_request, user)
trigger_merge_request_reviewers_updated(merge_request)
success
else

View File

@ -39,5 +39,5 @@
%div
= f.gitlab_ui_checkbox_component :active, _('Active'), checkbox_options: { value: @schedule.active, required: false }
.footer-block
= f.submit _('Save pipeline schedule'), class: 'btn gl-button btn-confirm'
= f.submit _('Save pipeline schedule'), pajamas_button: true
= link_to _('Cancel'), pipeline_schedules_path(@project), class: 'btn gl-button btn-default btn-cancel'

View File

@ -41,4 +41,4 @@
= form.gitlab_ui_radio_component :deploy_strategy, 'timed_incremental', (s_('CICD|Continuous deployment to production using timed incremental rollout') + ' ' + help_link_timed).html_safe
= form.gitlab_ui_radio_component :deploy_strategy, 'manual', (s_('CICD|Automatic deployment to staging, manual deployment to production') + ' ' + help_link_incremental).html_safe
= f.submit _('Save changes'), class: "btn gl-button btn-confirm gl-mt-5", data: { qa_selector: 'save_changes_button' }
= f.submit _('Save changes'), class: "gl-mt-5", data: { qa_selector: 'save_changes_button' }, pajamas_button: true

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class TmpIndexMembersOnIdWhereNamespaceIdNull < Gitlab::Database::Migration[2.0]
TMP_INDEX = 'tmp_index_members_on_id_where_namespace_id_null'
disable_ddl_transaction!
def up
add_concurrent_index :members, :id,
name: TMP_INDEX,
where: 'member_namespace_id IS NULL'
end
def down
remove_concurrent_index_by_name :members, name: TMP_INDEX
end
end

View File

@ -0,0 +1 @@
584d43304f92cc638783ffc5c8ab2dc8e511169c76da7661cb4c5ddded6c02d1

View File

@ -30982,6 +30982,8 @@ CREATE INDEX tmp_index_for_project_namespace_id_migration_on_routes ON routes US
CREATE INDEX tmp_index_issues_on_issue_type_and_id ON issues USING btree (issue_type, id);
CREATE INDEX tmp_index_members_on_id_where_namespace_id_null ON members USING btree (id) WHERE (member_namespace_id IS NULL);
CREATE INDEX tmp_index_members_on_state ON members USING btree (state) WHERE (state = 2);
CREATE INDEX tmp_index_migrated_container_registries ON container_repositories USING btree (project_id) WHERE ((migration_state = 'import_done'::text) OR (created_at >= '2022-01-23 00:00:00'::timestamp without time zone));

View File

@ -188,6 +188,25 @@ You must have the Owner role for the group.
From this page, you can edit, pause, and remove runners from the group, its subgroups, and projects.
#### Filter group runners to show only inherited
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/337838/) in GitLab 15.5, [with a flag](../../administration/feature_flags.md) named `runners_finder_all_available`. Disabled by default.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `runners_finder_all_available`. On GitLab.com, this feature is not available.
You can choose to show all runners in the list, or show only
those that are inherited from the instance or other groups.
By default, only those that are inherited are shown.
To show all runners available in the instance, including shared runners and
those in other groups:
1. On the top bar, select **Main menu > Groups** and find your group.
1. On the left sidebar, select **CI/CD > Runners**.
1. Above the list, turn off the **Show only inherited** toggle.
### Pause or remove a group runner
You can pause or remove a group runner for your self-managed GitLab instance or for GitLab.com.

View File

@ -889,6 +889,22 @@ aspects of the automated GLFM scripts and processes. They are located at
See the main [specification files](#specification-files) section for more context and details.
##### Configuration file validation
All of the manually curated example names in the configuration files must correspond to
an existing [Markdown example](#markdown-examples) name found in
[`example_snapshots/examples_index.yml`](#glfm_specificationexample_snapshotsexamples_indexyml),
which is automatically generated based on the [input specification files](#input-specification-files).
If there is an invalid reference to an example name that does not exist, the
[`scripts/glfm/update-example-snapshots.rb`](#update-example-snapshotsrb-script)
script fails with a descriptive error.
The only exceptions to this validation are example names beginning with `00_`, which are reserved
for [YAML aliases](https://yaml.org/spec/1.2.2/#692-node-anchors).
See the section on [`glfm_example_normalizations.yml`](#glfm_example_normalizationsyml)
for more details and examples.
##### `glfm_example_status.yml`
[`glfm_specification/input/gitlab_flavored_markdown/glfm_example_status.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/input/gitlab_flavored_markdown/glfm_example_status.yml)

View File

@ -44,6 +44,11 @@ module BulkImports
wikis = client.get(context.entity.wikis_url_path).parsed_response
wikis.any?
rescue BulkImports::NetworkError => e
# 403 is returned when wiki is disabled in settings
return if e.response&.forbidden? || e.response&.not_found?
raise
end
def client

View File

@ -4,13 +4,18 @@ module BulkImports
class NetworkError < Error
COUNTER_KEY = 'bulk_imports/%{entity_id}/%{stage}/%{tracker_id}/network_error/%{error}'
RETRIABLE_EXCEPTIONS = Gitlab::HTTP::HTTP_TIMEOUT_ERRORS
RETRIABLE_EXCEPTIONS = Gitlab::HTTP::HTTP_TIMEOUT_ERRORS + [
EOFError, SocketError, OpenSSL::SSL::SSLError, OpenSSL::OpenSSLError,
Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH
].freeze
RETRIABLE_HTTP_CODES = [429].freeze
DEFAULT_RETRY_DELAY_SECONDS = 30
MAX_RETRIABLE_COUNT = 10
attr_reader :response
def initialize(message = nil, response: nil)
raise ArgumentError, 'message or response required' if message.blank? && response.blank?
@ -37,8 +42,6 @@ module BulkImports
private
attr_reader :response
def retriable_exception?
RETRIABLE_EXCEPTIONS.include?(cause&.class)
end

View File

@ -17083,6 +17083,9 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
msgid "Free"
msgstr ""
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@ -17724,6 +17727,9 @@ msgstr ""
msgid "Geo|There was an error updating the Geo Settings"
msgstr ""
msgid "Geo|This GitLab instance is subscribed to the %{insufficient_license} tier. Geo is only available for users who have at least a Premium subscription."
msgstr ""
msgid "Geo|This will resync all %{replicableType}. It may take some time to complete. Are you sure you want to continue?"
msgstr ""
@ -24481,10 +24487,10 @@ msgstr ""
msgid "Manage two-factor authentication"
msgstr ""
msgid "Manage your license"
msgid "Manage your project's triggers"
msgstr ""
msgid "Manage your project's triggers"
msgid "Manage your subscription"
msgstr ""
msgid "Managed Account"
@ -40833,9 +40839,6 @@ msgstr ""
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
msgid "This GitLab instance is licensed at the %{insufficient_license} tier. Geo is only available for users who have at least a Premium license."
msgstr ""
msgid "This PDF is too large to display. Please download to view."
msgstr ""
@ -44123,6 +44126,9 @@ msgstr ""
msgid "View blame prior to this change"
msgstr ""
msgid "View card matches"
msgstr ""
msgid "View chart"
msgid_plural "View charts"
msgstr[0] ""
@ -48270,9 +48276,6 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
msgid "other card matches"
msgstr ""
msgid "out of %d total test"
msgid_plural "out of %d total tests"
msgstr[0] ""

View File

@ -53,13 +53,13 @@
"@gitlab/at.js": "1.5.7",
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/svgs": "3.4.0",
"@gitlab/ui": "43.21.0",
"@gitlab/ui": "44.0.0",
"@gitlab/visual-review-tools": "1.7.3",
"@gitlab/web-ide": "0.0.1-dev-20220815034418",
"@rails/actioncable": "6.1.4-7",
"@rails/ujs": "6.1.4-7",
"@sentry/browser": "5.30.0",
"@sourcegraph/code-host-integration": "0.0.60",
"@sourcegraph/code-host-integration": "0.0.82",
"@tiptap/core": "^2.0.0-beta.182",
"@tiptap/extension-blockquote": "^2.0.0-beta.29",
"@tiptap/extension-bold": "^2.0.0-beta.28",

View File

@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Projects::Prometheus::MetricsController do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:prometheus_project) }
let_it_be(:project) { create(:project, :with_prometheus_integration) }
let(:prometheus_adapter) { double('prometheus_adapter', can_query?: true) }

View File

@ -429,6 +429,24 @@ FactoryBot.define do
error_tracking_setting { association :project_error_tracking_setting }
end
trait :with_redmine_integration do
has_external_issue_tracker { true }
redmine_integration
end
trait :with_jira_integration do
has_external_issue_tracker { true }
jira_integration
end
trait :with_prometheus_integration do
after :create do |project|
create(:prometheus_integration, project: project)
end
end
# Project with empty repository
#
# This is a case when you just created a project
@ -455,42 +473,6 @@ FactoryBot.define do
end
end
factory :redmine_project, parent: :project do
has_external_issue_tracker { true }
redmine_integration
end
factory :youtrack_project, parent: :project do
has_external_issue_tracker { true }
youtrack_integration
end
factory :jira_project, parent: :project do
has_external_issue_tracker { true }
jira_integration
end
factory :prometheus_project, parent: :project do
after :create do |project|
project.create_prometheus_integration(
active: true,
properties: {
api_url: 'https://prometheus.example.com/',
manual_configuration: true
}
)
end
end
factory :ewm_project, parent: :project do
has_external_issue_tracker { true }
ewm_integration
end
factory :project_with_design, parent: :project do
after(:create) do |project|
issue = create(:issue, project: project)

View File

@ -114,6 +114,53 @@ RSpec.describe "Group Runners" do
end
end
context "with an online instance runner" do
let!(:instance_runner) do
create(:ci_runner, :instance, description: 'runner-baz', contacted_at: Time.zone.now)
end
context "when runners_finder_all_available is enabled" do
before do
stub_feature_flags(runners_finder_all_available: true)
visit group_runners_path(group)
end
context "when selecting 'Show only inherited'" do
before do
find("[data-testid='runner-membership-toggle'] button").click
wait_for_requests
end
it_behaves_like 'shows runner in list' do
let(:runner) { instance_runner }
end
it 'shows runner details page' do
click_link("##{instance_runner.id} (#{instance_runner.short_sha})")
expect(current_url).to include(group_runner_path(group, instance_runner))
expect(page).to have_content "#{s_('Runners|Description')} runner-baz"
end
end
end
context "when runners_finder_all_available is disabled" do
before do
stub_feature_flags(runners_finder_all_available: false)
visit group_runners_path(group)
end
it "does not display 'Show only inherited' toggle" do
expect(page).not_to have_content(s_('Runners|Show only inherited'))
end
it_behaves_like 'shows no runners registered'
end
end
context 'with a multi-project runner' do
let(:project) { create(:project, group: group) }
let(:project_2) { create(:project, group: group) }

View File

@ -9,7 +9,7 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st
include MetricsDashboardUrlHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:prometheus_project) }
let_it_be(:project) { create(:project, :with_prometheus_integration) }
let_it_be(:environment) { create(:environment, project: project) }
let(:issue) { create(:issue, project: project, description: description) }

View File

@ -6,7 +6,7 @@ RSpec.describe 'Merge request > User posts diff notes', :js do
include MergeRequestDiffHelpers
include Spec::Support::Helpers::ModalHelpers
let(:merge_request) { create(:merge_request) }
let_it_be(:merge_request) { create(:merge_request) }
let(:project) { merge_request.source_project }
let(:user) { project.creator }
let(:comment_button_class) { '.add-diff-note' }

View File

@ -6,7 +6,7 @@ RSpec.describe 'Environment > Metrics' do
include PrometheusHelpers
let(:user) { create(:user) }
let(:project) { create(:prometheus_project, :repository) }
let(:project) { create(:project, :with_prometheus_integration, :repository) }
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, pipeline: pipeline) }
let(:environment) { create(:environment, project: project) }

View File

@ -0,0 +1,162 @@
import { GlAvatarLabeled, GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import SuggestionsDropdown from '~/content_editor/components/suggestions_dropdown.vue';
describe('~/content_editor/components/suggestions_dropdown', () => {
let wrapper;
const buildWrapper = ({ propsData = {} } = {}) => {
wrapper = shallowMount(SuggestionsDropdown, {
propsData: {
nodeType: 'reference',
...propsData,
},
});
};
const exampleUser = { username: 'root', avatar_url: 'root_avatar.png', type: 'User' };
const exampleIssue = { iid: 123, title: 'Test Issue' };
const exampleMergeRequest = { iid: 224, title: 'Test MR' };
const exampleMilestone = { iid: 21, title: '1.3' };
const exampleEmoji = {
c: 'people',
e: '😃',
d: 'smiling face with open mouth',
u: '6.0',
name: 'smiley',
};
const insertedEmojiProps = {
name: 'smiley',
title: 'smiling face with open mouth',
moji: '😃',
unicodeVersion: '6.0',
};
describe('on item select', () => {
it.each`
nodeType | referenceType | char | reference | insertedText | insertedProps
${'reference'} | ${'user'} | ${'@'} | ${exampleUser} | ${`@root`} | ${{}}
${'reference'} | ${'issue'} | ${'#'} | ${exampleIssue} | ${`#123`} | ${{}}
${'reference'} | ${'merge_request'} | ${'!'} | ${exampleMergeRequest} | ${`!224`} | ${{}}
${'reference'} | ${'milestone'} | ${'%'} | ${exampleMilestone} | ${`%1.3`} | ${{}}
${'emoji'} | ${'emoji'} | ${':'} | ${exampleEmoji} | ${`😃`} | ${insertedEmojiProps}
`(
'runs a command to insert the selected $referenceType',
({ char, nodeType, referenceType, reference, insertedText, insertedProps }) => {
const commandSpy = jest.fn();
buildWrapper({
propsData: {
char,
command: commandSpy,
nodeType,
nodeProps: {
referenceType,
test: 'prop',
},
items: [reference],
},
});
wrapper.findComponent(GlDropdownItem).vm.$emit('click');
expect(commandSpy).toHaveBeenCalledWith(
expect.objectContaining({
text: insertedText,
test: 'prop',
...insertedProps,
}),
);
},
);
});
describe('rendering user references', () => {
it('displays avatar labeled component', () => {
const testUser = exampleUser;
buildWrapper({
propsData: {
char: '@',
command: jest.fn(),
nodeType: 'reference',
nodeProps: {
referenceType: 'user',
},
items: [testUser],
},
});
expect(wrapper.findComponent(GlAvatarLabeled).attributes()).toEqual(
expect.objectContaining({
label: testUser.username,
shape: 'circle',
src: testUser.avatar_url,
}),
);
});
describe.each`
referenceType | char | reference | displaysID
${'issue'} | ${'#'} | ${exampleIssue} | ${true}
${'merge_request'} | ${'!'} | ${exampleMergeRequest} | ${true}
${'milestone'} | ${'%'} | ${exampleMilestone} | ${false}
`('rendering $referenceType references', ({ referenceType, char, reference, displaysID }) => {
it(`displays ${referenceType} ID and title`, () => {
buildWrapper({
propsData: {
char,
command: jest.fn(),
nodeType: 'reference',
nodeProps: {
referenceType,
},
items: [reference],
},
});
if (displaysID) expect(wrapper.text()).toContain(`${reference.iid}`);
else expect(wrapper.text()).not.toContain(`${reference.iid}`);
expect(wrapper.text()).toContain(`${reference.title}`);
});
});
describe('rendering emoji references', () => {
it('displays emoji', () => {
const testEmojis = [
{
c: 'people',
e: '😄',
d: 'smiling face with open mouth and smiling eyes',
u: '6.0',
name: 'smile',
},
{
c: 'people',
e: '😸',
d: 'grinning cat face with smiling eyes',
u: '6.0',
name: 'smile_cat',
},
{ c: 'people', e: '😃', d: 'smiling face with open mouth', u: '6.0', name: 'smiley' },
];
buildWrapper({
propsData: {
char: ':',
command: jest.fn(),
nodeType: 'emoji',
nodeProps: {},
items: testEmojis,
},
});
testEmojis.forEach((testEmoji) => {
expect(wrapper.text()).toContain(testEmoji.e);
expect(wrapper.text()).toContain(testEmoji.d);
expect(wrapper.text()).toContain(testEmoji.name);
});
});
});
});
});

View File

@ -4,8 +4,8 @@ require 'spec_helper'
RSpec.describe IssuesHelper do
let(:project) { create(:project) }
let(:issue) { create :issue, project: project }
let(:ext_project) { create :redmine_project }
let(:issue) { create(:issue, project: project) }
let(:ext_project) { create(:project, :with_redmine_integration) }
describe '#work_item_type_icon' do
it 'returns icon of all standard base types' do

View File

@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Banzai::Pipeline::GfmPipeline do
describe 'integration between parsing regular and external issue references' do
let(:project) { create(:redmine_project, :public) }
let(:project) { create(:project, :with_redmine_integration, :public) }
context 'when internal issue tracker is enabled' do
context 'when shorthand pattern #ISSUE_ID is used' do

View File

@ -298,7 +298,7 @@ RSpec.describe Gitlab::ClosingIssueExtractor do
context 'with an external issue tracker reference' do
it 'extracts the referenced issue' do
jira_project = create(:jira_project, name: 'JIRA_EXT1')
jira_project = create(:project, :with_jira_integration, name: 'JIRA_EXT1')
jira_project.add_maintainer(jira_project.creator)
jira_issue = ExternalIssue.new("#{jira_project.name}-1", project: jira_project)
closing_issue_extractor = described_class.new(jira_project, jira_project.creator)

View File

@ -193,7 +193,7 @@ RSpec.describe Gitlab::ReferenceExtractor do
end
context 'with an external issue tracker' do
let(:project) { create(:jira_project) }
let(:project) { create(:project, :with_jira_integration) }
let(:issue) { create(:issue, project: project) }
context 'when GitLab issues are enabled' do

View File

@ -151,6 +151,18 @@ RSpec.describe BulkImports::Entity, type: :model do
expect(entity).to be_valid
end
end
context 'when bulk_import_projects feature flag is enabled on root ancestor level and source_type is a project_entity' do
it 'is valid' do
top_level_namespace = create(:group)
stub_feature_flags(bulk_import_projects: top_level_namespace)
entity = build(:bulk_import_entity, :project_entity, destination_namespace: top_level_namespace.full_path)
expect(entity).to be_valid
end
end
end
describe '#encoded_source_full_path' do

View File

@ -225,7 +225,7 @@ RSpec.describe Commit, 'Mentionable' do
end
context 'with external issue tracker' do
let(:project) { create(:jira_project, :repository) }
let(:project) { create(:project, :with_jira_integration, :repository) }
it 'is true if external issues referenced' do
allow(commit.raw).to receive(:message).and_return 'JIRA-123'

View File

@ -6,7 +6,7 @@ RSpec.describe PrometheusAdapter, :use_clean_rails_memory_store_caching do
include PrometheusHelpers
include ReactiveCachingHelpers
let(:project) { create(:prometheus_project) }
let(:project) { create(:project, :with_prometheus_integration) }
let(:integration) { project.prometheus_integration }
let(:described_class) do

View File

@ -1291,7 +1291,7 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
context 'when the environment is available' do
context 'with a deployment service' do
let(:project) { create(:prometheus_project, :repository) }
let(:project) { create(:project, :with_prometheus_integration, :repository) }
context 'and a deployment' do
let!(:deployment) { create(:deployment, environment: environment) }
@ -1364,7 +1364,7 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
end
context 'when the environment is unavailable' do
let(:project) { create(:prometheus_project) }
let(:project) { create(:project, :with_prometheus_integration) }
before do
environment.stop
@ -1391,7 +1391,7 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
end
describe '#metrics' do
let(:project) { create(:prometheus_project) }
let(:project) { create(:project, :with_prometheus_integration) }
subject { environment.metrics }
@ -1427,7 +1427,7 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
end
describe '#additional_metrics' do
let(:project) { create(:prometheus_project) }
let(:project) { create(:project, :with_prometheus_integration) }
let(:metric_params) { [] }
subject { environment.additional_metrics(*metric_params) }

View File

@ -8,7 +8,7 @@ RSpec.describe Integrations::Prometheus, :use_clean_rails_memory_store_caching,
include PrometheusHelpers
include ReactiveCachingHelpers
let_it_be_with_reload(:project) { create(:prometheus_project) }
let_it_be_with_reload(:project) { create(:project, :with_prometheus_integration) }
let(:integration) { project.prometheus_integration }
@ -318,7 +318,7 @@ RSpec.describe Integrations::Prometheus, :use_clean_rails_memory_store_caching,
context 'cluster belongs to projects group' do
let_it_be(:group) { create(:group) }
let(:project) { create(:prometheus_project, group: group) }
let(:project) { create(:project, :with_prometheus_integration, group: group) }
let(:cluster) { create(:cluster_for_group, groups: [group]) }
it 'returns true' do

View File

@ -1415,7 +1415,7 @@ RSpec.describe Project, factory_default: :keep do
it "is false if used other tracker" do
# NOTE: The current nature of this factory requires persistence
project = create(:redmine_project)
project = create(:project, :with_redmine_integration)
expect(project.default_issues_tracker?).to be_falsey
end
@ -1460,7 +1460,7 @@ RSpec.describe Project, factory_default: :keep do
describe '#external_issue_tracker' do
it 'sets Project#has_external_issue_tracker when it is nil' do
project_with_no_tracker = create(:project, has_external_issue_tracker: nil)
project_with_tracker = create(:redmine_project, has_external_issue_tracker: nil)
project_with_tracker = create(:project, :with_redmine_integration, has_external_issue_tracker: nil)
expect do
project_with_no_tracker.external_issue_tracker
@ -1479,7 +1479,7 @@ RSpec.describe Project, factory_default: :keep do
end
it 'retrieves external_issue_tracker querying services and cache it when there is external issue tracker' do
project = create(:redmine_project)
project = create(:project, :with_redmine_integration)
expect(project).to receive(:integrations).once.and_call_original
2.times { expect(project.external_issue_tracker).to be_a_kind_of(Integrations::Redmine) }
@ -5750,40 +5750,40 @@ RSpec.describe Project, factory_default: :keep do
describe '#has_active_hooks?' do
let_it_be_with_refind(:project) { create(:project) }
it { expect(project.has_active_hooks?).to be_falsey }
it { expect(project.has_active_hooks?).to eq(false) }
it 'returns true when a matching push hook exists' do
create(:project_hook, push_events: true, project: project)
expect(project.has_active_hooks?(:merge_request_events)).to be_falsey
expect(project.has_active_hooks?).to be_truthy
expect(project.has_active_hooks?(:merge_request_hooks)).to eq(false)
expect(project.has_active_hooks?).to eq(true)
end
it 'returns true when a matching system hook exists' do
create(:system_hook, push_events: true)
expect(project.has_active_hooks?(:merge_request_events)).to be_falsey
expect(project.has_active_hooks?).to be_truthy
expect(project.has_active_hooks?(:merge_request_hooks)).to eq(false)
expect(project.has_active_hooks?).to eq(true)
end
it 'returns true when a plugin exists' do
expect(Gitlab::FileHook).to receive(:any?).twice.and_return(true)
expect(project.has_active_hooks?(:merge_request_events)).to be_truthy
expect(project.has_active_hooks?).to be_truthy
expect(project.has_active_hooks?(:merge_request_hooks)).to eq(true)
expect(project.has_active_hooks?).to eq(true)
end
end
describe '#has_active_integrations?' do
let_it_be(:project) { create(:project) }
it { expect(project.has_active_integrations?).to be_falsey }
it { expect(project.has_active_integrations?).to eq(false) }
it 'returns true when a matching service exists' do
create(:custom_issue_tracker_integration, push_events: true, merge_requests_events: false, project: project)
expect(project.has_active_integrations?(:merge_request_hooks)).to be_falsey
expect(project.has_active_integrations?).to be_truthy
expect(project.has_active_integrations?(:merge_request_hooks)).to eq(false)
expect(project.has_active_integrations?).to eq(true)
end
end

View File

@ -3315,7 +3315,7 @@ RSpec.describe API::MergeRequests do
end
it 'handles external issues' do
jira_project = create(:jira_project, :public, :repository, name: 'JIR_EXT1')
jira_project = create(:project, :with_jira_integration, :public, :repository, name: 'JIR_EXT1')
ext_issue = ExternalIssue.new("#{jira_project.name}-123", jira_project)
issue = create(:issue, project: jira_project)
description = "Closes #{ext_issue.to_reference(jira_project)}\ncloses #{issue.to_reference}"

View File

@ -15,20 +15,28 @@ RSpec.describe MergeRequests::MarkReviewerReviewedService do
end
describe '#execute' do
describe 'invalid permissions' do
let(:service) { described_class.new(project: project, current_user: create(:user)) }
shared_examples_for 'failed service execution' do
it 'returns an error' do
expect(result[:status]).to eq :error
end
it 'does not trigger graphql subscription mergeRequestReviewersUpdated' do
expect(GraphqlTriggers).not_to receive(:merge_request_reviewers_updated)
result
end
end
describe 'invalid permissions' do
let(:service) { described_class.new(project: project, current_user: create(:user)) }
it_behaves_like 'failed service execution'
end
describe 'reviewer does not exist' do
let(:service) { described_class.new(project: project, current_user: create(:user)) }
it 'returns an error' do
expect(result[:status]).to eq :error
end
it_behaves_like 'failed service execution'
end
describe 'reviewer exists' do
@ -40,6 +48,12 @@ RSpec.describe MergeRequests::MarkReviewerReviewedService do
expect(result[:status]).to eq :success
expect(reviewer.state).to eq 'reviewed'
end
it 'triggers graphql subscription mergeRequestReviewersUpdated' do
expect(GraphqlTriggers).to receive(:merge_request_reviewers_updated).with(merge_request)
result
end
end
end
end

View File

@ -25,20 +25,28 @@ RSpec.describe MergeRequests::RequestReviewService do
end
describe '#execute' do
describe 'invalid permissions' do
let(:service) { described_class.new(project: project, current_user: create(:user)) }
shared_examples_for 'failed service execution' do
it 'returns an error' do
expect(result[:status]).to eq :error
end
it 'does not trigger graphql subscription mergeRequestReviewersUpdated' do
expect(GraphqlTriggers).not_to receive(:merge_request_reviewers_updated)
result
end
end
describe 'invalid permissions' do
let(:service) { described_class.new(project: project, current_user: create(:user)) }
it_behaves_like 'failed service execution'
end
describe 'reviewer does not exist' do
let(:result) { service.execute(merge_request, create(:user)) }
it 'returns an error' do
expect(result[:status]).to eq :error
end
it_behaves_like 'failed service execution'
end
describe 'reviewer exists' do
@ -64,6 +72,12 @@ RSpec.describe MergeRequests::RequestReviewService do
service.execute(merge_request, user)
end
it 'triggers graphql subscription mergeRequestReviewersUpdated' do
expect(GraphqlTriggers).to receive(:merge_request_reviewers_updated).with(merge_request)
result
end
end
end
end

View File

@ -57,5 +57,53 @@ RSpec.shared_examples 'wiki pipeline imports a wiki for an entity' do
expect(tracker.entity.failures.first.exception_message).to eq('Only allowed schemes are http, https')
end
end
context 'when wiki is disabled' do
before do
allow_next_instance_of(BulkImports::Clients::HTTP) do |client|
allow(client)
.to receive(:get)
.and_raise(
BulkImports::NetworkError.new(
'Unsuccessful response 403 from ...',
response: response_double
)
)
end
end
describe 'unsuccessful response' do
shared_examples 'does not raise an error' do
it 'does not raise an error' do
expect(parent.wiki).not_to receive(:ensure_repository)
expect(parent.wiki.repository).not_to receive(:ensure_repository)
expect { subject.run }.not_to raise_error
end
end
context 'when response is forbidden' do
let(:response_double) { instance_double(HTTParty::Response, forbidden?: true, code: 403) }
include_examples 'does not raise an error'
end
context 'when response is not found' do
let(:response_double) { instance_double(HTTParty::Response, forbidden?: false, not_found?: true) }
include_examples 'does not raise an error'
end
context 'when response is not 403' do
let(:response_double) { instance_double(HTTParty::Response, forbidden?: false, not_found?: false, code: 301) }
it 'marks tracker as failed' do
subject.run
expect(tracker.failed?).to eq(true)
end
end
end
end
end
end

View File

@ -245,11 +245,12 @@ RSpec.shared_examples 'edits content using the content editor' do
type_in_content_editor :enter
end
it 'shows suggestions for members' do
it 'shows suggestions for members with descriptions' do
type_in_content_editor '@a'
expect(find(suggestions_dropdown)).to have_text('abc123')
expect(find(suggestions_dropdown)).to have_text('all')
expect(find(suggestions_dropdown)).to have_text('Group Members (2)')
send_keys [:arrow_down, :enter]

View File

@ -6,7 +6,7 @@ RSpec.describe Integrations::CreateExternalCrossReferenceWorker do
include AfterNextHelpers
using RSpec::Parameterized::TableSyntax
let_it_be(:project) { create(:jira_project, :repository) }
let_it_be(:project) { create(:project, :with_jira_integration, :repository) }
let_it_be(:author) { create(:user) }
let_it_be(:commit) { project.commit }
let_it_be(:issue) { create(:issue, project: project) }

View File

@ -1074,10 +1074,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.4.0.tgz#cfc8319e259e5914ad0f48ee0ab6e0eec75d03da"
integrity sha512-myCYbjViOI2k6oHGRqL1iKaMKbYvPqWL6tYZ07QkUKziVz5kYjECWk5c0Qp6yu9NsFAMWuow5PkR3oFTGBHmbg==
"@gitlab/ui@43.21.0":
version "43.21.0"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-43.21.0.tgz#189094170c7ff0545685eaed3a4c4c55ead915e3"
integrity sha512-jKuZ3AGFfAA5UEOXxGaSxb2NHplLTcRJbbR+bl6/9ggGhoyGPhgl74WzX87ejDNVooY4vvWGGRzGJhN1NgDM+w==
"@gitlab/ui@44.0.0":
version "44.0.0"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-44.0.0.tgz#70693077ee9315e4743357a2306dd344b681203e"
integrity sha512-zfYL4c0ziGry1bDBjfYtd1t2qQ+z4cXGYCNprNKOIQCXgG9759EuopytyOEHf8yMJDwunTzFNOAkPtOsD7DzQA==
dependencies:
"@popperjs/core" "^2.11.2"
bootstrap-vue "2.20.1"
@ -1668,10 +1668,10 @@
dependencies:
"@sinonjs/commons" "^1.7.0"
"@sourcegraph/code-host-integration@0.0.60":
version "0.0.60"
resolved "https://registry.yarnpkg.com/@sourcegraph/code-host-integration/-/code-host-integration-0.0.60.tgz#2043877fabb7eb986fcb61b67ee480afbb29f4f0"
integrity sha512-T+MvM8SUF7daA279hyQgwmva3J5LvPqwgQ/mWwxdVshehOQIPLUd310I0c6x6nZ0F/x4UjDWgRWzAqy6NLwV1w==
"@sourcegraph/code-host-integration@0.0.82":
version "0.0.82"
resolved "https://registry.yarnpkg.com/@sourcegraph/code-host-integration/-/code-host-integration-0.0.82.tgz#9bf45d9a4bfb44be2ecbf86a63028df169f9dfc4"
integrity sha512-HOdCo1SZ5H2AXIdao77G+Hh4nJW6UVNA3b1TrcXXHqfYvXoWn6yzEoI9aZjRVR6K5gBk5FD7amd/FKmqLmyo5A==
"@testing-library/dom@^7.16.2":
version "7.24.5"