Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
965a92325a
commit
54cf744926
|
@ -267,8 +267,8 @@ export default {
|
||||||
this.searchTerm = trimmedInput;
|
this.searchTerm = trimmedInput;
|
||||||
}
|
}
|
||||||
}, 500),
|
}, 500),
|
||||||
navigateToAlertDetails({ iid }) {
|
navigateToAlertDetails({ iid }, index, { metaKey }) {
|
||||||
return visitUrl(joinPaths(window.location.pathname, iid, 'details'));
|
return visitUrl(joinPaths(window.location.pathname, iid, 'details'), metaKey);
|
||||||
},
|
},
|
||||||
trackPageViews() {
|
trackPageViews() {
|
||||||
const { category, action } = trackAlertListViewsOptions;
|
const { category, action } = trackAlertListViewsOptions;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
/* eslint-disable vue/no-v-html */
|
|
||||||
import { mapState, mapActions, mapGetters } from 'vuex';
|
import { mapState, mapActions, mapGetters } from 'vuex';
|
||||||
import { GlLink, GlLoadingIcon } from '@gitlab/ui';
|
import { GlLink, GlLoadingIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
|
||||||
import { sprintf, s__ } from '~/locale';
|
import { sprintf, s__ } from '~/locale';
|
||||||
import EnvironmentRow from './environment_row.vue';
|
import EnvironmentRow from './environment_row.vue';
|
||||||
import EmptyState from './empty_state.vue';
|
import EmptyState from './empty_state.vue';
|
||||||
|
@ -14,6 +13,9 @@ export default {
|
||||||
GlLink,
|
GlLink,
|
||||||
GlLoadingIcon,
|
GlLoadingIcon,
|
||||||
},
|
},
|
||||||
|
directives: {
|
||||||
|
SafeHtml,
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['installed', 'isLoading', 'hasFunctionData', 'helpPath', 'statusPath']),
|
...mapState(['installed', 'isLoading', 'hasFunctionData', 'helpPath', 'statusPath']),
|
||||||
...mapGetters(['getFunctions']),
|
...mapGetters(['getFunctions']),
|
||||||
|
@ -92,9 +94,9 @@ export default {
|
||||||
}}
|
}}
|
||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-html="noServerlessConfigFile"></li>
|
<li v-safe-html="noServerlessConfigFile"></li>
|
||||||
<li v-html="noGitlabYamlConfigured"></li>
|
<li v-safe-html="noGitlabYamlConfigured"></li>
|
||||||
<li v-html="mismatchedServerlessFunctions"></li>
|
<li v-safe-html="mismatchedServerlessFunctions"></li>
|
||||||
<li>{{ s__('Serverless|The deploy job has not finished.') }}</li>
|
<li>{{ s__('Serverless|The deploy job has not finished.') }}</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
|
@ -71,4 +71,5 @@ module Types
|
||||||
end
|
end
|
||||||
|
|
||||||
::Types::MutationType.prepend(::Types::DeprecatedMutations)
|
::Types::MutationType.prepend(::Types::DeprecatedMutations)
|
||||||
|
::Types::MutationType.prepend_if_ee('EE::Types::DeprecatedMutations')
|
||||||
::Types::MutationType.prepend_if_ee('::EE::Types::MutationType')
|
::Types::MutationType.prepend_if_ee('::EE::Types::MutationType')
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
= yield :customize_homepage_banner
|
= yield :customize_homepage_banner
|
||||||
- unless @hide_breadcrumbs
|
- unless @hide_breadcrumbs
|
||||||
= render "layouts/nav/breadcrumbs"
|
= render "layouts/nav/breadcrumbs"
|
||||||
.d-flex
|
|
||||||
%div{ class: "#{(container_class unless @no_container)} #{@content_class}" }
|
%div{ class: "#{(container_class unless @no_container)} #{@content_class}" }
|
||||||
.content{ id: "content-body" }
|
.content{ id: "content-body" }
|
||||||
= render "layouts/flash", extra_flash_class: 'limit-container-width'
|
= render "layouts/flash", extra_flash_class: 'limit-container-width'
|
||||||
|
|
|
@ -102,7 +102,12 @@
|
||||||
%tbody
|
%tbody
|
||||||
- @registrations.each do |registration|
|
- @registrations.each do |registration|
|
||||||
%tr
|
%tr
|
||||||
%td= registration[:name].presence || html_escape_once(_("<no name set>")).html_safe
|
%td
|
||||||
|
- if registration[:name].present?
|
||||||
|
= registration[:name]
|
||||||
|
- else
|
||||||
|
%span.gl-text-gray-500
|
||||||
|
= _("no name set")
|
||||||
%td= registration[:created_at].to_date.to_s(:medium)
|
%td= registration[:created_at].to_date.to_s(:medium)
|
||||||
%td= link_to _('Delete'), registration[:delete_path], method: :delete, class: "btn btn-danger float-right", data: { confirm: _('Are you sure you want to delete this device? This action cannot be undone.') }
|
%td= link_to _('Delete'), registration[:delete_path], method: :delete, class: "btn btn-danger float-right", data: { confirm: _('Are you sure you want to delete this device? This action cannot be undone.') }
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Fix triggering multiple children pipeline with the same artifact
|
||||||
|
merge_request: 42595
|
||||||
|
author:
|
||||||
|
type: fixed
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Allow alerts to open on new tab
|
||||||
|
merge_request: 42691
|
||||||
|
author:
|
||||||
|
type: changed
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Remove angle brackets from empty name in U2F device settings
|
||||||
|
merge_request: 42440
|
||||||
|
author:
|
||||||
|
type: changed
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Remove an unnecessary element from every page
|
||||||
|
merge_request: 42769
|
||||||
|
author: Takuya Noguchi
|
||||||
|
type: other
|
|
@ -4,4 +4,4 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40268
|
||||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/249588
|
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/249588
|
||||||
group: group::pipeline authoring
|
group: group::pipeline authoring
|
||||||
type: development
|
type: development
|
||||||
default_enabled: false
|
default_enabled: true
|
||||||
|
|
|
@ -10812,7 +10812,7 @@ type Mutation {
|
||||||
Toggles the resolved state of a discussion
|
Toggles the resolved state of a discussion
|
||||||
"""
|
"""
|
||||||
discussionToggleResolve(input: DiscussionToggleResolveInput!): DiscussionToggleResolvePayload
|
discussionToggleResolve(input: DiscussionToggleResolveInput!): DiscussionToggleResolvePayload
|
||||||
dismissVulnerability(input: DismissVulnerabilityInput!): DismissVulnerabilityPayload
|
dismissVulnerability(input: DismissVulnerabilityInput!): DismissVulnerabilityPayload @deprecated(reason: "Use vulnerabilityDismiss. Deprecated in 13.5")
|
||||||
epicAddIssue(input: EpicAddIssueInput!): EpicAddIssuePayload
|
epicAddIssue(input: EpicAddIssueInput!): EpicAddIssuePayload
|
||||||
epicSetSubscription(input: EpicSetSubscriptionInput!): EpicSetSubscriptionPayload
|
epicSetSubscription(input: EpicSetSubscriptionInput!): EpicSetSubscriptionPayload
|
||||||
epicTreeReorder(input: EpicTreeReorderInput!): EpicTreeReorderPayload
|
epicTreeReorder(input: EpicTreeReorderInput!): EpicTreeReorderPayload
|
||||||
|
@ -10876,6 +10876,7 @@ type Mutation {
|
||||||
updateRequirement(input: UpdateRequirementInput!): UpdateRequirementPayload
|
updateRequirement(input: UpdateRequirementInput!): UpdateRequirementPayload
|
||||||
updateSnippet(input: UpdateSnippetInput!): UpdateSnippetPayload
|
updateSnippet(input: UpdateSnippetInput!): UpdateSnippetPayload
|
||||||
vulnerabilityConfirm(input: VulnerabilityConfirmInput!): VulnerabilityConfirmPayload
|
vulnerabilityConfirm(input: VulnerabilityConfirmInput!): VulnerabilityConfirmPayload
|
||||||
|
vulnerabilityDismiss(input: VulnerabilityDismissInput!): VulnerabilityDismissPayload
|
||||||
vulnerabilityResolve(input: VulnerabilityResolveInput!): VulnerabilityResolvePayload
|
vulnerabilityResolve(input: VulnerabilityResolveInput!): VulnerabilityResolvePayload
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18836,6 +18837,46 @@ type VulnerabilityConnection {
|
||||||
pageInfo: PageInfo!
|
pageInfo: PageInfo!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
Autogenerated input type of VulnerabilityDismiss
|
||||||
|
"""
|
||||||
|
input VulnerabilityDismissInput {
|
||||||
|
"""
|
||||||
|
A unique identifier for the client performing the mutation.
|
||||||
|
"""
|
||||||
|
clientMutationId: String
|
||||||
|
|
||||||
|
"""
|
||||||
|
Reason why vulnerability should be dismissed
|
||||||
|
"""
|
||||||
|
comment: String
|
||||||
|
|
||||||
|
"""
|
||||||
|
ID of the vulnerability to be dismissed
|
||||||
|
"""
|
||||||
|
id: ID!
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
Autogenerated return type of VulnerabilityDismiss
|
||||||
|
"""
|
||||||
|
type VulnerabilityDismissPayload {
|
||||||
|
"""
|
||||||
|
A unique identifier for the client performing the mutation.
|
||||||
|
"""
|
||||||
|
clientMutationId: String
|
||||||
|
|
||||||
|
"""
|
||||||
|
Errors encountered during execution of the mutation.
|
||||||
|
"""
|
||||||
|
errors: [String!]!
|
||||||
|
|
||||||
|
"""
|
||||||
|
The vulnerability after dismissal
|
||||||
|
"""
|
||||||
|
vulnerability: Vulnerability
|
||||||
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
An edge in a connection.
|
An edge in a connection.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -31135,8 +31135,8 @@
|
||||||
"name": "DismissVulnerabilityPayload",
|
"name": "DismissVulnerabilityPayload",
|
||||||
"ofType": null
|
"ofType": null
|
||||||
},
|
},
|
||||||
"isDeprecated": false,
|
"isDeprecated": true,
|
||||||
"deprecationReason": null
|
"deprecationReason": "Use vulnerabilityDismiss. Deprecated in 13.5"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "epicAddIssue",
|
"name": "epicAddIssue",
|
||||||
|
@ -32434,6 +32434,33 @@
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": null
|
"deprecationReason": null
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "vulnerabilityDismiss",
|
||||||
|
"description": null,
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "input",
|
||||||
|
"description": null,
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "INPUT_OBJECT",
|
||||||
|
"name": "VulnerabilityDismissInput",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultValue": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "OBJECT",
|
||||||
|
"name": "VulnerabilityDismissPayload",
|
||||||
|
"ofType": null
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "vulnerabilityResolve",
|
"name": "vulnerabilityResolve",
|
||||||
"description": null,
|
"description": null,
|
||||||
|
@ -55100,6 +55127,118 @@
|
||||||
"enumValues": null,
|
"enumValues": null,
|
||||||
"possibleTypes": null
|
"possibleTypes": null
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"kind": "INPUT_OBJECT",
|
||||||
|
"name": "VulnerabilityDismissInput",
|
||||||
|
"description": "Autogenerated input type of VulnerabilityDismiss",
|
||||||
|
"fields": null,
|
||||||
|
"inputFields": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"description": "ID of the vulnerability to be dismissed",
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "ID",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultValue": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "comment",
|
||||||
|
"description": "Reason why vulnerability should be dismissed",
|
||||||
|
"type": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "String",
|
||||||
|
"ofType": null
|
||||||
|
},
|
||||||
|
"defaultValue": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "clientMutationId",
|
||||||
|
"description": "A unique identifier for the client performing the mutation.",
|
||||||
|
"type": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "String",
|
||||||
|
"ofType": null
|
||||||
|
},
|
||||||
|
"defaultValue": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interfaces": null,
|
||||||
|
"enumValues": null,
|
||||||
|
"possibleTypes": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "OBJECT",
|
||||||
|
"name": "VulnerabilityDismissPayload",
|
||||||
|
"description": "Autogenerated return type of VulnerabilityDismiss",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "clientMutationId",
|
||||||
|
"description": "A unique identifier for the client performing the mutation.",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "String",
|
||||||
|
"ofType": null
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "errors",
|
||||||
|
"description": "Errors encountered during execution of the mutation.",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "LIST",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "String",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vulnerability",
|
||||||
|
"description": "The vulnerability after dismissal",
|
||||||
|
"args": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"kind": "OBJECT",
|
||||||
|
"name": "Vulnerability",
|
||||||
|
"ofType": null
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inputFields": null,
|
||||||
|
"interfaces": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"enumValues": null,
|
||||||
|
"possibleTypes": null
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"kind": "OBJECT",
|
"kind": "OBJECT",
|
||||||
"name": "VulnerabilityEdge",
|
"name": "VulnerabilityEdge",
|
||||||
|
|
|
@ -2710,6 +2710,16 @@ Autogenerated return type of VulnerabilityConfirm.
|
||||||
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
|
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
|
||||||
| `vulnerability` | Vulnerability | The vulnerability after state change |
|
| `vulnerability` | Vulnerability | The vulnerability after state change |
|
||||||
|
|
||||||
|
### VulnerabilityDismissPayload
|
||||||
|
|
||||||
|
Autogenerated return type of VulnerabilityDismiss.
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
| ----- | ---- | ----------- |
|
||||||
|
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
|
||||||
|
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
|
||||||
|
| `vulnerability` | Vulnerability | The vulnerability after dismissal |
|
||||||
|
|
||||||
### VulnerabilityIdentifier
|
### VulnerabilityIdentifier
|
||||||
|
|
||||||
Represents a vulnerability identifier.
|
Represents a vulnerability identifier.
|
||||||
|
|
|
@ -13,7 +13,7 @@ module HamlLint
|
||||||
DOCS_DIRECTORY = File.join(File.expand_path('../..', __dir__), 'doc')
|
DOCS_DIRECTORY = File.join(File.expand_path('../..', __dir__), 'doc')
|
||||||
|
|
||||||
HELP_PATH_LINK_PATTERN = <<~PATTERN
|
HELP_PATH_LINK_PATTERN = <<~PATTERN
|
||||||
`(send nil? :help_page_path $...)
|
`(send nil? {:help_page_url :help_page_path} $...)
|
||||||
PATTERN
|
PATTERN
|
||||||
|
|
||||||
MARKDOWN_HEADER = %r{\A\#{1,6}\s+(?<header>.+)\Z}.freeze
|
MARKDOWN_HEADER = %r{\A\#{1,6}\s+(?<header>.+)\Z}.freeze
|
||||||
|
|
|
@ -72,7 +72,7 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.new_artifact_file_reader_enabled?(project)
|
def self.new_artifact_file_reader_enabled?(project)
|
||||||
::Feature.enabled?(:ci_new_artifact_file_reader, project, default_enabled: false)
|
::Feature.enabled?(:ci_new_artifact_file_reader, project, default_enabled: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -857,9 +857,6 @@ msgstr ""
|
||||||
msgid "< 1 hour"
|
msgid "< 1 hour"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "<no name set>"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "<no scopes selected>"
|
msgid "<no scopes selected>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -30684,6 +30681,9 @@ msgstr ""
|
||||||
msgid "no expiration"
|
msgid "no expiration"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "no name set"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "no one can merge"
|
msgid "no one can merge"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -26,3 +26,5 @@ module QA
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
QA::Page::Project::Packages::Index.prepend_if_ee('QA::EE::Page::Project::Packages::Index')
|
||||||
|
|
|
@ -11,6 +11,8 @@ module QA
|
||||||
Waiter.wait_until(log: false) do
|
Waiter.wait_until(log: false) do
|
||||||
finished_all_ajax_requests? && finished_all_axios_requests? && (!skip_finished_loading_check ? finished_loading?(wait: 1) : true)
|
finished_all_ajax_requests? && finished_all_axios_requests? && (!skip_finished_loading_check ? finished_loading?(wait: 1) : true)
|
||||||
end
|
end
|
||||||
|
rescue Repeater::WaitExceededError
|
||||||
|
raise $!, 'Page did not fully load. This could be due to an unending async request or loading icon.'
|
||||||
end
|
end
|
||||||
|
|
||||||
def finished_all_axios_requests?
|
def finished_all_axios_requests?
|
||||||
|
|
|
@ -295,10 +295,30 @@ describe('AlertManagementTable', () => {
|
||||||
loading: false,
|
loading: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
expect(visitUrl).not.toHaveBeenCalled();
|
||||||
|
|
||||||
findAlerts()
|
findAlerts()
|
||||||
.at(0)
|
.at(0)
|
||||||
.trigger('click');
|
.trigger('click');
|
||||||
expect(visitUrl).toHaveBeenCalledWith('/1527542/details');
|
expect(visitUrl).toHaveBeenCalledWith('/1527542/details', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('navigates to the detail page in new tab when alert row is clicked with the metaKey', () => {
|
||||||
|
mountComponent({
|
||||||
|
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
|
||||||
|
data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(visitUrl).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
findAlerts()
|
||||||
|
.at(0)
|
||||||
|
.trigger('click', {
|
||||||
|
metaKey: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(visitUrl).toHaveBeenCalledWith('/1527542/details', true);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('alert issue links', () => {
|
describe('alert issue links', () => {
|
||||||
|
|
|
@ -8,75 +8,85 @@ require Rails.root.join('haml_lint/linter/documentation_links')
|
||||||
RSpec.describe HamlLint::Linter::DocumentationLinks do
|
RSpec.describe HamlLint::Linter::DocumentationLinks do
|
||||||
include_context 'linter'
|
include_context 'linter'
|
||||||
|
|
||||||
context 'when link_to points to the existing file path' do
|
shared_examples 'link validation rules' do |link_pattern|
|
||||||
let(:haml) { "= link_to 'Description', help_page_path('README.md')" }
|
context 'when link_to points to the existing file path' do
|
||||||
|
let(:haml) { "= link_to 'Description', #{link_pattern}('README.md')" }
|
||||||
|
|
||||||
it { is_expected.not_to report_lint }
|
it { is_expected.not_to report_lint }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when link_to points to the existing file with valid anchor' do
|
context 'when link_to points to the existing file with valid anchor' do
|
||||||
let(:haml) { "= link_to 'Description', help_page_path('README.md', anchor: 'overview'), target: '_blank'" }
|
let(:haml) { "= link_to 'Description', #{link_pattern}('README.md', anchor: 'overview'), target: '_blank'" }
|
||||||
|
|
||||||
it { is_expected.not_to report_lint }
|
it { is_expected.not_to report_lint }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when link_to points to the existing file path without .md extension' do
|
context 'when link_to points to the existing file path without .md extension' do
|
||||||
let(:haml) { "= link_to 'Description', help_page_path('README')" }
|
let(:haml) { "= link_to 'Description', #{link_pattern}('README')" }
|
||||||
|
|
||||||
it { is_expected.not_to report_lint }
|
it { is_expected.not_to report_lint }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when anchor is not correct' do
|
context 'when anchor is not correct' do
|
||||||
let(:haml) { "= link_to 'Description', help_page_path('README.md', anchor: 'wrong')" }
|
let(:haml) { "= link_to 'Description', #{link_pattern}('README.md', anchor: 'wrong')" }
|
||||||
|
|
||||||
it { is_expected.to report_lint }
|
it { is_expected.to report_lint }
|
||||||
|
|
||||||
context 'when help_page_path has multiple options' do
|
context "when #{link_pattern} has multiple options" do
|
||||||
let(:haml) { "= link_to 'Description', help_page_path('README.md', key: :value, anchor: 'wrong')" }
|
let(:haml) { "= link_to 'Description', #{link_pattern}('README.md', key: :value, anchor: 'wrong')" }
|
||||||
|
|
||||||
|
it { is_expected.to report_lint }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when file path is wrong' do
|
||||||
|
let(:haml) { "= link_to 'Description', #{link_pattern}('wrong.md'), target: '_blank'" }
|
||||||
|
|
||||||
|
it { is_expected.to report_lint }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when link with wrong file path is assigned to a variable' do
|
||||||
|
let(:haml) { "- my_link = link_to 'Description', #{link_pattern}('wrong.md')" }
|
||||||
|
|
||||||
|
it { is_expected.to report_lint }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is a broken code' do
|
||||||
|
let(:haml) { "= I am broken! ]]]]" }
|
||||||
|
|
||||||
|
it { is_expected.not_to report_lint }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when anchor belongs to a different element' do
|
||||||
|
let(:haml) { "= link_to 'Description', #{link_pattern}('README.md'), target: (anchor: 'blank')" }
|
||||||
|
|
||||||
|
it { is_expected.not_to report_lint }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when a simple #{link_pattern}" do
|
||||||
|
let(:haml) { "- url = #{link_pattern}('wrong.md')" }
|
||||||
|
|
||||||
|
it { is_expected.to report_lint }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when link is not a string' do
|
||||||
|
let(:haml) { "- url = #{link_pattern}(help_url)" }
|
||||||
|
|
||||||
|
it { is_expected.not_to report_lint }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when link is a part of the tag' do
|
||||||
|
let(:haml) { ".data-form{ data: { url: #{link_pattern}('wrong.md') } }" }
|
||||||
|
|
||||||
it { is_expected.to report_lint }
|
it { is_expected.to report_lint }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when file path is wrong' do
|
context 'help_page_path' do
|
||||||
let(:haml) { "= link_to 'Description', help_page_path('wrong.md'), target: '_blank'" }
|
it_behaves_like 'link validation rules', 'help_page_path'
|
||||||
|
|
||||||
it { is_expected.to report_lint }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when link with wrong file path is assigned to a variable' do
|
context 'help_page_url' do
|
||||||
let(:haml) { "- my_link = link_to 'Description', help_page_path('wrong.md')" }
|
it_behaves_like 'link validation rules', 'help_page_url'
|
||||||
|
|
||||||
it { is_expected.to report_lint }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when it is a broken code' do
|
|
||||||
let(:haml) { "= I am broken! ]]]]" }
|
|
||||||
|
|
||||||
it { is_expected.not_to report_lint }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when anchor belongs to a different element' do
|
|
||||||
let(:haml) { "= link_to 'Description', help_page_path('README.md'), target: (anchor: 'blank')" }
|
|
||||||
|
|
||||||
it { is_expected.not_to report_lint }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when a simple help_page_path' do
|
|
||||||
let(:haml) { "- url = help_page_path('wrong.md')" }
|
|
||||||
|
|
||||||
it { is_expected.to report_lint }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when link is not a string' do
|
|
||||||
let(:haml) { "- url = help_page_path(help_url)" }
|
|
||||||
|
|
||||||
it { is_expected.not_to report_lint }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when link is a part of the tag' do
|
|
||||||
let(:haml) { ".data-form{ data: { url: help_page_path('wrong.md') } }" }
|
|
||||||
|
|
||||||
it { is_expected.to report_lint }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,77 +3,111 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe Todos::Destroy::EntityLeaveService do
|
RSpec.describe Todos::Destroy::EntityLeaveService do
|
||||||
let(:group) { create(:group, :private) }
|
let_it_be(:group, reload: true) { create(:group, :private) }
|
||||||
let(:project) { create(:project, group: group) }
|
let_it_be(:project, reload: true) { create(:project, group: group) }
|
||||||
let(:user) { create(:user) }
|
let_it_be(:user, reload: true) { create(:user) }
|
||||||
let(:user2) { create(:user) }
|
let_it_be(:user2, reload: true) { create(:user) }
|
||||||
let(:issue) { create(:issue, project: project, confidential: true) }
|
let_it_be(:issue) { create(:issue, project: project) }
|
||||||
let(:mr) { create(:merge_request, source_project: project) }
|
let_it_be(:issue_c) { create(:issue, project: project, confidential: true) }
|
||||||
|
let_it_be(:todo_group_user) { create(:todo, user: user, group: group) }
|
||||||
|
let_it_be(:todo_group_user2) { create(:todo, user: user2, group: group) }
|
||||||
|
|
||||||
let!(:todo_mr_user) { create(:todo, user: user, target: mr, project: project) }
|
let(:mr) { create(:merge_request, source_project: project) }
|
||||||
let!(:todo_issue_user) { create(:todo, user: user, target: issue, project: project) }
|
let!(:todo_mr_user) { create(:todo, user: user, target: mr, project: project) }
|
||||||
let!(:todo_group_user) { create(:todo, user: user, group: group) }
|
let!(:todo_issue_user) { create(:todo, user: user, target: issue, project: project) }
|
||||||
let!(:todo_issue_user2) { create(:todo, user: user2, target: issue, project: project) }
|
let!(:todo_issue_c_user) { create(:todo, user: user, target: issue_c, project: project) }
|
||||||
let!(:todo_group_user2) { create(:todo, user: user2, group: group) }
|
let!(:todo_issue_c_user2) { create(:todo, user: user2, target: issue_c, project: project) }
|
||||||
|
|
||||||
|
shared_examples 'using different access permissions' do |access_table|
|
||||||
|
using RSpec::Parameterized::TableSyntax
|
||||||
|
|
||||||
|
where(:group_access, :project_access, :c_todos, :mr_todos, :method, &access_table)
|
||||||
|
|
||||||
|
with_them do
|
||||||
|
before do
|
||||||
|
set_access(project, user, project_access) if project_access
|
||||||
|
set_access(group, user, group_access) if group_access
|
||||||
|
end
|
||||||
|
|
||||||
|
it "#{params[:method].to_s.humanize(capitalize: false)}" do
|
||||||
|
send(method)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
shared_examples 'does not remove any todos' do
|
||||||
|
it { does_not_remove_any_todos }
|
||||||
|
end
|
||||||
|
|
||||||
|
shared_examples 'removes only confidential issues todos' do
|
||||||
|
it { removes_only_confidential_issues_todos }
|
||||||
|
end
|
||||||
|
|
||||||
|
shared_examples 'removes confidential issues and merge request todos' do
|
||||||
|
it { removes_confidential_issues_and_merge_request_todos }
|
||||||
|
end
|
||||||
|
|
||||||
|
def does_not_remove_any_todos
|
||||||
|
expect { subject }.not_to change { Todo.count }
|
||||||
|
end
|
||||||
|
|
||||||
|
def removes_only_confidential_issues_todos
|
||||||
|
expect { subject }.to change { Todo.count }.from(6).to(5)
|
||||||
|
end
|
||||||
|
|
||||||
|
def removes_confidential_issues_and_merge_request_todos
|
||||||
|
expect { subject }.to change { Todo.count }.from(6).to(4)
|
||||||
|
expect(user.todos).to match_array([todo_issue_user, todo_group_user])
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_access(object, user, access_name)
|
||||||
|
case access_name
|
||||||
|
when :developer
|
||||||
|
object.add_developer(user)
|
||||||
|
when :reporter
|
||||||
|
object.add_reporter(user)
|
||||||
|
when :guest
|
||||||
|
object.add_guest(user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#execute' do
|
describe '#execute' do
|
||||||
context 'when a user leaves a project' do
|
describe 'updating a Project' do
|
||||||
subject { described_class.new(user.id, project.id, 'Project').execute }
|
subject { described_class.new(user.id, project.id, 'Project').execute }
|
||||||
|
|
||||||
context 'when project is private' do
|
context 'when project is private' do
|
||||||
it 'removes project todos for the provided user' do
|
context 'when a user leaves a project' do
|
||||||
expect { subject }.to change { Todo.count }.from(5).to(3)
|
it 'removes project todos for the provided user' do
|
||||||
|
expect { subject }.to change { Todo.count }.from(6).to(3)
|
||||||
|
|
||||||
expect(user.todos).to match_array([todo_group_user])
|
expect(user.todos).to match_array([todo_group_user])
|
||||||
expect(user2.todos).to match_array([todo_issue_user2, todo_group_user2])
|
expect(user2.todos).to match_array([todo_issue_c_user2, todo_group_user2])
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the user is member of the project' do
|
|
||||||
before do
|
|
||||||
project.add_developer(user)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not remove any todos' do
|
|
||||||
expect { subject }.not_to change { Todo.count }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the user is a project guest' do
|
context 'access permissions' do
|
||||||
before do
|
# rubocop:disable RSpec/LeakyConstantDeclaration
|
||||||
project.add_guest(user)
|
PROJECT_PRIVATE_ACCESS_TABLE =
|
||||||
end
|
lambda do |_|
|
||||||
|
[
|
||||||
|
# :group_access, :project_access, :c_todos, :mr_todos, :method
|
||||||
|
[nil, :reporter, :keep, :keep, :does_not_remove_any_todos],
|
||||||
|
[nil, :guest, :delete, :keep, :removes_only_confidential_issues_todos],
|
||||||
|
[:reporter, nil, :keep, :keep, :does_not_remove_any_todos],
|
||||||
|
[:guest, nil, :delete, :keep, :removes_only_confidential_issues_todos]
|
||||||
|
]
|
||||||
|
end
|
||||||
|
# rubocop:enable RSpec/LeakyConstantDeclaration
|
||||||
|
|
||||||
it 'removes only confidential issues todos' do
|
it_behaves_like 'using different access permissions', PROJECT_PRIVATE_ACCESS_TABLE
|
||||||
expect { subject }.to change { Todo.count }.from(5).to(4)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the user is member of a parent group' do
|
|
||||||
before do
|
|
||||||
group.add_developer(user)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not remove any todos' do
|
|
||||||
expect { subject }.not_to change { Todo.count }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the user is guest of a parent group' do
|
|
||||||
before do
|
|
||||||
project.add_guest(user)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'removes only confidential issues todos' do
|
|
||||||
expect { subject }.to change { Todo.count }.from(5).to(4)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when project is not private' do
|
context 'when project is not private' do
|
||||||
before do
|
let_it_be(:group, reload: true) { create(:group, :internal) }
|
||||||
group.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
|
let_it_be(:project, reload: true) { create(:project, :internal, group: group) }
|
||||||
project.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
|
let_it_be(:issue, reload: true) { create(:issue, project: project) }
|
||||||
end
|
let_it_be(:issue_c, reload: true) { create(:issue, project: project, confidential: true) }
|
||||||
|
|
||||||
it 'enqueues the PrivateFeaturesWorker' do
|
it 'enqueues the PrivateFeaturesWorker' do
|
||||||
expect(TodosDestroyer::PrivateFeaturesWorker)
|
expect(TodosDestroyer::PrivateFeaturesWorker)
|
||||||
|
@ -84,50 +118,41 @@ RSpec.describe Todos::Destroy::EntityLeaveService do
|
||||||
|
|
||||||
context 'confidential issues' do
|
context 'confidential issues' do
|
||||||
context 'when a user is not an author of confidential issue' do
|
context 'when a user is not an author of confidential issue' do
|
||||||
it 'removes only confidential issues todos' do
|
it_behaves_like 'removes only confidential issues todos'
|
||||||
expect { subject }.to change { Todo.count }.from(5).to(4)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a user is an author of confidential issue' do
|
context 'when a user is an author of confidential issue' do
|
||||||
before do
|
before do
|
||||||
issue.update!(author: user)
|
issue_c.update!(author: user)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not remove any todos' do
|
it_behaves_like 'does not remove any todos'
|
||||||
expect { subject }.not_to change { Todo.count }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a user is an assignee of confidential issue' do
|
context 'when a user is an assignee of confidential issue' do
|
||||||
before do
|
before do
|
||||||
issue.assignees << user
|
issue_c.assignees << user
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not remove any todos' do
|
it_behaves_like 'does not remove any todos'
|
||||||
expect { subject }.not_to change { Todo.count }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a user is a project guest' do
|
context 'access permissions' do
|
||||||
before do
|
# rubocop:disable RSpec/LeakyConstantDeclaration
|
||||||
project.add_guest(user)
|
PROJECT_NOT_PRIVATE_ACCESS_TABLE =
|
||||||
end
|
lambda do |_|
|
||||||
|
[
|
||||||
|
# :group_access, :project_access, :c_todos, :mr_todos, :method
|
||||||
|
[nil, :reporter, :keep, :keep, :does_not_remove_any_todos],
|
||||||
|
[nil, :guest, :delete, :keep, :removes_only_confidential_issues_todos],
|
||||||
|
[:reporter, nil, :keep, :keep, :does_not_remove_any_todos],
|
||||||
|
[:guest, nil, :delete, :keep, :removes_only_confidential_issues_todos],
|
||||||
|
[:reporter, :guest, :keep, :keep, :does_not_remove_any_todos]
|
||||||
|
]
|
||||||
|
end
|
||||||
|
# rubocop:enable RSpec/LeakyConstantDeclaration
|
||||||
|
|
||||||
it 'removes only confidential issues todos' do
|
it_behaves_like 'using different access permissions', PROJECT_NOT_PRIVATE_ACCESS_TABLE
|
||||||
expect { subject }.to change { Todo.count }.from(5).to(4)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when a user is a project guest but group developer' do
|
|
||||||
before do
|
|
||||||
project.add_guest(user)
|
|
||||||
group.add_developer(user)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not remove any todos' do
|
|
||||||
expect { subject }.not_to change { Todo.count }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -138,42 +163,39 @@ RSpec.describe Todos::Destroy::EntityLeaveService do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'removes only users issue todos' do
|
it 'removes only users issue todos' do
|
||||||
expect { subject }.to change { Todo.count }.from(5).to(4)
|
expect { subject }.to change { Todo.count }.from(6).to(5)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a user leaves a group' do
|
describe 'updating a Group' do
|
||||||
subject { described_class.new(user.id, group.id, 'Group').execute }
|
subject { described_class.new(user.id, group.id, 'Group').execute }
|
||||||
|
|
||||||
context 'when group is private' do
|
context 'when group is private' do
|
||||||
it 'removes group and subproject todos for the user' do
|
context 'when a user leaves a group' do
|
||||||
expect { subject }.to change { Todo.count }.from(5).to(2)
|
it 'removes group and subproject todos for the user' do
|
||||||
|
expect { subject }.to change { Todo.count }.from(6).to(2)
|
||||||
|
|
||||||
expect(user.todos).to be_empty
|
expect(user.todos).to be_empty
|
||||||
expect(user2.todos).to match_array([todo_issue_user2, todo_group_user2])
|
expect(user2.todos).to match_array([todo_issue_c_user2, todo_group_user2])
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the user is member of the group' do
|
|
||||||
before do
|
|
||||||
group.add_developer(user)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not remove any todos' do
|
|
||||||
expect { subject }.not_to change { Todo.count }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the user is member of the group project but not the group' do
|
context 'access permissions' do
|
||||||
before do
|
# rubocop:disable RSpec/LeakyConstantDeclaration
|
||||||
project.add_developer(user)
|
GROUP_PRIVATE_ACCESS_TABLE =
|
||||||
end
|
lambda do |_|
|
||||||
|
[
|
||||||
|
# :group_access, :project_access, :c_todos, :mr_todos, :method
|
||||||
|
[nil, :reporter, :keep, :keep, :does_not_remove_any_todos],
|
||||||
|
[:reporter, nil, :keep, :keep, :does_not_remove_any_todos]
|
||||||
|
]
|
||||||
|
end
|
||||||
|
# rubocop:enable RSpec/LeakyConstantDeclaration
|
||||||
|
|
||||||
it 'does not remove any todos' do
|
it_behaves_like 'using different access permissions', GROUP_PRIVATE_ACCESS_TABLE
|
||||||
expect { subject }.not_to change { Todo.count }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with nested groups' do
|
context 'with nested groups' do
|
||||||
|
@ -191,12 +213,12 @@ RSpec.describe Todos::Destroy::EntityLeaveService do
|
||||||
|
|
||||||
context 'when the user is not a member of any groups/projects' do
|
context 'when the user is not a member of any groups/projects' do
|
||||||
it 'removes todos for the user including subprojects todos' do
|
it 'removes todos for the user including subprojects todos' do
|
||||||
expect { subject }.to change { Todo.count }.from(11).to(4)
|
expect { subject }.to change { Todo.count }.from(12).to(4)
|
||||||
|
|
||||||
expect(user.todos).to be_empty
|
expect(user.todos).to be_empty
|
||||||
expect(user2.todos)
|
expect(user2.todos)
|
||||||
.to match_array(
|
.to match_array(
|
||||||
[todo_issue_user2, todo_group_user2, todo_subproject_user2, todo_subpgroup_user2]
|
[todo_issue_c_user2, todo_group_user2, todo_subproject_user2, todo_subpgroup_user2]
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -208,9 +230,7 @@ RSpec.describe Todos::Destroy::EntityLeaveService do
|
||||||
parent_group.add_developer(user)
|
parent_group.add_developer(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not remove any todos' do
|
it_behaves_like 'does not remove any todos'
|
||||||
expect { subject }.not_to change { Todo.count }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the user is member of a subgroup' do
|
context 'when the user is member of a subgroup' do
|
||||||
|
@ -219,12 +239,12 @@ RSpec.describe Todos::Destroy::EntityLeaveService do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not remove group and subproject todos' do
|
it 'does not remove group and subproject todos' do
|
||||||
expect { subject }.to change { Todo.count }.from(11).to(7)
|
expect { subject }.to change { Todo.count }.from(12).to(7)
|
||||||
|
|
||||||
expect(user.todos).to match_array([todo_group_user, todo_subgroup_user, todo_subproject_user])
|
expect(user.todos).to match_array([todo_group_user, todo_subgroup_user, todo_subproject_user])
|
||||||
expect(user2.todos)
|
expect(user2.todos)
|
||||||
.to match_array(
|
.to match_array(
|
||||||
[todo_issue_user2, todo_group_user2, todo_subproject_user2, todo_subpgroup_user2]
|
[todo_issue_c_user2, todo_group_user2, todo_subproject_user2, todo_subpgroup_user2]
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -235,12 +255,12 @@ RSpec.describe Todos::Destroy::EntityLeaveService do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not remove subproject and group todos' do
|
it 'does not remove subproject and group todos' do
|
||||||
expect { subject }.to change { Todo.count }.from(11).to(7)
|
expect { subject }.to change { Todo.count }.from(12).to(7)
|
||||||
|
|
||||||
expect(user.todos).to match_array([todo_subgroup_user, todo_group_user, todo_subproject_user])
|
expect(user.todos).to match_array([todo_subgroup_user, todo_group_user, todo_subproject_user])
|
||||||
expect(user2.todos)
|
expect(user2.todos)
|
||||||
.to match_array(
|
.to match_array(
|
||||||
[todo_issue_user2, todo_group_user2, todo_subproject_user2, todo_subpgroup_user2]
|
[todo_issue_c_user2, todo_group_user2, todo_subproject_user2, todo_subpgroup_user2]
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -248,10 +268,10 @@ RSpec.describe Todos::Destroy::EntityLeaveService do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when group is not private' do
|
context 'when group is not private' do
|
||||||
before do
|
let_it_be(:group, reload: true) { create(:group, :internal) }
|
||||||
group.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
|
let_it_be(:project, reload: true) { create(:project, :internal, group: group) }
|
||||||
project.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
|
let_it_be(:issue, reload: true) { create(:issue, project: project) }
|
||||||
end
|
let_it_be(:issue_c, reload: true) { create(:issue, project: project, confidential: true) }
|
||||||
|
|
||||||
it 'enqueues the PrivateFeaturesWorker' do
|
it 'enqueues the PrivateFeaturesWorker' do
|
||||||
expect(TodosDestroyer::PrivateFeaturesWorker)
|
expect(TodosDestroyer::PrivateFeaturesWorker)
|
||||||
|
@ -260,31 +280,20 @@ RSpec.describe Todos::Destroy::EntityLeaveService do
|
||||||
subject
|
subject
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when user is not member' do
|
context 'access permissions' do
|
||||||
it 'removes only confidential issues todos' do
|
# rubocop:disable RSpec/LeakyConstantDeclaration
|
||||||
expect { subject }.to change { Todo.count }.from(5).to(4)
|
GROUP_NOT_PRIVATE_ACCESS_TABLE =
|
||||||
end
|
lambda do |_|
|
||||||
end
|
[
|
||||||
|
# :group_access, :project_access, :c_todos, :mr_todos, :method
|
||||||
|
[nil, nil, :delete, :keep, :removes_only_confidential_issues_todos],
|
||||||
|
[nil, :guest, :delete, :keep, :removes_only_confidential_issues_todos],
|
||||||
|
[:reporter, :guest, :keep, :keep, :does_not_remove_any_todos]
|
||||||
|
]
|
||||||
|
end
|
||||||
|
# rubocop:enable RSpec/LeakyConstantDeclaration
|
||||||
|
|
||||||
context 'when user is a project guest' do
|
it_behaves_like 'using different access permissions', GROUP_NOT_PRIVATE_ACCESS_TABLE
|
||||||
before do
|
|
||||||
project.add_guest(user)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'removes only confidential issues todos' do
|
|
||||||
expect { subject }.to change { Todo.count }.from(5).to(4)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when user is a project guest & group developer' do
|
|
||||||
before do
|
|
||||||
project.add_guest(user)
|
|
||||||
group.add_developer(user)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not remove any todos' do
|
|
||||||
expect { subject }.not_to change { Todo.count }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue