Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-10-01 03:09:55 +00:00
parent 186e045e14
commit 4ed4dc08a8
36 changed files with 260 additions and 265 deletions

View File

@ -1 +1 @@
0ae7a0079068ca8ad3a074c87e1b39037bdaed80
87acab96b9eb16381a49f2c08a2eaa9664a2fa75

View File

@ -134,11 +134,6 @@
}
}
.label-description-wrapper {
margin-right: 8px;
margin-left: 8px;
}
.prioritized-labels {
margin-bottom: 30px;
@ -201,10 +196,6 @@
}
}
.label-options-toggle {
width: 100%;
}
.label-subscription {
vertical-align: middle;
@ -276,35 +267,6 @@
font-size: $label-font-size;
}
.label-badge-blue {
background-color: $theme-blue-100;
}
.label-badge-gray {
background-color: $gray-50;
}
.label-links {
list-style: none;
margin: 0;
padding: 0;
white-space: nowrap;
}
.label-link-item {
padding: 0;
}
.label-description {
.description-text {
margin-bottom: 10px;
.admin-labels & {
margin-bottom: 0;
}
}
}
.label-list-item {
.content-list &::before,
.content-list &::after {
@ -313,21 +275,12 @@
.label-name {
width: 200px;
flex-shrink: 0;
.gl-label {
line-height: $gl-line-height;
}
}
.label-description {
flex-grow: 1;
a {
color: $blue-600;
}
}
.label {
padding: 4px $grid-size;
font-size: $label-font-size;
@ -382,31 +335,8 @@
text-align: left;
}
.label-links {
white-space: normal;
}
.label-description {
order: 3;
width: 100%;
> .label-description-wrapper {
margin-left: 0;
margin-right: 0;
}
}
}
}
@media (max-width: 910px) {
.priority-badge {
display: block;
width: 100%;
margin-left: 0;
margin-top: $gl-padding;
.label-badge {
display: inline-block;
}
}
}

View File

@ -97,8 +97,6 @@ class SearchController < ApplicationController
end
def eager_load_user_status
return if Feature.disabled?(:users_search, default_enabled: true)
@search_objects = @search_objects.eager_load(:status) # rubocop:disable CodeReuse/ActiveRecord
end

View File

@ -36,11 +36,11 @@ module LabelsHelper
# link_to_label(label) { "My Custom Label Text" }
#
# Returns a String
def link_to_label(label, type: :issue, tooltip: true, small: false, &block)
def link_to_label(label, type: :issue, tooltip: true, small: false, css_class: nil, &block)
link = label.filter_path(type: type)
if block_given?
link_to link, &block
link_to link, class: css_class, &block
else
render_label(label, link: link, tooltip: tooltip, small: small)
end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module SearchHelper
SEARCH_PERMITTED_PARAMS = [:search, :scope, :project_id, :group_id, :repository_ref, :snippets, :state, :confidential].freeze
SEARCH_PERMITTED_PARAMS = [:search, :scope, :project_id, :group_id, :repository_ref, :snippets, :sort, :state, :confidential].freeze
def search_autocomplete_opts(term)
return unless current_user
@ -305,8 +305,6 @@ module SearchHelper
end
def show_user_search_tab?
return false if Feature.disabled?(:users_search, default_enabled: true)
if @project
project_search_tabs?(:members)
else

View File

@ -12,7 +12,7 @@ class SnippetRepository < ApplicationRecord
belongs_to :snippet, inverse_of: :snippet_repository
delegate :repository, to: :snippet
delegate :repository, :repository_storage, to: :snippet
class << self
def find_snippet(disk_path)

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
module NamespaceSettings
class UpdateService
include ::Gitlab::Allowable
attr_reader :current_user, :group, :settings_params
def initialize(current_user, group, settings)
@current_user = current_user
@group = group
@settings_params = settings
end
def execute
if group.namespace_settings
group.namespace_settings.attributes = settings_params
else
group.build_namespace_settings(settings_params)
end
end
end
end
NamespaceSettings::UpdateService.prepend_if_ee('EE::NamespaceSettings::UpdateService')

View File

@ -25,7 +25,10 @@ module Projects
tag_names = tags.map(&:name)
Projects::ContainerRepository::DeleteTagsService
.new(container_repository.project, current_user, tags: tag_names)
.new(container_repository.project,
current_user,
tags: tag_names,
container_expiration_policy: params['container_expiration_policy'])
.execute(container_repository)
end

View File

@ -7,7 +7,10 @@ module Projects
def execute(container_repository)
@container_repository = container_repository
return error('access denied') unless can?(current_user, :destroy_container_image, project)
unless params[:container_expiration_policy]
return error('access denied') unless can?(current_user, :destroy_container_image, project)
end
@tag_names = params[:tags]
return error('not tags specified') if @tag_names.blank?

View File

@ -4,6 +4,8 @@ module Search
class GlobalService
include Gitlab::Utils::StrongMemoize
ALLOWED_SCOPES = %w(issues merge_requests milestones users).freeze
attr_accessor :current_user, :params
def initialize(user, params)
@ -14,6 +16,7 @@ module Search
Gitlab::SearchResults.new(current_user,
params[:search],
projects,
sort: params[:sort],
filters: { state: params[:state], confidential: params[:confidential] })
end
@ -22,11 +25,7 @@ module Search
end
def allowed_scopes
strong_memoize(:allowed_scopes) do
allowed_scopes = %w[issues merge_requests milestones]
allowed_scopes << 'users' if Feature.enabled?(:users_search, default_enabled: true)
allowed_scopes
end
ALLOWED_SCOPES
end
def scope

View File

@ -2,6 +2,10 @@
module Search
class ProjectService
include Gitlab::Utils::StrongMemoize
ALLOWED_SCOPES = %w(notes issues merge_requests milestones wiki_blobs commits users).freeze
attr_accessor :project, :current_user, :params
def initialize(project, user, params)
@ -17,12 +21,13 @@ module Search
)
end
def scope
@scope ||= begin
allowed_scopes = %w[notes issues merge_requests milestones wiki_blobs commits]
allowed_scopes << 'users' if Feature.enabled?(:users_search, default_enabled: true)
def allowed_scopes
ALLOWED_SCOPES
end
allowed_scopes.delete(params[:scope]) { 'blobs' }
def scope
strong_memoize(:scope) do
allowed_scopes.include?(params[:scope]) ? params[:scope] : 'blobs'
end
end
end

View File

@ -27,5 +27,5 @@
= render 'shared/empty_states/labels'
%template#js-badge-item-template
%li.label-link-item.js-priority-badge.inline.gl-ml-3
.label-badge.label-badge-blue= _('Prioritized label')
%li.js-priority-badge.inline.gl-ml-3
.label-badge.gl-bg-blue-50= _('Prioritized label')

View File

@ -73,7 +73,7 @@
%span.gl-sr-only
= s_('Nav|Help')
= sprite_icon('question')
= sprite_icon('angle-down', css_class: 'caret-down')
= sprite_icon('chevron-down', css_class: 'caret-down')
.dropdown-menu.dropdown-menu-right
= render 'layouts/header/help_dropdown'
- if header_link?(:user_dropdown)
@ -81,7 +81,7 @@
= link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown" } do
= image_tag avatar_icon_for_user(current_user, 23), width: 23, height: 23, class: "header-user-avatar qa-user-avatar", alt: current_user.name
= render_if_exists 'layouts/header/user_notification_dot', project: project, namespace: group
= sprite_icon('angle-down', css_class: 'caret-down')
= sprite_icon('chevron-down', css_class: 'caret-down')
.dropdown-menu.dropdown-menu-right
= render 'layouts/header/current_user_dropdown'
- if has_impersonation_link

View File

@ -1,7 +1,7 @@
%li.header-new.dropdown{ data: { track_label: "new_dropdown", track_event: "click_dropdown", track_value: "" } }
= link_to new_project_path, class: "header-new-dropdown-toggle has-tooltip qa-new-menu-toggle", id: "js-onboarding-new-project-link", title: _("New..."), ref: 'tooltip', aria: { label: _("New...") }, data: { toggle: 'dropdown', placement: 'bottom', container: 'body', display: 'static' } do
= sprite_icon('plus-square')
= sprite_icon('angle-down', css_class: 'caret-down')
= sprite_icon('chevron-down', css_class: 'caret-down')
.dropdown-menu.dropdown-menu-right
%ul
- if @group&.persisted?

View File

@ -5,7 +5,7 @@
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown header-projects qa-projects-dropdown", data: { track_label: "projects_dropdown", track_event: "click_dropdown", track_value: "" } }) do
%button{ type: 'button', data: { toggle: "dropdown" } }
= _('Projects')
= sprite_icon('angle-down', css_class: 'caret-down')
= sprite_icon('chevron-down', css_class: 'caret-down')
.dropdown-menu.frequent-items-dropdown-menu
= render "layouts/nav/projects_dropdown/show"
@ -13,7 +13,7 @@
= nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { id: 'nav-groups-dropdown', class: "d-none d-md-block home dropdown header-groups qa-groups-dropdown", data: { track_label: "groups_dropdown", track_event: "click_dropdown", track_value: "" } }) do
%button{ type: 'button', data: { toggle: "dropdown" } }
= _('Groups')
= sprite_icon('angle-down', css_class: 'caret-down')
= sprite_icon('chevron-down', css_class: 'caret-down')
.dropdown-menu.frequent-items-dropdown-menu
= render "layouts/nav/groups_dropdown/show"
@ -21,7 +21,7 @@
%li.header-more.dropdown{ **tracking_attrs('main_navigation', 'click_more_link', 'navigation') }
%a{ href: "#", data: { toggle: "dropdown", qa_selector: 'more_dropdown' } }
= _('More')
= sprite_icon('angle-down', css_class: 'caret-down')
= sprite_icon('chevron-down', css_class: 'caret-down')
.dropdown-menu
%ul
- if dashboard_nav_link?(:groups)

View File

@ -52,5 +52,5 @@
= render 'shared/empty_states/labels'
%template#js-badge-item-template
%li.label-link-item.js-priority-badge.inline.gl-ml-3
.label-badge.label-badge-blue= _('Prioritized label')
%li.js-priority-badge.inline.gl-ml-3
.label-badge.gl-bg-blue-50= _('Prioritized label')

View File

@ -11,7 +11,7 @@
%ul.label-actions-list
- if @project
%li.inline
.label-badge.label-badge-gray= label.model_name.human.capitalize
.label-badge.gl-bg-gray-50= label.model_name.human.capitalize
- if can?(current_user, :admin_label, @project)
%li.inline.js-toggle-priority{ data: { url: remove_priority_project_label_path(@project, label),
dom_id: dom_id(label), type: label.type } }

View File

@ -3,23 +3,22 @@
- show_label_issues_link = subject_or_group_defined && show_label_issuables_link?(label, :issues)
- show_label_merge_requests_link = subject_or_group_defined && show_label_issuables_link?(label, :merge_requests)
.label-name
.label-name.gl-flex-shrink-0.gl-mr-3
= render_label(label, tooltip: false)
.label-description
.label-description-wrapper
- if label.description.present?
.description-text
= markdown_field(label, :description)
%ul.label-links
- if show_label_issues_link
%li.label-link-item.inline
= link_to_label(label) { _('Issues') }
- if show_label_merge_requests_link
&middot;
%li.label-link-item.inline
= link_to_label(label, type: :merge_request) { _('Merge requests') }
- if force_priority
&middot;
%li.label-link-item.priority-badge.js-priority-badge.inline.gl-ml-3
.label-badge.label-badge-blue= _('Prioritized label')
= render_if_exists 'shared/label_row_epics_link', label: label
.label-description.gl-flex-grow-1.gl-mr-3.gl-w-full
- if label.description.present?
.description-text.gl-mb-3
= markdown_field(label, :description)
%ul.label-links.gl-m-0.gl-p-0.gl-white-space-nowrap
- if show_label_issues_link
%li.inline.gl-text-blue-600
= link_to_label(label, css_class: 'gl-text-blue-600!') { _('Issues') }
- if show_label_merge_requests_link
&middot;
%li.inline.gl-text-blue-600
= link_to_label(label, type: :merge_request, css_class: 'gl-text-blue-600!') { _('Merge requests') }
= render_if_exists 'shared/label_row_epics_link', label: label
- if force_priority
&middot;
%li.js-priority-badge.inline.gl-ml-3
.label-badge.gl-bg-blue-50= _('Prioritized label')

View File

@ -29,10 +29,10 @@
%div
= render('shared/milestone_expired', milestone: milestone)
- if milestone.group_milestone?
.label-badge.label-badge-blue.d-inline-block
.label-badge.gl-bg-blue-50.d-inline-block
= milestone.group.full_name
- if milestone.project_milestone?
.label-badge.label-badge-gray.d-inline-block
.label-badge.gl-bg-gray-50.d-inline-block
= milestone.project.full_name
.col-sm-4.milestone-progress

View File

@ -0,0 +1,5 @@
---
title: Fix bug to allow container cleanup policies to properly run
merge_request: 43359
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Add sort parameter to Issue and Merge Request scopes
merge_request: 43295
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Update nav icons to chevron-down
merge_request: 43767
author:
type: changed

View File

@ -1,7 +0,0 @@
---
name: users_search
introduced_by_url:
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/255282
group: group::global search
type: development
default_enabled: true

View File

@ -62,12 +62,6 @@ module API
# Defining this method here as a noop allows us to easily extend it in
# EE, without having to modify this file directly.
end
def check_users_search_allowed!
if params[:scope].to_sym == :users && Feature.disabled?(:users_search, default_enabled: true)
render_api_error!({ error: _("Scope not supported with disabled 'users_search' feature!") }, 400)
end
end
end
resource :search do
@ -85,7 +79,6 @@ module API
end
get do
verify_search_scope!(resource: nil)
check_users_search_allowed!
present search, with: entity
end
@ -107,7 +100,6 @@ module API
end
get ':id/(-/)search' do
verify_search_scope!(resource: user_group)
check_users_search_allowed!
present search(group_id: user_group.id), with: entity
end
@ -129,8 +121,6 @@ module API
use :pagination
end
get ':id/(-/)search' do
check_users_search_allowed!
present search({ project_id: user_project.id, repository_ref: params[:ref] }), with: entity
end
end

View File

@ -60,13 +60,17 @@ module Gitlab
def check_valid_actor!
# TODO: Investigate if expanding actor/authentication types are needed.
# https://gitlab.com/gitlab-org/gitlab/issues/202190
if actor && !actor.is_a?(User) && !actor.instance_of?(Key)
if actor && !allowed_actor?
raise ForbiddenError, ERROR_MESSAGES[:authentication_mechanism]
end
super
end
def allowed_actor?
actor.is_a?(User) || actor.instance_of?(Key)
end
def project_snippet?
snippet.is_a?(ProjectSnippet)
end
@ -138,3 +142,5 @@ module Gitlab
end
end
end
Gitlab::GitAccessSnippet.prepend_if_ee('EE::Gitlab::GitAccessSnippet')

View File

@ -7,7 +7,7 @@ module Gitlab
DEFAULT_PAGE = 1
DEFAULT_PER_PAGE = 20
attr_reader :current_user, :query, :filters
attr_reader :current_user, :query, :sort, :filters
# Limit search results by passed projects
# It allows us to search only for projects user has access to
@ -19,11 +19,12 @@ module Gitlab
# query
attr_reader :default_project_filter
def initialize(current_user, query, limit_projects = nil, default_project_filter: false, filters: {})
def initialize(current_user, query, limit_projects = nil, sort: nil, default_project_filter: false, filters: {})
@current_user = current_user
@query = query
@limit_projects = limit_projects || Project.all
@default_project_filter = default_project_filter
@sort = sort
@filters = filters
end
@ -124,6 +125,19 @@ module Gitlab
end
end
# rubocop: disable CodeReuse/ActiveRecord
def apply_sort(scope)
case sort
when 'oldest'
scope.reorder('created_at ASC')
when 'newest'
scope.reorder('created_at DESC')
else
scope
end
end
# rubocop: enable CodeReuse/ActiveRecord
def projects
limit_projects.search(query)
end
@ -135,7 +149,7 @@ module Gitlab
issues = issues.where(project_id: project_ids_relation) # rubocop: disable CodeReuse/ActiveRecord
end
issues
apply_sort(issues)
end
# rubocop: disable CodeReuse/ActiveRecord
@ -155,7 +169,7 @@ module Gitlab
merge_requests = merge_requests.in_projects(project_ids_relation)
end
merge_requests
apply_sort(merge_requests)
end
def default_scope

View File

@ -4506,9 +4506,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
msgid "Can't remove group members without group managed account"
msgstr ""
msgid "Can't scan the code?"
msgstr ""
@ -12649,9 +12646,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
msgstr ""
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@ -22307,9 +22301,6 @@ msgstr ""
msgid "Scope"
msgstr ""
msgid "Scope not supported with disabled 'users_search' feature!"
msgstr ""
msgid "Scoped issue boards"
msgstr ""

View File

@ -357,14 +357,6 @@ RSpec.describe SearchHelper do
describe '#show_user_search_tab?' do
subject { show_user_search_tab? }
context 'when users_search feature is disabled' do
before do
stub_feature_flags(users_search: false)
end
it { is_expected.to eq(false) }
end
context 'when project search' do
before do
@project = :some_project

View File

@ -4,7 +4,7 @@ require 'fast_spec_helper'
RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
describe '#parse!' do
subject { described_class.new.parse!(junit, test_suite, args) }
subject { described_class.new.parse!(junit, test_suite, **args) }
let(:test_suite) { Gitlab::Ci::Reports::TestSuite.new('rspec') }
let(:test_cases) { flattened_test_cases(test_suite) }

View File

@ -232,29 +232,6 @@ RSpec.describe Gitlab::GitAccessSnippet do
end
end
context 'when geo is enabled', if: Gitlab.ee? do
let(:user) { snippet.author }
let!(:primary_node) { FactoryBot.create(:geo_node, :primary) }
before do
allow(::Gitlab::Database).to receive(:read_only?).and_return(true)
allow(::Gitlab::Geo).to receive(:secondary_with_primary?).and_return(true)
end
# Without override, push access would return Gitlab::GitAccessResult::CustomAction
it 'skips geo for snippet' do
expect { push_access_check }.to raise_forbidden(/You can't push code to a read-only GitLab instance/)
end
context 'when user is migration bot' do
let(:user) { migration_bot }
it 'skips geo for snippet' do
expect { push_access_check }.to raise_forbidden(/You can't push code to a read-only GitLab instance/)
end
end
end
context 'when changes are specific' do
let(:changes) { "2d1db523e11e777e49377cfb22d368deec3f0793 ddd0f15ae83993f5cb66a927a28673882e99100b master" }
let(:user) { snippet.author }

View File

@ -11,9 +11,11 @@ RSpec.describe Gitlab::SearchResults do
let_it_be(:issue) { create(:issue, project: project, title: 'foo') }
let_it_be(:milestone) { create(:milestone, project: project, title: 'foo') }
let(:merge_request) { create(:merge_request, source_project: project, title: 'foo') }
let(:query) { 'foo' }
let(:filters) { {} }
let(:sort) { nil }
subject(:results) { described_class.new(user, 'foo', Project.order(:id), filters: filters) }
subject(:results) { described_class.new(user, query, Project.order(:id), sort: sort, filters: filters) }
context 'as a user with access' do
before do
@ -137,10 +139,12 @@ RSpec.describe Gitlab::SearchResults do
end
describe '#merge_requests' do
let(:scope) { 'merge_requests' }
it 'includes project filter by default' do
expect(results).to receive(:project_ids_relation).and_call_original
results.objects('merge_requests')
results.objects(scope)
end
it 'skips project filter if default project context is used' do
@ -148,24 +152,34 @@ RSpec.describe Gitlab::SearchResults do
expect(results).not_to receive(:project_ids_relation)
results.objects('merge_requests')
results.objects(scope)
end
context 'filtering' do
let!(:opened_result) { create(:merge_request, :opened, source_project: project, title: 'foo opened') }
let!(:closed_result) { create(:merge_request, :closed, source_project: project, title: 'foo closed') }
let(:scope) { 'merge_requests' }
let(:query) { 'foo' }
include_examples 'search results filtered by state'
end
context 'ordering' do
let(:query) { 'sorted' }
let!(:old_result) { create(:merge_request, :opened, source_project: project, source_branch: 'old-1', title: 'sorted old', created_at: 1.month.ago) }
let!(:new_result) { create(:merge_request, :opened, source_project: project, source_branch: 'new-1', title: 'sorted recent', created_at: 1.day.ago) }
let!(:very_old_result) { create(:merge_request, :opened, source_project: project, source_branch: 'very-old-1', title: 'sorted very old', created_at: 1.year.ago) }
include_examples 'search results sorted'
end
end
describe '#issues' do
let(:scope) { 'issues' }
it 'includes project filter by default' do
expect(results).to receive(:project_ids_relation).and_call_original
results.objects('issues')
results.objects(scope)
end
it 'skips project filter if default project context is used' do
@ -173,12 +187,10 @@ RSpec.describe Gitlab::SearchResults do
expect(results).not_to receive(:project_ids_relation)
results.objects('issues')
results.objects(scope)
end
context 'filtering' do
let(:scope) { 'issues' }
let_it_be(:closed_result) { create(:issue, :closed, project: project, title: 'foo closed') }
let_it_be(:opened_result) { create(:issue, :opened, project: project, title: 'foo open') }
let_it_be(:confidential_result) { create(:issue, :confidential, project: project, title: 'foo confidential') }
@ -186,6 +198,15 @@ RSpec.describe Gitlab::SearchResults do
include_examples 'search results filtered by state'
include_examples 'search results filtered by confidential'
end
context 'ordering' do
let(:query) { 'sorted' }
let!(:old_result) { create(:issue, project: project, title: 'sorted old', created_at: 1.month.ago) }
let!(:new_result) { create(:issue, project: project, title: 'sorted recent', created_at: 1.day.ago) }
let!(:very_old_result) { create(:issue, project: project, title: 'sorted very old', created_at: 1.year.ago) }
include_examples 'search results sorted'
end
end
describe '#users' do

View File

@ -231,18 +231,6 @@ RSpec.describe API::Search do
it_behaves_like 'pagination', scope: :users
it_behaves_like 'ping counters', scope: :users
context 'when users search feature is disabled' do
before do
stub_feature_flags(users_search: false)
get api(endpoint, user), params: { scope: 'users', search: 'billy' }
end
it 'returns 400 error' do
expect(response).to have_gitlab_http_status(:bad_request)
end
end
end
context 'for snippet_titles scope' do
@ -416,18 +404,6 @@ RSpec.describe API::Search do
include_examples 'pagination', scope: :users
end
context 'when users search feature is disabled' do
before do
stub_feature_flags(users_search: false)
get api(endpoint, user), params: { scope: 'users', search: 'billy' }
end
it 'returns 400 error' do
expect(response).to have_gitlab_http_status(:bad_request)
end
end
end
context 'for users scope with group path as id' do
@ -589,18 +565,6 @@ RSpec.describe API::Search do
include_examples 'pagination', scope: :users
end
context 'when users search feature is disabled' do
before do
stub_feature_flags(users_search: false)
get api(endpoint, user), params: { scope: 'users', search: 'billy' }
end
it 'returns 400 error' do
expect(response).to have_gitlab_http_status(:bad_request)
end
end
end
context 'for notes scope' do

View File

@ -0,0 +1,35 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe NamespaceSettings::UpdateService do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:settings) { {} }
subject(:service) { described_class.new(user, group, settings) }
describe "#execute" do
context "group has no namespace_settings" do
it "builds out a new namespace_settings record" do
expect do
service.execute
end.to change { NamespaceSetting.count }.by(1)
end
end
context "group has a namespace_settings" do
before do
create(:namespace_settings, namespace: group)
service.execute
end
it "doesn't create a new namespace_setting record" do
expect do
service.execute
end.not_to change { NamespaceSetting.count }
end
end
end
end

View File

@ -245,7 +245,7 @@ RSpec.describe Projects::ContainerRepository::CleanupTagsService do
end
it 'succeeds without a user' do
expect_delete(%w(Bb Ba C))
expect_delete(%w(Bb Ba C), container_expiration_policy: true)
is_expected.to include(status: :success, deleted: %w(Bb Ba C))
end
@ -287,10 +287,10 @@ RSpec.describe Projects::ContainerRepository::CleanupTagsService do
end
end
def expect_delete(tags)
def expect_delete(tags, container_expiration_policy: nil)
expect(Projects::ContainerRepository::DeleteTagsService)
.to receive(:new)
.with(repository.project, user, tags: tags)
.with(repository.project, user, tags: tags, container_expiration_policy: container_expiration_policy)
.and_call_original
expect_any_instance_of(Projects::ContainerRepository::DeleteTagsService)

View File

@ -85,6 +85,41 @@ RSpec.describe Projects::ContainerRepository::DeleteTagsService do
end
end
RSpec.shared_examples 'supporting fast delete' do
context 'when the registry supports fast delete' do
before do
allow(repository.client).to receive(:supports_tag_delete?).and_return(true)
end
it_behaves_like 'calling the correct delete tags service', ::Projects::ContainerRepository::Gitlab::DeleteTagsService
it_behaves_like 'handling invalid params'
context 'with the real service' do
before do
stub_delete_reference_requests(tags)
expect_delete_tag_by_names(tags)
end
it { is_expected.to include(status: :success) }
it_behaves_like 'logging a success response'
end
context 'with a timeout error' do
before do
expect_next_instance_of(::Projects::ContainerRepository::Gitlab::DeleteTagsService) do |delete_service|
expect(delete_service).to receive(:delete_tags).and_raise(::Projects::ContainerRepository::Gitlab::DeleteTagsService::TimeoutError)
end
end
it { is_expected.to include(status: :error, message: 'timeout while deleting tags') }
it_behaves_like 'logging an error response', message: 'timeout while deleting tags'
end
end
end
describe '#execute' do
let(:tags) { %w[A Ba] }
@ -103,38 +138,7 @@ RSpec.describe Projects::ContainerRepository::DeleteTagsService do
project.add_developer(user)
end
context 'when the registry supports fast delete' do
before do
allow(repository.client).to receive(:supports_tag_delete?).and_return(true)
end
it_behaves_like 'calling the correct delete tags service', ::Projects::ContainerRepository::Gitlab::DeleteTagsService
it_behaves_like 'handling invalid params'
context 'with the real service' do
before do
stub_delete_reference_requests(tags)
expect_delete_tag_by_names(tags)
end
it { is_expected.to include(status: :success) }
it_behaves_like 'logging a success response'
end
context 'with a timeout error' do
before do
expect_next_instance_of(::Projects::ContainerRepository::Gitlab::DeleteTagsService) do |delete_service|
expect(delete_service).to receive(:delete_tags).and_raise(::Projects::ContainerRepository::Gitlab::DeleteTagsService::TimeoutError)
end
end
it { is_expected.to include(status: :error, message: 'timeout while deleting tags') }
it_behaves_like 'logging an error response', message: 'timeout while deleting tags'
end
end
it_behaves_like 'supporting fast delete'
context 'when the registry does not support fast delete' do
before do
@ -146,5 +150,19 @@ RSpec.describe Projects::ContainerRepository::DeleteTagsService do
it_behaves_like 'handling invalid params'
end
end
context 'without user' do
let_it_be(:user) { nil }
context 'when not run by a cleanup policy' do
it { is_expected.to include(status: :error) }
end
context 'when run by a cleanup policy' do
let(:params) { { tags: tags, container_expiration_policy: true } }
it_behaves_like 'supporting fast delete'
end
end
end
end

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
RSpec.shared_examples 'search results sorted' do
context 'sort: newest' do
let(:sort) { 'newest' }
it 'sorts results by created_at' do
expect(results.objects(scope).map(&:id)).to eq([new_result.id, old_result.id, very_old_result.id])
end
end
context 'sort: oldest' do
let(:sort) { 'oldest' }
it 'sorts results by created_at' do
expect(results.objects(scope).map(&:id)).to eq([very_old_result.id, old_result.id, new_result.id])
end
end
end