Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
412fe7ab55
commit
cd99e8611a
|
|
@ -802,7 +802,7 @@ rspec fail-fast:
|
|||
needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets", "detect-tests"]
|
||||
script:
|
||||
- !reference [.base-script, script]
|
||||
- rspec_fail_fast "${RSPEC_MATCHING_TESTS_PATH}" "--tag ~quarantine"
|
||||
- rspec_fail_fast "${RSPEC_MATCHING_TESTS_PATH}" "--tag ~quarantine --tag ~zoekt"
|
||||
artifacts:
|
||||
expire_in: 7d
|
||||
paths:
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ rspec foss-impact:
|
|||
<% end %>
|
||||
script:
|
||||
- !reference [.base-script, script]
|
||||
- rspec_paralellized_job "--tag ~quarantine --tag ~level:migration"
|
||||
- rspec_paralellized_job "--tag ~quarantine --tag ~level:migration --tag ~zoekt"
|
||||
artifacts:
|
||||
expire_in: 7d
|
||||
paths:
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ include:
|
|||
.rspec-base-migration:
|
||||
script:
|
||||
- !reference [.base-script, script]
|
||||
- rspec_paralellized_job "--tag ~quarantine"
|
||||
- rspec_paralellized_job "--tag ~quarantine --tag ~zoekt"
|
||||
|
||||
.rspec-base-pg11:
|
||||
extends:
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="gl-display-flex">
|
||||
<div class="gl-display-flex gl-w-full">
|
||||
<input
|
||||
v-if="fieldName"
|
||||
:name="fieldName"
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
import axios from '~/lib/utils/axios_utils';
|
||||
|
||||
function showCount(el, count) {
|
||||
el.textContent = count;
|
||||
el.classList.remove('hidden');
|
||||
}
|
||||
|
||||
function refreshCount(el) {
|
||||
const { url } = el.dataset;
|
||||
|
||||
return axios
|
||||
.get(url)
|
||||
.then(({ data }) => showCount(el, data.count))
|
||||
.catch((e) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`Failed to fetch search count from '${url}'.`, e);
|
||||
});
|
||||
}
|
||||
|
||||
export default function refreshCounts() {
|
||||
const elements = Array.from(document.querySelectorAll('.js-search-count'));
|
||||
|
||||
return Promise.all(elements.map(refreshCount));
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import setHighlightClass from 'ee_else_ce/search/highlight_blob_search_result';
|
||||
import { queryToObject } from '~/lib/utils/url_utility';
|
||||
import refreshCounts from '~/pages/search/show/refresh_counts';
|
||||
import syntaxHighlight from '~/syntax_highlight';
|
||||
import { initSidebar, sidebarInitState } from './sidebar';
|
||||
import { initSearchSort } from './sort';
|
||||
|
|
@ -24,8 +23,4 @@ export const initSearchApp = () => {
|
|||
|
||||
setHighlightClass(query.search); // Code Highlighting
|
||||
initBlobRefSwitcher(); // Code Search Branch Picker
|
||||
|
||||
if (!gon.features?.searchPageVerticalNav) {
|
||||
refreshCounts(); // Other Scope Tab Counts
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<script>
|
||||
import { mapState } from 'vuex';
|
||||
import ScopeNavigation from '~/search/sidebar/components/scope_navigation.vue';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { SCOPE_ISSUES, SCOPE_MERGE_REQUESTS } from '../constants';
|
||||
import ResultsFilters from './results_filters.vue';
|
||||
|
||||
|
|
@ -11,7 +10,6 @@ export default {
|
|||
ResultsFilters,
|
||||
ScopeNavigation,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
computed: {
|
||||
...mapState(['urlQuery']),
|
||||
showFilters() {
|
||||
|
|
@ -23,7 +21,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<section class="search-sidebar gl-display-flex gl-flex-direction-column gl-mr-4 gl-mb-6 gl-mt-5">
|
||||
<scope-navigation v-if="glFeatures.searchPageVerticalNav" />
|
||||
<scope-navigation />
|
||||
<results-filters v-if="showFilters" />
|
||||
</section>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script>
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { confidentialFilterData } from '../constants/confidential_filter_data';
|
||||
import RadioFilter from './radio_filter.vue';
|
||||
|
||||
|
|
@ -8,19 +7,13 @@ export default {
|
|||
components: {
|
||||
RadioFilter,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
computed: {
|
||||
ffBasedXPadding() {
|
||||
return this.glFeatures.searchPageVerticalNav ? 'gl-px-5' : 'gl-px-0';
|
||||
},
|
||||
},
|
||||
confidentialFilterData,
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<radio-filter :class="ffBasedXPadding" :filter-data="$options.confidentialFilterData" />
|
||||
<radio-filter class="gl-px-5" :filter-data="$options.confidentialFilterData" />
|
||||
<hr class="gl-my-5 gl-mx-5 gl-border-gray-100" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<script>
|
||||
import { GlButton, GlLink } from '@gitlab/ui';
|
||||
import { mapActions, mapState } from 'vuex';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { confidentialFilterData } from '../constants/confidential_filter_data';
|
||||
import { stateFilterData } from '../constants/state_filter_data';
|
||||
import ConfidentialityFilter from './confidentiality_filter.vue';
|
||||
|
|
@ -15,24 +14,17 @@ export default {
|
|||
StatusFilter,
|
||||
ConfidentialityFilter,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
computed: {
|
||||
...mapState(['urlQuery', 'sidebarDirty']),
|
||||
showReset() {
|
||||
return this.urlQuery.state || this.urlQuery.confidential;
|
||||
},
|
||||
searchPageVerticalNavFeatureFlag() {
|
||||
return this.glFeatures.searchPageVerticalNav;
|
||||
},
|
||||
showConfidentialityFilter() {
|
||||
return Object.values(confidentialFilterData.scopes).includes(this.urlQuery.scope);
|
||||
},
|
||||
showStatusFilter() {
|
||||
return Object.values(stateFilterData.scopes).includes(this.urlQuery.scope);
|
||||
},
|
||||
ffBasedXPadding() {
|
||||
return this.glFeatures.searchPageVerticalNav ? 'gl-px-5' : 'gl-px-0';
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['applyQuery', 'resetQuery']),
|
||||
|
|
@ -42,13 +34,10 @@ export default {
|
|||
|
||||
<template>
|
||||
<form class="gl-pt-5 gl-md-pt-0" @submit.prevent="applyQuery">
|
||||
<hr
|
||||
v-if="searchPageVerticalNavFeatureFlag"
|
||||
class="gl-my-5 gl-mx-5 gl-border-gray-100 gl-display-none gl-md-display-block"
|
||||
/>
|
||||
<hr class="gl-my-5 gl-mx-5 gl-border-gray-100 gl-display-none gl-md-display-block" />
|
||||
<status-filter v-if="showStatusFilter" />
|
||||
<confidentiality-filter v-if="showConfidentialityFilter" />
|
||||
<div class="gl-display-flex gl-align-items-center gl-mt-4" :class="ffBasedXPadding">
|
||||
<div class="gl-display-flex gl-align-items-center gl-mt-4 gl-px-5">
|
||||
<gl-button category="primary" variant="confirm" type="submit" :disabled="!sidebarDirty">
|
||||
{{ __('Apply') }}
|
||||
</gl-button>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { s__ } from '~/locale';
|
|||
import Tracking from '~/tracking';
|
||||
import { NAV_LINK_DEFAULT_CLASSES, NAV_LINK_COUNT_DEFAULT_CLASSES } from '../constants';
|
||||
import { formatSearchResultCount } from '../../store/utils';
|
||||
import { slugifyWithUnderscore } from '../../../lib/utils/text_utility';
|
||||
|
||||
export default {
|
||||
name: 'ScopeNavigation',
|
||||
|
|
@ -46,6 +47,9 @@ export default {
|
|||
isActive(scope, index) {
|
||||
return this.urlQuery.scope ? this.urlQuery.scope === scope : index === 0;
|
||||
},
|
||||
qaSelectorValue(item) {
|
||||
return `${slugifyWithUnderscore(item.label)}_tab`;
|
||||
},
|
||||
},
|
||||
NAV_LINK_DEFAULT_CLASSES,
|
||||
NAV_LINK_COUNT_DEFAULT_CLASSES,
|
||||
|
|
@ -62,6 +66,7 @@ export default {
|
|||
class="gl-mb-1"
|
||||
:href="item.link"
|
||||
:active="isActive(scope, index)"
|
||||
:data-qa-selector="qaSelectorValue(item)"
|
||||
@click="handleClick(scope)"
|
||||
><span>{{ item.label }}</span
|
||||
><span v-if="item.count" :class="countClasses(isActive(scope, index))">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script>
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { stateFilterData } from '../constants/state_filter_data';
|
||||
import RadioFilter from './radio_filter.vue';
|
||||
|
||||
|
|
@ -8,19 +7,13 @@ export default {
|
|||
components: {
|
||||
RadioFilter,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
computed: {
|
||||
ffBasedXPadding() {
|
||||
return this.glFeatures.searchPageVerticalNav ? 'gl-px-5' : 'gl-px-0';
|
||||
},
|
||||
},
|
||||
stateFilterData,
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<radio-filter :class="ffBasedXPadding" :filter-data="$options.stateFilterData" />
|
||||
<radio-filter class="gl-px-5" :filter-data="$options.stateFilterData" />
|
||||
<hr class="gl-my-5 gl-mx-5 gl-border-gray-100" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<script>
|
||||
import { GlSearchBoxByClick, GlButton } from '@gitlab/ui';
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { s__ } from '~/locale';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import MarkdownDrawer from '~/vue_shared/components/markdown_drawer/markdown_drawer.vue';
|
||||
|
|
@ -31,7 +30,6 @@ export default {
|
|||
ProjectFilter,
|
||||
MarkdownDrawer,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
props: {
|
||||
groupInitialJson: {
|
||||
type: Object,
|
||||
|
|
@ -70,9 +68,6 @@ export default {
|
|||
showSyntaxOptions() {
|
||||
return this.elasticsearchEnabled && this.isDefaultBranch;
|
||||
},
|
||||
hasVerticalNav() {
|
||||
return this.glFeatures.searchPageVerticalNav;
|
||||
},
|
||||
isDefaultBranch() {
|
||||
return !this.query.repository_ref || this.query.repository_ref === this.defaultBranchName;
|
||||
},
|
||||
|
|
@ -130,6 +125,6 @@ export default {
|
|||
<project-filter :initial-data="projectInitialJson" />
|
||||
</div>
|
||||
</div>
|
||||
<hr v-if="hasVerticalNav" class="gl-mt-5 gl-mb-0 gl-border-gray-100" />
|
||||
<hr class="gl-mt-5 gl-mb-0 gl-border-gray-100" />
|
||||
</section>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -239,6 +239,8 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
@last_commit = @repository.last_commit_for_path(@commit.id, @blob.path, literal_pathspec: true)
|
||||
@code_navigation_path = Gitlab::CodeNavigationPath.new(@project, @blob.commit_id).full_json_path_for(@blob.path)
|
||||
|
||||
allow_lfs_direct_download
|
||||
|
||||
render 'show'
|
||||
end
|
||||
|
||||
|
|
@ -282,6 +284,30 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
def visitor_id
|
||||
current_user&.id
|
||||
end
|
||||
|
||||
def allow_lfs_direct_download
|
||||
return unless directly_downloading_lfs_object? && content_security_policy_enabled?
|
||||
return unless (lfs_object = @project.lfs_objects.find_by_oid(@blob.lfs_oid))
|
||||
|
||||
request.content_security_policy.directives['connect-src'] ||= []
|
||||
request.content_security_policy.directives['connect-src'] << lfs_src(lfs_object)
|
||||
end
|
||||
|
||||
def directly_downloading_lfs_object?
|
||||
Gitlab.config.lfs.enabled &&
|
||||
!Gitlab.config.lfs.object_store.proxy_download &&
|
||||
@blob&.stored_externally?
|
||||
end
|
||||
|
||||
def content_security_policy_enabled?
|
||||
Gitlab.config.gitlab.content_security_policy.enabled
|
||||
end
|
||||
|
||||
def lfs_src(lfs_object)
|
||||
file = lfs_object.file
|
||||
file = file.cdn_enabled_url(request.remote_ip) if file.respond_to?(:cdn_enabled_url)
|
||||
file.url
|
||||
end
|
||||
end
|
||||
|
||||
Projects::BlobController.prepend_mod
|
||||
|
|
|
|||
|
|
@ -30,9 +30,6 @@ class SearchController < ApplicationController
|
|||
end
|
||||
before_action :check_search_rate_limit!, only: search_rate_limited_endpoints
|
||||
|
||||
before_action only: :show do
|
||||
push_frontend_feature_flag(:search_page_vertical_nav, current_user)
|
||||
end
|
||||
before_action only: :show do
|
||||
update_scope_for_code_search
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module BizibleHelper
|
||||
def bizible_enabled?
|
||||
Feature.enabled?(:ecomm_instrumentation, type: :ops) &&
|
||||
def bizible_enabled?(invite_email = nil)
|
||||
invite_email.blank? &&
|
||||
Feature.enabled?(:ecomm_instrumentation, type: :ops) &&
|
||||
Gitlab.config.extra.has_key?('bizible') &&
|
||||
Gitlab.config.extra.bizible.present? &&
|
||||
Gitlab.config.extra.bizible == true
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ module ExploreHelper
|
|||
namespace_id: params[:namespace_id]
|
||||
}
|
||||
|
||||
exist_opts[:language] = params[:language] if Feature.enabled?(:project_language_search, current_user)
|
||||
|
||||
options = exist_opts.merge(options).delete_if { |key, value| value.blank? }
|
||||
request_path_with_options(options)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ module Ci
|
|||
has_one :"job_artifacts_#{key}", -> { where(file_type: value) }, class_name: 'Ci::JobArtifact', foreign_key: :job_id, inverse_of: :job
|
||||
end
|
||||
|
||||
has_one :runner_machine, through: :metadata, class_name: 'Ci::RunnerMachine'
|
||||
|
||||
has_one :runner_session, class_name: 'Ci::BuildRunnerSession', validate: true, foreign_key: :build_id, inverse_of: :build
|
||||
has_one :trace_metadata, class_name: 'Ci::BuildTraceMetadata', foreign_key: :build_id, inverse_of: :build
|
||||
|
||||
|
|
@ -179,6 +181,8 @@ module Ci
|
|||
run_after_commit { build.execute_hooks }
|
||||
end
|
||||
|
||||
after_commit :track_ci_secrets_management_id_tokens_usage, on: :create, if: :id_tokens?
|
||||
|
||||
class << self
|
||||
# This is needed for url_for to work,
|
||||
# as the controller is JobsController
|
||||
|
|
@ -1281,6 +1285,10 @@ module Ci
|
|||
.increment(status: status)
|
||||
end
|
||||
end
|
||||
|
||||
def track_ci_secrets_management_id_tokens_usage
|
||||
::Gitlab::UsageDataCounters::HLLRedisCounter.track_event('i_ci_secrets_management_id_tokens_build_created', values: user_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ module Ci
|
|||
belongs_to :runner
|
||||
|
||||
has_many :build_metadata, class_name: 'Ci::BuildMetadata'
|
||||
has_many :builds, through: :build_metadata, class_name: 'Ci::Build'
|
||||
belongs_to :runner_version, inverse_of: :runner_machines, primary_key: :version, foreign_key: :version,
|
||||
class_name: 'Ci::RunnerVersion'
|
||||
|
||||
validates :runner, presence: true
|
||||
validates :machine_xid, presence: true, length: { maximum: 64 }
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ module Ci
|
|||
recommended: 'Upgrade is available and recommended for the runner.'
|
||||
}.freeze
|
||||
|
||||
has_many :runner_machines, inverse_of: :runner_version, foreign_key: :version, class_name: 'Ci::RunnerMachine'
|
||||
|
||||
# Override auto generated negative scope (from available) so the scope has expected behavior
|
||||
scope :not_available, -> { where(status: :not_available) }
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
- add_page_specific_style 'page_bundles/search'
|
||||
- params[:visibility_level] ||= []
|
||||
|
||||
.top-area
|
||||
.top-area.gl-flex-direction-column-reverse
|
||||
.scrolling-tabs-container.inner-page-scroll-tabs.gl-flex-grow-1.gl-min-w-0.gl-w-full
|
||||
.fade-left= sprite_icon('chevron-lg-left', size: 12)
|
||||
.fade-right= sprite_icon('chevron-lg-right', size: 12)
|
||||
|
|
@ -12,16 +12,7 @@
|
|||
= gl_tab_link_to _('Internal'), admin_projects_path(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
|
||||
= gl_tab_link_to _('Public'), admin_projects_path(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
|
||||
|
||||
|
||||
.nav-controls.gl-pl-2
|
||||
.search-holder
|
||||
= render 'shared/projects/search_form', autofocus: true, admin_view: true
|
||||
- if params[:namespace_id].present?
|
||||
- namespace = Namespace.find(params[:namespace_id])
|
||||
- selected_text = "#{namespace.kind}: #{namespace.full_path}" if namespace
|
||||
.js-namespace-select{ data: { field_name: 'namespace_id', selected_id: namespace&.id, selected_text: selected_text, update_location: 'true' } }
|
||||
|
||||
= link_to new_project_path, class: 'gl-button btn btn-confirm' do
|
||||
= _('New Project')
|
||||
.nav-controls
|
||||
= render 'shared/projects/search_form', autofocus: true, admin_view: true
|
||||
|
||||
= render 'projects'
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
= content_for :flash_message do
|
||||
= render 'shared/project_limit'
|
||||
|
||||
.page-title-holder.d-flex.align-items-center
|
||||
.page-title-holder.gl-display-flex.gl-align-items-center
|
||||
%h1.page-title.gl-font-size-h-display= _('Projects')
|
||||
|
||||
- if current_user.can_create_project?
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
= _("New project")
|
||||
|
||||
.top-area
|
||||
.scrolling-tabs-container.inner-page-scroll-tabs.gl-flex-grow-1.gl-min-w-0
|
||||
.scrolling-tabs-container.inner-page-scroll-tabs.gl-flex-grow-1.gl-flex-basis-0.gl-min-w-0
|
||||
.fade-left= sprite_icon('chevron-lg-left', size: 12)
|
||||
.fade-right= sprite_icon('chevron-lg-right', size: 12)
|
||||
= render 'dashboard/projects_nav'
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
- if bizible_enabled?
|
||||
- if bizible_enabled?(@invite_email)
|
||||
<!-- Bizible -->
|
||||
= javascript_tag nonce: content_security_policy_nonce do
|
||||
:plain
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
- users = capture_haml do
|
||||
- if show_user_search_tab?
|
||||
= search_filter_link 'users', _("Users")
|
||||
|
||||
.scrolling-tabs-container.inner-page-scroll-tabs.is-smaller
|
||||
.fade-left= sprite_icon('chevron-lg-left', size: 12)
|
||||
.fade-right= sprite_icon('chevron-lg-right', size: 12)
|
||||
= gl_tabs_nav({ class: 'scrolling-tabs nav-links', data: { testid: 'search-filter' } }) do
|
||||
- if @project
|
||||
- if project_search_tabs?(:blobs)
|
||||
= search_filter_link 'blobs', _("Code"), data: { qa_selector: 'code_tab' }
|
||||
- if project_search_tabs?(:issues)
|
||||
= search_filter_link 'issues', _("Issues")
|
||||
- if project_search_tabs?(:merge_requests)
|
||||
= search_filter_link 'merge_requests', _("Merge requests")
|
||||
- if project_search_tabs?(:wiki)
|
||||
= search_filter_link 'wiki_blobs', _("Wiki")
|
||||
- if project_search_tabs?(:commits)
|
||||
= search_filter_link 'commits', _("Commits")
|
||||
- if project_search_tabs?(:notes)
|
||||
= search_filter_link 'notes', _("Comments")
|
||||
- if project_search_tabs?(:milestones)
|
||||
= search_filter_link 'milestones', _("Milestones")
|
||||
= users
|
||||
|
||||
- elsif @search_service_presenter.show_snippets?
|
||||
= search_filter_link 'snippet_titles', _("Titles and Descriptions"), search: { snippets: true, group_id: nil, project_id: nil }
|
||||
- else
|
||||
= search_filter_link 'projects', _("Projects"), data: { qa_selector: 'projects_tab' }
|
||||
= render_if_exists 'search/category_code' if feature_flag_tab_enabled?(:global_search_code_tab)
|
||||
= render_if_exists 'search/epics_filter_link'
|
||||
= search_filter_link 'issues', _("Issues") if feature_flag_tab_enabled?(:global_search_issues_tab)
|
||||
= search_filter_link 'merge_requests', _("Merge requests") if feature_flag_tab_enabled?(:global_search_merge_requests_tab)
|
||||
= render_if_exists 'search/category_wiki' if feature_flag_tab_enabled?(:global_search_wiki_tab)
|
||||
= render_if_exists 'search/category_elasticsearch'
|
||||
= search_filter_link 'milestones', _("Milestones")
|
||||
= users
|
||||
|
|
@ -1,18 +1,9 @@
|
|||
- search_bar_classes = 'search-sidebar gl-display-flex gl-flex-direction-column gl-mr-4'
|
||||
|
||||
= render_if_exists 'shared/promotions/promote_advanced_search'
|
||||
- if Feature.enabled?(:search_page_vertical_nav, current_user)
|
||||
.results.gl-md-display-flex.gl-mt-0
|
||||
#js-search-sidebar{ class: search_bar_classes, data: { navigation_json: search_navigation_json } }
|
||||
.gl-w-full.gl-flex-grow-1.gl-overflow-x-hidden
|
||||
= render partial: 'search/results_status' unless @search_objects.to_a.empty?
|
||||
= render partial: 'search/results_list'
|
||||
- else
|
||||
= render partial: 'search/results_status' unless @search_objects.to_a.empty?
|
||||
|
||||
.results.gl-md-display-flex.gl-mt-3
|
||||
- if %w[issues merge_requests].include?(@scope)
|
||||
#js-search-sidebar{ class: search_bar_classes, data: { navigation_json: search_navigation_json } }
|
||||
|
||||
.gl-w-full.gl-flex-grow-1.gl-overflow-x-hidden
|
||||
= render partial: 'search/results_list'
|
||||
.results.gl-md-display-flex.gl-mt-0
|
||||
#js-search-sidebar{ class: search_bar_classes, data: { navigation_json: search_navigation_json } }
|
||||
.gl-w-full.gl-flex-grow-1.gl-overflow-x-hidden
|
||||
= render partial: 'search/results_status' unless @search_objects.to_a.empty?
|
||||
= render partial: 'search/results_list'
|
||||
|
|
|
|||
|
|
@ -1,6 +1,25 @@
|
|||
- return unless @search_service_presenter.show_results_status?
|
||||
|
||||
- if Feature.enabled?(:search_page_vertical_nav, current_user)
|
||||
= render partial: 'search/results_status_vert_nav'
|
||||
- else
|
||||
= render partial: 'search/results_status_horiz_nav'
|
||||
.search-results-status
|
||||
.gl-display-flex.gl-flex-direction-column
|
||||
.gl-p-5.gl-display-flex
|
||||
.gl-md-display-flex.gl-text-left.gl-align-items-center.gl-flex-grow-1
|
||||
- unless @search_service_presenter.without_count?
|
||||
= search_entries_info(@search_objects, @scope, @search_term)
|
||||
- unless @search_service_presenter.show_snippets?
|
||||
- if @project
|
||||
- link_to_project = link_to(@project.full_name, @project, class: 'ml-md-1')
|
||||
- if @scope == 'blobs'
|
||||
= _("in")
|
||||
.mx-md-1
|
||||
#js-blob-ref-switcher{ data: { "project-id" => @project.id, "ref" => repository_ref(@project), "field-name": "repository_ref" } }
|
||||
= s_('SearchCodeResults|of %{link_to_project}').html_safe % { link_to_project: link_to_project }
|
||||
- else
|
||||
= _("in project %{link_to_project}").html_safe % { link_to_project: link_to_project }
|
||||
- elsif @group
|
||||
- link_to_group = link_to(@group.name, @group, class: 'ml-md-1')
|
||||
= _("in group %{link_to_group}").html_safe % { link_to_group: link_to_group }
|
||||
- if @search_service_presenter.show_sort_dropdown?
|
||||
.gl-md-display-flex.gl-flex-direction-column
|
||||
#js-search-sort{ data: { "search-sort-options" => search_sort_options.to_json } }
|
||||
%hr.gl-mb-5.gl-mt-0.gl-border-gray-100.gl-w-full
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
.search-results-status
|
||||
.row-content-block.gl-display-flex
|
||||
.gl-md-display-flex.gl-text-left.gl-align-items-center.gl-flex-grow-1
|
||||
- unless @search_service_presenter.without_count?
|
||||
= search_entries_info(@search_objects, @scope, @search_term)
|
||||
- unless @search_service_presenter.show_snippets?
|
||||
- if @project
|
||||
- link_to_project = link_to(@project.full_name, @project, class: 'ml-md-1')
|
||||
- if @scope == 'blobs'
|
||||
= _("in")
|
||||
.mx-md-1
|
||||
#js-blob-ref-switcher{ data: { "project-id" => @project.id, "ref" => repository_ref(@project), "field-name": "repository_ref" } }
|
||||
= s_('SearchCodeResults|of %{link_to_project}').html_safe % { link_to_project: link_to_project }
|
||||
- else
|
||||
= _("in project %{link_to_project}").html_safe % { link_to_project: link_to_project }
|
||||
- elsif @group
|
||||
- link_to_group = link_to(@group.name, @group, class: 'ml-md-1')
|
||||
= _("in group %{link_to_group}").html_safe % { link_to_group: link_to_group }
|
||||
- if @search_service_presenter.show_sort_dropdown?
|
||||
.gl-md-display-flex.gl-flex-direction-column
|
||||
#js-search-sort{ data: { "search-sort-options" => search_sort_options.to_json } }
|
||||
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
.search-results-status
|
||||
.gl-display-flex.gl-flex-direction-column
|
||||
.gl-p-5.gl-display-flex.gl-max-w-full.gl-sm-flex-direction-column
|
||||
.gl-md-display-flex.gl-text-left.gl-align-items-center.gl-flex-grow-1.gl-text-truncate
|
||||
- unless @search_service_presenter.without_count?
|
||||
= search_entries_info(@search_objects, @scope, @search_term)
|
||||
- unless @search_service_presenter.show_snippets?
|
||||
- if @project
|
||||
- link_to_project = link_to(@project.full_name, @project, class: 'ml-md-1 gl-text-truncate search-wrap-f-md-down')
|
||||
- if @scope == 'blobs'
|
||||
= _("in")
|
||||
.mx-md-1
|
||||
#js-blob-ref-switcher{ data: { "project-id" => @project.id, "ref" => repository_ref(@project), "field-name": "repository_ref" } }
|
||||
= s_('SearchCodeResults|of %{link_to_project}').html_safe % { link_to_project: link_to_project }
|
||||
- else
|
||||
= _("in project %{link_to_project}").html_safe % { link_to_project: link_to_project }
|
||||
- elsif @group
|
||||
- link_to_group = link_to(@group.name, @group, class: 'ml-md-1')
|
||||
= _("in group %{link_to_group}").html_safe % { link_to_group: link_to_group }
|
||||
- if @search_service_presenter.show_sort_dropdown?
|
||||
.gl-md-display-flex.gl-flex-direction-column
|
||||
#js-search-sort{ data: { "search-sort-options" => search_sort_options.to_json } }
|
||||
%hr.gl-mb-5.gl-mt-0.gl-border-gray-100.gl-w-full
|
||||
|
|
@ -22,6 +22,4 @@
|
|||
.gl-mt-3
|
||||
#js-search-topbar{ data: { "group-initial-json": group_attributes.to_json, "project-initial-json": project_attributes.to_json, "elasticsearch-enabled": @search_service_presenter.advanced_search_enabled?.to_s, "default-branch-name": @project&.default_branch } }
|
||||
- if @search_term
|
||||
- if Feature.disabled?(:search_page_vertical_nav, current_user)
|
||||
= render 'search/category'
|
||||
= render 'search/results'
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
- @sort ||= sort_value_latest_activity
|
||||
.dropdown.js-project-filter-dropdown-wrap.gl-display-inline
|
||||
.dropdown.js-project-filter-dropdown-wrap.gl-display-inline{ class: 'gl-m-0!' }
|
||||
= dropdown_toggle(projects_sort_options_hash[@sort], { toggle: 'dropdown', display: 'static' }, { id: 'sort-projects-dropdown' })
|
||||
%ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable
|
||||
%li.dropdown-header
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
- placeholder = local_assigns[:search_form_placeholder] ? search_form_placeholder : _('Filter by name')
|
||||
- admin_view ||= false
|
||||
- top_padding = admin_view ? 'gl-lg-pt-3' : ''
|
||||
|
||||
= form_tag filter_projects_path, method: :get, class: 'project-filter-form', data: { qa_selector: 'project_filter_form_container' }, id: 'project-filter-form' do |f|
|
||||
= form_tag filter_projects_path, method: :get, class: "project-filter-form gl-display-flex! gl-flex-wrap-wrap gl-w-full gl-gap-3 #{top_padding}", data: { qa_selector: 'project_filter_form_container' }, id: 'project-filter-form' do |f|
|
||||
= search_field_tag :name, params[:name],
|
||||
placeholder: placeholder,
|
||||
class: "project-filter-form-field form-control input-short js-projects-list-filter",
|
||||
class: "project-filter-form-field form-control input-short js-projects-list-filter gl-m-0!",
|
||||
spellcheck: false,
|
||||
id: 'project-filter-form-field',
|
||||
autofocus: local_assigns[:autofocus]
|
||||
|
|
@ -27,14 +29,14 @@
|
|||
= hidden_field_tag :language, params[:language]
|
||||
|
||||
- if Feature.enabled?(:project_language_search, current_user)
|
||||
.dropdown.inline
|
||||
.dropdown{ class: 'gl-m-0!' }
|
||||
= dropdown_toggle(search_language_placeholder, { toggle: 'dropdown', testid: 'project-language-dropdown' })
|
||||
%ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable
|
||||
%li
|
||||
= link_to _('Any'), filter_projects_path(language: nil)
|
||||
= link_to _('Any'), filter_projects_path(language: nil, name: nil)
|
||||
- programming_languages.each do |language|
|
||||
%li
|
||||
= link_to filter_projects_path(language: language.id), class: language_state_class(language) do
|
||||
= link_to filter_projects_path(language: language.id, name: nil), class: language_state_class(language) do
|
||||
= language.name
|
||||
|
||||
= submit_tag nil, class: 'gl-display-none!'
|
||||
|
|
@ -42,3 +44,13 @@
|
|||
= render 'shared/projects/dropdown'
|
||||
|
||||
= render_if_exists 'shared/projects/search_fields'
|
||||
|
||||
- if admin_view
|
||||
- if params[:namespace_id].present?
|
||||
- namespace = Namespace.find(params[:namespace_id])
|
||||
- selected_text = "#{namespace.kind}: #{namespace.full_path}" if namespace
|
||||
.gl-display-flex.gl-w-full.gl-md-w-auto{ class: 'gl-m-0!' }
|
||||
.js-namespace-select{ data: { field_name: 'namespace_id', selected_id: namespace&.id, selected_text: selected_text, update_location: 'true' } }
|
||||
|
||||
= link_to new_project_path, class: 'gl-button btn btn-confirm gl-display-inline gl-mb-0!' do
|
||||
= _('New Project')
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: search_page_vertical_nav
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97784
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/373613
|
||||
milestone: '15.5'
|
||||
type: development
|
||||
group: group::global search
|
||||
default_enabled: true
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
key_path: redis_hll_counters.ci_secrets_management.i_ci_secrets_management_id_tokens_build_created_monthly
|
||||
description: Monthly count of unique users who created a pipeline with id_tokens (JWT tokens)
|
||||
product_section: ops
|
||||
product_stage: verify
|
||||
product_group: pipeline_authoring
|
||||
product_category: secrets_management
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "15.9"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109686
|
||||
time_frame: 28d
|
||||
data_source: redis_hll
|
||||
data_category: optional
|
||||
instrumentation_class: RedisHLLMetric
|
||||
performance_indicator_type: []
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
options:
|
||||
events:
|
||||
- i_ci_secrets_management_id_tokens_build_created
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
key_path: redis_hll_counters.ci_secrets_management.i_ci_secrets_management_id_tokens_build_created_weekly
|
||||
description: Weekly count of unique users who created a pipeline with id_tokens (JWT tokens)
|
||||
product_section: ops
|
||||
product_stage: verify
|
||||
product_group: pipeline_authoring
|
||||
product_category: secrets_management
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "15.9"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109686
|
||||
time_frame: 7d
|
||||
data_source: redis_hll
|
||||
data_category: optional
|
||||
instrumentation_class: RedisHLLMetric
|
||||
performance_indicator_type: []
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
options:
|
||||
events:
|
||||
- i_ci_secrets_management_id_tokens_build_created
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddMergeRequestMetaToMergeRequestsComplianceViolations < Gitlab::Database::Migration[2.1]
|
||||
def change
|
||||
add_column :merge_requests_compliance_violations, :merged_at, :datetime_with_timezone
|
||||
add_column :merge_requests_compliance_violations, :target_project_id, :integer
|
||||
add_column :merge_requests_compliance_violations, :title, :text # rubocop:disable Migration/AddLimitToTextColumns
|
||||
add_column :merge_requests_compliance_violations, :target_branch, :text # rubocop:disable Migration/AddLimitToTextColumns
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
1ed2531b3655b46f67c523f4a588471b1b0cb291b24c9491e6efe89d644546d8
|
||||
|
|
@ -17920,7 +17920,11 @@ CREATE TABLE merge_requests_compliance_violations (
|
|||
violating_user_id bigint NOT NULL,
|
||||
merge_request_id bigint NOT NULL,
|
||||
reason smallint NOT NULL,
|
||||
severity_level smallint DEFAULT 0 NOT NULL
|
||||
severity_level smallint DEFAULT 0 NOT NULL,
|
||||
merged_at timestamp with time zone,
|
||||
target_project_id integer,
|
||||
title text,
|
||||
target_branch text
|
||||
);
|
||||
|
||||
CREATE SEQUENCE merge_requests_compliance_violations_id_seq
|
||||
|
|
|
|||
|
|
@ -43,6 +43,17 @@ a feature has become "implemented", major changes should get new blueprints.
|
|||
|
||||
The canonical place for the latest set of instructions (and the likely source
|
||||
of this file) is [here](/doc/architecture/blueprints/_template.md).
|
||||
|
||||
Blueprint statuses you can use:
|
||||
|
||||
- "proposed"
|
||||
- "ongoing"
|
||||
- "accepted"
|
||||
- "implemented"
|
||||
- "rejected"
|
||||
|
||||
Any other one-word status should be fine, see which ones have colors defined:
|
||||
https://gitlab.com/gitlab-org/gitlab-docs/-/blob/main/content/assets/stylesheets/labels.scss#L22
|
||||
-->
|
||||
|
||||
# {+ Title of Blueprint +}
|
||||
|
|
|
|||
|
|
@ -943,7 +943,7 @@ To open the Admin Area:
|
|||
To select your avatar:
|
||||
|
||||
```markdown
|
||||
1. On the top bar, in the top right corner, select your avatar.
|
||||
1. On the top bar, in the upper-right corner, select your avatar.
|
||||
```
|
||||
|
||||
To save the selection in some dropdown lists:
|
||||
|
|
|
|||
|
|
@ -1288,6 +1288,12 @@ you're talking about the product version or the subscription tier.
|
|||
|
||||
See also [downgrade](#downgrade) and [roll back](#roll-back).
|
||||
|
||||
## upper left, upper right
|
||||
|
||||
Use **upper left** and **upper right** instead of **top left** and **top right**. Hyphenate as adjectives (for example, **upper-left corner**).
|
||||
|
||||
For details, see the [Microsoft style guide](https://learn.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/u/upper-left-upper-right).
|
||||
|
||||
## useful
|
||||
|
||||
Do not use **useful**. If the user doesn't find the process to be useful, we lose their trust. ([Vale](../testing.md#vale) rule: [`Simplicity.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/Simplicity.yml))
|
||||
|
|
|
|||
|
|
@ -233,14 +233,40 @@ Sidekiq performance. Return them to their default values if you see increased `s
|
|||
in your Sidekiq logs. For more information, see
|
||||
[issue 322147](https://gitlab.com/gitlab-org/gitlab/-/issues/322147).
|
||||
|
||||
### Access requirements for self-managed AWS OpenSearch Service using fine-grained access control
|
||||
### Access requirements
|
||||
|
||||
#### Elasticsearch with role privileges
|
||||
|
||||
To access Elasticsearch, you must have at least the following privileges in GitLab:
|
||||
|
||||
```json
|
||||
{
|
||||
"cluster": ["monitor"],
|
||||
"indices": [
|
||||
{
|
||||
"names": ["gitlab-*"],
|
||||
"privileges": [
|
||||
"create_index",
|
||||
"delete_index",
|
||||
"view_index_metadata",
|
||||
"read",
|
||||
"manage",
|
||||
"write"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
For more information, see [Elasticsearch security privileges](https://www.elastic.co/guide/en/elasticsearch/reference/current/security-privileges.html).
|
||||
|
||||
#### AWS OpenSearch Service with fine-grained access control
|
||||
|
||||
To use the self-managed AWS OpenSearch Service with GitLab using fine-grained access control, try one of the
|
||||
[recommended configurations](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/fgac.html#fgac-recommendations).
|
||||
|
||||
Configure your instance's domain access policies to allow `es:ESHttp*` actions. You can customize
|
||||
the following example configuration to limit principals or resources.
|
||||
See [Identity and Access Management in Amazon OpenSearch Service](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/ac.html) for details.
|
||||
the following example configuration to limit principals or resources:
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
@ -262,18 +288,20 @@ See [Identity and Access Management in Amazon OpenSearch Service](https://docs.a
|
|||
}
|
||||
```
|
||||
|
||||
#### Connecting with a master user in the internal database
|
||||
For more information, see [Identity and Access Management in Amazon OpenSearch Service](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/ac.html).
|
||||
|
||||
##### Connecting with a master user in the internal database
|
||||
|
||||
When using fine-grained access control with a user in the internal database, you should use HTTP basic
|
||||
authentication to connect to OpenSearch. You can provide the master username and password as part of the
|
||||
OpenSearch URL or in the **Username** and **Password** text boxes in the Advanced Search settings. See
|
||||
[Tutorial: Internal user database and HTTP basic authentication](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/fgac-walkthrough-basic.html) for details.
|
||||
|
||||
#### Connecting with an IAM user
|
||||
##### Connecting with an IAM user
|
||||
|
||||
When using fine-grained access control with IAM credentials, you can provide the credentials in the **AWS OpenSearch IAM credentials** section in the Advanced Search settings.
|
||||
|
||||
#### Permissions for fine-grained access control
|
||||
##### Permissions for fine-grained access control
|
||||
|
||||
The following permissions are required for Advanced Search. See [Creating roles](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/fgac.html#fgac-roles) for details.
|
||||
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@
|
|||
category: terraform
|
||||
redis_slot: terraform
|
||||
aggregation: weekly
|
||||
# Pipeline Authoring
|
||||
# Pipeline Authoring group
|
||||
- name: o_pipeline_authoring_unique_users_committing_ciconfigfile
|
||||
category: pipeline_authoring
|
||||
redis_slot: pipeline_authoring
|
||||
|
|
@ -263,6 +263,10 @@
|
|||
category: pipeline_authoring
|
||||
redis_slot: pipeline_authoring
|
||||
aggregation: weekly
|
||||
- name: i_ci_secrets_management_id_tokens_build_created
|
||||
category: ci_secrets_management
|
||||
redis_slot: ci_secrets_management
|
||||
aggregation: weekly
|
||||
# Merge request widgets
|
||||
- name: users_expanding_secure_security_report
|
||||
redis_slot: secure
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ module QA
|
|||
module Page
|
||||
module Search
|
||||
class Results < QA::Page::Base
|
||||
view 'app/views/search/_category.html.haml' do
|
||||
element :code_tab
|
||||
element :projects_tab
|
||||
view 'app/assets/javascripts/search/sidebar/components/scope_navigation.vue' do
|
||||
element :code_tab, ':data-qa-selector="qaSelectorValue(item)"' # rubocop:disable QA/ElementWithPattern
|
||||
element :projects_tab, ':data-qa-selector="qaSelectorValue(item)"' # rubocop:disable QA/ElementWithPattern
|
||||
end
|
||||
|
||||
view 'app/views/search/results/_blob_data.html.haml' do
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ RSpec.describe 'Database schema', feature_category: :database do
|
|||
ldap_group_links: %w[group_id],
|
||||
members: %w[source_id created_by_id],
|
||||
merge_requests: %w[last_edited_by_id state_id],
|
||||
merge_requests_compliance_violations: %w[target_project_id],
|
||||
merge_request_diff_commits: %w[commit_author_id committer_id],
|
||||
namespaces: %w[owner_id parent_id],
|
||||
notes: %w[author_id commit_id noteable_id updated_by_id resolved_by_id confirmed_by_id discussion_id],
|
||||
|
|
|
|||
|
|
@ -20,4 +20,11 @@ FactoryBot.define do
|
|||
trait :object_storage do
|
||||
file_store { LfsObjectUploader::Store::REMOTE }
|
||||
end
|
||||
|
||||
trait :with_lfs_object_dot_iso_file do
|
||||
with_file
|
||||
object_storage
|
||||
oid { '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897' }
|
||||
size { 133 }
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -253,9 +253,35 @@ FactoryBot.define do
|
|||
create_templates { nil }
|
||||
create_branch { nil }
|
||||
create_tag { nil }
|
||||
lfs { false }
|
||||
end
|
||||
|
||||
after :create do |project, evaluator|
|
||||
# Specify `lfs: true` to create the LfsObject for the LFS file in the test repo:
|
||||
# https://gitlab.com/gitlab-org/gitlab-test/-/blob/master/files/lfs/lfs_object.iso
|
||||
if evaluator.lfs
|
||||
RSpec::Mocks.with_temporary_scope do
|
||||
# If lfs object store is disabled we need to mock
|
||||
unless Gitlab.config.lfs.object_store.enabled
|
||||
config = Gitlab.config.lfs.object_store.merge('enabled' => true)
|
||||
allow(LfsObjectUploader).to receive(:object_store_options).and_return(config)
|
||||
Fog.mock!
|
||||
Fog::Storage.new(LfsObjectUploader.object_store_credentials).tap do |connection|
|
||||
connection.directories.create(key: config.remote_directory) # rubocop:disable Rails/SaveBang
|
||||
|
||||
# Cleanup remaining files
|
||||
connection.directories.each do |directory|
|
||||
directory.files.map(&:destroy)
|
||||
end
|
||||
rescue Excon::Error::Conflict
|
||||
end
|
||||
end
|
||||
|
||||
lfs_object = create(:lfs_object, :with_lfs_object_dot_iso_file)
|
||||
create(:lfs_objects_project, project: project, lfs_object: lfs_object)
|
||||
end
|
||||
end
|
||||
|
||||
if evaluator.create_templates
|
||||
templates_path = "#{evaluator.create_templates}_templates"
|
||||
|
||||
|
|
@ -286,7 +312,6 @@ FactoryBot.define do
|
|||
"README on branch #{evaluator.create_branch}",
|
||||
message: 'Add README.md',
|
||||
branch_name: evaluator.create_branch)
|
||||
|
||||
end
|
||||
|
||||
if evaluator.create_tag
|
||||
|
|
|
|||
|
|
@ -3,242 +3,235 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'User searches for code', :js, :disable_rate_limiter, feature_category: :global_search do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be_with_reload(:project) { create(:project, :repository, namespace: user.namespace) }
|
||||
|
||||
where(search_page_vertical_nav_enabled: [true, false])
|
||||
with_them do
|
||||
context 'when signed in' do
|
||||
context 'when signed in' do
|
||||
before do
|
||||
project.add_maintainer(user)
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
context 'when on a project page' do
|
||||
before do
|
||||
stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
|
||||
project.add_maintainer(user)
|
||||
sign_in(user)
|
||||
visit(project_path(project))
|
||||
end
|
||||
|
||||
context 'when on a project page' do
|
||||
it 'finds a file' do
|
||||
submit_search('application.js')
|
||||
select_search_scope('Code')
|
||||
|
||||
expect(page).to have_selector('.results', text: 'application.js')
|
||||
expect(page).to have_selector('.file-content .code')
|
||||
expect(page).to have_selector("span.line[lang='javascript']")
|
||||
expect(page).to have_link('application.js', href: %r{master/files/js/application.js})
|
||||
expect(page).to have_button('Copy file path')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when on a project search page' do
|
||||
before do
|
||||
visit(search_path)
|
||||
find('[data-testid="project-filter"]').click
|
||||
|
||||
wait_for_requests
|
||||
|
||||
page.within('[data-testid="project-filter"]') do
|
||||
click_on(project.name)
|
||||
end
|
||||
end
|
||||
|
||||
include_examples 'top right search form'
|
||||
include_examples 'search timeouts', 'blobs' do
|
||||
let(:additional_params) { { project_id: project.id } }
|
||||
end
|
||||
|
||||
context 'when searching code' do
|
||||
let(:expected_result) { 'Update capybara, rspec-rails, poltergeist to recent versions' }
|
||||
|
||||
before do
|
||||
visit(project_path(project))
|
||||
fill_in('dashboard_search', with: 'rspec')
|
||||
find('.gl-search-box-by-click-search-button').click
|
||||
end
|
||||
|
||||
it 'finds a file' do
|
||||
submit_search('application.js')
|
||||
it 'finds code and links to blob' do
|
||||
expect(page).to have_selector('.results', text: expected_result)
|
||||
|
||||
find("#blob-L3").click
|
||||
expect(current_url).to match(%r{blob/master/.gitignore#L3})
|
||||
end
|
||||
|
||||
it 'finds code and links to blame' do
|
||||
expect(page).to have_selector('.results', text: expected_result)
|
||||
|
||||
find("#blame-L3").click
|
||||
expect(current_url).to match(%r{blame/master/.gitignore#L3})
|
||||
end
|
||||
|
||||
it_behaves_like 'code highlight' do
|
||||
subject { page }
|
||||
end
|
||||
end
|
||||
|
||||
it 'search multiple words with refs switching' do
|
||||
expected_result = 'Use `snake_case` for naming files'
|
||||
search = 'for naming files'
|
||||
ref_selector = 'v1.0.0'
|
||||
|
||||
fill_in('dashboard_search', with: search)
|
||||
find('.gl-search-box-by-click-search-button').click
|
||||
|
||||
expect(page).to have_selector('.results', text: expected_result)
|
||||
|
||||
find('.ref-selector').click
|
||||
wait_for_requests
|
||||
|
||||
page.within('.ref-selector') do
|
||||
fill_in 'Search by Git revision', with: ref_selector
|
||||
wait_for_requests
|
||||
find('li', text: ref_selector, match: :prefer_exact).click
|
||||
end
|
||||
|
||||
expect(page).to have_selector('.results', text: expected_result)
|
||||
|
||||
expect(find_field('dashboard_search').value).to eq(search)
|
||||
expect(find("#blob-L1502")[:href]).to match(%r{blob/v1.0.0/files/markdown/ruby-style-guide.md#L1502})
|
||||
expect(find("#blame-L1502")[:href]).to match(%r{blame/v1.0.0/files/markdown/ruby-style-guide.md#L1502})
|
||||
end
|
||||
end
|
||||
|
||||
context 'when :new_header_search is true' do
|
||||
context 'search code within refs' do
|
||||
let(:ref_name) { 'v1.0.0' }
|
||||
|
||||
before do
|
||||
# This feature is disabled by default in spec_helper.rb.
|
||||
# We missed a feature breaking bug, so to prevent this regression, testing both scenarios for this spec.
|
||||
# This can be removed as part of closing https://gitlab.com/gitlab-org/gitlab/-/issues/339348.
|
||||
stub_feature_flags(new_header_search: true)
|
||||
visit(project_tree_path(project, ref_name))
|
||||
|
||||
submit_search('gitlab-grack')
|
||||
select_search_scope('Code')
|
||||
|
||||
expect(page).to have_selector('.results', text: 'application.js')
|
||||
expect(page).to have_selector('.file-content .code')
|
||||
expect(page).to have_selector("span.line[lang='javascript']")
|
||||
expect(page).to have_link('application.js', href: %r{master/files/js/application.js})
|
||||
expect(page).to have_button('Copy file path')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when on a project search page' do
|
||||
before do
|
||||
visit(search_path)
|
||||
find('[data-testid="project-filter"]').click
|
||||
it 'shows ref switcher in code result summary' do
|
||||
expect(find('.ref-selector')).to have_text(ref_name)
|
||||
end
|
||||
|
||||
it 'persists branch name across search' do
|
||||
find('.gl-search-box-by-click-search-button').click
|
||||
expect(find('.ref-selector')).to have_text(ref_name)
|
||||
end
|
||||
|
||||
# this example is use to test the design that the refs is not
|
||||
# only represent the branch as well as the tags.
|
||||
it 'ref switcher list all the branches and tags' do
|
||||
find('.ref-selector').click
|
||||
wait_for_requests
|
||||
|
||||
page.within('[data-testid="project-filter"]') do
|
||||
click_on(project.name)
|
||||
page.within('.ref-selector') do
|
||||
expect(page).to have_selector('li', text: 'add-ipython-files')
|
||||
expect(page).to have_selector('li', text: 'v1.0.0')
|
||||
end
|
||||
end
|
||||
|
||||
include_examples 'top right search form'
|
||||
include_examples 'search timeouts', 'blobs' do
|
||||
let(:additional_params) { { project_id: project.id } }
|
||||
end
|
||||
|
||||
context 'when searching code' do
|
||||
let(:expected_result) { 'Update capybara, rspec-rails, poltergeist to recent versions' }
|
||||
|
||||
before do
|
||||
fill_in('dashboard_search', with: 'rspec')
|
||||
find('.gl-search-box-by-click-search-button').click
|
||||
end
|
||||
|
||||
it 'finds code and links to blob' do
|
||||
expect(page).to have_selector('.results', text: expected_result)
|
||||
|
||||
find("#blob-L3").click
|
||||
expect(current_url).to match(%r{blob/master/.gitignore#L3})
|
||||
end
|
||||
|
||||
it 'finds code and links to blame' do
|
||||
expect(page).to have_selector('.results', text: expected_result)
|
||||
|
||||
find("#blame-L3").click
|
||||
expect(current_url).to match(%r{blame/master/.gitignore#L3})
|
||||
end
|
||||
|
||||
it_behaves_like 'code highlight' do
|
||||
subject { page }
|
||||
end
|
||||
end
|
||||
|
||||
it 'search multiple words with refs switching' do
|
||||
expected_result = 'Use `snake_case` for naming files'
|
||||
search = 'for naming files'
|
||||
|
||||
fill_in('dashboard_search', with: search)
|
||||
find('.gl-search-box-by-click-search-button').click
|
||||
|
||||
expect(page).to have_selector('.results', text: expected_result)
|
||||
it 'search result changes when refs switched' do
|
||||
ref = 'master'
|
||||
expect(find('.results')).not_to have_content('path = gitlab-grack')
|
||||
|
||||
find('.ref-selector').click
|
||||
wait_for_requests
|
||||
|
||||
page.within('.ref-selector') do
|
||||
find('li', text: 'v1.0.0').click
|
||||
fill_in _('Search by Git revision'), with: ref
|
||||
wait_for_requests
|
||||
|
||||
find('li', text: ref).click
|
||||
end
|
||||
|
||||
expect(page).to have_selector('.results', text: expected_result)
|
||||
|
||||
expect(find_field('dashboard_search').value).to eq(search)
|
||||
expect(find("#blob-L1502")[:href]).to match(%r{blob/v1.0.0/files/markdown/ruby-style-guide.md#L1502})
|
||||
expect(find("#blame-L1502")[:href]).to match(%r{blame/v1.0.0/files/markdown/ruby-style-guide.md#L1502})
|
||||
expect(page).to have_selector('.results', text: 'path = gitlab-grack')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when :new_header_search is true' do
|
||||
context 'search code within refs' do
|
||||
let(:ref_name) { 'v1.0.0' }
|
||||
|
||||
before do
|
||||
# This feature is disabled by default in spec_helper.rb.
|
||||
# We missed a feature breaking bug, so to prevent this regression, testing both scenarios for this spec.
|
||||
# This can be removed as part of closing https://gitlab.com/gitlab-org/gitlab/-/issues/339348.
|
||||
stub_feature_flags(new_header_search: true)
|
||||
visit(project_tree_path(project, ref_name))
|
||||
|
||||
submit_search('gitlab-grack')
|
||||
select_search_scope('Code')
|
||||
end
|
||||
|
||||
it 'shows ref switcher in code result summary' do
|
||||
expect(find('.ref-selector')).to have_text(ref_name)
|
||||
end
|
||||
|
||||
it 'persists branch name across search' do
|
||||
find('.gl-search-box-by-click-search-button').click
|
||||
expect(find('.ref-selector')).to have_text(ref_name)
|
||||
end
|
||||
|
||||
# this example is use to test the design that the refs is not
|
||||
# only represent the branch as well as the tags.
|
||||
it 'ref switcher list all the branches and tags' do
|
||||
find('.ref-selector').click
|
||||
wait_for_requests
|
||||
|
||||
page.within('.ref-selector') do
|
||||
expect(page).to have_selector('li', text: 'add-ipython-files')
|
||||
expect(page).to have_selector('li', text: 'v1.0.0')
|
||||
end
|
||||
end
|
||||
|
||||
it 'search result changes when refs switched' do
|
||||
ref = 'master'
|
||||
expect(find('.results')).not_to have_content('path = gitlab-grack')
|
||||
|
||||
find('.ref-selector').click
|
||||
wait_for_requests
|
||||
|
||||
page.within('.ref-selector') do
|
||||
fill_in _('Search by Git revision'), with: ref
|
||||
wait_for_requests
|
||||
|
||||
find('li', text: ref).click
|
||||
end
|
||||
|
||||
expect(page).to have_selector('.results', text: 'path = gitlab-grack')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when :new_header_search is false' do
|
||||
context 'search code within refs' do
|
||||
let(:ref_name) { 'v1.0.0' }
|
||||
|
||||
before do
|
||||
# This feature is disabled by default in spec_helper.rb.
|
||||
# We missed a feature breaking bug, so to prevent this regression, testing both scenarios for this spec.
|
||||
# This can be removed as part of closing https://gitlab.com/gitlab-org/gitlab/-/issues/339348.
|
||||
stub_feature_flags(new_header_search: false)
|
||||
visit(project_tree_path(project, ref_name))
|
||||
|
||||
submit_search('gitlab-grack')
|
||||
select_search_scope('Code')
|
||||
end
|
||||
|
||||
it 'shows ref switcher in code result summary' do
|
||||
expect(find('.ref-selector')).to have_text(ref_name)
|
||||
end
|
||||
|
||||
it 'persists branch name across search' do
|
||||
find('.gl-search-box-by-click-search-button').click
|
||||
expect(find('.ref-selector')).to have_text(ref_name)
|
||||
end
|
||||
|
||||
# this example is use to test the design that the refs is not
|
||||
# only represent the branch as well as the tags.
|
||||
it 'ref switcher list all the branches and tags' do
|
||||
find('.ref-selector').click
|
||||
wait_for_requests
|
||||
|
||||
page.within('.ref-selector') do
|
||||
expect(page).to have_selector('li', text: 'add-ipython-files')
|
||||
expect(page).to have_selector('li', text: 'v1.0.0')
|
||||
end
|
||||
end
|
||||
|
||||
it 'search result changes when refs switched' do
|
||||
ref = 'master'
|
||||
expect(find('.results')).not_to have_content('path = gitlab-grack')
|
||||
|
||||
find('.ref-selector').click
|
||||
wait_for_requests
|
||||
|
||||
page.within('.ref-selector') do
|
||||
fill_in _('Search by Git revision'), with: ref
|
||||
wait_for_requests
|
||||
|
||||
find('li', text: ref).click
|
||||
end
|
||||
|
||||
expect(page).to have_selector('.results', text: 'path = gitlab-grack')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'no ref switcher shown in issue result summary' do
|
||||
issue = create(:issue, title: 'test', project: project)
|
||||
visit(project_tree_path(project))
|
||||
|
||||
submit_search('test')
|
||||
select_search_scope('Code')
|
||||
|
||||
expect(page).to have_selector('.ref-selector')
|
||||
|
||||
select_search_scope('Issues')
|
||||
|
||||
expect(find(:css, '.results')).to have_link(issue.title)
|
||||
expect(page).not_to have_selector('.ref-selector')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when signed out' do
|
||||
before do
|
||||
stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
|
||||
end
|
||||
context 'when :new_header_search is false' do
|
||||
context 'search code within refs' do
|
||||
let(:ref_name) { 'v1.0.0' }
|
||||
|
||||
context 'when block_anonymous_global_searches is enabled' do
|
||||
it 'is redirected to login page' do
|
||||
visit(search_path)
|
||||
before do
|
||||
# This feature is disabled by default in spec_helper.rb.
|
||||
# We missed a feature breaking bug, so to prevent this regression, testing both scenarios for this spec.
|
||||
# This can be removed as part of closing https://gitlab.com/gitlab-org/gitlab/-/issues/339348.
|
||||
stub_feature_flags(new_header_search: false)
|
||||
visit(project_tree_path(project, ref_name))
|
||||
|
||||
expect(page).to have_content('You must be logged in to search across all of GitLab')
|
||||
submit_search('gitlab-grack')
|
||||
select_search_scope('Code')
|
||||
end
|
||||
|
||||
it 'shows ref switcher in code result summary' do
|
||||
expect(find('.ref-selector')).to have_text(ref_name)
|
||||
end
|
||||
|
||||
it 'persists branch name across search' do
|
||||
find('.gl-search-box-by-click-search-button').click
|
||||
expect(find('.ref-selector')).to have_text(ref_name)
|
||||
end
|
||||
|
||||
# this example is use to test the design that the refs is not
|
||||
# only represent the branch as well as the tags.
|
||||
it 'ref switcher list all the branches and tags' do
|
||||
find('.ref-selector').click
|
||||
wait_for_requests
|
||||
|
||||
page.within('.ref-selector') do
|
||||
expect(page).to have_selector('li', text: 'add-ipython-files')
|
||||
expect(page).to have_selector('li', text: 'v1.0.0')
|
||||
end
|
||||
end
|
||||
|
||||
it 'search result changes when refs switched' do
|
||||
ref = 'master'
|
||||
expect(find('.results')).not_to have_content('path = gitlab-grack')
|
||||
|
||||
find('.ref-selector').click
|
||||
wait_for_requests
|
||||
|
||||
page.within('.ref-selector') do
|
||||
fill_in _('Search by Git revision'), with: ref
|
||||
wait_for_requests
|
||||
|
||||
find('li', text: ref).click
|
||||
end
|
||||
|
||||
expect(page).to have_selector('.results', text: 'path = gitlab-grack')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'no ref switcher shown in issue result summary' do
|
||||
issue = create(:issue, title: 'test', project: project)
|
||||
visit(project_tree_path(project))
|
||||
|
||||
submit_search('test')
|
||||
select_search_scope('Code')
|
||||
|
||||
expect(page).to have_selector('.ref-selector')
|
||||
|
||||
select_search_scope('Issues')
|
||||
|
||||
expect(find(:css, '.results')).to have_link(issue.title)
|
||||
expect(page).not_to have_selector('.ref-selector')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when signed out' do
|
||||
context 'when block_anonymous_global_searches is enabled' do
|
||||
it 'is redirected to login page' do
|
||||
visit(search_path)
|
||||
|
||||
expect(page).to have_content('You must be logged in to search across all of GitLab')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,51 +3,45 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'User searches for comments', :js, :disable_rate_limiter, feature_category: :global_search do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
where(search_page_vertical_nav_enabled: [true, false])
|
||||
with_them do
|
||||
before do
|
||||
stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
|
||||
project.add_reporter(user)
|
||||
sign_in(user)
|
||||
before do
|
||||
project.add_reporter(user)
|
||||
sign_in(user)
|
||||
|
||||
visit(project_path(project))
|
||||
end
|
||||
visit(project_path(project))
|
||||
end
|
||||
|
||||
include_examples 'search timeouts', 'notes' do
|
||||
let(:additional_params) { { project_id: project.id } }
|
||||
end
|
||||
include_examples 'search timeouts', 'notes' do
|
||||
let(:additional_params) { { project_id: project.id } }
|
||||
end
|
||||
|
||||
context 'when a comment is in commits' do
|
||||
context 'when comment belongs to an invalid commit' do
|
||||
let(:comment) { create(:note_on_commit, author: user, project: project, commit_id: 12345678, note: 'Bug here') }
|
||||
context 'when a comment is in commits' do
|
||||
context 'when comment belongs to an invalid commit' do
|
||||
let(:comment) { create(:note_on_commit, author: user, project: project, commit_id: 12345678, note: 'Bug here') }
|
||||
|
||||
it 'finds a commit' do
|
||||
submit_search(comment.note)
|
||||
select_search_scope('Comments')
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_content('Commit deleted')
|
||||
expect(page).to have_content('12345678')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a comment is in a snippet' do
|
||||
let(:snippet) { create(:project_snippet, :private, project: project, author: user, title: 'Some title') }
|
||||
let(:comment) { create(:note, noteable: snippet, author: user, note: 'Supercalifragilisticexpialidocious', project: project) }
|
||||
|
||||
it 'finds a snippet' do
|
||||
it 'finds a commit' do
|
||||
submit_search(comment.note)
|
||||
select_search_scope('Comments')
|
||||
|
||||
expect(page).to have_selector('.results', text: snippet.title)
|
||||
page.within('.results') do
|
||||
expect(page).to have_content('Commit deleted')
|
||||
expect(page).to have_content('12345678')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a comment is in a snippet' do
|
||||
let(:snippet) { create(:project_snippet, :private, project: project, author: user, title: 'Some title') }
|
||||
let(:comment) { create(:note, noteable: snippet, author: user, note: 'Supercalifragilisticexpialidocious', project: project) }
|
||||
|
||||
it 'finds a snippet' do
|
||||
submit_search(comment.note)
|
||||
select_search_scope('Comments')
|
||||
|
||||
expect(page).to have_selector('.results', text: snippet.title)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,61 +3,55 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'User searches for commits', :js, :clean_gitlab_redis_rate_limiting, feature_category: :global_search do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:sha) { '6d394385cf567f80a8fd85055db1ab4c5295806f' }
|
||||
|
||||
where(search_page_vertical_nav_enabled: [true, false])
|
||||
with_them do
|
||||
before do
|
||||
stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
|
||||
project.add_reporter(user)
|
||||
sign_in(user)
|
||||
before do
|
||||
project.add_reporter(user)
|
||||
sign_in(user)
|
||||
|
||||
visit(search_path(project_id: project.id))
|
||||
visit(search_path(project_id: project.id))
|
||||
end
|
||||
|
||||
include_examples 'search timeouts', 'commits' do
|
||||
let(:additional_params) { { project_id: project.id } }
|
||||
end
|
||||
|
||||
context 'when searching by SHA' do
|
||||
it 'finds a commit and redirects to its page' do
|
||||
submit_search(sha)
|
||||
|
||||
expect(page).to have_current_path(project_commit_path(project, sha))
|
||||
end
|
||||
|
||||
include_examples 'search timeouts', 'commits' do
|
||||
let(:additional_params) { { project_id: project.id } }
|
||||
it 'finds a commit in uppercase and redirects to its page' do
|
||||
submit_search(sha.upcase)
|
||||
|
||||
expect(page).to have_current_path(project_commit_path(project, sha))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when searching by message' do
|
||||
it 'finds a commit and holds on /search page' do
|
||||
project.repository.commit_files(
|
||||
user,
|
||||
message: 'Message referencing another sha: "deadbeef"',
|
||||
branch_name: 'master',
|
||||
actions: [{ action: :create, file_path: 'a/new.file', contents: 'new file' }]
|
||||
)
|
||||
|
||||
submit_search('deadbeef')
|
||||
|
||||
expect(page).to have_current_path('/search', ignore_query: true)
|
||||
end
|
||||
|
||||
context 'when searching by SHA' do
|
||||
it 'finds a commit and redirects to its page' do
|
||||
submit_search(sha)
|
||||
it 'finds multiple commits' do
|
||||
submit_search('See merge request')
|
||||
select_search_scope('Commits')
|
||||
|
||||
expect(page).to have_current_path(project_commit_path(project, sha))
|
||||
end
|
||||
|
||||
it 'finds a commit in uppercase and redirects to its page' do
|
||||
submit_search(sha.upcase)
|
||||
|
||||
expect(page).to have_current_path(project_commit_path(project, sha))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when searching by message' do
|
||||
it 'finds a commit and holds on /search page' do
|
||||
project.repository.commit_files(
|
||||
user,
|
||||
message: 'Message referencing another sha: "deadbeef"',
|
||||
branch_name: 'master',
|
||||
actions: [{ action: :create, file_path: 'a/new.file', contents: 'new file' }]
|
||||
)
|
||||
|
||||
submit_search('deadbeef')
|
||||
|
||||
expect(page).to have_current_path('/search', ignore_query: true)
|
||||
end
|
||||
|
||||
it 'finds multiple commits' do
|
||||
submit_search('See merge request')
|
||||
select_search_scope('Commits')
|
||||
|
||||
expect(page).to have_selector('.commit-row-description', visible: false, count: 9)
|
||||
end
|
||||
expect(page).to have_selector('.commit-row-description', visible: false, count: 9)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'User searches for issues', :js, :clean_gitlab_redis_rate_limiting, feature_category: :global_search do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, namespace: user.namespace) }
|
||||
|
||||
|
|
@ -17,21 +15,107 @@ RSpec.describe 'User searches for issues', :js, :clean_gitlab_redis_rate_limitin
|
|||
select_search_scope('Issues')
|
||||
end
|
||||
|
||||
where(search_page_vertical_nav_enabled: [true, false])
|
||||
context 'when signed in' do
|
||||
before do
|
||||
project.add_maintainer(user)
|
||||
sign_in(user)
|
||||
|
||||
visit(search_path)
|
||||
end
|
||||
|
||||
include_examples 'top right search form'
|
||||
include_examples 'search timeouts', 'issues'
|
||||
|
||||
it 'finds an issue' do
|
||||
search_for_issue(issue1.title)
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_link(issue1.title)
|
||||
expect(page).not_to have_link(issue2.title)
|
||||
end
|
||||
end
|
||||
|
||||
it 'hides confidential icon for non-confidential issues' do
|
||||
search_for_issue(issue1.title)
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).not_to have_css('[data-testid="eye-slash-icon"]')
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows confidential icon for confidential issues' do
|
||||
search_for_issue(issue2.title)
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_css('[data-testid="eye-slash-icon"]')
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows correct badge for open issues' do
|
||||
search_for_issue(issue1.title)
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_css('.badge-success')
|
||||
expect(page).not_to have_css('.badge-info')
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows correct badge for closed issues' do
|
||||
search_for_issue(issue2.title)
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).not_to have_css('.badge-success')
|
||||
expect(page).to have_css('.badge-info')
|
||||
end
|
||||
end
|
||||
|
||||
it 'sorts by created date' do
|
||||
search_for_issue('issue')
|
||||
|
||||
page.within('.results') do
|
||||
expect(page.all('.search-result-row').first).to have_link(issue2.title)
|
||||
expect(page.all('.search-result-row').last).to have_link(issue1.title)
|
||||
end
|
||||
|
||||
find('[data-testid="sort-highest-icon"]').click
|
||||
|
||||
page.within('.results') do
|
||||
expect(page.all('.search-result-row').first).to have_link(issue1.title)
|
||||
expect(page.all('.search-result-row').last).to have_link(issue2.title)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when on a project page' do
|
||||
it 'finds an issue' do
|
||||
find('[data-testid="project-filter"]').click
|
||||
|
||||
wait_for_requests
|
||||
|
||||
page.within('[data-testid="project-filter"]') do
|
||||
click_on(project.name)
|
||||
end
|
||||
|
||||
search_for_issue(issue1.title)
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_link(issue1.title)
|
||||
expect(page).not_to have_link(issue2.title)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when signed out' do
|
||||
context 'when block_anonymous_global_searches is disabled' do
|
||||
let_it_be(:project) { create(:project, :public) }
|
||||
|
||||
with_them do
|
||||
context 'when signed in' do
|
||||
before do
|
||||
stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
|
||||
|
||||
project.add_maintainer(user)
|
||||
sign_in(user)
|
||||
stub_feature_flags(block_anonymous_global_searches: false)
|
||||
|
||||
visit(search_path)
|
||||
end
|
||||
|
||||
include_examples 'top right search form'
|
||||
include_examples 'search timeouts', 'issues'
|
||||
|
||||
it 'finds an issue' do
|
||||
search_for_issue(issue1.title)
|
||||
|
|
@ -41,109 +125,13 @@ RSpec.describe 'User searches for issues', :js, :clean_gitlab_redis_rate_limitin
|
|||
expect(page).not_to have_link(issue2.title)
|
||||
end
|
||||
end
|
||||
|
||||
it 'hides confidential icon for non-confidential issues' do
|
||||
search_for_issue(issue1.title)
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).not_to have_css('[data-testid="eye-slash-icon"]')
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows confidential icon for confidential issues' do
|
||||
search_for_issue(issue2.title)
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_css('[data-testid="eye-slash-icon"]')
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows correct badge for open issues' do
|
||||
search_for_issue(issue1.title)
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_css('.badge-success')
|
||||
expect(page).not_to have_css('.badge-info')
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows correct badge for closed issues' do
|
||||
search_for_issue(issue2.title)
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).not_to have_css('.badge-success')
|
||||
expect(page).to have_css('.badge-info')
|
||||
end
|
||||
end
|
||||
|
||||
it 'sorts by created date' do
|
||||
search_for_issue('issue')
|
||||
|
||||
page.within('.results') do
|
||||
expect(page.all('.search-result-row').first).to have_link(issue2.title)
|
||||
expect(page.all('.search-result-row').last).to have_link(issue1.title)
|
||||
end
|
||||
|
||||
find('[data-testid="sort-highest-icon"]').click
|
||||
|
||||
page.within('.results') do
|
||||
expect(page.all('.search-result-row').first).to have_link(issue1.title)
|
||||
expect(page.all('.search-result-row').last).to have_link(issue2.title)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when on a project page' do
|
||||
it 'finds an issue' do
|
||||
find('[data-testid="project-filter"]').click
|
||||
|
||||
wait_for_requests
|
||||
|
||||
page.within('[data-testid="project-filter"]') do
|
||||
click_on(project.name)
|
||||
end
|
||||
|
||||
search_for_issue(issue1.title)
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_link(issue1.title)
|
||||
expect(page).not_to have_link(issue2.title)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when signed out' do
|
||||
before do
|
||||
stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
|
||||
end
|
||||
context 'when block_anonymous_global_searches is enabled' do
|
||||
it 'is redirected to login page' do
|
||||
visit(search_path)
|
||||
|
||||
context 'when block_anonymous_global_searches is disabled' do
|
||||
let_it_be(:project) { create(:project, :public) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(block_anonymous_global_searches: false)
|
||||
|
||||
visit(search_path)
|
||||
end
|
||||
|
||||
include_examples 'top right search form'
|
||||
|
||||
it 'finds an issue' do
|
||||
search_for_issue(issue1.title)
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_link(issue1.title)
|
||||
expect(page).not_to have_link(issue2.title)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when block_anonymous_global_searches is enabled' do
|
||||
it 'is redirected to login page' do
|
||||
visit(search_path)
|
||||
|
||||
expect(page).to have_content('You must be logged in to search across all of GitLab')
|
||||
end
|
||||
expect(page).to have_content('You must be logged in to search across all of GitLab')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,12 +3,10 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'User searches for merge requests', :js, :clean_gitlab_redis_rate_limiting, feature_category: :global_search do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project, namespace: user.namespace) }
|
||||
let!(:merge_request1) { create(:merge_request, title: 'Merge Request Foo', source_project: project, target_project: project, created_at: 1.hour.ago) }
|
||||
let!(:merge_request2) { create(:merge_request, :simple, title: 'Merge Request Bar', source_project: project, target_project: project) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, namespace: user.namespace) }
|
||||
let_it_be(:merge_request1) { create(:merge_request, title: 'Merge Request Foo', source_project: project, target_project: project, created_at: 1.hour.ago) }
|
||||
let_it_be(:merge_request2) { create(:merge_request, :simple, title: 'Merge Request Bar', source_project: project, target_project: project) }
|
||||
|
||||
def search_for_mr(search)
|
||||
fill_in('dashboard_search', with: search)
|
||||
|
|
@ -16,64 +14,60 @@ RSpec.describe 'User searches for merge requests', :js, :clean_gitlab_redis_rate
|
|||
select_search_scope('Merge requests')
|
||||
end
|
||||
|
||||
where(search_page_vertical_nav_enabled: [true, false])
|
||||
with_them do
|
||||
before do
|
||||
stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
|
||||
sign_in(user)
|
||||
before do
|
||||
sign_in(user)
|
||||
|
||||
visit(search_path)
|
||||
visit(search_path)
|
||||
end
|
||||
|
||||
include_examples 'top right search form'
|
||||
include_examples 'search timeouts', 'merge_requests'
|
||||
|
||||
it 'finds a merge request' do
|
||||
search_for_mr(merge_request1.title)
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_link(merge_request1.title)
|
||||
expect(page).not_to have_link(merge_request2.title)
|
||||
|
||||
# Each result should have MR refs like `gitlab-org/gitlab!1`
|
||||
page.all('.search-result-row').each do |e|
|
||||
expect(e.text).to match(/!\d+/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'sorts by created date' do
|
||||
search_for_mr('Merge Request')
|
||||
|
||||
page.within('.results') do
|
||||
expect(page.all('.search-result-row').first).to have_link(merge_request2.title)
|
||||
expect(page.all('.search-result-row').last).to have_link(merge_request1.title)
|
||||
end
|
||||
|
||||
include_examples 'top right search form'
|
||||
include_examples 'search timeouts', 'merge_requests'
|
||||
find('[data-testid="sort-highest-icon"]').click
|
||||
|
||||
page.within('.results') do
|
||||
expect(page.all('.search-result-row').first).to have_link(merge_request1.title)
|
||||
expect(page.all('.search-result-row').last).to have_link(merge_request2.title)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when on a project page' do
|
||||
it 'finds a merge request' do
|
||||
find('[data-testid="project-filter"]').click
|
||||
|
||||
wait_for_requests
|
||||
|
||||
page.within('[data-testid="project-filter"]') do
|
||||
click_on(project.name)
|
||||
end
|
||||
|
||||
search_for_mr(merge_request1.title)
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_link(merge_request1.title)
|
||||
expect(page).not_to have_link(merge_request2.title)
|
||||
|
||||
# Each result should have MR refs like `gitlab-org/gitlab!1`
|
||||
page.all('.search-result-row').each do |e|
|
||||
expect(e.text).to match(/!\d+/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'sorts by created date' do
|
||||
search_for_mr('Merge Request')
|
||||
|
||||
page.within('.results') do
|
||||
expect(page.all('.search-result-row').first).to have_link(merge_request2.title)
|
||||
expect(page.all('.search-result-row').last).to have_link(merge_request1.title)
|
||||
end
|
||||
|
||||
find('[data-testid="sort-highest-icon"]').click
|
||||
|
||||
page.within('.results') do
|
||||
expect(page.all('.search-result-row').first).to have_link(merge_request1.title)
|
||||
expect(page.all('.search-result-row').last).to have_link(merge_request2.title)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when on a project page' do
|
||||
it 'finds a merge request' do
|
||||
find('[data-testid="project-filter"]').click
|
||||
|
||||
wait_for_requests
|
||||
|
||||
page.within('[data-testid="project-filter"]') do
|
||||
click_on(project.name)
|
||||
end
|
||||
|
||||
search_for_mr(merge_request1.title)
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_link(merge_request1.title)
|
||||
expect(page).not_to have_link(merge_request2.title)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,29 +4,42 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe 'User searches for milestones', :js, :clean_gitlab_redis_rate_limiting,
|
||||
feature_category: :global_search do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, namespace: user.namespace) }
|
||||
let_it_be(:milestone1) { create(:milestone, title: 'Foo', project: project) }
|
||||
let_it_be(:milestone2) { create(:milestone, title: 'Bar', project: project) }
|
||||
|
||||
let!(:milestone1) { create(:milestone, title: 'Foo', project: project) }
|
||||
let!(:milestone2) { create(:milestone, title: 'Bar', project: project) }
|
||||
before do
|
||||
project.add_maintainer(user)
|
||||
sign_in(user)
|
||||
|
||||
where(search_page_vertical_nav_enabled: [true, false])
|
||||
visit(search_path)
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
project.add_maintainer(user)
|
||||
sign_in(user)
|
||||
stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
|
||||
include_examples 'top right search form'
|
||||
include_examples 'search timeouts', 'milestones'
|
||||
|
||||
visit(search_path)
|
||||
it 'finds a milestone' do
|
||||
fill_in('dashboard_search', with: milestone1.title)
|
||||
find('.gl-search-box-by-click-search-button').click
|
||||
select_search_scope('Milestones')
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_link(milestone1.title)
|
||||
expect(page).not_to have_link(milestone2.title)
|
||||
end
|
||||
end
|
||||
|
||||
include_examples 'top right search form'
|
||||
include_examples 'search timeouts', 'milestones'
|
||||
|
||||
context 'when on a project page' do
|
||||
it 'finds a milestone' do
|
||||
find('[data-testid="project-filter"]').click
|
||||
|
||||
wait_for_requests
|
||||
|
||||
page.within('[data-testid="project-filter"]') do
|
||||
click_on(project.name)
|
||||
end
|
||||
|
||||
fill_in('dashboard_search', with: milestone1.title)
|
||||
find('.gl-search-box-by-click-search-button').click
|
||||
select_search_scope('Milestones')
|
||||
|
|
@ -36,26 +49,5 @@ feature_category: :global_search do
|
|||
expect(page).not_to have_link(milestone2.title)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when on a project page' do
|
||||
it 'finds a milestone' do
|
||||
find('[data-testid="project-filter"]').click
|
||||
|
||||
wait_for_requests
|
||||
|
||||
page.within('[data-testid="project-filter"]') do
|
||||
click_on(project.name)
|
||||
end
|
||||
|
||||
fill_in('dashboard_search', with: milestone1.title)
|
||||
find('.gl-search-box-by-click-search-button').click
|
||||
select_search_scope('Milestones')
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_link(milestone1.title)
|
||||
expect(page).not_to have_link(milestone2.title)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,85 +7,80 @@ RSpec.describe 'User searches for users', :js, :clean_gitlab_redis_rate_limiting
|
|||
let_it_be(:user2) { create(:user, username: 'michael_bluth', name: 'Michael Bluth') }
|
||||
let_it_be(:user3) { create(:user, username: 'gob_2018', name: 'George Oscar Bluth') }
|
||||
|
||||
where(search_page_vertical_nav_enabled: [true, false])
|
||||
with_them do
|
||||
before do
|
||||
sign_in(user1)
|
||||
end
|
||||
|
||||
include_examples 'search timeouts', 'users' do
|
||||
before do
|
||||
stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
|
||||
|
||||
sign_in(user1)
|
||||
visit(search_path)
|
||||
end
|
||||
end
|
||||
|
||||
include_examples 'search timeouts', 'users' do
|
||||
before do
|
||||
visit(search_path)
|
||||
context 'when on the dashboard' do
|
||||
it 'finds the user' do
|
||||
visit dashboard_projects_path
|
||||
|
||||
submit_search('gob')
|
||||
select_search_scope('Users')
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_content('Gob Bluth')
|
||||
expect(page).to have_content('@gob_bluth')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when on the dashboard' do
|
||||
it 'finds the user' do
|
||||
visit dashboard_projects_path
|
||||
context 'when on the project page' do
|
||||
let_it_be_with_reload(:project) { create(:project) }
|
||||
|
||||
submit_search('gob')
|
||||
select_search_scope('Users')
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_content('Gob Bluth')
|
||||
expect(page).to have_content('@gob_bluth')
|
||||
end
|
||||
end
|
||||
before do
|
||||
project.add_developer(user1)
|
||||
project.add_developer(user2)
|
||||
end
|
||||
|
||||
context 'when on the project page' do
|
||||
let_it_be_with_reload(:project) { create(:project) }
|
||||
it 'finds the user belonging to the project' do
|
||||
visit project_path(project)
|
||||
|
||||
before do
|
||||
project.add_developer(user1)
|
||||
project.add_developer(user2)
|
||||
end
|
||||
submit_search('gob')
|
||||
select_search_scope('Users')
|
||||
|
||||
it 'finds the user belonging to the project' do
|
||||
visit project_path(project)
|
||||
page.within('.results') do
|
||||
expect(page).to have_content('Gob Bluth')
|
||||
expect(page).to have_content('@gob_bluth')
|
||||
|
||||
submit_search('gob')
|
||||
select_search_scope('Users')
|
||||
expect(page).not_to have_content('Michael Bluth')
|
||||
expect(page).not_to have_content('@michael_bluth')
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_content('Gob Bluth')
|
||||
expect(page).to have_content('@gob_bluth')
|
||||
|
||||
expect(page).not_to have_content('Michael Bluth')
|
||||
expect(page).not_to have_content('@michael_bluth')
|
||||
|
||||
expect(page).not_to have_content('George Oscar Bluth')
|
||||
expect(page).not_to have_content('@gob_2018')
|
||||
end
|
||||
expect(page).not_to have_content('George Oscar Bluth')
|
||||
expect(page).not_to have_content('@gob_2018')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when on the group page' do
|
||||
let(:group) { create(:group) }
|
||||
context 'when on the group page' do
|
||||
let(:group) { create(:group) }
|
||||
|
||||
before do
|
||||
group.add_developer(user1)
|
||||
group.add_developer(user2)
|
||||
end
|
||||
before do
|
||||
group.add_developer(user1)
|
||||
group.add_developer(user2)
|
||||
end
|
||||
|
||||
it 'finds the user belonging to the group' do
|
||||
visit group_path(group)
|
||||
it 'finds the user belonging to the group' do
|
||||
visit group_path(group)
|
||||
|
||||
submit_search('gob')
|
||||
select_search_scope('Users')
|
||||
submit_search('gob')
|
||||
select_search_scope('Users')
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_content('Gob Bluth')
|
||||
expect(page).to have_content('@gob_bluth')
|
||||
page.within('.results') do
|
||||
expect(page).to have_content('Gob Bluth')
|
||||
expect(page).to have_content('@gob_bluth')
|
||||
|
||||
expect(page).not_to have_content('Michael Bluth')
|
||||
expect(page).not_to have_content('@michael_bluth')
|
||||
expect(page).not_to have_content('Michael Bluth')
|
||||
expect(page).not_to have_content('@michael_bluth')
|
||||
|
||||
expect(page).not_to have_content('George Oscar Bluth')
|
||||
expect(page).not_to have_content('@gob_2018')
|
||||
end
|
||||
expect(page).not_to have_content('George Oscar Bluth')
|
||||
expect(page).not_to have_content('@gob_2018')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,58 +4,53 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe 'User searches for wiki pages', :js, :clean_gitlab_redis_rate_limiting,
|
||||
feature_category: :global_search do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, :repository, :wiki_repo, namespace: user.namespace) }
|
||||
let_it_be(:wiki_page) do
|
||||
create(:wiki_page, wiki: project.wiki, title: 'directory/title', content: 'Some Wiki content')
|
||||
end
|
||||
|
||||
let(:project) { create(:project, :repository, :wiki_repo, namespace: user.namespace) }
|
||||
let!(:wiki_page) { create(:wiki_page, wiki: project.wiki, title: 'directory/title', content: 'Some Wiki content') }
|
||||
before do
|
||||
project.add_maintainer(user)
|
||||
sign_in(user)
|
||||
|
||||
where(search_page_vertical_nav_enabled: [true, false])
|
||||
with_them do
|
||||
before do
|
||||
stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
|
||||
project.add_maintainer(user)
|
||||
sign_in(user)
|
||||
visit(search_path)
|
||||
end
|
||||
|
||||
visit(search_path)
|
||||
end
|
||||
include_examples 'top right search form'
|
||||
include_examples 'search timeouts', 'wiki_blobs' do
|
||||
let(:additional_params) { { project_id: project.id } }
|
||||
end
|
||||
|
||||
include_examples 'top right search form'
|
||||
include_examples 'search timeouts', 'wiki_blobs' do
|
||||
let(:additional_params) { { project_id: project.id } }
|
||||
end
|
||||
shared_examples 'search wiki blobs' do
|
||||
it 'finds a page' do
|
||||
find('[data-testid="project-filter"]').click
|
||||
|
||||
shared_examples 'search wiki blobs' do
|
||||
it 'finds a page' do
|
||||
find('[data-testid="project-filter"]').click
|
||||
wait_for_requests
|
||||
|
||||
wait_for_requests
|
||||
|
||||
page.within('[data-testid="project-filter"]') do
|
||||
click_on(project.name)
|
||||
end
|
||||
|
||||
fill_in('dashboard_search', with: search_term)
|
||||
find('.gl-search-box-by-click-search-button').click
|
||||
select_search_scope('Wiki')
|
||||
|
||||
page.within('.results') do
|
||||
expect(page).to have_link(wiki_page.title, href: project_wiki_path(project, wiki_page.slug))
|
||||
end
|
||||
page.within('[data-testid="project-filter"]') do
|
||||
click_on(project.name)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when searching by content' do
|
||||
it_behaves_like 'search wiki blobs' do
|
||||
let(:search_term) { 'content' }
|
||||
end
|
||||
end
|
||||
fill_in('dashboard_search', with: search_term)
|
||||
find('.gl-search-box-by-click-search-button').click
|
||||
select_search_scope('Wiki')
|
||||
|
||||
context 'when searching by title' do
|
||||
it_behaves_like 'search wiki blobs' do
|
||||
let(:search_term) { 'title' }
|
||||
page.within('.results') do
|
||||
expect(page).to have_link(wiki_page.title, href: project_wiki_path(project, wiki_page.slug))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when searching by content' do
|
||||
it_behaves_like 'search wiki blobs' do
|
||||
let(:search_term) { 'content' }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when searching by title' do
|
||||
it_behaves_like 'search wiki blobs' do
|
||||
let(:search_term) { 'title' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`pages/search/show/refresh_counts fetches and displays search counts 1`] = `
|
||||
"<div class=\\"badge\\">22</div>
|
||||
<div class=\\"badge js-search-count\\" data-url=\\"http://test.host/search/count?search=lorem+ipsum&project_id=3&scope=issues\\">4</div>
|
||||
<div class=\\"badge js-search-count\\" data-url=\\"http://test.host/search/count?search=lorem+ipsum&project_id=3&scope=merge_requests\\">5</div>"
|
||||
`;
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
|
||||
import { TEST_HOST } from 'helpers/test_constants';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import refreshCounts from '~/pages/search/show/refresh_counts';
|
||||
|
||||
const URL = `${TEST_HOST}/search/count?search=lorem+ipsum&project_id=3`;
|
||||
const urlWithScope = (scope) => `${URL}&scope=${scope}`;
|
||||
const counts = [
|
||||
{ scope: 'issues', count: 4 },
|
||||
{ scope: 'merge_requests', count: 5 },
|
||||
];
|
||||
const fixture = `<div class="badge">22</div>
|
||||
<div class="badge js-search-count hidden" data-url="${urlWithScope('issues')}"></div>
|
||||
<div class="badge js-search-count hidden" data-url="${urlWithScope('merge_requests')}"></div>`;
|
||||
|
||||
describe('pages/search/show/refresh_counts', () => {
|
||||
let mock;
|
||||
|
||||
beforeEach(() => {
|
||||
mock = new MockAdapter(axios);
|
||||
setHTMLFixture(fixture);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
resetHTMLFixture();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mock.restore();
|
||||
});
|
||||
|
||||
it('fetches and displays search counts', () => {
|
||||
counts.forEach(({ scope, count }) => {
|
||||
mock.onGet(urlWithScope(scope)).reply(200, { count });
|
||||
});
|
||||
|
||||
// assert before act behavior
|
||||
return refreshCounts().then(() => {
|
||||
expect(document.body.innerHTML).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -84,23 +84,14 @@ describe('GlobalSearchSidebar', () => {
|
|||
expect(findFilters().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when search_page_vertical_nav is enabled', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({}, { searchPageVerticalNav: true });
|
||||
});
|
||||
it('shows the vertical navigation', () => {
|
||||
expect(findSidebarNavigation().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when search_page_vertical_nav is disabled', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({}, { searchPageVerticalNav: false });
|
||||
});
|
||||
it('hides the vertical navigation', () => {
|
||||
expect(findSidebarNavigation().exists()).toBe(false);
|
||||
describe('renders navigation', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({});
|
||||
});
|
||||
it('shows the vertical navigation', () => {
|
||||
expect(findSidebarNavigation().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,24 +22,4 @@ describe('ConfidentialityFilter', () => {
|
|||
expect(findRadioFilter().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe.each`
|
||||
hasFeatureFlagEnabled | paddingClass
|
||||
${true} | ${'gl-px-5'}
|
||||
${false} | ${'gl-px-0'}
|
||||
`(`RadioFilter`, ({ hasFeatureFlagEnabled, paddingClass }) => {
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
provide: {
|
||||
glFeatures: {
|
||||
searchPageVerticalNav: hasFeatureFlagEnabled,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it(`has ${paddingClass} class`, () => {
|
||||
expect(findRadioFilter().classes(paddingClass)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,24 +22,4 @@ describe('StatusFilter', () => {
|
|||
expect(findRadioFilter().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe.each`
|
||||
hasFeatureFlagEnabled | paddingClass
|
||||
${true} | ${'gl-px-5'}
|
||||
${false} | ${'gl-px-0'}
|
||||
`(`RadioFilter`, ({ hasFeatureFlagEnabled, paddingClass }) => {
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
provide: {
|
||||
glFeatures: {
|
||||
searchPageVerticalNav: hasFeatureFlagEnabled,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it(`has ${paddingClass} class`, () => {
|
||||
expect(findRadioFilter().classes(paddingClass)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,43 +4,43 @@ require "spec_helper"
|
|||
|
||||
RSpec.describe BizibleHelper do
|
||||
describe '#bizible_enabled?' do
|
||||
before do
|
||||
stub_config(extra: { bizible: SecureRandom.uuid })
|
||||
end
|
||||
|
||||
context 'when bizible is disabled' do
|
||||
context 'when bizible config is not true' do
|
||||
before do
|
||||
allow(helper).to receive(:bizible_enabled?).and_return(false)
|
||||
stub_config(extra: { bizible: false })
|
||||
end
|
||||
|
||||
it { is_expected.to be_falsey }
|
||||
it { expect(helper.bizible_enabled?).to be_falsy }
|
||||
end
|
||||
|
||||
context 'when bizible is enabled' do
|
||||
context 'when bizible config is enabled' do
|
||||
before do
|
||||
allow(helper).to receive(:bizible_enabled?).and_return(true)
|
||||
stub_config(extra: { bizible: true })
|
||||
end
|
||||
|
||||
it { is_expected.to be_truthy }
|
||||
end
|
||||
it { expect(helper.bizible_enabled?).to be_truthy }
|
||||
|
||||
subject(:bizible_enabled?) { helper.bizible_enabled? }
|
||||
|
||||
context 'with ecomm_instrumentation feature flag disabled' do
|
||||
before do
|
||||
stub_feature_flags(ecomm_instrumentation: false)
|
||||
end
|
||||
|
||||
it { is_expected.to be_falsey }
|
||||
end
|
||||
|
||||
context 'with ecomm_instrumentation feature flag enabled' do
|
||||
context 'when no id is set' do
|
||||
context 'with ecomm_instrumentation feature flag disabled' do
|
||||
before do
|
||||
stub_config(extra: {})
|
||||
stub_feature_flags(ecomm_instrumentation: false)
|
||||
end
|
||||
|
||||
it { is_expected.to be_falsey }
|
||||
it { expect(helper.bizible_enabled?).to be_falsey }
|
||||
end
|
||||
|
||||
context 'with ecomm_instrumentation feature flag enabled' do
|
||||
before do
|
||||
stub_feature_flags(ecomm_instrumentation: true)
|
||||
end
|
||||
|
||||
it { expect(helper.bizible_enabled?).to be_truthy }
|
||||
end
|
||||
|
||||
context 'with invite_email present' do
|
||||
before do
|
||||
stub_feature_flags(ecomm_instrumentation: true)
|
||||
end
|
||||
|
||||
it { expect(helper.bizible_enabled?('test@test.com')).to be_falsy }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities, feature_category: :pipeline_execution do
|
||||
RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities, feature_category: :continuous_integration do
|
||||
let(:project) { create(:project, :test_repo) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
|
|||
it { is_expected.to have_many(:pages_deployments).with_foreign_key(:ci_build_id) }
|
||||
|
||||
it { is_expected.to have_one(:deployment) }
|
||||
it { is_expected.to have_one(:runner_machine).through(:metadata) }
|
||||
it { is_expected.to have_one(:runner_session).with_foreign_key(:build_id) }
|
||||
it { is_expected.to have_one(:trace_metadata).with_foreign_key(:build_id) }
|
||||
it { is_expected.to have_one(:runtime_metadata).with_foreign_key(:build_id) }
|
||||
|
|
@ -2047,6 +2048,16 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#runner_machine' do
|
||||
let_it_be(:runner) { create(:ci_runner) }
|
||||
let_it_be(:runner_machine) { create(:ci_runner_machine, runner: runner) }
|
||||
let_it_be(:build) { create(:ci_build, runner_machine: runner_machine) }
|
||||
|
||||
subject(:build_runner_machine) { described_class.find(build.id).runner_machine }
|
||||
|
||||
it { is_expected.to eq(runner_machine) }
|
||||
end
|
||||
|
||||
describe '#tag_list' do
|
||||
let_it_be(:build) { create(:ci_build, tag_list: ['tag']) }
|
||||
|
||||
|
|
@ -5781,4 +5792,43 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration do
|
|||
expect(build.metadata.partition_id).to eq(ci_testing_partition_id)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'secrets management id_tokens usage data' do
|
||||
context 'when ID tokens are defined' do
|
||||
let(:ci_build) { FactoryBot.build(:ci_build, user: user, id_tokens: { 'ID_TOKEN_1' => { aud: 'developers' } }) }
|
||||
|
||||
context 'on create' do
|
||||
it 'tracks event with user_id' do
|
||||
expect(::Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event)
|
||||
.with('i_ci_secrets_management_id_tokens_build_created', values: user.id)
|
||||
|
||||
ci_build.save!
|
||||
end
|
||||
end
|
||||
|
||||
context 'on update' do
|
||||
before do
|
||||
ci_build.save!
|
||||
end
|
||||
|
||||
it 'does not track event' do
|
||||
expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
|
||||
|
||||
ci_build.success
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ID tokens are not defined' do
|
||||
let(:ci_build) { FactoryBot.build(:ci_build, user: user) }
|
||||
|
||||
context 'on create' do
|
||||
it 'does not track event' do
|
||||
expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
|
||||
|
||||
ci_build.save!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Ci::Processable do
|
||||
RSpec.describe Ci::Processable, feature_category: :continuous_integration do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
|
||||
|
||||
|
|
@ -83,7 +83,7 @@ RSpec.describe Ci::Processable do
|
|||
runner_id tag_taggings taggings tags trigger_request_id
|
||||
user_id auto_canceled_by_id retried failure_reason
|
||||
sourced_pipelines sourced_pipeline artifacts_file_store artifacts_metadata_store
|
||||
metadata runner_session trace_chunks upstream_pipeline_id
|
||||
metadata runner_machine_id runner_machine runner_session trace_chunks upstream_pipeline_id
|
||||
artifacts_file artifacts_metadata artifacts_size commands
|
||||
resource resource_group_id processed security_scans author
|
||||
pipeline_id report_results pending_state pages_deployments
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model
|
|||
it_behaves_like 'having unique enum values'
|
||||
|
||||
it { is_expected.to belong_to(:runner) }
|
||||
it { is_expected.to belong_to(:runner_version).with_foreign_key(:version) }
|
||||
it { is_expected.to have_many(:build_metadata) }
|
||||
it { is_expected.to have_many(:builds).through(:build_metadata) }
|
||||
|
||||
describe 'validation' do
|
||||
it { is_expected.to validate_presence_of(:runner) }
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ RSpec.describe Ci::RunnerVersion, feature_category: :runner_fleet do
|
|||
create(:ci_runner_version, version: 'abc123', status: :not_available)
|
||||
end
|
||||
|
||||
it { is_expected.to have_many(:runner_machines).with_foreign_key(:version) }
|
||||
|
||||
it_behaves_like 'having unique enum values'
|
||||
|
||||
describe '.not_available' do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Blobs', feature_category: :source_code_management do
|
||||
let_it_be(:project) { create(:project, :public, :repository, lfs: true) }
|
||||
|
||||
describe 'GET /:namespace_id/:project_id/-/blob/:id' do
|
||||
subject(:request) do
|
||||
get namespace_project_blob_path(namespace_id: project.namespace, project_id: project, id: id)
|
||||
end
|
||||
|
||||
context 'with LFS file' do
|
||||
let(:id) { 'master/files/lfs/lfs_object.iso' }
|
||||
let(:object_store_host) { 'http://127.0.0.1:9000' }
|
||||
let(:connect_src) do
|
||||
csp = response.headers['Content-Security-Policy']
|
||||
csp.split('; ').find { |src| src.starts_with?('connect-src') }
|
||||
end
|
||||
|
||||
let(:gitlab_config) do
|
||||
Gitlab.config.gitlab.deep_merge(
|
||||
'content_security_policy' => {
|
||||
'enabled' => content_security_policy_enabled
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
let(:lfs_config) do
|
||||
Gitlab.config.lfs.deep_merge(
|
||||
'enabled' => lfs_enabled,
|
||||
'object_store' => {
|
||||
'remote_directory' => 'lfs-objects',
|
||||
'enabled' => true,
|
||||
'proxy_download' => proxy_download,
|
||||
'connection' => {
|
||||
'endpoint' => object_store_host,
|
||||
'path_style' => true
|
||||
}
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
stub_config_setting(gitlab_config)
|
||||
stub_lfs_setting(lfs_config)
|
||||
stub_lfs_object_storage(proxy_download: proxy_download)
|
||||
|
||||
request
|
||||
end
|
||||
|
||||
describe 'directly downloading lfs file' do
|
||||
let(:lfs_enabled) { true }
|
||||
let(:proxy_download) { false }
|
||||
let(:content_security_policy_enabled) { true }
|
||||
|
||||
it { expect(response).to have_gitlab_http_status(:success) }
|
||||
|
||||
it { expect(connect_src).to include(object_store_host) }
|
||||
|
||||
context 'when lfs is disabled' do
|
||||
let(:lfs_enabled) { false }
|
||||
|
||||
it { expect(response).to have_gitlab_http_status(:success) }
|
||||
|
||||
it { expect(connect_src).not_to include(object_store_host) }
|
||||
end
|
||||
|
||||
context 'when content_security_policy is disabled' do
|
||||
let(:content_security_policy_enabled) { false }
|
||||
|
||||
it { expect(response).to have_gitlab_http_status(:success) }
|
||||
|
||||
it { expect(connect_src).not_to include(object_store_host) }
|
||||
end
|
||||
|
||||
context 'when proxy download is enabled' do
|
||||
let(:proxy_download) { true }
|
||||
|
||||
it { expect(response).to have_gitlab_http_status(:success) }
|
||||
|
||||
it { expect(connect_src).not_to include(object_store_host) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -78,7 +78,8 @@ RSpec.describe 'gitlab:usage data take tasks', :silence_stdout, feature_category
|
|||
`git checkout -- #{Gitlab::UsageDataCounters::CiTemplateUniqueCounter::KNOWN_EVENTS_FILE_PATH}`
|
||||
end
|
||||
|
||||
it "generates #{Gitlab::UsageDataCounters::CiTemplateUniqueCounter::KNOWN_EVENTS_FILE_PATH}" do
|
||||
it "generates #{Gitlab::UsageDataCounters::CiTemplateUniqueCounter::KNOWN_EVENTS_FILE_PATH}",
|
||||
quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/386191' do
|
||||
run_rake_task('gitlab:usage_data:generate_ci_template_events')
|
||||
|
||||
expect(File.exist?(Gitlab::UsageDataCounters::CiTemplateUniqueCounter::KNOWN_EVENTS_FILE_PATH)).to be true
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'search/_results', feature_category: :global_search do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
let(:search_objects) { Issue.page(1).per(2) }
|
||||
|
|
@ -32,30 +30,22 @@ RSpec.describe 'search/_results', feature_category: :global_search do
|
|||
assign(:search_service_presenter, search_service_presenter)
|
||||
end
|
||||
|
||||
where(search_page_vertical_nav_enabled: [true, false])
|
||||
describe 'page size' do
|
||||
context 'when search results have a count' do
|
||||
it 'displays the page size' do
|
||||
render
|
||||
|
||||
with_them do
|
||||
describe 'page size' do
|
||||
before do
|
||||
stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
|
||||
expect(rendered).to have_content('Showing 1 - 2 of 3 issues for foo')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when search results have a count' do
|
||||
it 'displays the page size' do
|
||||
render
|
||||
context 'when search results do not have a count' do
|
||||
let(:search_objects) { Issue.page(1).per(2).without_count }
|
||||
|
||||
expect(rendered).to have_content('Showing 1 - 2 of 3 issues for foo')
|
||||
end
|
||||
end
|
||||
it 'does not display the page size' do
|
||||
render
|
||||
|
||||
context 'when search results do not have a count' do
|
||||
let(:search_objects) { Issue.page(1).per(2).without_count }
|
||||
|
||||
it 'does not display the page size' do
|
||||
render
|
||||
|
||||
expect(rendered).not_to have_content(/Showing .* of .*/)
|
||||
end
|
||||
expect(rendered).not_to have_content(/Showing .* of .*/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,122 +10,96 @@ RSpec.describe 'search/show', feature_category: :global_search do
|
|||
end
|
||||
|
||||
before do
|
||||
stub_template "search/_category.html.haml" => 'Category Partial'
|
||||
stub_template "search/_results.html.haml" => 'Results Partial'
|
||||
|
||||
allow(view).to receive(:current_user) { user }
|
||||
|
||||
assign(:search_service_presenter, search_service_presenter)
|
||||
assign(:search_term, search_term)
|
||||
end
|
||||
|
||||
context 'search_page_vertical_nav feature flag enabled' do
|
||||
before do
|
||||
allow(view).to receive(:current_user) { user }
|
||||
assign(:search_term, search_term)
|
||||
end
|
||||
context 'when search term is supplied' do
|
||||
let(:search_term) { 'Search Foo' }
|
||||
|
||||
context 'when search term is supplied' do
|
||||
let(:search_term) { 'Search Foo' }
|
||||
it 'renders the results partial' do
|
||||
render
|
||||
|
||||
it 'will not render category partial' do
|
||||
render
|
||||
|
||||
expect(rendered).not_to render_template('search/_category')
|
||||
expect(rendered).to render_template('search/_results')
|
||||
end
|
||||
expect(rendered).to render_template('search/_results')
|
||||
end
|
||||
end
|
||||
|
||||
context 'search_page_vertical_nav feature flag disabled' do
|
||||
context 'when the search page is opened' do
|
||||
it 'displays the title' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_selector('h1.page-title', text: 'Search')
|
||||
expect(rendered).not_to have_selector('h1.page-title code')
|
||||
end
|
||||
|
||||
it 'does not render the results partial' do
|
||||
render
|
||||
|
||||
expect(rendered).not_to render_template('search/_results')
|
||||
end
|
||||
end
|
||||
|
||||
context 'unfurling support' do
|
||||
let(:group) { build(:group) }
|
||||
let(:search_results) do
|
||||
instance_double(Gitlab::GroupSearchResults).tap do |double|
|
||||
allow(double).to receive(:formatted_count).and_return(0)
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
stub_feature_flags(search_page_vertical_nav: false)
|
||||
|
||||
assign(:search_term, search_term)
|
||||
assign(:search_results, search_results)
|
||||
assign(:scope, 'issues')
|
||||
assign(:group, group)
|
||||
end
|
||||
|
||||
context 'when the search page is opened' do
|
||||
it 'displays the title' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_selector('h1.page-title', text: 'Search')
|
||||
expect(rendered).not_to have_selector('h1.page-title code')
|
||||
context 'search with full count' do
|
||||
let(:search_service_presenter) do
|
||||
instance_double(SearchServicePresenter, without_count?: false, advanced_search_enabled?: false)
|
||||
end
|
||||
|
||||
it 'does not render partials' do
|
||||
it 'renders meta tags for a group' do
|
||||
render
|
||||
|
||||
expect(rendered).not_to render_template('search/_category')
|
||||
expect(rendered).not_to render_template('search/_results')
|
||||
expect(view.page_description).to match(/\d+ issues for term '#{search_term}'/)
|
||||
expect(view.page_card_attributes).to eq("Namespace" => group.full_path)
|
||||
end
|
||||
|
||||
it 'renders meta tags for both group and project' do
|
||||
project = build(:project, group: group)
|
||||
assign(:project, project)
|
||||
|
||||
render
|
||||
|
||||
expect(view.page_description).to match(/\d+ issues for term '#{search_term}'/)
|
||||
expect(view.page_card_attributes).to eq("Namespace" => group.full_path, "Project" => project.full_path)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when search term is supplied' do
|
||||
let(:search_term) { 'Search Foo' }
|
||||
|
||||
it 'renders partials' do
|
||||
render
|
||||
|
||||
expect(rendered).to render_template('search/_category')
|
||||
expect(rendered).to render_template('search/_results')
|
||||
context 'search without full count' do
|
||||
let(:search_service_presenter) do
|
||||
instance_double(SearchServicePresenter, without_count?: true, advanced_search_enabled?: false)
|
||||
end
|
||||
|
||||
context 'unfurling support' do
|
||||
let(:group) { build(:group) }
|
||||
let(:search_results) do
|
||||
instance_double(Gitlab::GroupSearchResults).tap do |double|
|
||||
allow(double).to receive(:formatted_count).and_return(0)
|
||||
end
|
||||
end
|
||||
it 'renders meta tags for a group' do
|
||||
render
|
||||
|
||||
before do
|
||||
assign(:search_results, search_results)
|
||||
assign(:scope, 'issues')
|
||||
assign(:group, group)
|
||||
end
|
||||
expect(view.page_description).to match(/issues results for term '#{search_term}'/)
|
||||
expect(view.page_card_attributes).to eq("Namespace" => group.full_path)
|
||||
end
|
||||
|
||||
context 'search with full count' do
|
||||
let(:search_service_presenter) do
|
||||
instance_double(SearchServicePresenter, without_count?: false, advanced_search_enabled?: false)
|
||||
end
|
||||
it 'renders meta tags for both group and project' do
|
||||
project = build(:project, group: group)
|
||||
assign(:project, project)
|
||||
|
||||
it 'renders meta tags for a group' do
|
||||
render
|
||||
render
|
||||
|
||||
expect(view.page_description).to match(/\d+ issues for term '#{search_term}'/)
|
||||
expect(view.page_card_attributes).to eq("Namespace" => group.full_path)
|
||||
end
|
||||
|
||||
it 'renders meta tags for both group and project' do
|
||||
project = build(:project, group: group)
|
||||
assign(:project, project)
|
||||
|
||||
render
|
||||
|
||||
expect(view.page_description).to match(/\d+ issues for term '#{search_term}'/)
|
||||
expect(view.page_card_attributes).to eq("Namespace" => group.full_path, "Project" => project.full_path)
|
||||
end
|
||||
end
|
||||
|
||||
context 'search without full count' do
|
||||
let(:search_service_presenter) do
|
||||
instance_double(SearchServicePresenter, without_count?: true, advanced_search_enabled?: false)
|
||||
end
|
||||
|
||||
it 'renders meta tags for a group' do
|
||||
render
|
||||
|
||||
expect(view.page_description).to match(/issues results for term '#{search_term}'/)
|
||||
expect(view.page_card_attributes).to eq("Namespace" => group.full_path)
|
||||
end
|
||||
|
||||
it 'renders meta tags for both group and project' do
|
||||
project = build(:project, group: group)
|
||||
assign(:project, project)
|
||||
|
||||
render
|
||||
|
||||
expect(view.page_description).to match(/issues results for term '#{search_term}'/)
|
||||
expect(view.page_card_attributes).to eq("Namespace" => group.full_path, "Project" => project.full_path)
|
||||
end
|
||||
end
|
||||
expect(view.page_description).to match(/issues results for term '#{search_term}'/)
|
||||
expect(view.page_card_attributes).to eq("Namespace" => group.full_path, "Project" => project.full_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue