Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
411cc77938
commit
167894d0e7
32 changed files with 167 additions and 121 deletions
|
@ -299,17 +299,17 @@ export default {
|
|||
stacked="sm"
|
||||
tbody-tr-class="table-row mb-4"
|
||||
>
|
||||
<template v-slot:head(error)>
|
||||
<template #head(error)>
|
||||
<div class="d-none d-sm-block">{{ __('Open errors') }}</div>
|
||||
</template>
|
||||
<template v-slot:head(events)="data">
|
||||
<template #head(events)="data">
|
||||
<div class="text-sm-right">{{ data.label }}</div>
|
||||
</template>
|
||||
<template v-slot:head(users)="data">
|
||||
<template #head(users)="data">
|
||||
<div class="text-sm-right">{{ data.label }}</div>
|
||||
</template>
|
||||
|
||||
<template v-slot:error="errors">
|
||||
<template #cell(error)="errors">
|
||||
<div class="d-flex flex-column">
|
||||
<gl-link class="d-flex mw-100 text-dark" :href="getDetailsLink(errors.item.id)">
|
||||
<strong class="text-truncate">{{ errors.item.title.trim() }}</strong>
|
||||
|
@ -319,20 +319,20 @@ export default {
|
|||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:events="errors">
|
||||
<template #cell(events)="errors">
|
||||
<div class="text-right">{{ errors.item.count }}</div>
|
||||
</template>
|
||||
|
||||
<template v-slot:users="errors">
|
||||
<template #cell(users)="errors">
|
||||
<div class="text-right">{{ errors.item.userCount }}</div>
|
||||
</template>
|
||||
|
||||
<template v-slot:lastSeen="errors">
|
||||
<template #cell(lastSeen)="errors">
|
||||
<div class="text-md-left text-right">
|
||||
<time-ago :time="errors.item.lastSeen" class="text-secondary" />
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:ignore="errors">
|
||||
<template #cell(ignore)="errors">
|
||||
<gl-button
|
||||
ref="ignoreError"
|
||||
v-gl-tooltip.hover
|
||||
|
@ -342,7 +342,7 @@ export default {
|
|||
<gl-icon name="eye-slash" :size="12" />
|
||||
</gl-button>
|
||||
</template>
|
||||
<template v-slot:resolved="errors">
|
||||
<template #cell(resolved)="errors">
|
||||
<gl-button
|
||||
ref="resolveError"
|
||||
v-gl-tooltip
|
||||
|
@ -352,7 +352,7 @@ export default {
|
|||
<gl-icon name="check-circle" :size="12" />
|
||||
</gl-button>
|
||||
</template>
|
||||
<template v-slot:details="errors">
|
||||
<template #cell(details)="errors">
|
||||
<gl-button
|
||||
:href="getDetailsLink(errors.item.id)"
|
||||
variant="outline-info"
|
||||
|
@ -361,7 +361,7 @@ export default {
|
|||
{{ __('More details') }}
|
||||
</gl-button>
|
||||
</template>
|
||||
<template v-slot:empty>
|
||||
<template #empty>
|
||||
{{ __('No errors to display.') }}
|
||||
<gl-link class="js-try-again" @click="restartPolling">
|
||||
{{ __('Check again') }}
|
||||
|
|
|
@ -128,8 +128,8 @@ export default {
|
|||
@click="handleSuggestDismissed"
|
||||
/>
|
||||
<gl-popover
|
||||
v-if="showSuggestPopover"
|
||||
:target="() => $refs.suggestButton"
|
||||
v-if="showSuggestPopover && $refs.suggestButton"
|
||||
:target="$refs.suggestButton"
|
||||
:css-classes="['diff-suggest-popover']"
|
||||
placement="bottom"
|
||||
:show="showSuggestPopover"
|
||||
|
|
|
@ -26,7 +26,7 @@ module API
|
|||
end
|
||||
|
||||
get ":id/#{noteables_path}/:noteable_id/discussions" do
|
||||
noteable = find_noteable(parent_type, params[:id], noteable_type, params[:noteable_id])
|
||||
noteable = find_noteable(noteable_type, params[:noteable_id])
|
||||
|
||||
notes = readable_discussion_notes(noteable)
|
||||
discussions = Kaminari.paginate_array(Discussion.build_collection(notes, noteable))
|
||||
|
@ -42,7 +42,7 @@ module API
|
|||
requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
|
||||
end
|
||||
get ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id" do
|
||||
noteable = find_noteable(parent_type, params[:id], noteable_type, params[:noteable_id])
|
||||
noteable = find_noteable(noteable_type, params[:noteable_id])
|
||||
notes = readable_discussion_notes(noteable, params[:discussion_id])
|
||||
|
||||
if notes.empty?
|
||||
|
@ -77,7 +77,7 @@ module API
|
|||
end
|
||||
end
|
||||
post ":id/#{noteables_path}/:noteable_id/discussions" do
|
||||
noteable = find_noteable(parent_type, params[:id], noteable_type, params[:noteable_id])
|
||||
noteable = find_noteable(noteable_type, params[:noteable_id])
|
||||
type = params[:position] ? 'DiffNote' : 'DiscussionNote'
|
||||
id_key = noteable.is_a?(Commit) ? :commit_id : :noteable_id
|
||||
|
||||
|
@ -107,7 +107,7 @@ module API
|
|||
requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
|
||||
end
|
||||
get ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id/notes" do
|
||||
noteable = find_noteable(parent_type, params[:id], noteable_type, params[:noteable_id])
|
||||
noteable = find_noteable(noteable_type, params[:noteable_id])
|
||||
notes = readable_discussion_notes(noteable, params[:discussion_id])
|
||||
|
||||
if notes.empty?
|
||||
|
@ -127,7 +127,7 @@ module API
|
|||
optional :created_at, type: String, desc: 'The creation date of the note'
|
||||
end
|
||||
post ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id/notes" do
|
||||
noteable = find_noteable(parent_type, params[:id], noteable_type, params[:noteable_id])
|
||||
noteable = find_noteable(noteable_type, params[:noteable_id])
|
||||
notes = readable_discussion_notes(noteable, params[:discussion_id])
|
||||
first_note = notes.first
|
||||
|
||||
|
@ -161,7 +161,7 @@ module API
|
|||
requires :note_id, type: Integer, desc: 'The ID of a note'
|
||||
end
|
||||
get ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id/notes/:note_id" do
|
||||
noteable = find_noteable(parent_type, params[:id], noteable_type, params[:noteable_id])
|
||||
noteable = find_noteable(noteable_type, params[:noteable_id])
|
||||
|
||||
get_note(noteable, params[:note_id])
|
||||
end
|
||||
|
@ -178,7 +178,7 @@ module API
|
|||
exactly_one_of :body, :resolved
|
||||
end
|
||||
put ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id/notes/:note_id" do
|
||||
noteable = find_noteable(parent_type, params[:id], noteable_type, params[:noteable_id])
|
||||
noteable = find_noteable(noteable_type, params[:noteable_id])
|
||||
|
||||
if params[:resolved].nil?
|
||||
update_note(noteable, params[:note_id])
|
||||
|
@ -196,7 +196,7 @@ module API
|
|||
requires :note_id, type: Integer, desc: 'The ID of a note'
|
||||
end
|
||||
delete ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id/notes/:note_id" do
|
||||
noteable = find_noteable(parent_type, params[:id], noteable_type, params[:noteable_id])
|
||||
noteable = find_noteable(noteable_type, params[:noteable_id])
|
||||
|
||||
delete_note(noteable, params[:note_id])
|
||||
end
|
||||
|
@ -211,7 +211,7 @@ module API
|
|||
requires :resolved, type: Boolean, desc: 'Mark discussion resolved/unresolved'
|
||||
end
|
||||
put ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id" do
|
||||
noteable = find_noteable(parent_type, params[:id], noteable_type, params[:noteable_id])
|
||||
noteable = find_noteable(noteable_type, params[:noteable_id])
|
||||
|
||||
resolve_discussion(noteable, params[:discussion_id], params[:resolved])
|
||||
end
|
||||
|
|
|
@ -83,15 +83,15 @@ module API
|
|||
end
|
||||
end
|
||||
|
||||
def find_noteable(parent_type, parent_id, noteable_type, noteable_id)
|
||||
params = finder_params_by_noteable_type_and_id(noteable_type, noteable_id, parent_id)
|
||||
def find_noteable(noteable_type, noteable_id)
|
||||
params = finder_params_by_noteable_type_and_id(noteable_type, noteable_id)
|
||||
|
||||
noteable = NotesFinder.new(current_user, params).target
|
||||
noteable = nil unless can?(current_user, noteable_read_ability_name(noteable), noteable)
|
||||
noteable || not_found!(noteable_type)
|
||||
end
|
||||
|
||||
def finder_params_by_noteable_type_and_id(type, id, parent_id)
|
||||
def finder_params_by_noteable_type_and_id(type, id)
|
||||
target_type = type.name.underscore
|
||||
{ target_type: target_type }.tap do |h|
|
||||
if %w(issue merge_request).include?(target_type)
|
||||
|
@ -100,11 +100,11 @@ module API
|
|||
h[:target_id] = id
|
||||
end
|
||||
|
||||
add_parent_to_finder_params(h, type, parent_id)
|
||||
add_parent_to_finder_params(h, type)
|
||||
end
|
||||
end
|
||||
|
||||
def add_parent_to_finder_params(finder_params, noteable_type, parent_id)
|
||||
def add_parent_to_finder_params(finder_params, noteable_type)
|
||||
finder_params[:project] = user_project
|
||||
end
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ module API
|
|||
end
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
get ":id/#{noteables_str}/:noteable_id/notes" do
|
||||
noteable = find_noteable(parent_type, params[:id], noteable_type, params[:noteable_id])
|
||||
noteable = find_noteable(noteable_type, params[:noteable_id])
|
||||
|
||||
# We exclude notes that are cross-references and that cannot be viewed
|
||||
# by the current user. By doing this exclusion at this level and not
|
||||
|
@ -58,7 +58,7 @@ module API
|
|||
requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
|
||||
end
|
||||
get ":id/#{noteables_str}/:noteable_id/notes/:note_id" do
|
||||
noteable = find_noteable(parent_type, params[:id], noteable_type, params[:noteable_id])
|
||||
noteable = find_noteable(noteable_type, params[:noteable_id])
|
||||
get_note(noteable, params[:note_id])
|
||||
end
|
||||
|
||||
|
@ -71,7 +71,7 @@ module API
|
|||
optional :created_at, type: String, desc: 'The creation date of the note'
|
||||
end
|
||||
post ":id/#{noteables_str}/:noteable_id/notes" do
|
||||
noteable = find_noteable(parent_type, params[:id], noteable_type, params[:noteable_id])
|
||||
noteable = find_noteable(noteable_type, params[:noteable_id])
|
||||
|
||||
opts = {
|
||||
note: params[:body],
|
||||
|
@ -98,7 +98,7 @@ module API
|
|||
requires :body, type: String, desc: 'The content of a note'
|
||||
end
|
||||
put ":id/#{noteables_str}/:noteable_id/notes/:note_id" do
|
||||
noteable = find_noteable(parent_type, params[:id], noteable_type, params[:noteable_id])
|
||||
noteable = find_noteable(noteable_type, params[:noteable_id])
|
||||
|
||||
update_note(noteable, params[:note_id])
|
||||
end
|
||||
|
@ -111,7 +111,7 @@ module API
|
|||
requires :note_id, type: Integer, desc: 'The ID of a note'
|
||||
end
|
||||
delete ":id/#{noteables_str}/:noteable_id/notes/:note_id" do
|
||||
noteable = find_noteable(parent_type, params[:id], noteable_type, params[:noteable_id])
|
||||
noteable = find_noteable(noteable_type, params[:noteable_id])
|
||||
|
||||
delete_note(noteable, params[:note_id])
|
||||
end
|
||||
|
|
|
@ -25,7 +25,7 @@ module API
|
|||
end
|
||||
|
||||
get ":id/#{eventables_str}/:eventable_id/resource_label_events" do
|
||||
eventable = find_noteable(parent_type, params[:id], eventable_type, params[:eventable_id])
|
||||
eventable = find_noteable(eventable_type, params[:eventable_id])
|
||||
|
||||
opts = { page: params[:page], per_page: params[:per_page] }
|
||||
events = ResourceLabelEventFinder.new(current_user, eventable, opts).execute
|
||||
|
@ -42,7 +42,8 @@ module API
|
|||
requires :eventable_id, types: [Integer, String], desc: 'The ID of the eventable'
|
||||
end
|
||||
get ":id/#{eventables_str}/:eventable_id/resource_label_events/:event_id" do
|
||||
eventable = find_noteable(parent_type, params[:id], eventable_type, params[:eventable_id])
|
||||
eventable = find_noteable(eventable_type, params[:eventable_id])
|
||||
|
||||
event = eventable.resource_label_events.find(params[:event_id])
|
||||
|
||||
not_found!('ResourceLabelEvent') unless can?(current_user, :read_resource_label_event, event)
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
"@babel/plugin-syntax-import-meta": "^7.2.0",
|
||||
"@babel/preset-env": "^7.6.2",
|
||||
"@gitlab/svgs": "^1.90.0",
|
||||
"@gitlab/ui": "^8.21.0",
|
||||
"@gitlab/ui": "^9.0.0",
|
||||
"@gitlab/visual-review-tools": "1.5.1",
|
||||
"@sentry/browser": "^5.10.2",
|
||||
"@sourcegraph/code-host-integration": "0.0.21",
|
||||
|
|
|
@ -12,6 +12,12 @@ module QA
|
|||
|
||||
yield
|
||||
|
||||
# Workaround for a bug preventing sign out from secondary nodes
|
||||
# See https://gitlab.com/gitlab-org/gitlab/issues/198289
|
||||
if address == :geo_secondary
|
||||
Runtime::Browser.visit(:geo_primary, Page::Dashboard::Projects)
|
||||
end
|
||||
|
||||
Page::Main::Menu.perform(&:sign_out)
|
||||
end
|
||||
|
||||
|
|
|
@ -26,13 +26,13 @@ module QA
|
|||
wait_for_requests
|
||||
end
|
||||
|
||||
def wait_until(max_duration: 60, sleep_interval: 0.1, reload: true, raise_on_failure: false)
|
||||
def wait_until(max_duration: 60, sleep_interval: 0.1, reload: true, raise_on_failure: true)
|
||||
Support::Waiter.wait_until(max_duration: max_duration, sleep_interval: sleep_interval, raise_on_failure: raise_on_failure) do
|
||||
yield || (reload && refresh && false)
|
||||
end
|
||||
end
|
||||
|
||||
def retry_until(max_attempts: 3, reload: false, sleep_interval: 0, raise_on_failure: false)
|
||||
def retry_until(max_attempts: 3, reload: false, sleep_interval: 0, raise_on_failure: true)
|
||||
Support::Retrier.retry_until(max_attempts: max_attempts, reload_page: (reload && self), sleep_interval: sleep_interval, raise_on_failure: raise_on_failure) do
|
||||
yield
|
||||
end
|
||||
|
|
|
@ -16,13 +16,6 @@ module QA
|
|||
super
|
||||
end
|
||||
|
||||
def wait_until(max_duration: 60, sleep_interval: 0.1, reload: true, raise_on_failure: false)
|
||||
log("next wait uses reload: #{reload}")
|
||||
# Logging of wait start/end/duration is handled by QA::Support::Waiter
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def scroll_to(selector, text: nil)
|
||||
msg = "scrolling to :#{selector}"
|
||||
msg += " with text: #{text}" if text
|
||||
|
|
|
@ -34,7 +34,7 @@ module QA
|
|||
result
|
||||
end
|
||||
|
||||
def retry_until(max_attempts: nil, max_duration: nil, reload_page: nil, sleep_interval: 0, raise_on_failure: false, retry_on_exception: false)
|
||||
def retry_until(max_attempts: nil, max_duration: nil, reload_page: nil, sleep_interval: 0, raise_on_failure: true, retry_on_exception: false)
|
||||
# For backwards-compatibility
|
||||
max_attempts = 3 if max_attempts.nil? && max_duration.nil?
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ module QA
|
|||
|
||||
module_function
|
||||
|
||||
def wait_until(max_duration: singleton_class::DEFAULT_MAX_WAIT_TIME, reload_page: nil, sleep_interval: 0.1, raise_on_failure: false, retry_on_exception: false)
|
||||
def wait_until(max_duration: singleton_class::DEFAULT_MAX_WAIT_TIME, reload_page: nil, sleep_interval: 0.1, raise_on_failure: true, retry_on_exception: false)
|
||||
QA::Runtime::Logger.debug(
|
||||
<<~MSG.tr("\n", ' ')
|
||||
with wait_until: max_duration: #{max_duration};
|
||||
|
|
|
@ -27,24 +27,6 @@ describe QA::Support::Page::Logging do
|
|||
.to output(%r{refreshing http://current-url}).to_stdout_from_any_process
|
||||
end
|
||||
|
||||
it 'logs wait' do
|
||||
expect { subject.wait_until(max_duration: 0) {} }
|
||||
.to output(/next wait uses reload: true/).to_stdout_from_any_process
|
||||
expect { subject.wait_until(max_duration: 0) {} }
|
||||
.to output(/with wait_until/).to_stdout_from_any_process
|
||||
expect { subject.wait_until(max_duration: 0) {} }
|
||||
.to output(/ended wait_until$/).to_stdout_from_any_process
|
||||
end
|
||||
|
||||
it 'logs wait with reload false' do
|
||||
expect { subject.wait_until(max_duration: 0, reload: false) {} }
|
||||
.to output(/next wait uses reload: false/).to_stdout_from_any_process
|
||||
expect { subject.wait_until(max_duration: 0, reload: false) {} }
|
||||
.to output(/with wait_until/).to_stdout_from_any_process
|
||||
expect { subject.wait_until(max_duration: 0, reload: false) {} }
|
||||
.to output(/ended wait_until$/).to_stdout_from_any_process
|
||||
end
|
||||
|
||||
it 'logs scroll_to' do
|
||||
expect { subject.scroll_to(:element) }
|
||||
.to output(/scrolling to :element/).to_stdout_from_any_process
|
||||
|
|
|
@ -14,12 +14,12 @@ describe QA::Support::Retrier do
|
|||
context 'when the condition is true' do
|
||||
it 'logs max attempts (3 by default)' do
|
||||
expect { subject.retry_until { true } }
|
||||
.to output(/with retry_until: max_attempts: 3; reload_page: ; sleep_interval: 0; raise_on_failure: false; retry_on_exception: false/).to_stdout_from_any_process
|
||||
.to output(/with retry_until: max_attempts: 3; reload_page: ; sleep_interval: 0; raise_on_failure: true; retry_on_exception: false/).to_stdout_from_any_process
|
||||
end
|
||||
|
||||
it 'logs max duration' do
|
||||
expect { subject.retry_until(max_duration: 1) { true } }
|
||||
.to output(/with retry_until: max_duration: 1; reload_page: ; sleep_interval: 0; raise_on_failure: false; retry_on_exception: false/).to_stdout_from_any_process
|
||||
.to output(/with retry_until: max_duration: 1; reload_page: ; sleep_interval: 0; raise_on_failure: true; retry_on_exception: false/).to_stdout_from_any_process
|
||||
end
|
||||
|
||||
it 'logs the end' do
|
||||
|
@ -30,12 +30,12 @@ describe QA::Support::Retrier do
|
|||
|
||||
context 'when the condition is false' do
|
||||
it 'logs the start' do
|
||||
expect { subject.retry_until(max_duration: 0) { false } }
|
||||
expect { subject.retry_until(max_duration: 0, raise_on_failure: false) { false } }
|
||||
.to output(/with retry_until: max_duration: 0; reload_page: ; sleep_interval: 0; raise_on_failure: false; retry_on_exception: false/).to_stdout_from_any_process
|
||||
end
|
||||
|
||||
it 'logs the end' do
|
||||
expect { subject.retry_until(max_duration: 0) { false } }
|
||||
expect { subject.retry_until(max_duration: 0, raise_on_failure: false) { false } }
|
||||
.to output(/ended retry_until$/).to_stdout_from_any_process
|
||||
end
|
||||
end
|
||||
|
@ -54,8 +54,8 @@ describe QA::Support::Retrier do
|
|||
subject.retry_until
|
||||
end
|
||||
|
||||
it 'sets raise_on_failure to false by default' do
|
||||
expect(subject).to receive(:repeat_until).with(hash_including(raise_on_failure: false))
|
||||
it 'sets raise_on_failure to true by default' do
|
||||
expect(subject).to receive(:repeat_until).with(hash_including(raise_on_failure: true))
|
||||
|
||||
subject.retry_until
|
||||
end
|
||||
|
|
|
@ -46,8 +46,8 @@ describe QA::Support::Waiter do
|
|||
subject.wait_until
|
||||
end
|
||||
|
||||
it 'sets raise_on_failure to false by default' do
|
||||
expect(subject).to receive(:repeat_until).with(hash_including(raise_on_failure: false))
|
||||
it 'sets raise_on_failure to true by default' do
|
||||
expect(subject).to receive(:repeat_until).with(hash_including(raise_on_failure: true))
|
||||
|
||||
subject.wait_until
|
||||
end
|
||||
|
|
|
@ -11,7 +11,7 @@ describe 'Resolving all open threads in a merge request from an issue', :js do
|
|||
def resolve_all_discussions_link_selector
|
||||
text = "Resolve all threads in new issue"
|
||||
url = new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)
|
||||
%Q{a[data-original-title="#{text}"][href="#{url}"]}
|
||||
%Q{a[title="#{text}"][href="#{url}"]}
|
||||
end
|
||||
|
||||
describe 'as a user with access to the project' do
|
||||
|
|
|
@ -11,7 +11,7 @@ describe 'Resolve an open thread in a merge request by creating an issue', :js d
|
|||
def resolve_discussion_selector
|
||||
title = 'Resolve this thread in a new issue'
|
||||
url = new_project_issue_path(project, discussion_to_resolve: discussion.id, merge_request_to_resolve_discussions_of: merge_request.iid)
|
||||
"a[data-original-title=\"#{title}\"][href=\"#{url}\"]"
|
||||
"a[title=\"#{title}\"][href=\"#{url}\"]"
|
||||
end
|
||||
|
||||
describe 'As a user with access to the project' do
|
||||
|
|
|
@ -16,7 +16,7 @@ describe 'Merge request > User edits assignees sidebar', :js do
|
|||
# DOM finders to simplify and improve readability
|
||||
let(:sidebar_assignee_block) { page.find('.js-issuable-sidebar .assignee') }
|
||||
let(:sidebar_assignee_avatar_link) { sidebar_assignee_block.find_all('a').find { |a| a['href'].include? assignee.username } }
|
||||
let(:sidebar_assignee_tooltip) { sidebar_assignee_avatar_link['data-original-title'] || '' }
|
||||
let(:sidebar_assignee_tooltip) { sidebar_assignee_avatar_link['title'] || '' }
|
||||
let(:sidebar_assignee_dropdown_item) { sidebar_assignee_block.find(".dropdown-menu li[data-user-id=\"#{assignee.id}\"]") }
|
||||
let(:sidebar_assignee_dropdown_tooltip) { sidebar_assignee_dropdown_item.find('a')['data-title'] || '' }
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ describe 'Merge request > User sees deployment widget', :js do
|
|||
wait_for_requests
|
||||
|
||||
expect(page).to have_content("Deployed to #{environment.name}")
|
||||
expect(find('.js-deploy-time')['data-original-title']).to eq(deployment.created_at.to_time.in_time_zone.to_s(:medium))
|
||||
expect(find('.js-deploy-time')['title']).to eq(deployment.created_at.to_time.in_time_zone.to_s(:medium))
|
||||
end
|
||||
|
||||
context 'when a user created a new merge request with the same SHA' do
|
||||
|
|
|
@ -112,7 +112,7 @@ describe 'User comments on a diff', :js do
|
|||
changes = sample_compare(expanded_changes).changes.last(expanded_changes.size)
|
||||
|
||||
page.within("[id='#{hash}']") do
|
||||
find("button[data-original-title='Show full file']").click
|
||||
find("button[title='Show full file']").click
|
||||
wait_for_requests
|
||||
|
||||
click_diff_line(find("[id='#{changes.first[:line_code]}']"))
|
||||
|
|
|
@ -13,7 +13,7 @@ describe 'Environments page', :js do
|
|||
end
|
||||
|
||||
def stop_button_selector
|
||||
%q{button[data-original-title="Stop environment"]}
|
||||
%q{button[title="Stop environment"]}
|
||||
end
|
||||
|
||||
describe 'page tabs' do
|
||||
|
|
|
@ -217,7 +217,7 @@ describe 'Pipeline', :js do
|
|||
it 'includes the failure reason' do
|
||||
page.within('#ci-badge-test') do
|
||||
build_link = page.find('.js-pipeline-graph-job-link')
|
||||
expect(build_link['data-original-title']).to eq('test - failed - (unknown failure)')
|
||||
expect(build_link['title']).to eq('test - failed - (unknown failure)')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -270,7 +270,7 @@ describe 'Pipelines', :js do
|
|||
it 'contains badge with tooltip which contains error' do
|
||||
expect(pipeline).to have_yaml_errors
|
||||
expect(page).to have_selector(
|
||||
%Q{span[data-original-title="#{pipeline.yaml_errors}"]})
|
||||
%Q{span[title="#{pipeline.yaml_errors}"]})
|
||||
end
|
||||
|
||||
it 'contains badge that indicates failure reason' do
|
||||
|
@ -280,7 +280,7 @@ describe 'Pipelines', :js do
|
|||
it 'contains badge with tooltip which contains failure reason' do
|
||||
expect(pipeline.failure_reason?).to eq true
|
||||
expect(page).to have_selector(
|
||||
%Q{span[data-original-title="#{pipeline.present.failure_reason}"]})
|
||||
%Q{span[title="#{pipeline.present.failure_reason}"]})
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -569,7 +569,7 @@ describe 'Pipelines', :js do
|
|||
|
||||
within('.js-builds-dropdown-list') do
|
||||
build_element = page.find('.mini-pipeline-graph-dropdown-item')
|
||||
expect(build_element['data-original-title']).to eq('build - failed - (unknown failure)')
|
||||
expect(build_element['title']).to eq('build - failed - (unknown failure)')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -65,7 +65,7 @@ describe 'View on environment', :js do
|
|||
within '.diffs' do
|
||||
text = 'View on feature.review.example.com'
|
||||
url = 'http://feature.review.example.com/ruby/feature'
|
||||
expect(page).to have_selector("a[data-original-title='#{text}'][href='#{url}']")
|
||||
expect(page).to have_selector("a[title='#{text}'][href='#{url}']")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
exports[`Remove cluster confirmation modal renders splitbutton with modal included 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="dropdown btn-group b-dropdown gl-dropdown"
|
||||
class="dropdown b-dropdown gl-dropdown btn-group"
|
||||
>
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
|
@ -31,7 +31,9 @@ exports[`Remove cluster confirmation modal renders splitbutton with modal includ
|
|||
role="menu"
|
||||
tabindex="-1"
|
||||
>
|
||||
<li>
|
||||
<li
|
||||
role="presentation"
|
||||
>
|
||||
<button
|
||||
class="dropdown-item is-active"
|
||||
role="menuitem"
|
||||
|
@ -47,14 +49,18 @@ exports[`Remove cluster confirmation modal renders splitbutton with modal includ
|
|||
</button>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<li
|
||||
role="presentation"
|
||||
>
|
||||
<hr
|
||||
aria-orientation="horizontal"
|
||||
class="dropdown-divider"
|
||||
role="separator"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<li
|
||||
role="presentation"
|
||||
>
|
||||
<button
|
||||
class="dropdown-item"
|
||||
role="menuitem"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::TcpChecker do
|
||||
describe Gitlab::TcpChecker, :permit_dns do
|
||||
before do
|
||||
@server = TCPServer.new('localhost', 0)
|
||||
_, @port, _, @ip = @server.addr
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::UrlBlocker do
|
||||
describe Gitlab::UrlBlocker, :stub_invalid_dns_only do
|
||||
include StubRequests
|
||||
|
||||
describe '#validate!' do
|
||||
|
|
20
spec/support/dns.rb
Normal file
20
spec/support/dns.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require Rails.root.join("spec/support/helpers/dns_helpers")
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.include DnsHelpers
|
||||
|
||||
config.before do
|
||||
block_dns!
|
||||
end
|
||||
|
||||
config.before(:each, :permit_dns) do
|
||||
permit_dns!
|
||||
end
|
||||
|
||||
config.before(:each, :stub_invalid_dns_only) do
|
||||
permit_dns!
|
||||
stub_invalid_dns!
|
||||
end
|
||||
end
|
30
spec/support/helpers/dns_helpers.rb
Normal file
30
spec/support/helpers/dns_helpers.rb
Normal file
|
@ -0,0 +1,30 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module DnsHelpers
|
||||
def block_dns!
|
||||
stub_all_dns!
|
||||
stub_invalid_dns!
|
||||
permit_local_dns!
|
||||
end
|
||||
|
||||
def permit_dns!
|
||||
allow(Addrinfo).to receive(:getaddrinfo).and_call_original
|
||||
end
|
||||
|
||||
def stub_all_dns!
|
||||
allow(Addrinfo).to receive(:getaddrinfo).with(anything, anything, nil, :STREAM).and_return([])
|
||||
allow(Addrinfo).to receive(:getaddrinfo).with(anything, anything, nil, :STREAM, anything, anything).and_return([])
|
||||
end
|
||||
|
||||
def stub_invalid_dns!
|
||||
allow(Addrinfo).to receive(:getaddrinfo).with(/foobar\.\w|(\d{1,3}\.){4,}\d{1,3}/i, anything, nil, :STREAM) do
|
||||
raise SocketError.new("getaddrinfo: Name or service not known")
|
||||
end
|
||||
end
|
||||
|
||||
def permit_local_dns!
|
||||
local_addresses = /(127|10)\.0\.0\.\d{1,3}|(192\.168|172\.16)\.\d{1,3}\.\d{1,3}|0\.0\.0\.0|localhost/i
|
||||
allow(Addrinfo).to receive(:getaddrinfo).with(local_addresses, anything, nil, :STREAM).and_call_original
|
||||
allow(Addrinfo).to receive(:getaddrinfo).with(local_addresses, anything, nil, :STREAM, anything, anything).and_call_original
|
||||
end
|
||||
end
|
|
@ -8,7 +8,7 @@ shared_examples 'error tracking index page' do
|
|||
end
|
||||
|
||||
within('div.error-list') do
|
||||
expect(page).to have_content('Error')
|
||||
expect(page).to have_content('Open errors')
|
||||
expect(page).to have_content('Events')
|
||||
expect(page).to have_content('Users')
|
||||
expect(page).to have_content('Last Seen')
|
||||
|
|
|
@ -20,6 +20,14 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
|
|||
expect(response_dates).to eq(response_dates.sort.reverse)
|
||||
end
|
||||
|
||||
it 'fetches notes using parent path as id paremeter' do
|
||||
parent_id = CGI.escape(parent.full_path)
|
||||
|
||||
get api("/#{parent_type}/#{parent_id}/#{noteable_type}/#{noteable[id_name]}/notes", user)
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
|
||||
context '2 notes with equal created_at' do
|
||||
before do
|
||||
@first_note = Note.first
|
||||
|
|
62
yarn.lock
62
yarn.lock
|
@ -737,14 +737,14 @@
|
|||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.90.0.tgz#e6fe0ca3d353fcdbd792c10d82444383c33f539d"
|
||||
integrity sha512-6UikaIMGosmrDAd6Lf3QIJWDM4FwhoGIN+CJuFcWeHDMbZT69LnTabuGfvOQmp2+nlI68baRTSDufaux7m9Ajw==
|
||||
|
||||
"@gitlab/ui@^8.21.0":
|
||||
version "8.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-8.21.0.tgz#30869847251d525c8402487cea16886b43f134e9"
|
||||
integrity sha512-CLtpvF11aNOt+ttdE4xZTGM3sg124U/nYPrmGkre5FLcLqmSoK1LmRkflLHMUAwHWXz7CvxmSDZa2YshC3SsyQ==
|
||||
"@gitlab/ui@^9.0.0":
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-9.0.0.tgz#16d637f47ba0537100fd1c6d452b56174b50171b"
|
||||
integrity sha512-OfP8UAticpqKkqbPBZ+7bbCBsd9Fxq3eL55Uq5nEwxJ8gGXm+nSc+HFnbzX/ryv0iz5+7nCI4DfIfgy9E4QAeQ==
|
||||
dependencies:
|
||||
"@babel/standalone" "^7.0.0"
|
||||
"@gitlab/vue-toasted" "^1.3.0"
|
||||
bootstrap-vue "2.0.0-rc.27"
|
||||
bootstrap-vue "2.1.0"
|
||||
copy-to-clipboard "^3.0.8"
|
||||
echarts "^4.2.1"
|
||||
highlight.js "^9.13.1"
|
||||
|
@ -925,14 +925,14 @@
|
|||
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
|
||||
integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
|
||||
|
||||
"@nuxt/opencollective@^0.2.2":
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@nuxt/opencollective/-/opencollective-0.2.2.tgz#17adc7d380457379cd14cbb64a435ea196cc4a6e"
|
||||
integrity sha512-ie50SpS47L+0gLsW4yP23zI/PtjsDRglyozX2G09jeiUazC1AJlGPZo0JUs9iuCDUoIgsDEf66y7/bSfig0BpA==
|
||||
"@nuxt/opencollective@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@nuxt/opencollective/-/opencollective-0.3.0.tgz#11d8944dcf2d526e31660bb69570be03f8fb72b7"
|
||||
integrity sha512-Vf09BxCdj1iT2IRqVwX5snaY2WCTkvM0O4cWWSO1ThCFuc4if0Q/nNwAgCxRU0FeYHJ7DdyMUNSdswCLKlVqeg==
|
||||
dependencies:
|
||||
chalk "^2.4.1"
|
||||
consola "^2.3.0"
|
||||
node-fetch "^2.3.0"
|
||||
chalk "^2.4.2"
|
||||
consola "^2.10.1"
|
||||
node-fetch "^2.6.0"
|
||||
|
||||
"@sentry/browser@^5.10.2":
|
||||
version "5.10.2"
|
||||
|
@ -2061,18 +2061,18 @@ bonjour@^3.5.0:
|
|||
multicast-dns "^6.0.1"
|
||||
multicast-dns-service-types "^1.1.0"
|
||||
|
||||
bootstrap-vue@2.0.0-rc.27:
|
||||
version "2.0.0-rc.27"
|
||||
resolved "https://registry.yarnpkg.com/bootstrap-vue/-/bootstrap-vue-2.0.0-rc.27.tgz#884a46a71948d13c9729134cb564467f79a7b2b9"
|
||||
integrity sha512-gXdpt2IsKbmC3SU0bf/RgldWwgrXK7G47yslOtkk4OA1z6fOzb2orM2vU5L8NCNZQomYax9LapRucv+8PByfdA==
|
||||
bootstrap-vue@2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/bootstrap-vue/-/bootstrap-vue-2.1.0.tgz#41c0cd265a6cea14ffe29eeea71543ec396d1789"
|
||||
integrity sha512-dftb5fc42x7QLv814nN+3Cx8MMuCB+xrGQjOmSXH81ET0+yo7KYb4lUN3/pOnf+8Tkv8oaawZ1OOth5/AZfktg==
|
||||
dependencies:
|
||||
"@nuxt/opencollective" "^0.2.2"
|
||||
bootstrap "^4.3.1"
|
||||
popper.js "^1.15.0"
|
||||
portal-vue "^2.1.5"
|
||||
"@nuxt/opencollective" "^0.3.0"
|
||||
bootstrap ">=4.3.1 <5.0.0"
|
||||
popper.js "^1.16.0"
|
||||
portal-vue "^2.1.6"
|
||||
vue-functional-data-merge "^3.1.0"
|
||||
|
||||
bootstrap@4.3.1, bootstrap@^4.3.1:
|
||||
bootstrap@4.3.1, "bootstrap@>=4.3.1 <5.0.0":
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.3.1.tgz#280ca8f610504d99d7b6b4bfc4b68cec601704ac"
|
||||
integrity sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag==
|
||||
|
@ -2893,10 +2893,10 @@ connect@^3.6.0:
|
|||
parseurl "~1.3.2"
|
||||
utils-merge "1.0.1"
|
||||
|
||||
consola@^2.3.0:
|
||||
version "2.11.3"
|
||||
resolved "https://registry.yarnpkg.com/consola/-/consola-2.11.3.tgz#f7315836224c143ac5094b47fd4c816c2cd1560e"
|
||||
integrity sha512-aoW0YIIAmeftGR8GSpw6CGQluNdkWMWh3yEFjH/hmynTYnMtibXszii3lxCXmk8YxJtI3FAK5aTiquA5VH68Gw==
|
||||
consola@^2.10.1:
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/consola/-/consola-2.10.1.tgz#4693edba714677c878d520e4c7e4f69306b4b927"
|
||||
integrity sha512-4sxpH6SGFYLADfUip4vuY65f/gEogrzJoniVhNUYkJHtng0l8ZjnDCqxxrSVRHOHwKxsy8Vm5ONZh1wOR3/l/w==
|
||||
|
||||
console-browserify@^1.1.0:
|
||||
version "1.1.0"
|
||||
|
@ -7964,7 +7964,7 @@ node-ensure@^0.0.0:
|
|||
resolved "https://registry.yarnpkg.com/node-ensure/-/node-ensure-0.0.0.tgz#ecae764150de99861ec5c810fd5d096b183932a7"
|
||||
integrity sha1-7K52QVDemYYexcgQ/V0Jaxg5Mqc=
|
||||
|
||||
node-fetch@^2.3.0:
|
||||
node-fetch@^2.6.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
|
||||
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
|
||||
|
@ -8800,15 +8800,15 @@ pofile@^1:
|
|||
resolved "https://registry.yarnpkg.com/pofile/-/pofile-1.0.11.tgz#35aff58c17491d127a07336d5522ebc9df57c954"
|
||||
integrity sha512-Vy9eH1dRD9wHjYt/QqXcTz+RnX/zg53xK+KljFSX30PvdDMb2z+c6uDUeblUGqqJgz3QFsdlA0IJvHziPmWtQg==
|
||||
|
||||
popper.js@^1.14.7, popper.js@^1.15.0:
|
||||
popper.js@^1.14.7, popper.js@^1.16.0:
|
||||
version "1.16.0"
|
||||
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.0.tgz#2e1816bcbbaa518ea6c2e15a466f4cb9c6e2fbb3"
|
||||
integrity sha512-+G+EkOPoE5S/zChTpmBSSDYmhXJ5PsW8eMhH8cP/CQHMFPBG/kC9Y5IIw6qNYgdJ+/COf0ddY2li28iHaZRSjw==
|
||||
|
||||
portal-vue@^2.1.5, portal-vue@^2.1.6:
|
||||
version "2.1.7"
|
||||
resolved "https://registry.yarnpkg.com/portal-vue/-/portal-vue-2.1.7.tgz#ea08069b25b640ca08a5b86f67c612f15f4e4ad4"
|
||||
integrity sha512-+yCno2oB3xA7irTt0EU5Ezw22L2J51uKAacE/6hMPMoO/mx3h4rXFkkBkT4GFsMDv/vEe8TNKC3ujJJ0PTwb6g==
|
||||
portal-vue@^2.1.6:
|
||||
version "2.1.6"
|
||||
resolved "https://registry.yarnpkg.com/portal-vue/-/portal-vue-2.1.6.tgz#a7d4790b14a79af7fd159a60ec88c30cddc6c639"
|
||||
integrity sha512-lvCF85D4e8whd0nN32D8FqKwwkk7nYUI3Ku8UAEx4Z1reomu75dv5evRUTZNaj1EalxxWNXiNl0EHRq36fG8WA==
|
||||
|
||||
portfinder@^1.0.24:
|
||||
version "1.0.24"
|
||||
|
|
Loading…
Reference in a new issue