Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-06-03 18:08:54 +00:00
parent f5f6cb45c7
commit 27484d1465
38 changed files with 562 additions and 198 deletions

View file

@ -1,5 +1,6 @@
<script> <script>
import { GlButton, GlSafeHtmlDirective } from '@gitlab/ui'; import { GlButton, GlSafeHtmlDirective } from '@gitlab/ui';
import { snakeCase } from 'lodash';
import highlight from '~/lib/utils/highlight'; import highlight from '~/lib/utils/highlight';
import { truncateNamespace } from '~/lib/utils/text_utility'; import { truncateNamespace } from '~/lib/utils/text_utility';
import { mapVuexModuleState } from '~/lib/utils/vuex_module_mappers'; import { mapVuexModuleState } from '~/lib/utils/vuex_module_mappers';
@ -56,6 +57,9 @@ export default {
highlightedItemName() { highlightedItemName() {
return highlight(this.itemName, this.matcher); return highlight(this.itemName, this.matcher);
}, },
itemTrackingLabel() {
return `${this.dropdownType}_dropdown_frequent_items_list_item_${snakeCase(this.itemName)}`;
},
}, },
}; };
</script> </script>
@ -66,7 +70,7 @@ export default {
category="tertiary" category="tertiary"
:href="webUrl" :href="webUrl"
class="gl-text-left gl-justify-content-start!" class="gl-text-left gl-justify-content-start!"
@click="track('click_link', { label: `${dropdownType}_dropdown_frequent_items_list_item` })" @click="track('click_link', { label: itemTrackingLabel })"
> >
<project-avatar <project-avatar
class="gl-float-left gl-mr-3" class="gl-float-left gl-mr-3"

View file

@ -30,12 +30,46 @@ export const integrationFormSections = {
CONNECTION: 'connection', CONNECTION: 'connection',
JIRA_TRIGGER: 'jira_trigger', JIRA_TRIGGER: 'jira_trigger',
JIRA_ISSUES: 'jira_issues', JIRA_ISSUES: 'jira_issues',
TRIGGER: 'trigger',
}; };
export const integrationFormSectionComponents = { export const integrationFormSectionComponents = {
[integrationFormSections.CONNECTION]: 'IntegrationSectionConnection', [integrationFormSections.CONNECTION]: 'IntegrationSectionConnection',
[integrationFormSections.JIRA_TRIGGER]: 'IntegrationSectionJiraTrigger', [integrationFormSections.JIRA_TRIGGER]: 'IntegrationSectionJiraTrigger',
[integrationFormSections.JIRA_ISSUES]: 'IntegrationSectionJiraIssues', [integrationFormSections.JIRA_ISSUES]: 'IntegrationSectionJiraIssues',
[integrationFormSections.TRIGGER]: 'IntegrationSectionTrigger',
};
export const integrationTriggerEvents = {
PUSH: 'push_events',
ISSUE: 'issues_events',
CONFIDENTIAL_ISSUE: 'confidential_issues_events',
MERGE_REQUEST: 'merge_requests_events',
NOTE: 'note_events',
CONFIDENTIAL_NOTE: 'confidential_note_events',
TAG_PUSH: 'tag_push_events',
PIPELINE: 'pipeline_events',
WIKI_PAGE: 'wiki_page_events',
};
export const integrationTriggerEventTitles = {
[integrationTriggerEvents.PUSH]: s__('IntegrationEvents|A push is made to the repository'),
[integrationTriggerEvents.ISSUE]: s__(
'IntegrationEvents|An issue is created, updated, or closed',
),
[integrationTriggerEvents.CONFIDENTIAL_ISSUE]: s__(
'IntegrationEvents|A confidential issue is created, updated, or closed',
),
[integrationTriggerEvents.MERGE_REQUEST]: s__(
'IntegrationEvents|A merge request is created, updated, or merged',
),
[integrationTriggerEvents.NOTE]: s__('IntegrationEvents|A comment is added on an issue'),
[integrationTriggerEvents.CONFIDENTIAL_NOTE]: s__(
'IntegrationEvents|A comment is added on a confidential issue',
),
[integrationTriggerEvents.TAG_PUSH]: s__('IntegrationEvents|A tag is pushed to the repository'),
[integrationTriggerEvents.PIPELINE]: s__('IntegrationEvents|A pipeline status changes'),
[integrationTriggerEvents.WIKI_PAGE]: s__('IntegrationEvents|A wiki page is created or updated'),
}; };
export const billingPlans = { export const billingPlans = {

View file

@ -49,6 +49,10 @@ export default {
import( import(
/* webpackChunkName: 'integrationSectionJiraTrigger' */ '~/integrations/edit/components/sections/jira_trigger.vue' /* webpackChunkName: 'integrationSectionJiraTrigger' */ '~/integrations/edit/components/sections/jira_trigger.vue'
), ),
IntegrationSectionTrigger: () =>
import(
/* webpackChunkName: 'integrationSectionTrigger' */ '~/integrations/edit/components/sections/trigger.vue'
),
GlBadge, GlBadge,
GlButton, GlButton,
GlForm, GlForm,

View file

@ -0,0 +1,26 @@
<script>
import { mapGetters } from 'vuex';
import TriggerField from '../trigger_field.vue';
export default {
name: 'IntegrationSectionTrigger',
components: {
TriggerField,
},
computed: {
...mapGetters(['currentKey', 'propsSource']),
},
};
</script>
<template>
<div>
<trigger-field
v-for="event in propsSource.triggerEvents"
:key="`${currentKey}-trigger-fields-${event.name}`"
:event="event"
class="gl-mb-3"
/>
</div>
</template>

View file

@ -0,0 +1,46 @@
<script>
import { GlFormCheckbox } from '@gitlab/ui';
import { mapGetters } from 'vuex';
import { integrationTriggerEventTitles } from '~/integrations/constants';
export default {
name: 'TriggerField',
components: {
GlFormCheckbox,
},
props: {
event: {
type: Object,
required: false,
default: () => ({}),
},
},
data() {
return {
value: false,
};
},
computed: {
...mapGetters(['isInheriting']),
name() {
return `service[${this.event.name}]`;
},
title() {
return integrationTriggerEventTitles[this.event.name];
},
},
mounted() {
this.value = this.event.value || false;
},
};
</script>
<template>
<div>
<input :name="name" type="hidden" :value="value" />
<gl-form-checkbox v-model="value" :disabled="isInheriting">
{{ title }}
</gl-form-checkbox>
</div>
</template>

View file

@ -83,7 +83,7 @@ function parseDatasetToProps(data) {
learnMorePath, learnMorePath,
aboutPricingUrl, aboutPricingUrl,
triggerEvents: JSON.parse(triggerEvents), triggerEvents: JSON.parse(triggerEvents),
sections: JSON.parse(sections, { deep: true }), sections: JSON.parse(sections),
fields: convertObjectPropsToCamelCase(JSON.parse(fields), { deep: true }), fields: convertObjectPropsToCamelCase(JSON.parse(fields), { deep: true }),
inheritFromId: parseInt(inheritFromId, 10), inheritFromId: parseInt(inheritFromId, 10),
integrationLevel, integrationLevel,

View file

@ -45,7 +45,7 @@ module Registrations
end end
def update_params def update_params
params.require(:user).permit(:role, :other_role, :setup_for_company) params.require(:user).permit(:role, :setup_for_company)
end end
def requires_confirmation?(user) def requires_confirmation?(user)

View file

@ -127,7 +127,7 @@ module Nav
href: dashboard_milestones_path, href: dashboard_milestones_path,
active: active_nav_link?(controller: 'dashboard/milestones'), active: active_nav_link?(controller: 'dashboard/milestones'),
icon: 'clock', icon: 'clock',
data: { qa_selector: 'milestones_link' }, data: { qa_selector: 'milestones_link', **menu_data_tracking_attrs('milestones') },
shortcut_class: 'dashboard-shortcuts-milestones' shortcut_class: 'dashboard-shortcuts-milestones'
) )
end end
@ -135,7 +135,7 @@ module Nav
if dashboard_nav_link?(:snippets) if dashboard_nav_link?(:snippets)
builder.add_primary_menu_item_with_shortcut( builder.add_primary_menu_item_with_shortcut(
active: active_nav_link?(controller: 'dashboard/snippets'), active: active_nav_link?(controller: 'dashboard/snippets'),
data: { qa_selector: 'snippets_link' }, data: { qa_selector: 'snippets_link', **menu_data_tracking_attrs('snippets') },
href: dashboard_snippets_path, href: dashboard_snippets_path,
**snippets_menu_item_attrs **snippets_menu_item_attrs
) )
@ -148,7 +148,7 @@ module Nav
href: activity_dashboard_path, href: activity_dashboard_path,
active: active_nav_link?(path: 'dashboard#activity'), active: active_nav_link?(path: 'dashboard#activity'),
icon: 'history', icon: 'history',
data: { qa_selector: 'activity_link' }, data: { qa_selector: 'activity_link', **menu_data_tracking_attrs('activity') },
shortcut_class: 'dashboard-shortcuts-activity' shortcut_class: 'dashboard-shortcuts-activity'
) )
end end
@ -158,13 +158,16 @@ module Nav
# we should be good. # we should be good.
# rubocop: disable Cop/UserAdmin # rubocop: disable Cop/UserAdmin
if current_user&.admin? if current_user&.admin?
title = _('Admin')
builder.add_secondary_menu_item( builder.add_secondary_menu_item(
id: 'admin', id: 'admin',
title: _('Admin'), title: title,
active: active_nav_link?(controller: 'admin/dashboard'), active: active_nav_link?(controller: 'admin/dashboard'),
icon: 'admin', icon: 'admin',
css_class: 'qa-admin-area-link', css_class: 'qa-admin-area-link',
href: admin_root_path href: admin_root_path,
data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
) )
end end
@ -176,15 +179,18 @@ module Nav
active: active_nav_link?(controller: 'admin/sessions'), active: active_nav_link?(controller: 'admin/sessions'),
icon: 'lock-open', icon: 'lock-open',
href: destroy_admin_session_path, href: destroy_admin_session_path,
data: { method: 'post' } data: { method: 'post', **menu_data_tracking_attrs('leave_admin_mode') }
) )
elsif current_user.admin? elsif current_user.admin?
title = _('Enter Admin Mode')
builder.add_secondary_menu_item( builder.add_secondary_menu_item(
id: 'enter_admin_mode', id: 'enter_admin_mode',
title: _('Enter Admin Mode'), title: title,
active: active_nav_link?(controller: 'admin/sessions'), active: active_nav_link?(controller: 'admin/sessions'),
icon: 'lock', icon: 'lock',
href: new_admin_session_path href: new_admin_session_path,
data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
) )
end end
end end
@ -218,6 +224,14 @@ module Nav
} }
end end
def menu_data_tracking_attrs(label)
tracking_attrs(
"menu_#{label.underscore.parameterize(separator: '_')}",
'click_dropdown',
'navigation'
)[:data] || {}
end
def container_view_props(namespace:, current_item:, submenu:) def container_view_props(namespace:, current_item:, submenu:)
{ {
namespace: namespace, namespace: namespace,
@ -260,21 +274,51 @@ module Nav
def projects_submenu_items(builder:) def projects_submenu_items(builder:)
# These project links come from `app/views/layouts/nav/projects_dropdown/_show.html.haml` # These project links come from `app/views/layouts/nav/projects_dropdown/_show.html.haml`
builder.add_primary_menu_item(id: 'your', title: _('Your projects'), href: dashboard_projects_path) [
builder.add_primary_menu_item(id: 'starred', title: _('Starred projects'), href: starred_dashboard_projects_path) { id: 'your', title: _('Your projects'), href: dashboard_projects_path },
builder.add_primary_menu_item(id: 'explore', title: _('Explore projects'), href: explore_root_path) { id: 'starred', title: _('Starred projects'), href: starred_dashboard_projects_path },
builder.add_primary_menu_item(id: 'topics', title: _('Explore topics'), href: topics_explore_projects_path) { id: 'explore', title: _('Explore projects'), href: explore_root_path },
builder.add_secondary_menu_item(id: 'create', title: _('Create new project'), href: new_project_path) { id: 'topics', title: _('Explore topics'), href: topics_explore_projects_path }
].each do |item|
builder.add_primary_menu_item(
**item,
data: { qa_selector: 'menu_item_link', qa_title: item[:title], **menu_data_tracking_attrs(item[:title]) }
)
end
title = _('Create new project')
builder.add_secondary_menu_item(
id: 'create',
title: title,
href: new_project_path,
data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
)
end end
def groups_submenu def groups_submenu
# These group links come from `app/views/layouts/nav/groups_dropdown/_show.html.haml` # These group links come from `app/views/layouts/nav/groups_dropdown/_show.html.haml`
builder = ::Gitlab::Nav::TopNavMenuBuilder.new builder = ::Gitlab::Nav::TopNavMenuBuilder.new
builder.add_primary_menu_item(id: 'your', title: _('Your groups'), href: dashboard_groups_path)
builder.add_primary_menu_item(id: 'explore', title: _('Explore groups'), href: explore_groups_path) [
{ id: 'your', title: _('Your groups'), href: dashboard_groups_path },
{ id: 'explore', title: _('Explore groups'), href: explore_groups_path }
].each do |item|
builder.add_primary_menu_item(
**item,
data: { qa_selector: 'menu_item_link', qa_title: item[:title], **menu_data_tracking_attrs(item[:title]) }
)
end
if current_user.can_create_group? if current_user.can_create_group?
builder.add_secondary_menu_item(id: 'create', title: _('Create group'), href: new_group_path) title = _('Create group')
builder.add_secondary_menu_item(
id: 'create',
title: title,
href: new_group_path,
data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
)
end end
builder.build builder.build

View file

@ -338,7 +338,6 @@ class User < ApplicationRecord
delegate :path, to: :namespace, allow_nil: true, prefix: true delegate :path, to: :namespace, allow_nil: true, prefix: true
delegate :job_title, :job_title=, to: :user_detail, allow_nil: true delegate :job_title, :job_title=, to: :user_detail, allow_nil: true
delegate :other_role, :other_role=, to: :user_detail, allow_nil: true
delegate :bio, :bio=, to: :user_detail, allow_nil: true delegate :bio, :bio=, to: :user_detail, allow_nil: true
delegate :webauthn_xid, :webauthn_xid=, to: :user_detail, allow_nil: true delegate :webauthn_xid, :webauthn_xid=, to: :user_detail, allow_nil: true
delegate :pronouns, :pronouns=, to: :user_detail, allow_nil: true delegate :pronouns, :pronouns=, to: :user_detail, allow_nil: true

View file

@ -2,6 +2,9 @@
class UserDetail < ApplicationRecord class UserDetail < ApplicationRecord
extend ::Gitlab::Utils::Override extend ::Gitlab::Utils::Override
include IgnorableColumns
ignore_columns :other_role, remove_after: '2022-07-22', remove_with: '15.3'
REGISTRATION_OBJECTIVE_PAIRS = { basics: 0, move_repository: 1, code_storage: 2, exploring: 3, ci: 4, other: 5, joining_team: 6 }.freeze REGISTRATION_OBJECTIVE_PAIRS = { basics: 0, move_repository: 1, code_storage: 2, exploring: 3, ci: 4, other: 5, joining_team: 6 }.freeze

View file

@ -16,7 +16,7 @@
= _('Next') = _('Next')
- if current_user - if current_user
.gl-display-none.gl-sm-display-block{ **tracking_attrs('Menu', 'click_dropdown', 'navigation') } .gl-display-none.gl-sm-display-block
= render "layouts/nav/top_nav" = render "layouts/nav/top_nav"
- else - else
- experiment(:logged_out_marketing_header, actor: nil) do |e| - experiment(:logged_out_marketing_header, actor: nil) do |e|

View file

@ -24,11 +24,6 @@
.form-group.col-sm-12 .form-group.col-sm-12
= f.label :role, _('Role'), class: 'label-bold' = f.label :role, _('Role'), class: 'label-bold'
= f.select :role, ::User.roles.keys.map { |role| [role.titleize, role] }, { include_blank: _('Select a role') }, class: 'form-control js-user-role-dropdown', autofocus: true, required: true, data: { qa_selector: 'role_dropdown' } = f.select :role, ::User.roles.keys.map { |role| [role.titleize, role] }, { include_blank: _('Select a role') }, class: 'form-control js-user-role-dropdown', autofocus: true, required: true, data: { qa_selector: 'role_dropdown' }
- if Feature.enabled?(:user_other_role_details)
.row
.form-group.col-sm-12.js-other-role-group.hidden
= f.label :other_role, _('What is your job title? (optional)')
= f.text_field :other_role, class: 'form-control'
= render_if_exists "registrations/welcome/jobs_to_be_done", f: f = render_if_exists "registrations/welcome/jobs_to_be_done", f: f
= render_if_exists "registrations/welcome/setup_for_company", f: f = render_if_exists "registrations/welcome/setup_for_company", f: f
= render_if_exists "registrations/welcome/joining_project" = render_if_exists "registrations/welcome/joining_project"

View file

@ -13,8 +13,6 @@ module Database
version 1 version 1
def perform def perform
return if Feature.disabled?(:ci_namespace_mirrors_consistency_check)
results = ConsistencyCheckService.new( results = ConsistencyCheckService.new(
source_model: Namespace, source_model: Namespace,
target_model: Ci::NamespaceMirror, target_model: Ci::NamespaceMirror,

View file

@ -13,8 +13,6 @@ module Database
version 1 version 1
def perform def perform
return if Feature.disabled?(:ci_project_mirrors_consistency_check)
results = ConsistencyCheckService.new( results = ConsistencyCheckService.new(
source_model: Project, source_model: Project,
target_model: Ci::ProjectMirror, target_model: Ci::ProjectMirror,

View file

@ -1,8 +0,0 @@
---
name: ci_namespace_mirrors_consistency_check
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81836
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/356577
milestone: '14.10'
type: development
group: group::sharding
default_enabled: true

View file

@ -1,8 +0,0 @@
---
name: ci_project_mirrors_consistency_check
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81836
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/356583
milestone: '14.10'
type: development
group: group::sharding
default_enabled: true

View file

@ -1,8 +0,0 @@
---
name: user_other_role_details
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45635
rollout_issue_url: https://gitlab.com/gitlab-org/growth/team-tasks/-/issues/282
milestone: '13.7'
type: development
group: group::conversion
default_enabled: false

View file

@ -1,8 +0,0 @@
---
name: vsa_incremental_worker
introduced_by_url:
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/353453
milestone: '14.9'
type: development
group: group::optimize
default_enabled: true

View file

@ -138,3 +138,28 @@ installed Ruby manually or via tools like `asdf`. Users of the `gitlab-developme
are also affected by this problem. are also affected by this problem.
Build images are not affected because they include the patch set addressing this bug. Build images are not affected because they include the patch set addressing this bug.
## Deprecations are not caught in DeprecationToolkit if the method is stubbed
We rely on `deprecation_toolkit` to fail fast when using functionality that is deprecated in Ruby 2 and removed in Ruby 3.
A common issue caught during the transition from Ruby 2 to Ruby 3 relates to
the [separation of positional and keyword arguments in Ruby 3.0](https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/).
Unfortunately, if the author has stubbed such methods in tests, deprecations would not be caught.
We run automated detection for this warning in tests via `deprecation_toolkit`,
but it relies on the fact that `Kernel#warn` emits a warning, so stubbing out this call will effectively remove the call to warn, which means `deprecation_toolkit` will never see the deprecation warnings.
Stubbing out the implementation removes that warning, and we never pick it up, so the build is green.
Please refer to [issue 364099](https://gitlab.com/gitlab-org/gitlab/-/issues/364099) for more context.
## Testing in `irb` and `rails console`
Another pitfall is that testing in `irb`/`rails c` silences the deprecation warning,
since `irb` in Ruby 2.7.x has a [bug](https://bugs.ruby-lang.org/issues/17377) that prevents deprecation warnings from showing.
When writing code and performing code reviews, pay extra attention to method calls of the form `f({k: v})`.
This is valid in Ruby 2 when `f` takes either a `Hash` or keyword arguments, but Ruby 3 only considers this valid if `f` takes a `Hash`.
For Ruby 3 compliance, this should be changed to one of the following invocations if `f` takes keyword arguments:
- `f(**{k: v})`
- `f(k: v)`

View file

@ -1,7 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
# Check a user's access to perform a git action. All public methods in this # Checks a user's access to perform a git action.
# class return an instance of `GitlabAccessStatus` # All public methods in this class return an instance of `GitlabAccessStatus`
module Gitlab module Gitlab
class GitAccess class GitAccess
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
@ -99,7 +100,7 @@ module Gitlab
@logger ||= Checks::TimedLogger.new(timeout: INTERNAL_TIMEOUT, header: LOG_HEADER) @logger ||= Checks::TimedLogger.new(timeout: INTERNAL_TIMEOUT, header: LOG_HEADER)
end end
def guest_can_download_code? def guest_can_download?
Guest.can?(download_ability, container) Guest.can?(download_ability, container)
end end
@ -110,7 +111,7 @@ module Gitlab
(project? && project&.repository_access_level != ::Featurable::DISABLED) (project? && project&.repository_access_level != ::Featurable::DISABLED)
end end
def user_can_download_code? def user_can_download?
authentication_abilities.include?(:download_code) && authentication_abilities.include?(:download_code) &&
user_access.can_do_action?(download_ability) user_access.can_do_action?(download_ability)
end end
@ -125,10 +126,6 @@ module Gitlab
raise NotImplementedError raise NotImplementedError
end end
def build_can_download_code?
authentication_abilities.include?(:build_download_code) && user_access.can_do_action?(:build_download_code)
end
def request_from_ci_build? def request_from_ci_build?
return false unless protocol == 'http' return false unless protocol == 'http'
@ -141,6 +138,31 @@ module Gitlab
private private
# when accessing via the CI_JOB_TOKEN
def build_can_download_code?
authentication_abilities.include?(:build_download_code) && user_access.can_do_action?(:build_download_code)
end
def build_can_download?
build_can_download_code?
end
def deploy_token_can_download?
deploy_token?
end
# When overriding this method, be careful using super
# as deploy_token_can_download? and build_can_download?
# do not consider the download_ability in the inheriting class
# for deploy tokens and builds
def can_download?
deploy_key_can_download_code? ||
deploy_token_can_download? ||
build_can_download? ||
user_can_download? ||
guest_can_download?
end
def check_container! def check_container!
# Strict nil check, to avoid any surprises with Object#present? # Strict nil check, to avoid any surprises with Object#present?
# which can delegate to #empty? # which can delegate to #empty?
@ -273,16 +295,10 @@ module Gitlab
end end
def check_download_access! def check_download_access!
passed = deploy_key_can_download_code? || return if can_download?
deploy_token? ||
user_can_download_code? ||
build_can_download_code? ||
guest_can_download_code?
unless passed
raise ForbiddenError, download_forbidden_message raise ForbiddenError, download_forbidden_message
end end
end
def download_forbidden_message def download_forbidden_message
error_message(:download) error_message(:download)

View file

@ -90,13 +90,14 @@ module Gitlab
super super
end end
override :check_download_access! override :can_download?
def check_download_access! def can_download?
passed = guest_can_download_code? || user_can_download_code? guest_can_download? || user_can_download?
unless passed
raise ForbiddenError, error_message(:read_snippet)
end end
override :download_forbidden_message
def download_forbidden_message
error_message(:read_snippet)
end end
override :check_change_access! override :check_change_access!

View file

@ -27,12 +27,16 @@ module Gitlab
:create_wiki :create_wiki
end end
override :check_download_access! private
def check_download_access!
super
raise ForbiddenError, download_forbidden_message if build_cannot_download? override :build_can_download?
raise ForbiddenError, download_forbidden_message if deploy_token_cannot_download? def build_can_download?
super && user_access.can_do_action?(download_ability)
end
override :deploy_token_can_download?
def deploy_token_can_download?
super && deploy_token.can?(download_ability, container)
end end
override :check_change_access! override :check_change_access!
@ -53,17 +57,6 @@ module Gitlab
def not_found_message def not_found_message
error_message(:not_found) error_message(:not_found)
end end
private
# when accessing via the CI_JOB_TOKEN
def build_cannot_download?
build_can_download_code? && !user_access.can_do_action?(download_ability)
end
def deploy_token_cannot_download?
deploy_token && !deploy_token.can?(download_ability, container)
end
end end
end end

View file

@ -20464,6 +20464,33 @@ msgstr ""
msgid "Integration Settings" msgid "Integration Settings"
msgstr "" msgstr ""
msgid "IntegrationEvents|A comment is added on a confidential issue"
msgstr ""
msgid "IntegrationEvents|A comment is added on an issue"
msgstr ""
msgid "IntegrationEvents|A confidential issue is created, updated, or closed"
msgstr ""
msgid "IntegrationEvents|A merge request is created, updated, or merged"
msgstr ""
msgid "IntegrationEvents|A pipeline status changes"
msgstr ""
msgid "IntegrationEvents|A push is made to the repository"
msgstr ""
msgid "IntegrationEvents|A tag is pushed to the repository"
msgstr ""
msgid "IntegrationEvents|A wiki page is created or updated"
msgstr ""
msgid "IntegrationEvents|An issue is created, updated, or closed"
msgstr ""
msgid "Integrations" msgid "Integrations"
msgstr "" msgstr ""
@ -42780,9 +42807,6 @@ msgstr ""
msgid "What is squashing?" msgid "What is squashing?"
msgstr "" msgstr ""
msgid "What is your job title? (optional)"
msgstr ""
msgid "What templates can I create?" msgid "What templates can I create?"
msgstr "" msgstr ""

View file

@ -57,7 +57,7 @@
"@gitlab/at.js": "1.5.7", "@gitlab/at.js": "1.5.7",
"@gitlab/favicon-overlay": "2.0.0", "@gitlab/favicon-overlay": "2.0.0",
"@gitlab/svgs": "2.14.0", "@gitlab/svgs": "2.14.0",
"@gitlab/ui": "40.6.6", "@gitlab/ui": "40.7.1",
"@gitlab/visual-review-tools": "1.7.3", "@gitlab/visual-review-tools": "1.7.3",
"@rails/actioncable": "6.1.4-7", "@rails/actioncable": "6.1.4-7",
"@rails/ujs": "6.1.4-7", "@rails/ujs": "6.1.4-7",

View file

@ -95,7 +95,7 @@ RSpec.describe 'User adds pages domain', :js do
fill_in 'Domain', with: 'my.test.domain.com' fill_in 'Domain', with: 'my.test.domain.com'
find('.js-auto-ssl-toggle-container .js-project-feature-toggle').click find('.js-auto-ssl-toggle-container .js-project-feature-toggle button').click
fill_in 'Certificate (PEM)', with: certificate_pem fill_in 'Certificate (PEM)', with: certificate_pem
fill_in 'Key (PEM)', with: certificate_key fill_in 'Key (PEM)', with: certificate_key

View file

@ -50,7 +50,7 @@ RSpec.describe "Pages with Let's Encrypt", :https_pages_enabled do
expect(page).to have_selector '.card-header', text: 'Certificate' expect(page).to have_selector '.card-header', text: 'Certificate'
expect(page).to have_text domain.subject expect(page).to have_text domain.subject
find('.js-auto-ssl-toggle-container .js-project-feature-toggle').click find('.js-auto-ssl-toggle-container .js-project-feature-toggle button').click
expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'true' expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'true'
expect(page).not_to have_selector '.card-header', text: 'Certificate' expect(page).not_to have_selector '.card-header', text: 'Certificate'
@ -74,7 +74,7 @@ RSpec.describe "Pages with Let's Encrypt", :https_pages_enabled do
expect(page).not_to have_field 'Certificate (PEM)', type: 'textarea' expect(page).not_to have_field 'Certificate (PEM)', type: 'textarea'
expect(page).not_to have_field 'Key (PEM)', type: 'textarea' expect(page).not_to have_field 'Key (PEM)', type: 'textarea'
find('.js-auto-ssl-toggle-container .js-project-feature-toggle').click find('.js-auto-ssl-toggle-container .js-project-feature-toggle button').click
expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'false' expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'false'
expect(page).to have_field 'Certificate (PEM)', type: 'textarea' expect(page).to have_field 'Certificate (PEM)', type: 'textarea'

View file

@ -117,7 +117,7 @@ describe('FrequentItemsListItemComponent', () => {
link.vm.$emit('click'); link.vm.$emit('click');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_link', { expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_link', {
label: 'projects_dropdown_frequent_items_list_item', label: 'projects_dropdown_frequent_items_list_item_git_lab_community_edition',
}); });
}); });
}); });

View file

@ -0,0 +1,38 @@
import { shallowMount } from '@vue/test-utils';
import IntegrationSectionTrigger from '~/integrations/edit/components/sections/trigger.vue';
import TriggerField from '~/integrations/edit/components/trigger_field.vue';
import { createStore } from '~/integrations/edit/store';
import { mockIntegrationProps } from '../../mock_data';
describe('IntegrationSectionTrigger', () => {
let wrapper;
const createComponent = () => {
const store = createStore({
customState: { ...mockIntegrationProps },
});
wrapper = shallowMount(IntegrationSectionTrigger, {
store,
});
};
afterEach(() => {
wrapper.destroy();
});
const findAllTriggerFields = () => wrapper.findAllComponents(TriggerField);
describe('template', () => {
it('renders correct number of TriggerField components', () => {
createComponent();
const fields = findAllTriggerFields();
expect(fields.length).toBe(mockIntegrationProps.triggerEvents.length);
fields.wrappers.forEach((field, index) => {
expect(field.props('event')).toBe(mockIntegrationProps.triggerEvents[index]);
});
});
});
});

View file

@ -0,0 +1,71 @@
import { nextTick } from 'vue';
import { shallowMount } from '@vue/test-utils';
import { GlFormCheckbox } from '@gitlab/ui';
import TriggerField from '~/integrations/edit/components/trigger_field.vue';
import { integrationTriggerEventTitles } from '~/integrations/constants';
describe('TriggerField', () => {
let wrapper;
const defaultProps = {
event: { name: 'push_events' },
};
const createComponent = ({ props = {}, isInheriting = false } = {}) => {
wrapper = shallowMount(TriggerField, {
propsData: { ...defaultProps, ...props },
computed: {
isInheriting: () => isInheriting,
},
});
};
afterEach(() => {
wrapper.destroy();
});
const findGlFormCheckbox = () => wrapper.findComponent(GlFormCheckbox);
const findHiddenInput = () => wrapper.find('input[type="hidden"]');
describe('template', () => {
it('renders enabled GlFormCheckbox', () => {
createComponent();
expect(findGlFormCheckbox().attributes('disabled')).toBeUndefined();
});
it('when isInheriting is true, renders disabled GlFormCheckbox', () => {
createComponent({ isInheriting: true });
expect(findGlFormCheckbox().attributes('disabled')).toBe('true');
});
it('renders correct title', () => {
createComponent();
expect(findGlFormCheckbox().text()).toMatchInterpolatedText(
integrationTriggerEventTitles[defaultProps.event.name],
);
});
it('sets default value for hidden input', () => {
createComponent();
expect(findHiddenInput().attributes('value')).toBe('false');
});
it('toggles value of hidden input on checkbox input', async () => {
createComponent({
props: { event: { name: 'push_events', value: true } },
});
await nextTick;
expect(findHiddenInput().attributes('value')).toBe('true');
await findGlFormCheckbox().vm.$emit('input', false);
expect(findHiddenInput().attributes('value')).toBe('false');
});
});
});

View file

@ -9,7 +9,10 @@ export const mockIntegrationProps = {
initialEnableComments: false, initialEnableComments: false,
}, },
jiraIssuesProps: {}, jiraIssuesProps: {},
triggerEvents: [], triggerEvents: [
{ name: 'push_events', title: 'Push', value: true },
{ name: 'issues_events', title: 'Issue', value: true },
],
sections: [], sections: [],
fields: [], fields: [],
type: '', type: '',

View file

@ -10,6 +10,7 @@ RSpec.describe Nav::TopNavHelper do
let(:current_user) { nil } let(:current_user) { nil }
before do before do
stub_application_setting(snowplow_enabled: true)
allow(helper).to receive(:current_user) { current_user } allow(helper).to receive(:current_user) { current_user }
end end
@ -50,49 +51,40 @@ RSpec.describe Nav::TopNavHelper do
context 'when current_user is nil (anonymous)' do context 'when current_user is nil (anonymous)' do
it 'has expected :primary' do it 'has expected :primary' do
expected_primary = [ expected_primary = [
::Gitlab::Nav::TopNavMenuItem.build( { href: '/explore', icon: 'project', id: 'project', title: 'Projects' },
href: '/explore', { href: '/explore/groups', icon: 'group', id: 'groups', title: 'Groups' },
icon: 'project', { href: '/explore/snippets', icon: 'snippet', id: 'snippets', title: 'Snippets' }
id: 'project', ].map do |item|
title: 'Projects' ::Gitlab::Nav::TopNavMenuItem.build(**item)
), end
::Gitlab::Nav::TopNavMenuItem.build(
href: '/explore/groups',
icon: 'group',
id: 'groups',
title: 'Groups'
),
::Gitlab::Nav::TopNavMenuItem.build(
href: '/explore/snippets',
icon: 'snippet',
id: 'snippets',
title: 'Snippets'
)
]
expect(subject[:primary]).to eq(expected_primary) expect(subject[:primary]).to eq(expected_primary)
end end
it 'has expected :shortcuts' do it 'has expected :shortcuts' do
expected_shortcuts = [ expected_shortcuts = [
::Gitlab::Nav::TopNavMenuItem.build( {
href: '/explore', href: '/explore',
id: 'project-shortcut', id: 'project-shortcut',
title: 'Projects', title: 'Projects',
css_class: 'dashboard-shortcuts-projects' css_class: 'dashboard-shortcuts-projects'
), },
::Gitlab::Nav::TopNavMenuItem.build( {
href: '/explore/groups', href: '/explore/groups',
id: 'groups-shortcut', id: 'groups-shortcut',
title: 'Groups', title: 'Groups',
css_class: 'dashboard-shortcuts-groups' css_class: 'dashboard-shortcuts-groups'
), },
::Gitlab::Nav::TopNavMenuItem.build( {
href: '/explore/snippets', href: '/explore/snippets',
id: 'snippets-shortcut', id: 'snippets-shortcut',
title: 'Snippets', title: 'Snippets',
css_class: 'dashboard-shortcuts-snippets' css_class: 'dashboard-shortcuts-snippets'
) }
] ].map do |item|
::Gitlab::Nav::TopNavMenuItem.build(**item)
end
expect(subject[:shortcuts]).to eq(expected_shortcuts) expect(subject[:shortcuts]).to eq(expected_shortcuts)
end end
@ -171,21 +163,41 @@ RSpec.describe Nav::TopNavHelper do
it 'has expected :linksPrimary' do it 'has expected :linksPrimary' do
expected_links_primary = [ expected_links_primary = [
::Gitlab::Nav::TopNavMenuItem.build( ::Gitlab::Nav::TopNavMenuItem.build(
data: {
qa_selector: 'menu_item_link',
qa_title: 'Your projects',
**menu_data_tracking_attrs('your_projects')
},
href: '/dashboard/projects', href: '/dashboard/projects',
id: 'your', id: 'your',
title: 'Your projects' title: 'Your projects'
), ),
::Gitlab::Nav::TopNavMenuItem.build( ::Gitlab::Nav::TopNavMenuItem.build(
data: {
qa_selector: 'menu_item_link',
qa_title: 'Starred projects',
**menu_data_tracking_attrs('starred_projects')
},
href: '/dashboard/projects/starred', href: '/dashboard/projects/starred',
id: 'starred', id: 'starred',
title: 'Starred projects' title: 'Starred projects'
), ),
::Gitlab::Nav::TopNavMenuItem.build( ::Gitlab::Nav::TopNavMenuItem.build(
data: {
qa_selector: 'menu_item_link',
qa_title: 'Explore projects',
**menu_data_tracking_attrs('explore_projects')
},
href: '/explore', href: '/explore',
id: 'explore', id: 'explore',
title: 'Explore projects' title: 'Explore projects'
), ),
::Gitlab::Nav::TopNavMenuItem.build( ::Gitlab::Nav::TopNavMenuItem.build(
data: {
qa_selector: 'menu_item_link',
qa_title: 'Explore topics',
**menu_data_tracking_attrs('explore_topics')
},
href: '/explore/projects/topics', href: '/explore/projects/topics',
id: 'topics', id: 'topics',
title: 'Explore topics' title: 'Explore topics'
@ -197,6 +209,11 @@ RSpec.describe Nav::TopNavHelper do
it 'has expected :linksSecondary' do it 'has expected :linksSecondary' do
expected_links_secondary = [ expected_links_secondary = [
::Gitlab::Nav::TopNavMenuItem.build( ::Gitlab::Nav::TopNavMenuItem.build(
data: {
qa_selector: 'menu_item_link',
qa_title: 'Create new project',
**menu_data_tracking_attrs('create_new_project')
},
href: '/projects/new', href: '/projects/new',
id: 'create', id: 'create',
title: 'Create new project' title: 'Create new project'
@ -282,11 +299,21 @@ RSpec.describe Nav::TopNavHelper do
it 'has expected :linksPrimary' do it 'has expected :linksPrimary' do
expected_links_primary = [ expected_links_primary = [
::Gitlab::Nav::TopNavMenuItem.build( ::Gitlab::Nav::TopNavMenuItem.build(
data: {
qa_selector: 'menu_item_link',
qa_title: 'Your groups',
**menu_data_tracking_attrs('your_groups')
},
href: '/dashboard/groups', href: '/dashboard/groups',
id: 'your', id: 'your',
title: 'Your groups' title: 'Your groups'
), ),
::Gitlab::Nav::TopNavMenuItem.build( ::Gitlab::Nav::TopNavMenuItem.build(
data: {
qa_selector: 'menu_item_link',
qa_title: 'Explore groups',
**menu_data_tracking_attrs('explore_groups')
},
href: '/explore/groups', href: '/explore/groups',
id: 'explore', id: 'explore',
title: 'Explore groups' title: 'Explore groups'
@ -298,6 +325,11 @@ RSpec.describe Nav::TopNavHelper do
it 'has expected :linksSecondary' do it 'has expected :linksSecondary' do
expected_links_secondary = [ expected_links_secondary = [
::Gitlab::Nav::TopNavMenuItem.build( ::Gitlab::Nav::TopNavMenuItem.build(
data: {
qa_selector: 'menu_item_link',
qa_title: 'Create group',
**menu_data_tracking_attrs('create_group')
},
href: '/groups/new', href: '/groups/new',
id: 'create', id: 'create',
title: 'Create group' title: 'Create group'
@ -356,7 +388,8 @@ RSpec.describe Nav::TopNavHelper do
it 'has expected :primary' do it 'has expected :primary' do
expected_primary = ::Gitlab::Nav::TopNavMenuItem.build( expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
data: { data: {
qa_selector: 'milestones_link' qa_selector: 'milestones_link',
**menu_data_tracking_attrs('milestones')
}, },
href: '/dashboard/milestones', href: '/dashboard/milestones',
icon: 'clock', icon: 'clock',
@ -383,7 +416,8 @@ RSpec.describe Nav::TopNavHelper do
it 'has expected :primary' do it 'has expected :primary' do
expected_primary = ::Gitlab::Nav::TopNavMenuItem.build( expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
data: { data: {
qa_selector: 'snippets_link' qa_selector: 'snippets_link',
**menu_data_tracking_attrs('snippets')
}, },
href: '/dashboard/snippets', href: '/dashboard/snippets',
icon: 'snippet', icon: 'snippet',
@ -410,7 +444,8 @@ RSpec.describe Nav::TopNavHelper do
it 'has expected :primary' do it 'has expected :primary' do
expected_primary = ::Gitlab::Nav::TopNavMenuItem.build( expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
data: { data: {
qa_selector: 'activity_link' qa_selector: 'activity_link',
**menu_data_tracking_attrs('activity')
}, },
href: '/dashboard/activity', href: '/dashboard/activity',
icon: 'history', icon: 'history',
@ -439,6 +474,11 @@ RSpec.describe Nav::TopNavHelper do
it 'has admin as first :secondary item' do it 'has admin as first :secondary item' do
expected_admin_item = ::Gitlab::Nav::TopNavMenuItem.build( expected_admin_item = ::Gitlab::Nav::TopNavMenuItem.build(
data: {
qa_selector: 'menu_item_link',
qa_title: 'Admin',
**menu_data_tracking_attrs('admin')
},
id: 'admin', id: 'admin',
title: 'Admin', title: 'Admin',
icon: 'admin', icon: 'admin',
@ -458,7 +498,7 @@ RSpec.describe Nav::TopNavHelper do
title: 'Leave Admin Mode', title: 'Leave Admin Mode',
icon: 'lock-open', icon: 'lock-open',
href: '/admin/session/destroy', href: '/admin/session/destroy',
data: { method: 'post' } data: { method: 'post', **menu_data_tracking_attrs('leave_admin_mode') }
) )
expect(subject[:secondary].last).to eq(expected_leave_admin_mode_item) expect(subject[:secondary].last).to eq(expected_leave_admin_mode_item)
end end
@ -469,6 +509,11 @@ RSpec.describe Nav::TopNavHelper do
it 'has enter_admin_mode as last :secondary item' do it 'has enter_admin_mode as last :secondary item' do
expected_enter_admin_mode_item = ::Gitlab::Nav::TopNavMenuItem.build( expected_enter_admin_mode_item = ::Gitlab::Nav::TopNavMenuItem.build(
data: {
qa_selector: 'menu_item_link',
qa_title: 'Enter Admin Mode',
**menu_data_tracking_attrs('enter_admin_mode')
},
id: 'enter_admin_mode', id: 'enter_admin_mode',
title: 'Enter Admin Mode', title: 'Enter Admin Mode',
icon: 'lock', icon: 'lock',
@ -533,4 +578,12 @@ RSpec.describe Nav::TopNavHelper do
end end
end end
end end
def menu_data_tracking_attrs(label)
{
track_label: "menu_#{label}",
track_action: 'click_dropdown',
track_property: 'navigation'
}
end
end end

View file

@ -121,13 +121,19 @@ RSpec.describe Gitlab::GitAccessSnippet do
if Ability.allowed?(user, :update_snippet, snippet) if Ability.allowed?(user, :update_snippet, snippet)
expect { push_access_check }.not_to raise_error expect { push_access_check }.not_to raise_error
else else
expect { push_access_check }.to raise_error(described_class::ForbiddenError) expect { push_access_check }.to raise_error(
described_class::ForbiddenError,
described_class::ERROR_MESSAGES[:update_snippet]
)
end end
if Ability.allowed?(user, :read_snippet, snippet) if Ability.allowed?(user, :read_snippet, snippet)
expect { pull_access_check }.not_to raise_error expect { pull_access_check }.not_to raise_error
else else
expect { pull_access_check }.to raise_error(described_class::ForbiddenError) expect { pull_access_check }.to raise_error(
described_class::ForbiddenError,
described_class::ERROR_MESSAGES[:read_snippet]
)
end end
end end
end end

View file

@ -18,7 +18,7 @@ RSpec.describe Gitlab::GitAccessWiki do
redirected_path: redirected_path) redirected_path: redirected_path)
end end
RSpec.shared_examples 'wiki access by level' do RSpec.shared_examples 'download wiki access by level' do
where(:project_visibility, :project_member?, :wiki_access_level, :wiki_repo?, :expected_behavior) do where(:project_visibility, :project_member?, :wiki_access_level, :wiki_repo?, :expected_behavior) do
[ [
# Private project - is a project member # Private project - is a project member
@ -103,7 +103,7 @@ RSpec.describe Gitlab::GitAccessWiki do
subject { access.check('git-upload-pack', Gitlab::GitAccess::ANY) } subject { access.check('git-upload-pack', Gitlab::GitAccess::ANY) }
context 'when actor is a user' do context 'when actor is a user' do
it_behaves_like 'wiki access by level' it_behaves_like 'download wiki access by level'
end end
context 'when the actor is a deploy token' do context 'when the actor is a deploy token' do
@ -116,17 +116,23 @@ RSpec.describe Gitlab::GitAccessWiki do
subject { access.check('git-upload-pack', changes) } subject { access.check('git-upload-pack', changes) }
context 'when the wiki is enabled' do context 'when the wiki feature is enabled' do
let(:wiki_access_level) { ProjectFeature::ENABLED } let(:wiki_access_level) { ProjectFeature::ENABLED }
it { expect { subject }.not_to raise_error } it { expect { subject }.not_to raise_error }
end end
context 'when the wiki is disabled' do context 'when the wiki feature is disabled' do
let(:wiki_access_level) { ProjectFeature::DISABLED } let(:wiki_access_level) { ProjectFeature::DISABLED }
it { expect { subject }.to raise_wiki_forbidden } it { expect { subject }.to raise_wiki_forbidden }
end end
context 'when the wiki feature is private' do
let(:wiki_access_level) { ProjectFeature::PRIVATE }
it { expect { subject }.to raise_wiki_forbidden }
end
end end
describe 'when actor is a user provided by build via CI_JOB_TOKEN' do describe 'when actor is a user provided by build via CI_JOB_TOKEN' do
@ -140,7 +146,7 @@ RSpec.describe Gitlab::GitAccessWiki do
subject { access.check('git-upload-pack', changes) } subject { access.check('git-upload-pack', changes) }
it_behaves_like 'wiki access by level' it_behaves_like 'download wiki access by level'
end end
end end

View file

@ -0,0 +1,10 @@
# frozen_string_literal: true
require 'spec_helper'
# See https://docs.gitlab.com/ee/development/gitlab_flavored_markdown/specification_guide/#markdown-snapshot-testing
# for documentation on this spec.
RSpec.describe API::Markdown, 'Snapshot' do
glfm_example_snapshots_dir = File.expand_path('../../fixtures/glfm/example_snapshots', __dir__)
include_context 'API::Markdown Snapshot shared context', glfm_example_snapshots_dir
end

View file

@ -0,0 +1,37 @@
# frozen_string_literal: true
require 'spec_helper'
# See https://docs.gitlab.com/ee/development/gitlab_flavored_markdown/specification_guide/#markdown-snapshot-testing
# for documentation on this spec.
RSpec.shared_context 'API::Markdown Snapshot shared context' do |glfm_example_snapshots_dir|
include ApiHelpers
markdown_examples, html_examples = %w[markdown.yml html.yml].map do |file_name|
yaml = File.read("#{glfm_example_snapshots_dir}/#{file_name}")
YAML.safe_load(yaml, symbolize_names: true, aliases: true)
end
if focused_markdown_examples_string = ENV['FOCUSED_MARKDOWN_EXAMPLES']
focused_markdown_examples = focused_markdown_examples_string.split(',').map(&:strip).map(&:to_sym)
markdown_examples.select! { |example_name| focused_markdown_examples.include?(example_name) }
end
markdown_examples.each do |name, markdown|
context "for #{name}" do
let(:html) { html_examples.fetch(name).fetch(:static) }
it "verifies conversion of GLFM to HTML", :unlimited_max_formatted_output_length do
api_url = api "/markdown"
post api_url, params: { text: markdown, gfm: true }
expect(response).to be_successful
response_body = Gitlab::Json.parse(response.body)
# Some requests have the HTML in the `html` key, others in the `body` key.
response_html = response_body['body'] ? response_body.fetch('body') : response_body.fetch('html')
expect(response_html).to eq(html)
end
end
end
end

View file

@ -6,30 +6,12 @@ RSpec.describe Database::CiNamespaceMirrorsConsistencyCheckWorker do
let(:worker) { described_class.new } let(:worker) { described_class.new }
describe '#perform' do describe '#perform' do
context 'feature flag is disabled' do
before do
stub_feature_flags(ci_namespace_mirrors_consistency_check: false)
end
it 'does not perform the consistency check on namespaces' do
expect(Database::ConsistencyCheckService).not_to receive(:new)
expect(worker).not_to receive(:log_extra_metadata_on_done)
worker.perform
end
end
context 'feature flag is enabled' do
before do
stub_feature_flags(ci_namespace_mirrors_consistency_check: true)
end
it 'executes the consistency check on namespaces' do it 'executes the consistency check on namespaces' do
expect(Database::ConsistencyCheckService).to receive(:new).and_call_original expect(Database::ConsistencyCheckService).to receive(:new).and_call_original
expected_result = { batches: 0, matches: 0, mismatches: 0, mismatches_details: [] } expected_result = { batches: 0, matches: 0, mismatches: 0, mismatches_details: [] }
expect(worker).to receive(:log_extra_metadata_on_done).with(:results, expected_result) expect(worker).to receive(:log_extra_metadata_on_done).with(:results, expected_result)
worker.perform worker.perform
end end
end
context 'logs should contain the detailed mismatches' do context 'logs should contain the detailed mismatches' do
let(:first_namespace) { Namespace.all.order(:id).limit(1).first } let(:first_namespace) { Namespace.all.order(:id).limit(1).first }
@ -37,7 +19,6 @@ RSpec.describe Database::CiNamespaceMirrorsConsistencyCheckWorker do
before do before do
redis_shared_state_cleanup! redis_shared_state_cleanup!
stub_feature_flags(ci_namespace_mirrors_consistency_check: true)
create_list(:namespace, 10) # This will also create Ci::NameSpaceMirror objects create_list(:namespace, 10) # This will also create Ci::NameSpaceMirror objects
missing_namespace.delete missing_namespace.delete

View file

@ -6,30 +6,12 @@ RSpec.describe Database::CiProjectMirrorsConsistencyCheckWorker do
let(:worker) { described_class.new } let(:worker) { described_class.new }
describe '#perform' do describe '#perform' do
context 'feature flag is disabled' do
before do
stub_feature_flags(ci_project_mirrors_consistency_check: false)
end
it 'does not perform the consistency check on projects' do
expect(Database::ConsistencyCheckService).not_to receive(:new)
expect(worker).not_to receive(:log_extra_metadata_on_done)
worker.perform
end
end
context 'feature flag is enabled' do
before do
stub_feature_flags(ci_project_mirrors_consistency_check: true)
end
it 'executes the consistency check on projects' do it 'executes the consistency check on projects' do
expect(Database::ConsistencyCheckService).to receive(:new).and_call_original expect(Database::ConsistencyCheckService).to receive(:new).and_call_original
expected_result = { batches: 0, matches: 0, mismatches: 0, mismatches_details: [] } expected_result = { batches: 0, matches: 0, mismatches: 0, mismatches_details: [] }
expect(worker).to receive(:log_extra_metadata_on_done).with(:results, expected_result) expect(worker).to receive(:log_extra_metadata_on_done).with(:results, expected_result)
worker.perform worker.perform
end end
end
context 'logs should contain the detailed mismatches' do context 'logs should contain the detailed mismatches' do
let(:first_project) { Project.all.order(:id).limit(1).first } let(:first_project) { Project.all.order(:id).limit(1).first }
@ -37,7 +19,6 @@ RSpec.describe Database::CiProjectMirrorsConsistencyCheckWorker do
before do before do
redis_shared_state_cleanup! redis_shared_state_cleanup!
stub_feature_flags(ci_project_mirrors_consistency_check: true)
create_list(:project, 10) # This will also create Ci::ProjectMirror objects create_list(:project, 10) # This will also create Ci::ProjectMirror objects
missing_project.delete missing_project.delete

View file

@ -968,10 +968,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.14.0.tgz#92b36bc98ccbed49a4dbca310862146275091cb2" resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.14.0.tgz#92b36bc98ccbed49a4dbca310862146275091cb2"
integrity sha512-U9EYmEIiTMl7R3X5DmCrw6fz7gz8c1kjvQtaF6HfJ15xDtR7trRAyCNbn3z7YGk1QJ8Cv/Ifw2/T5SxXwYd7dw== integrity sha512-U9EYmEIiTMl7R3X5DmCrw6fz7gz8c1kjvQtaF6HfJ15xDtR7trRAyCNbn3z7YGk1QJ8Cv/Ifw2/T5SxXwYd7dw==
"@gitlab/ui@40.6.6": "@gitlab/ui@40.7.1":
version "40.6.6" version "40.7.1"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-40.6.6.tgz#07e95edd1b0afe8cb2f42880f634657ffbcaa3cd" resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-40.7.1.tgz#e6595c5cc37d994e3f0ba780626fbf4e8174df2a"
integrity sha512-hHwu63oldEtALYS3KPkU0CUVIznpoScAURzCKscw2/wNmXc+siVOA4iGPJ012h5Jza7itTeQg0UFCWGjigUaYA== integrity sha512-u100mDpdI7RfNVcAYi8n0RRH2FfIiYuMVgt5jPrQ7AAL+QrwLAkqfBZtkT9pSMpycBuuQsxSMHJK5FlnXum46g==
dependencies: dependencies:
"@popperjs/core" "^2.11.2" "@popperjs/core" "^2.11.2"
bootstrap-vue "2.20.1" bootstrap-vue "2.20.1"