Commit 3abef158 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents d838e6c3 82f32b6f
......@@ -124,7 +124,7 @@ export default {
type="submit"
class="js-no-auto-disable"
category="primary"
variant="success"
variant="confirm"
:disabled="submitDisabled"
:loading="isSaving"
>
......
# frozen_string_literal: true
module Mutations
module ReleaseAssetLinks
class Delete < BaseMutation
graphql_name 'ReleaseAssetLinkDelete'
authorize :destroy_release
ReleaseAssetLinkID = ::Types::GlobalIDType[::Releases::Link]
argument :id, ReleaseAssetLinkID,
required: true,
description: 'ID of the release asset link to delete.'
field :link,
Types::ReleaseAssetLinkType,
null: true,
description: 'The deleted release asset link.'
def resolve(id:)
link = authorized_find!(id)
unless link.destroy
return { link: nil, errors: link.errors.full_messages }
end
{ link: link, errors: [] }
end
def find_object(id)
# TODO: remove this line when the compatibility layer is removed
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
id = ReleaseAssetLinkID.coerce_isolated_input(id)
GitlabSchema.find_by_gid(id)
end
end
end
end
......@@ -68,6 +68,7 @@ module Types
mount_mutation Mutations::Releases::Delete
mount_mutation Mutations::ReleaseAssetLinks::Create
mount_mutation Mutations::ReleaseAssetLinks::Update
mount_mutation Mutations::ReleaseAssetLinks::Delete
mount_mutation Mutations::Terraform::State::Delete
mount_mutation Mutations::Terraform::State::Lock
mount_mutation Mutations::Terraform::State::Unlock
......
......@@ -39,5 +39,5 @@
= f.check_box :active, required: false, value: @schedule.active?
= f.label :active, _('Active'), class: 'gl-font-weight-normal'
.footer-block.row-content-block
= f.submit _('Save pipeline schedule'), class: 'btn gl-button btn-success'
= f.submit _('Save pipeline schedule'), class: 'btn gl-button btn-confirm'
= link_to _('Cancel'), pipeline_schedules_path(@project), class: 'btn gl-button btn-default btn-cancel'
......@@ -9,7 +9,7 @@
- if can?(current_user, :create_pipeline_schedule, @project)
.nav-controls
= link_to new_project_pipeline_schedule_path(@project), class: 'btn gl-button btn-success' do
= link_to new_project_pipeline_schedule_path(@project), class: 'btn gl-button btn-confirm' do
%span= _('New schedule')
- if @schedules.present?
......
---
title: Move to confirm varient from success in pipeline_editor directory
merge_request: 56200
author: Yogi (@yo)
type: changed
---
title: Move from btn-success to btn-confirm in pipeline_schedules directory
merge_request: 56201
author: Yogi (@yo)
type: changed
---
title: Add GraphQL mutation to delete an existing release asset link
merge_request: 56417
author:
type: added
---
title: Update android template to default branch
merge_request: 56738
author:
type: other
......@@ -5048,6 +5048,16 @@ Autogenerated return type of ReleaseAssetLinkCreate.
| `errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| `link` | [`ReleaseAssetLink`](#releaseassetlink) | The asset link after mutation. |
### `ReleaseAssetLinkDeletePayload`
Autogenerated return type of ReleaseAssetLinkDelete.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| `errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| `link` | [`ReleaseAssetLink`](#releaseassetlink) | The deleted release asset link. |
### `ReleaseAssetLinkEdge`
An edge in a connection.
......
......@@ -957,7 +957,10 @@ Example aggregated metric entries:
```yaml
- name: example_metrics_union
operator: OR
events: ['i_search_total', 'i_search_advanced', 'i_search_paid']
events:
- 'i_search_total'
- 'i_search_advanced'
- 'i_search_paid'
source: redis
time_frame:
- 7d
......@@ -968,7 +971,9 @@ Example aggregated metric entries:
time_frame:
- 28d
- all
events: ['dependency_scanning_pipeline_all_time', 'container_scanning_pipeline_all_time']
events:
- 'dependency_scanning_pipeline_all_time'
- 'container_scanning_pipeline_all_time'
feature_flag: example_aggregated_metric
```
......@@ -1099,7 +1104,9 @@ Example definition:
- name: example_metrics_intersection_database_sourced
operator: AND
source: database
events: ['dependency_scanning_pipeline', 'container_scanning_pipeline']
events:
- 'dependency_scanning_pipeline'
- 'container_scanning_pipeline'
time_frame:
- 28d
- all
......
......@@ -19,11 +19,8 @@ export default {
GlLoadingIcon,
VulnerabilitiesCountList,
},
inject: ['groupFullPath'],
props: {
groupFullPath: {
type: String,
required: true,
},
vulnerabilitiesExportEndpoint: {
type: String,
required: true,
......@@ -88,7 +85,7 @@ export default {
<template #sticky>
<filters :projects="projects" @filterChange="handleFilterChange" />
</template>
<group-security-vulnerabilities :group-full-path="groupFullPath" :filters="filters" />
<group-security-vulnerabilities :filters="filters" />
</security-dashboard-layout>
</div>
</template>
......@@ -13,11 +13,8 @@ export default {
GlIntersectionObserver,
VulnerabilityList,
},
inject: ['groupFullPath'],
props: {
groupFullPath: {
type: String,
required: true,
},
filters: {
type: Object,
required: false,
......
......@@ -25,9 +25,9 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
inject: ['groupFullPath'],
props: {
query: { type: Object, required: true },
groupFullPath: { type: String, required: false, default: undefined },
},
data() {
return {
......
......@@ -32,6 +32,7 @@ export default {
directives: {
'gl-tooltip': GlTooltipDirective,
},
inject: ['groupFullPath'],
props: {
helpPagePath: {
type: String,
......@@ -42,11 +43,6 @@ export default {
type: Object,
required: true,
},
groupFullPath: {
type: String,
required: false,
default: undefined,
},
},
data() {
return {
......
......@@ -18,12 +18,7 @@ export default {
VulnerabilitySeverities,
VulnerabilityChart,
},
props: {
groupFullPath: {
type: String,
required: true,
},
},
inject: ['groupFullPath'],
apollo: {
projects: {
query: vulnerableProjectsQuery,
......@@ -65,11 +60,8 @@ export default {
<dashboard-not-configured />
</template>
<template v-else-if="shouldShowCharts" #default>
<vulnerability-chart :query="vulnerabilityHistoryQuery" :group-full-path="groupFullPath" />
<vulnerability-severities
:query="vulnerabilityGradesQuery"
:group-full-path="groupFullPath"
/>
<vulnerability-chart :query="vulnerabilityHistoryQuery" />
<vulnerability-severities :query="vulnerabilityGradesQuery" />
</template>
<template v-else #loading>
<gl-loading-icon size="lg" class="gl-mt-6" />
......
......@@ -61,6 +61,7 @@ export default (el, dashboardType) => {
emptyStateSvgPath,
notEnabledScannersHelpPath,
noPipelineRunScannersHelpPath,
groupFullPath,
securityConfigurationPath,
hasVulnerabilities: parseBoolean(hasVulnerabilities),
scanners: scanners ? JSON.parse(scanners) : [],
......@@ -92,7 +93,6 @@ export default (el, dashboardType) => {
provide.autoFixMrsPath = autoFixMrsPath;
} else if (dashboardType === DASHBOARD_TYPES.GROUP) {
component = FirstClassGroupSecurityDashboard;
props.groupFullPath = groupFullPath;
} else if (dashboardType === DASHBOARD_TYPES.INSTANCE) {
provide.instanceDashboardSettingsPath = instanceDashboardSettingsPath;
component = FirstClassInstanceSecurityDashboard;
......
......@@ -32,6 +32,7 @@ export default (el, dashboardType) => {
const provide = {
dashboardDocumentation: el.dataset.dashboardDocumentation,
emptyStateSvgPath: el.dataset.emptyStateSvgPath,
groupFullPath: el.dataset.groupFullPath,
securityConfigurationPath: el.dataset.securityConfigurationPath,
};
......
---
title: Use provide/inject for groupFullPath instead of props
merge_request: 56472
author:
type: other
......@@ -17,5 +17,7 @@
- name: product_analytics_test_metrics_intersection_database_sourced
source: database
time_frame: [28d]
events: ['dependency_scanning_pipeline', 'container_scanning_pipeline']
events:
- 'dependency_scanning_pipeline'
- 'container_scanning_pipeline'
operator: AND
......@@ -29,9 +29,9 @@ describe('First Class Group Dashboard Component', () => {
propsData: {
dashboardDocumentation,
emptyStateSvgPath,
groupFullPath,
vulnerabilitiesExportEndpoint,
},
provide: { groupFullPath },
data,
stubs: {
SecurityDashboardLayout,
......@@ -66,7 +66,6 @@ describe('First Class Group Dashboard Component', () => {
it('should render correctly', () => {
expect(findGroupVulnerabilities().props()).toEqual({
groupFullPath,
filters: {},
});
});
......
......@@ -24,15 +24,13 @@ describe('First Class Group Dashboard Vulnerabilities Component', () => {
const createWrapper = ({ $apollo = apolloMock, stubs } = {}) => {
return shallowMount(FirstClassGroupVulnerabilities, {
propsData: {
groupFullPath,
},
stubs,
mocks: {
$apollo,
fetchNextPage: () => {},
},
provide: {
groupFullPath,
hasVulnerabilities: true,
hasJiraVulnerabilitiesIntegrationEnabled: false,
},
......
......@@ -21,10 +21,11 @@ describe('First class vulnerability chart component', () => {
const findActiveChartButton = () => findChartButtons().find('.selected');
const find90DaysChartButton = () => findChartButtons().find('[data-days="90"]');
const createComponent = ({ $apollo, propsData, stubs, data } = {}) => {
const createComponent = ({ $apollo, propsData, stubs, data, provide } = {}) => {
const instance = shallowMount(VulnerabilityChart, {
$apollo,
propsData: { query: {}, ...propsData },
provide: { groupFullPath: undefined, ...provide },
stubs: {
...stubChildren(VulnerabilityChart),
...stubs,
......@@ -84,7 +85,7 @@ describe('First class vulnerability chart component', () => {
describe('when loading the history chart for group level dashboard', () => {
beforeEach(() => {
wrapper = createComponent({
propsData: { groupFullPath: 'gitlab-org' },
provide: { groupFullPath: 'gitlab-org' },
$apollo: {
queries: { vulnerabilitiesHistory: { group: responseData } },
},
......
......@@ -33,7 +33,7 @@ describe('Vulnerability Severity component', () => {
return createMockApollo([...queries]);
};
const createComponent = ({ propsData, data, apolloProvider }) => {
const createComponent = ({ propsData, data, apolloProvider, provide }) => {
return shallowMount(VulnerabilitySeverity, {
localVue,
apolloProvider,
......@@ -42,6 +42,7 @@ describe('Vulnerability Severity component', () => {
helpPagePath,
...propsData,
},
provide: { groupFullPath: undefined, ...provide },
stubs: {
Accordion,
AccordionItem,
......@@ -69,7 +70,8 @@ describe('Vulnerability Severity component', () => {
]);
wrapper = createComponent({
propsData: { groupFullPath: 'gitlab-org', query: groupVulnerabilityGradesQuery },
propsData: { query: groupVulnerabilityGradesQuery },
provide: { groupFullPath: 'gitlab-org' },
apolloProvider,
});
......
......@@ -41,7 +41,7 @@ describe('Group Security Charts component', () => {
},
},
},
propsData: { groupFullPath },
provide: { groupFullPath },
stubs: {
SecurityChartsLayout,
},
......@@ -100,11 +100,10 @@ describe('Group Security Charts component', () => {
expect(dashboardNotConfigured.exists()).toBe(false);
expect(loadingIcon.exists()).toBe(false);
expect(vulnerabilityChart.exists()).toBe(true);
expect(vulnerabilityChart.props()).toEqual({ query: vulnerabilityHistoryQuery, groupFullPath });
expect(vulnerabilityChart.props()).toEqual({ query: vulnerabilityHistoryQuery });
expect(vulnerabilitySeverities.exists()).toBe(true);
expect(vulnerabilitySeverities.props()).toEqual({
query: vulnerabilityGradesQuery,
groupFullPath,
helpPagePath: '',
});
});
......
......@@ -113,9 +113,10 @@ promoteBeta:
promoteProduction:
extends: .promote_job
stage: production
# We only allow production promotion on `master` because
# it has its own production scoped secret variables
# We only allow production promotion on the default branch because
# it has its own production scoped secret variables.
only:
- master
variables:
- $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
script:
- bundle exec fastlane promote_beta_to_production
......@@ -12,97 +12,94 @@
feature_flag: usage_data_code_review_aggregation
source: redis
time_frame: [7d, 28d]
events: [
'i_code_review_user_single_file_diffs',
'i_code_review_user_create_mr',
'i_code_review_user_close_mr',
'i_code_review_user_reopen_mr',
'i_code_review_user_resolve_thread',
'i_code_review_user_unresolve_thread',
'i_code_review_edit_mr_title',
'i_code_review_edit_mr_desc',
'i_code_review_user_merge_mr',
'i_code_review_user_create_mr_comment',
'i_code_review_user_edit_mr_comment',
'i_code_review_user_remove_mr_comment',
'i_code_review_user_create_review_note',
'i_code_review_user_publish_review',
'i_code_review_user_create_multiline_mr_comment',
'i_code_review_user_edit_multiline_mr_comment',
'i_code_review_user_remove_multiline_mr_comment',
'i_code_review_user_add_suggestion',
'i_code_review_user_apply_suggestion',
'i_code_review_user_assigned',
'i_code_review_user_review_requested',
'i_code_review_user_approve_mr',
'i_code_review_user_unapprove_mr',
'i_code_review_user_marked_as_draft',
'i_code_review_user_unmarked_as_draft',
'i_code_review_user_approval_rule_added',
'i_code_review_user_approval_rule_deleted',
'i_code_review_user_approval_rule_edited',
'i_code_review_user_vs_code_api_request',
'i_code_review_user_toggled_task_item_status',
'i_code_review_user_create_mr_from_issue',
'i_code_review_user_mr_discussion_locked',
'i_code_review_user_mr_discussion_unlocked',
'i_code_review_user_time_estimate_changed',
'i_code_review_user_time_spent_changed',
'i_code_review_user_assignees_changed',
'i_code_review_user_reviewers_changed',
'i_code_review_user_milestone_changed',
'i_code_review_user_labels_changed'
]
events:
- 'i_code_review_user_single_file_diffs'
- 'i_code_review_user_create_mr'
- 'i_code_review_user_close_mr'
- 'i_code_review_user_reopen_mr'
- 'i_code_review_user_resolve_thread'
- 'i_code_review_user_unresolve_thread'
- 'i_code_review_edit_mr_title'
- 'i_code_review_edit_mr_desc'
- 'i_code_review_user_merge_mr'
- 'i_code_review_user_create_mr_comment'
- 'i_code_review_user_edit_mr_comment'
- 'i_code_review_user_remove_mr_comment'
- 'i_code_review_user_create_review_note'
- 'i_code_review_user_publish_review'
- 'i_code_review_user_create_multiline_mr_comment'
- 'i_code_review_user_edit_multiline_mr_comment'
- 'i_code_review_user_remove_multiline_mr_comment'
- 'i_code_review_user_add_suggestion'
- 'i_code_review_user_apply_suggestion'
- 'i_code_review_user_assigned'
- 'i_code_review_user_review_requested'
- 'i_code_review_user_approve_mr'
- 'i_code_review_user_unapprove_mr'
- 'i_code_review_user_marked_as_draft'
- 'i_code_review_user_unmarked_as_draft'
- 'i_code_review_user_approval_rule_added'
- 'i_code_review_user_approval_rule_deleted'
- 'i_code_review_user_approval_rule_edited'
- 'i_code_review_user_vs_code_api_request'
- 'i_code_review_user_toggled_task_item_status'
- 'i_code_review_user_create_mr_from_issue'
- 'i_code_review_user_mr_discussion_locked'
- 'i_code_review_user_mr_discussion_unlocked'
- 'i_code_review_user_time_estimate_changed'
- 'i_code_review_user_time_spent_changed'
- 'i_code_review_user_assignees_changed'
- 'i_code_review_user_reviewers_changed'
- 'i_code_review_user_milestone_changed'
- 'i_code_review_user_labels_changed'
- name: code_review_category_monthly_active_users
operator: OR
feature_flag: usage_data_code_review_aggregation
source: redis
time_frame: [7d, 28d]
events: [
'i_code_review_user_single_file_diffs',
'i_code_review_user_create_mr',
'i_code_review_user_close_mr',
'i_code_review_user_reopen_mr',
'i_code_review_user_resolve_thread',
'i_code_review_user_unresolve_thread',
'i_code_review_edit_mr_title',
'i_code_review_edit_mr_desc',
'i_code_review_user_merge_mr',
'i_code_review_user_create_mr_comment',
'i_code_review_user_edit_mr_comment',
'i_code_review_user_remove_mr_comment',
'i_code_review_user_create_review_note',
'i_code_review_user_publish_review',
'i_code_review_user_create_multiline_mr_comment',
'i_code_review_user_edit_multiline_mr_comment',
'i_code_review_user_remove_multiline_mr_comment',
'i_code_review_user_add_suggestion',
'i_code_review_user_apply_suggestion',
'i_code_review_user_assigned',
'i_code_review_user_review_requested',
'i_code_review_user_approve_mr',
'i_code_review_user_unapprove_mr',
'i_code_review_user_marked_as_draft',
'i_code_review_user_unmarked_as_draft',
'i_code_review_user_approval_rule_added',
'i_code_review_user_approval_rule_deleted',
'i_code_review_user_approval_rule_edited',
'i_code_review_user_toggled_task_item_status',
'i_code_review_user_create_mr_from_issue',
'i_code_review_user_mr_discussion_locked',
'i_code_review_user_mr_discussion_unlocked',
'i_code_review_user_time_estimate_changed',
'i_code_review_user_time_spent_changed',
'i_code_review_user_assignees_changed',
'i_code_review_user_reviewers_changed',
'i_code_review_user_milestone_changed',
'i_code_review_user_labels_changed'
]
events:
- 'i_code_review_user_single_file_diffs'
- 'i_code_review_user_create_mr'
- 'i_code_review_user_close_mr'
- 'i_code_review_user_reopen_mr'
- 'i_code_review_user_resolve_thread'
- 'i_code_review_user_unresolve_thread'
- 'i_code_review_edit_mr_title'
- 'i_code_review_edit_mr_desc'
- 'i_code_review_user_merge_mr'
- 'i_code_review_user_create_mr_comment'
- 'i_code_review_user_edit_mr_comment'
- 'i_code_review_user_remove_mr_comment'
- 'i_code_review_user_create_review_note'
- 'i_code_review_user_publish_review'
- 'i_code_review_user_create_multiline_mr_comment'
- 'i_code_review_user_edit_multiline_mr_comment'
- 'i_code_review_user_remove_multiline_mr_comment'
- 'i_code_review_user_add_suggestion'
- 'i_code_review_user_apply_suggestion'
- 'i_code_review_user_assigned'
- 'i_code_review_user_review_requested'
- 'i_code_review_user_approve_mr'
- 'i_code_review_user_unapprove_mr'
- 'i_code_review_user_marked_as_draft'
- 'i_code_review_user_unmarked_as_draft'
- 'i_code_review_user_approval_rule_added'
- 'i_code_review_user_approval_rule_deleted'
- 'i_code_review_user_approval_rule_edited'
- 'i_code_review_user_toggled_task_item_status'
- 'i_code_review_user_create_mr_from_issue'
- 'i_code_review_user_mr_discussion_locked'
- 'i_code_review_user_mr_discussion_unlocked'
- 'i_code_review_user_time_estimate_changed'
- 'i_code_review_user_time_spent_changed'
- 'i_code_review_user_assignees_changed'
- 'i_code_review_user_reviewers_changed'
- 'i_code_review_user_milestone_changed'
- 'i_code_review_user_labels_changed'
- name: code_review_extension_category_monthly_active_users
operator: OR
feature_flag: usage_data_code_review_aggregation
source: redis
time_frame: [7d, 28d]
events: [
'i_code_review_user_vs_code_api_request'
]
events:
- 'i_code_review_user_vs_code_api_request'
......@@ -21,52 +21,60 @@
operator: OR
source: redis
time_frame: [7d, 28d]
events: ['g_compliance_audit_events', 'g_compliance_dashboard', 'i_compliance_audit_events', 'a_compliance_audit_events_api', 'i_compliance_credential_inventory']
events:
- 'g_compliance_audit_events'
- 'g_compliance_dashboard'
- 'i_compliance_audit_events'
- 'a_compliance_audit_events_api'
- 'i_compliance_credential_inventory'
- name: product_analytics_test_metrics_union
operator: OR
source: redis
time_frame: [7d, 28d]
events: ['i_search_total', 'i_search_advanced', 'i_search_paid']
events:
- 'i_search_total'
- 'i_search_advanced'
- 'i_search_paid'
- name: product_analytics_test_metrics_intersection
operator: AND
source: redis
time_frame: [7d, 28d]
events: ['i_search_total', 'i_search_advanced', 'i_search_paid']
events:
- 'i_search_total'
- 'i_search_advanced'
- 'i_search_paid'
- name: incident_management_alerts_total_unique_counts
operator: OR
source: redis
time_frame: [7d, 28d]
events: [
'incident_management_alert_status_changed',
'incident_management_alert_assigned',
'incident_management_alert_todo',
'incident_management_alert_create_incident'
]
events:
- 'incident_management_alert_status_changed'
- 'incident_management_alert_assigned'
- 'incident_management_alert_todo'
- 'incident_management_alert_create_incident'
- name: incident_management_incidents_total_unique_counts
operator: OR
source: redis
time_frame: [7d, 28d]
events: [
'incident_management_incident_created',
'incident_management_incident_reopened',
'incident_management_incident_closed',
'incident_management_incident_assigned',
'incident_management_incident_todo',
'incident_management_incident_comment',
'incident_management_incident_zoom_meeting',
'incident_management_incident_published',
'incident_management_incident_relate',
'incident_management_incident_unrelate',
'incident_management_incident_change_confidential'
]
events:
- 'incident_management_incident_created'
- 'incident_management_incident_reopened'
- 'incident_management_incident_closed'
- 'incident_management_incident_assigned'
- 'incident_management_incident_todo'
- 'incident_management_incident_comment'
- 'incident_management_incident_zoom_meeting'
- 'incident_management_incident_published'
- 'incident_management_incident_relate'
- 'incident_management_incident_unrelate'
- 'incident_management_incident_change_confidential'
- name: i_testing_paid_monthly_active_user_total
operator: OR
source: redis
time_frame: [7d, 28d]
events: [
'i_testing_web_performance_widget_total',
'i_testing_full_code_quality_report_total',
'i_testing_group_code_coverage_visit_total',
'i_testing_load_performance_widget_total',
'i_testing_metrics_report_widget_total'
]
events:
- 'i_testing_web_performance_widget_total'
- 'i_testing_full_code_quality_report_total'
- 'i_testing_group_code_coverage_visit_total'
- 'i_testing_load_performance_widget_total'
- 'i_testing_metrics_report_widget_total'
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Mutations::ReleaseAssetLinks::Delete do
include GraphqlHelpers
let_it_be(:project) { create(:project, :private, :repository) }
let_it_be_with_reload(:release) { create(:release, project: project) }
let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } }
let_it_be(:maintainer) { create(:user).tap { |u| project.add_maintainer(u) } }
let_it_be_with_reload(:release_link) { create(:release_link, release: release) }
let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
let(:mutation_arguments) { { id: release_link.to_global_id } }
describe '#resolve' do
subject(:resolve) do
mutation.resolve(**mutation_arguments)
end
let(:deleted_link) { subject[:link] }
context 'when the current user has access to delete the link' do
let(:current_user) { maintainer }
it 'deletes the link and returns it', :aggregate_failures do
expect(deleted_link).to eq(release_link)
expect(release.links).to be_empty
end
context "when the link doesn't exist" do
let(:mutation_arguments) { super().merge(id: "gid://gitlab/Releases::Link/#{non_existing_record_id}") }
it 'raises an error' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
context "when the provided ID is invalid" do
let(:mutation_arguments) { super().merge(id: 'not-a-valid-gid') }
it 'raises an error' do
expect { subject }.to raise_error(::GraphQL::CoercionError)
end
end
end
context 'when the current user does not have access to delete the link' do
let(:current_user) { developer }
it 'raises an error' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Deletes a release asset link' do
include GraphqlHelpers
let_it_be(:project) { create(:project, :private, :repository) }
let_it_be(:release) { create(:release, project: project) }
let_it_be(:maintainer) { create(:user).tap { |u| project.add_maintainer(u) } }
let_it_be(:release_link) { create(:release_link, release: release) }
let(:current_user) { maintainer }
let(:mutation_name) { :release_asset_link_delete }
let(:mutation_arguments) { { id: release_link.to_global_id.to_s } }
let(:mutation) do
graphql_mutation(mutation_name, mutation_arguments, <<~FIELDS)
link {
id
name
url
linkType
directAssetUrl
external
}
errors
FIELDS
end
let(:delete_link) { post_graphql_mutation(mutation, current_user: current_user) }
let(:mutation_response) { graphql_mutation_response(mutation_name)&.with_indifferent_access }
it 'deletes the release asset link and returns the deleted link', :aggregate_failures do
delete_link
expected_response = {
id: release_link.to_global_id.to_s,
name: release_link.name,
url: release_link.url,
linkType: release_link.link_type.upcase,
directAssetUrl: end_with(release_link.filepath),
external: true
}.with_indifferent_access
expect(mutation_response[:link]).to match(expected_response)
expect(mutation_response[:errors]).to eq([])
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment