Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
3007cf75a9
commit
afbf001676
|
@ -232,13 +232,11 @@ export const trackTransaction = (transactionDetails) => {
|
||||||
pushEnhancedEcommerceEvent('EECtransactionSuccess', eventData);
|
pushEnhancedEcommerceEvent('EECtransactionSuccess', eventData);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const trackAddToCartUsageTab = () => {
|
export const pushEECproductAddToCartEvent = () => {
|
||||||
if (!isSupported()) {
|
if (!isSupported()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getStartedButton = document.querySelector('.js-buy-additional-minutes');
|
|
||||||
getStartedButton.addEventListener('click', () => {
|
|
||||||
window.dataLayer.push({
|
window.dataLayer.push({
|
||||||
event: 'EECproductAddToCart',
|
event: 'EECproductAddToCart',
|
||||||
ecommerce: {
|
ecommerce: {
|
||||||
|
@ -258,7 +256,14 @@ export const trackAddToCartUsageTab = () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
|
|
||||||
|
export const trackAddToCartUsageTab = () => {
|
||||||
|
const getStartedButton = document.querySelector('.js-buy-additional-minutes');
|
||||||
|
if (!getStartedButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getStartedButton.addEventListener('click', pushEECproductAddToCartEvent);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const trackCombinedGroupProjectForm = () => {
|
export const trackCombinedGroupProjectForm = () => {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<script>
|
<script>
|
||||||
import { GlTooltipDirective, GlButton } from '@gitlab/ui';
|
import { GlButton, GlLink, GlTooltip, GlSprintf } from '@gitlab/ui';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DeleteButton',
|
name: 'DeleteButton',
|
||||||
components: {
|
components: {
|
||||||
GlButton,
|
GlButton,
|
||||||
},
|
GlLink,
|
||||||
directives: {
|
GlTooltip,
|
||||||
GlTooltip: GlTooltipDirective,
|
GlSprintf,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
title: {
|
title: {
|
||||||
|
@ -18,6 +18,11 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
tooltipLink: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
disabled: {
|
disabled: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
|
@ -29,21 +34,12 @@ export default {
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
tooltipConfiguration() {
|
|
||||||
return {
|
|
||||||
disabled: this.tooltipDisabled,
|
|
||||||
title: this.tooltipTitle,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-gl-tooltip="tooltipConfiguration">
|
<div ref="deleteImageButton">
|
||||||
<gl-button
|
<gl-button
|
||||||
v-gl-tooltip
|
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:title="title"
|
:title="title"
|
||||||
:aria-label="title"
|
:aria-label="title"
|
||||||
|
@ -52,5 +48,14 @@ export default {
|
||||||
icon="remove"
|
icon="remove"
|
||||||
@click="$emit('delete')"
|
@click="$emit('delete')"
|
||||||
/>
|
/>
|
||||||
|
<gl-tooltip :target="() => $refs.deleteImageButton" :disabled="tooltipDisabled" placement="top">
|
||||||
|
<gl-sprintf :message="tooltipTitle">
|
||||||
|
<template #docLink="{ content }">
|
||||||
|
<gl-link v-if="tooltipLink" :href="tooltipLink" target="_blank">
|
||||||
|
{{ content }}
|
||||||
|
</gl-link>
|
||||||
|
</template>
|
||||||
|
</gl-sprintf>
|
||||||
|
</gl-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -8,11 +8,13 @@ import ListItem from '~/vue_shared/components/registry/list_item.vue';
|
||||||
import {
|
import {
|
||||||
ASYNC_DELETE_IMAGE_ERROR_MESSAGE,
|
ASYNC_DELETE_IMAGE_ERROR_MESSAGE,
|
||||||
LIST_DELETE_BUTTON_DISABLED,
|
LIST_DELETE_BUTTON_DISABLED,
|
||||||
|
LIST_DELETE_BUTTON_DISABLED_FOR_MIGRATION,
|
||||||
REMOVE_REPOSITORY_LABEL,
|
REMOVE_REPOSITORY_LABEL,
|
||||||
ROW_SCHEDULED_FOR_DELETION,
|
ROW_SCHEDULED_FOR_DELETION,
|
||||||
CLEANUP_TIMED_OUT_ERROR_MESSAGE,
|
CLEANUP_TIMED_OUT_ERROR_MESSAGE,
|
||||||
IMAGE_DELETE_SCHEDULED_STATUS,
|
IMAGE_DELETE_SCHEDULED_STATUS,
|
||||||
IMAGE_FAILED_DELETED_STATUS,
|
IMAGE_FAILED_DELETED_STATUS,
|
||||||
|
IMAGE_MIGRATING_STATE,
|
||||||
ROOT_IMAGE_TEXT,
|
ROOT_IMAGE_TEXT,
|
||||||
} from '../../constants/index';
|
} from '../../constants/index';
|
||||||
import DeleteButton from '../delete_button.vue';
|
import DeleteButton from '../delete_button.vue';
|
||||||
|
@ -32,6 +34,7 @@ export default {
|
||||||
directives: {
|
directives: {
|
||||||
GlTooltip: GlTooltipDirective,
|
GlTooltip: GlTooltipDirective,
|
||||||
},
|
},
|
||||||
|
inject: ['config'],
|
||||||
props: {
|
props: {
|
||||||
item: {
|
item: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -44,13 +47,12 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
i18n: {
|
i18n: {
|
||||||
LIST_DELETE_BUTTON_DISABLED,
|
|
||||||
REMOVE_REPOSITORY_LABEL,
|
REMOVE_REPOSITORY_LABEL,
|
||||||
ROW_SCHEDULED_FOR_DELETION,
|
ROW_SCHEDULED_FOR_DELETION,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
disabledDelete() {
|
disabledDelete() {
|
||||||
return !this.item.canDelete || this.deleting;
|
return !this.item.canDelete || this.deleting || this.migrating;
|
||||||
},
|
},
|
||||||
id() {
|
id() {
|
||||||
return getIdFromGraphQLId(this.item.id);
|
return getIdFromGraphQLId(this.item.id);
|
||||||
|
@ -58,6 +60,9 @@ export default {
|
||||||
deleting() {
|
deleting() {
|
||||||
return this.item.status === IMAGE_DELETE_SCHEDULED_STATUS;
|
return this.item.status === IMAGE_DELETE_SCHEDULED_STATUS;
|
||||||
},
|
},
|
||||||
|
migrating() {
|
||||||
|
return this.item.migrationState === IMAGE_MIGRATING_STATE;
|
||||||
|
},
|
||||||
failedDelete() {
|
failedDelete() {
|
||||||
return this.item.status === IMAGE_FAILED_DELETED_STATUS;
|
return this.item.status === IMAGE_FAILED_DELETED_STATUS;
|
||||||
},
|
},
|
||||||
|
@ -83,6 +88,11 @@ export default {
|
||||||
routerLinkEvent() {
|
routerLinkEvent() {
|
||||||
return this.deleting ? '' : 'click';
|
return this.deleting ? '' : 'click';
|
||||||
},
|
},
|
||||||
|
deleteButtonTooltipTitle() {
|
||||||
|
return this.migrating
|
||||||
|
? LIST_DELETE_BUTTON_DISABLED_FOR_MIGRATION
|
||||||
|
: LIST_DELETE_BUTTON_DISABLED;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -144,8 +154,9 @@ export default {
|
||||||
<delete-button
|
<delete-button
|
||||||
:title="$options.i18n.REMOVE_REPOSITORY_LABEL"
|
:title="$options.i18n.REMOVE_REPOSITORY_LABEL"
|
||||||
:disabled="disabledDelete"
|
:disabled="disabledDelete"
|
||||||
:tooltip-disabled="item.canDelete"
|
:tooltip-disabled="!disabledDelete"
|
||||||
:tooltip-title="$options.i18n.LIST_DELETE_BUTTON_DISABLED"
|
:tooltip-link="config.containerRegistryImportingHelpPagePath"
|
||||||
|
:tooltip-title="deleteButtonTooltipTitle"
|
||||||
@delete="$emit('delete', item)"
|
@delete="$emit('delete', item)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -14,6 +14,9 @@ export const LIST_INTRO_TEXT = s__(
|
||||||
export const LIST_DELETE_BUTTON_DISABLED = s__(
|
export const LIST_DELETE_BUTTON_DISABLED = s__(
|
||||||
'ContainerRegistry|Missing or insufficient permission, delete button disabled',
|
'ContainerRegistry|Missing or insufficient permission, delete button disabled',
|
||||||
);
|
);
|
||||||
|
export const LIST_DELETE_BUTTON_DISABLED_FOR_MIGRATION = s__(
|
||||||
|
`ContainerRegistry|Image repository temporarily cannot be marked for deletion. Please try again in a few minutes. %{docLinkStart}More details%{docLinkEnd}`,
|
||||||
|
);
|
||||||
export const REMOVE_REPOSITORY_LABEL = s__('ContainerRegistry|Remove repository');
|
export const REMOVE_REPOSITORY_LABEL = s__('ContainerRegistry|Remove repository');
|
||||||
export const REMOVE_REPOSITORY_MODAL_TEXT = s__(
|
export const REMOVE_REPOSITORY_MODAL_TEXT = s__(
|
||||||
'ContainerRegistry|You are about to remove repository %{title}. Once you confirm, this repository will be permanently deleted.',
|
'ContainerRegistry|You are about to remove repository %{title}. Once you confirm, this repository will be permanently deleted.',
|
||||||
|
@ -45,6 +48,7 @@ export const EMPTY_RESULT_MESSAGE = s__(
|
||||||
|
|
||||||
export const IMAGE_DELETE_SCHEDULED_STATUS = 'DELETE_SCHEDULED';
|
export const IMAGE_DELETE_SCHEDULED_STATUS = 'DELETE_SCHEDULED';
|
||||||
export const IMAGE_FAILED_DELETED_STATUS = 'DELETE_FAILED';
|
export const IMAGE_FAILED_DELETED_STATUS = 'DELETE_FAILED';
|
||||||
|
export const IMAGE_MIGRATING_STATE = 'importing';
|
||||||
export const GRAPHQL_PAGE_SIZE = 10;
|
export const GRAPHQL_PAGE_SIZE = 10;
|
||||||
|
|
||||||
export const SORT_FIELDS = [
|
export const SORT_FIELDS = [
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
@import 'mixins_and_variables_and_functions';
|
||||||
|
|
||||||
|
.description.work-items-enabled {
|
||||||
|
ul.task-list {
|
||||||
|
> li.task-list-item {
|
||||||
|
padding-inline-start: 2.5rem;
|
||||||
|
|
||||||
|
.js-add-task {
|
||||||
|
svg {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus svg {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> input.task-list-item-checkbox {
|
||||||
|
left: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus-within {
|
||||||
|
.js-add-task svg {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -307,32 +307,3 @@ ul.related-merge-requests > li gl-emoji {
|
||||||
.issuable-header-slide-leave-to {
|
.issuable-header-slide-leave-to {
|
||||||
transform: translateY(-100%);
|
transform: translateY(-100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.description.work-items-enabled {
|
|
||||||
ul.task-list {
|
|
||||||
> li.task-list-item {
|
|
||||||
padding-inline-start: 2.5rem;
|
|
||||||
|
|
||||||
.js-add-task {
|
|
||||||
svg {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus svg {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> input.task-list-item-checkbox {
|
|
||||||
left: 1.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus-within {
|
|
||||||
.js-add-task svg {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ query getProjectContainerRepositories(
|
||||||
__typename
|
__typename
|
||||||
nodes {
|
nodes {
|
||||||
id
|
id
|
||||||
|
migrationState
|
||||||
name
|
name
|
||||||
path
|
path
|
||||||
status
|
status
|
||||||
|
@ -57,6 +58,7 @@ query getProjectContainerRepositories(
|
||||||
__typename
|
__typename
|
||||||
nodes {
|
nodes {
|
||||||
id
|
id
|
||||||
|
migrationState
|
||||||
name
|
name
|
||||||
path
|
path
|
||||||
status
|
status
|
||||||
|
|
|
@ -9,6 +9,13 @@ module Types
|
||||||
field_class Types::BaseField
|
field_class Types::BaseField
|
||||||
edge_type_class Types::BaseEdge
|
edge_type_class Types::BaseEdge
|
||||||
|
|
||||||
|
def self.authorize(*args)
|
||||||
|
raise 'Cannot redefine authorize' if @authorize_args && args.any?
|
||||||
|
|
||||||
|
@authorize_args = args.freeze if args.any?
|
||||||
|
@authorize_args || (superclass.respond_to?(:authorize) ? superclass.authorize : nil)
|
||||||
|
end
|
||||||
|
|
||||||
def self.accepts(*types)
|
def self.accepts(*types)
|
||||||
@accepts ||= []
|
@accepts ||= []
|
||||||
@accepts += types
|
@accepts += types
|
||||||
|
|
|
@ -14,6 +14,7 @@ module Types
|
||||||
field :expiration_policy_started_at, Types::TimeType, null: true, description: 'Timestamp when the cleanup done by the expiration policy was started on the container repository.'
|
field :expiration_policy_started_at, Types::TimeType, null: true, description: 'Timestamp when the cleanup done by the expiration policy was started on the container repository.'
|
||||||
field :id, GraphQL::Types::ID, null: false, description: 'ID of the container repository.'
|
field :id, GraphQL::Types::ID, null: false, description: 'ID of the container repository.'
|
||||||
field :location, GraphQL::Types::String, null: false, description: 'URL of the container repository.'
|
field :location, GraphQL::Types::String, null: false, description: 'URL of the container repository.'
|
||||||
|
field :migration_state, GraphQL::Types::String, null: false, description: 'Migration state of the container repository.'
|
||||||
field :name, GraphQL::Types::String, null: false, description: 'Name of the container repository.'
|
field :name, GraphQL::Types::String, null: false, description: 'Name of the container repository.'
|
||||||
field :path, GraphQL::Types::String, null: false, description: 'Path of the container repository.'
|
field :path, GraphQL::Types::String, null: false, description: 'Path of the container repository.'
|
||||||
field :project, Types::ProjectType, null: false, description: 'Project of the container registry.'
|
field :project, Types::ProjectType, null: false, description: 'Project of the container registry.'
|
||||||
|
|
|
@ -88,6 +88,15 @@ module NamespacesHelper
|
||||||
}.to_json
|
}.to_json
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def pipeline_usage_quota_app_data(namespace)
|
||||||
|
{
|
||||||
|
namespace_actual_plan_name: namespace.actual_plan_name,
|
||||||
|
namespace_path: namespace.full_path,
|
||||||
|
namespace_id: namespace.id,
|
||||||
|
page_size: page_size
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Many importers create a temporary Group, so use the real
|
# Many importers create a temporary Group, so use the real
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
- add_to_breadcrumbs _("Issues"), project_issues_path(@project)
|
- add_to_breadcrumbs _("Issues"), project_issues_path(@project)
|
||||||
- breadcrumb_title @issue.to_reference
|
- breadcrumb_title @issue.to_reference
|
||||||
- page_title "#{@issue.title} (#{@issue.to_reference})", _("Issues")
|
- page_title "#{@issue.title} (#{@issue.to_reference})", _("Issues")
|
||||||
|
- add_page_specific_style 'page_bundles/issues_show'
|
||||||
|
|
||||||
= render 'projects/issuable/show', issuable: @issue, api_awards_path: award_emoji_issue_api_path(@issue)
|
= render 'projects/issuable/show', issuable: @issue, api_awards_path: award_emoji_issue_api_path(@issue)
|
||||||
= render 'projects/invite_members_modal', project: @project
|
= render 'projects/invite_members_modal', project: @project
|
||||||
|
|
|
@ -12,12 +12,24 @@ module BulkImports
|
||||||
worker_has_external_dependencies!
|
worker_has_external_dependencies!
|
||||||
|
|
||||||
def perform(entity_id, current_stage = nil)
|
def perform(entity_id, current_stage = nil)
|
||||||
return if stage_running?(entity_id, current_stage)
|
if stage_running?(entity_id, current_stage)
|
||||||
|
logger.info(
|
||||||
|
structured_payload(
|
||||||
|
entity_id: entity_id,
|
||||||
|
current_stage: current_stage,
|
||||||
|
message: 'Stage running'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
worker: self.class.name,
|
structured_payload(
|
||||||
entity_id: entity_id,
|
entity_id: entity_id,
|
||||||
current_stage: current_stage
|
current_stage: current_stage,
|
||||||
|
message: 'Stage starting'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
next_pipeline_trackers_for(entity_id).each do |pipeline_tracker|
|
next_pipeline_trackers_for(entity_id).each do |pipeline_tracker|
|
||||||
|
@ -29,10 +41,11 @@ module BulkImports
|
||||||
end
|
end
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
logger.error(
|
logger.error(
|
||||||
worker: self.class.name,
|
structured_payload(
|
||||||
entity_id: entity_id,
|
entity_id: entity_id,
|
||||||
current_stage: current_stage,
|
current_stage: current_stage,
|
||||||
error_message: e.message
|
message: e.message
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
Gitlab::ErrorTracking.track_exception(e, entity_id: entity_id)
|
Gitlab::ErrorTracking.track_exception(e, entity_id: entity_id)
|
||||||
|
|
|
@ -42,12 +42,14 @@ module BulkImports
|
||||||
correlation_id_value: Labkit::Correlation::CorrelationId.current_or_new_id
|
correlation_id_value: Labkit::Correlation::CorrelationId.current_or_new_id
|
||||||
}
|
}
|
||||||
|
|
||||||
Gitlab::Import::Logger.warn(
|
Gitlab::Import::Logger.error(
|
||||||
|
structured_payload(
|
||||||
attributes.merge(
|
attributes.merge(
|
||||||
bulk_import_id: entity.bulk_import.id,
|
bulk_import_id: entity.bulk_import.id,
|
||||||
bulk_import_entity_type: entity.source_type
|
bulk_import_entity_type: entity.source_type
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
BulkImports::Failure.create(attributes)
|
BulkImports::Failure.create(attributes)
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,19 +18,21 @@ module BulkImports
|
||||||
|
|
||||||
if pipeline_tracker.present?
|
if pipeline_tracker.present?
|
||||||
logger.info(
|
logger.info(
|
||||||
worker: self.class.name,
|
structured_payload(
|
||||||
entity_id: pipeline_tracker.entity.id,
|
entity_id: pipeline_tracker.entity.id,
|
||||||
pipeline_name: pipeline_tracker.pipeline_name
|
pipeline_name: pipeline_tracker.pipeline_name
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
run(pipeline_tracker)
|
run(pipeline_tracker)
|
||||||
else
|
else
|
||||||
logger.error(
|
logger.error(
|
||||||
worker: self.class.name,
|
structured_payload(
|
||||||
entity_id: entity_id,
|
entity_id: entity_id,
|
||||||
pipeline_tracker_id: pipeline_tracker_id,
|
pipeline_tracker_id: pipeline_tracker_id,
|
||||||
message: 'Unstarted pipeline not found'
|
message: 'Unstarted pipeline not found'
|
||||||
)
|
)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
ensure
|
ensure
|
||||||
|
@ -63,11 +65,12 @@ module BulkImports
|
||||||
rescue BulkImports::NetworkError => e
|
rescue BulkImports::NetworkError => e
|
||||||
if e.retriable?(pipeline_tracker)
|
if e.retriable?(pipeline_tracker)
|
||||||
logger.error(
|
logger.error(
|
||||||
worker: self.class.name,
|
structured_payload(
|
||||||
entity_id: pipeline_tracker.entity.id,
|
entity_id: pipeline_tracker.entity.id,
|
||||||
pipeline_name: pipeline_tracker.pipeline_name,
|
pipeline_name: pipeline_tracker.pipeline_name,
|
||||||
message: "Retrying error: #{e.message}"
|
message: "Retrying error: #{e.message}"
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
pipeline_tracker.update!(status_event: 'retry', jid: jid)
|
pipeline_tracker.update!(status_event: 'retry', jid: jid)
|
||||||
|
|
||||||
|
@ -83,11 +86,12 @@ module BulkImports
|
||||||
pipeline_tracker.update!(status_event: 'fail_op', jid: jid)
|
pipeline_tracker.update!(status_event: 'fail_op', jid: jid)
|
||||||
|
|
||||||
logger.error(
|
logger.error(
|
||||||
worker: self.class.name,
|
structured_payload(
|
||||||
entity_id: pipeline_tracker.entity.id,
|
entity_id: pipeline_tracker.entity.id,
|
||||||
pipeline_name: pipeline_tracker.pipeline_name,
|
pipeline_name: pipeline_tracker.pipeline_name,
|
||||||
message: exception.message
|
message: exception.message
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
Gitlab::ErrorTracking.track_exception(
|
Gitlab::ErrorTracking.track_exception(
|
||||||
exception,
|
exception,
|
||||||
|
|
|
@ -272,6 +272,7 @@ module Gitlab
|
||||||
config.assets.precompile << "page_bundles/import.css"
|
config.assets.precompile << "page_bundles/import.css"
|
||||||
config.assets.precompile << "page_bundles/incident_management_list.css"
|
config.assets.precompile << "page_bundles/incident_management_list.css"
|
||||||
config.assets.precompile << "page_bundles/issues_list.css"
|
config.assets.precompile << "page_bundles/issues_list.css"
|
||||||
|
config.assets.precompile << "page_bundles/issues_show.css"
|
||||||
config.assets.precompile << "page_bundles/jira_connect.css"
|
config.assets.precompile << "page_bundles/jira_connect.css"
|
||||||
config.assets.precompile << "page_bundles/jira_connect_users.css"
|
config.assets.precompile << "page_bundles/jira_connect_users.css"
|
||||||
config.assets.precompile << "page_bundles/learn_gitlab.css"
|
config.assets.precompile << "page_bundles/learn_gitlab.css"
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
GraphQL::ObjectType.accepts_definitions(authorize: GraphQL::Define.assign_metadata_key(:authorize))
|
|
||||||
|
|
||||||
GraphQL::Schema::Object.accepts_definition(:authorize)
|
|
|
@ -66,7 +66,7 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
|
|
||||||
Gitlab.ee do
|
Gitlab.ee do
|
||||||
resources :company, only: [:new]
|
resource :company, only: [:new, :create], controller: 'company'
|
||||||
resources :groups, only: [:new, :create]
|
resources :groups, only: [:new, :create]
|
||||||
resources :projects, only: [:new, :create]
|
resources :projects, only: [:new, :create]
|
||||||
resources :groups_projects, only: [:new, :create] do
|
resources :groups_projects, only: [:new, :create] do
|
||||||
|
|
|
@ -4,6 +4,6 @@ classes:
|
||||||
- Ci::NamespaceMirror
|
- Ci::NamespaceMirror
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- sharding
|
- sharding
|
||||||
description: TODO
|
description: Mirrors some data from the `main` database into the `ci` database so that we can join directly in a single query
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75621
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75621
|
||||||
milestone: '14.6'
|
milestone: '14.6'
|
||||||
|
|
|
@ -4,6 +4,6 @@ classes:
|
||||||
- Ci::ProjectMirror
|
- Ci::ProjectMirror
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- sharding
|
- sharding
|
||||||
description: TODO
|
description: Mirrors some data from the `main` database into the `ci` database so that we can join directly in a single query
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75621
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75621
|
||||||
milestone: '14.6'
|
milestone: '14.6'
|
||||||
|
|
|
@ -4,6 +4,6 @@ classes:
|
||||||
- LooseForeignKeys::DeletedRecord
|
- LooseForeignKeys::DeletedRecord
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- sharding
|
- sharding
|
||||||
description: TODO
|
description: Used by the loose foreign keys feature as a queue of parent records whose child records (via foreign keys) need to be deleted/nullified
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70152
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70152
|
||||||
milestone: '14.3'
|
milestone: '14.3'
|
||||||
|
|
|
@ -4,6 +4,6 @@ classes:
|
||||||
- Namespaces::SyncEvent
|
- Namespaces::SyncEvent
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- sharding
|
- sharding
|
||||||
description: TODO
|
description: Used as a queue of data that needs to be synchronized between the `ci` and `main` database
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75517
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75517
|
||||||
milestone: '14.6'
|
milestone: '14.6'
|
||||||
|
|
|
@ -4,6 +4,6 @@ classes:
|
||||||
- Projects::SyncEvent
|
- Projects::SyncEvent
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- sharding
|
- sharding
|
||||||
description: TODO
|
description: Used as a queue of data that needs to be synchronized between the `ci` and `main` database
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75517
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75517
|
||||||
milestone: '14.6'
|
milestone: '14.6'
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class FinalizeTraversalIdsBackgroundMigrations < Gitlab::Database::Migration[1.0]
|
||||||
|
def up
|
||||||
|
finalize_background_migration('BackfillNamespaceTraversalIdsRoots')
|
||||||
|
finalize_background_migration('BackfillNamespaceTraversalIdsChildren')
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
# no-op
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1 @@
|
||||||
|
1d6ed98ad2da7be75e09d853db86905ed1fb1847d387cc6d1980ff5516db06d9
|
|
@ -348,13 +348,23 @@ If this occurs, run `remove-repository` again.
|
||||||
|
|
||||||
### Manually list untracked repositories
|
### Manually list untracked repositories
|
||||||
|
|
||||||
> [Introduced](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/3926) in GitLab 14.4.
|
> - [Introduced](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/3926) in GitLab 14.4.
|
||||||
|
> - `older-than` option added in GitLab 15.0.
|
||||||
|
|
||||||
The `list-untracked-repositories` Praefect sub-command lists repositories of the Gitaly Cluster that both:
|
The `list-untracked-repositories` Praefect sub-command lists repositories of the Gitaly Cluster that both:
|
||||||
|
|
||||||
- Exist for at least one Gitaly storage.
|
- Exist for at least one Gitaly storage.
|
||||||
- Aren't tracked in the Praefect database.
|
- Aren't tracked in the Praefect database.
|
||||||
|
|
||||||
|
Add the `-older-than` option to avoid showing repositories that are the process of being created and for which a record doesn't yet exist in the
|
||||||
|
Praefect database. Replace <duration> with a time duration (for example, `5s`, `10m`, or `1h`). Defaults to `6h`.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml list-untracked-repositories -older-than <duration>
|
||||||
|
```
|
||||||
|
|
||||||
|
Only repositories with a creation time before the specified duration are considered.
|
||||||
|
|
||||||
The command outputs:
|
The command outputs:
|
||||||
|
|
||||||
- Result to `STDOUT` and the command's logs.
|
- Result to `STDOUT` and the command's logs.
|
||||||
|
|
|
@ -9773,6 +9773,7 @@ A container repository.
|
||||||
| <a id="containerrepositoryexpirationpolicystartedat"></a>`expirationPolicyStartedAt` | [`Time`](#time) | Timestamp when the cleanup done by the expiration policy was started on the container repository. |
|
| <a id="containerrepositoryexpirationpolicystartedat"></a>`expirationPolicyStartedAt` | [`Time`](#time) | Timestamp when the cleanup done by the expiration policy was started on the container repository. |
|
||||||
| <a id="containerrepositoryid"></a>`id` | [`ID!`](#id) | ID of the container repository. |
|
| <a id="containerrepositoryid"></a>`id` | [`ID!`](#id) | ID of the container repository. |
|
||||||
| <a id="containerrepositorylocation"></a>`location` | [`String!`](#string) | URL of the container repository. |
|
| <a id="containerrepositorylocation"></a>`location` | [`String!`](#string) | URL of the container repository. |
|
||||||
|
| <a id="containerrepositorymigrationstate"></a>`migrationState` | [`String!`](#string) | Migration state of the container repository. |
|
||||||
| <a id="containerrepositoryname"></a>`name` | [`String!`](#string) | Name of the container repository. |
|
| <a id="containerrepositoryname"></a>`name` | [`String!`](#string) | Name of the container repository. |
|
||||||
| <a id="containerrepositorypath"></a>`path` | [`String!`](#string) | Path of the container repository. |
|
| <a id="containerrepositorypath"></a>`path` | [`String!`](#string) | Path of the container repository. |
|
||||||
| <a id="containerrepositoryproject"></a>`project` | [`Project!`](#project) | Project of the container registry. |
|
| <a id="containerrepositoryproject"></a>`project` | [`Project!`](#project) | Project of the container registry. |
|
||||||
|
@ -9794,6 +9795,7 @@ Details of a container repository.
|
||||||
| <a id="containerrepositorydetailsexpirationpolicystartedat"></a>`expirationPolicyStartedAt` | [`Time`](#time) | Timestamp when the cleanup done by the expiration policy was started on the container repository. |
|
| <a id="containerrepositorydetailsexpirationpolicystartedat"></a>`expirationPolicyStartedAt` | [`Time`](#time) | Timestamp when the cleanup done by the expiration policy was started on the container repository. |
|
||||||
| <a id="containerrepositorydetailsid"></a>`id` | [`ID!`](#id) | ID of the container repository. |
|
| <a id="containerrepositorydetailsid"></a>`id` | [`ID!`](#id) | ID of the container repository. |
|
||||||
| <a id="containerrepositorydetailslocation"></a>`location` | [`String!`](#string) | URL of the container repository. |
|
| <a id="containerrepositorydetailslocation"></a>`location` | [`String!`](#string) | URL of the container repository. |
|
||||||
|
| <a id="containerrepositorydetailsmigrationstate"></a>`migrationState` | [`String!`](#string) | Migration state of the container repository. |
|
||||||
| <a id="containerrepositorydetailsname"></a>`name` | [`String!`](#string) | Name of the container repository. |
|
| <a id="containerrepositorydetailsname"></a>`name` | [`String!`](#string) | Name of the container repository. |
|
||||||
| <a id="containerrepositorydetailspath"></a>`path` | [`String!`](#string) | Path of the container repository. |
|
| <a id="containerrepositorydetailspath"></a>`path` | [`String!`](#string) | Path of the container repository. |
|
||||||
| <a id="containerrepositorydetailsproject"></a>`project` | [`Project!`](#project) | Project of the container registry. |
|
| <a id="containerrepositorydetailsproject"></a>`project` | [`Project!`](#project) | Project of the container registry. |
|
||||||
|
|
|
@ -366,8 +366,8 @@ The docs generator code comes from our side giving us more flexibility, like usi
|
||||||
|
|
||||||
To edit the content, you may need to edit the following:
|
To edit the content, you may need to edit the following:
|
||||||
|
|
||||||
- The template. You can edit the template at `lib/gitlab/graphql/docs/templates/default.md.haml`.
|
- The template. You can edit the template at `tooling/graphql/docs/templates/default.md.haml`.
|
||||||
The actual renderer is at `Gitlab::Graphql::Docs::Renderer`.
|
The actual renderer is at `Tooling::Graphql::Docs::Renderer`.
|
||||||
- The applicable `description` field in the code, which
|
- The applicable `description` field in the code, which
|
||||||
[Updates machine-readable schema files](#update-machine-readable-schema-files),
|
[Updates machine-readable schema files](#update-machine-readable-schema-files),
|
||||||
which is then used by the `rake` task described earlier.
|
which is then used by the `rake` task described earlier.
|
||||||
|
|
|
@ -592,6 +592,7 @@ profile increases as the number of tests increases.
|
||||||
| `FUZZAPI_CONFIG` | [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/276395) in GitLab 13.12, replaced with default `.gitlab/gitlab-api-fuzzing-config.yml`. API Fuzzing configuration file. |
|
| `FUZZAPI_CONFIG` | [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/276395) in GitLab 13.12, replaced with default `.gitlab/gitlab-api-fuzzing-config.yml`. API Fuzzing configuration file. |
|
||||||
|[`FUZZAPI_PROFILE`](#api-fuzzing-profiles) | Configuration profile to use during testing. Defaults to `Quick-10`. |
|
|[`FUZZAPI_PROFILE`](#api-fuzzing-profiles) | Configuration profile to use during testing. Defaults to `Quick-10`. |
|
||||||
|[`FUZZAPI_EXCLUDE_PATHS`](#exclude-paths) | Exclude API URL paths from testing. |
|
|[`FUZZAPI_EXCLUDE_PATHS`](#exclude-paths) | Exclude API URL paths from testing. |
|
||||||
|
|[`FUZZAPI_EXCLUDE_URLS`](#exclude-urls) | Exclude API URL from testing. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/357195) in GitLab 14.10. |
|
||||||
|[`FUZZAPI_EXCLUDE_PARAMETER_ENV`](#exclude-parameters) | JSON string containing excluded parameters. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/292196) in GitLab 14.10. |
|
|[`FUZZAPI_EXCLUDE_PARAMETER_ENV`](#exclude-parameters) | JSON string containing excluded parameters. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/292196) in GitLab 14.10. |
|
||||||
|[`FUZZAPI_EXCLUDE_PARAMETER_FILE`](#exclude-parameters) | Path to a JSON file containing excluded parameters. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/292196) in GitLab 14.10. |
|
|[`FUZZAPI_EXCLUDE_PARAMETER_FILE`](#exclude-parameters) | Path to a JSON file containing excluded parameters. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/292196) in GitLab 14.10. |
|
||||||
|[`FUZZAPI_OPENAPI`](#openapi-specification) | OpenAPI Specification file or URL. |
|
|[`FUZZAPI_OPENAPI`](#openapi-specification) | OpenAPI Specification file or URL. |
|
||||||
|
@ -1295,6 +1296,65 @@ variables:
|
||||||
|
|
||||||
The `api-fuzzing-exclude-parameters.json` is a JSON document that follows the structure of [exclude parameters document](#exclude-parameters-using-a-json-document).
|
The `api-fuzzing-exclude-parameters.json` is a JSON document that follows the structure of [exclude parameters document](#exclude-parameters-using-a-json-document).
|
||||||
|
|
||||||
|
### Exclude URLS
|
||||||
|
|
||||||
|
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/357195) in GitLab 14.10.
|
||||||
|
|
||||||
|
As an alternative to excluding by paths, you can filter by any other component in the URL by using the `FUZZAPI_EXCLUDE_URLS` CI/CD variable. This variable can be set in your `.gitlab-ci.yml` file. The variable can store multiple values, separated by commas (`,`). Each value is a regular expression. Because each entry is a regular expression, an entry such as `.*` excludes all URLs because it is a regular expression that matches everything.
|
||||||
|
|
||||||
|
In your job output you can check if any URLs matched any provided regular expression from `FUZZAPI_EXCLUDE_URLS`. Matching operations are listed in the **Excluded Operations** section. Operations listed in the **Excluded Operations** should not be listed in the **Tested Operations** section. For example the following portion of a job output:
|
||||||
|
|
||||||
|
```plaintext
|
||||||
|
2021-05-27 21:51:08 [INF] API Security: --[ Tested Operations ]-------------------------
|
||||||
|
2021-05-27 21:51:08 [INF] API Security: 201 POST http://target:7777/api/users CREATED
|
||||||
|
2021-05-27 21:51:08 [INF] API Security: ------------------------------------------------
|
||||||
|
2021-05-27 21:51:08 [INF] API Security: --[ Excluded Operations ]-----------------------
|
||||||
|
2021-05-27 21:51:08 [INF] API Security: GET http://target:7777/api/messages
|
||||||
|
2021-05-27 21:51:08 [INF] API Security: POST http://target:7777/api/messages
|
||||||
|
2021-05-27 21:51:08 [INF] API Security: ------------------------------------------------
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
Each value in `FUZZAPI_EXCLUDE_URLS` is a regular expression. Characters such as `.` , `*` and `$` among many others have special meanings in [regular expressions](https://en.wikipedia.org/wiki/Regular_expression#Standards).
|
||||||
|
|
||||||
|
#### Examples
|
||||||
|
|
||||||
|
##### Excluding a URL and child resources
|
||||||
|
|
||||||
|
The following example excludes the URL `http://target/api/auth` and its child resources.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
variables:
|
||||||
|
FUZZAPI_EXCLUDE_URLS: http://target/api/auth
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Excluding two URLs and allow their child resources
|
||||||
|
|
||||||
|
To exclude the URLs `http://target/api/buy` and `http://target/api/sell` but allowing to scan their child resources, for instance: `http://target/api/buy/toy` or `http://target/api/sell/chair`. You could use the value `http://target/api/buy/$,http://target/api/sell/$`. This value is using two regular expressions, each of them separated by a `,` character. Hence, it contains `http://target/api/buy$` and `http://target/api/sell$`. In each regular expression, the trailing `$` character points out where the matching URL should end.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
variables:
|
||||||
|
FUZZAPI_EXCLUDE_URLS: http://target/api/buy/$,http://target/api/sell/$
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Excluding two URLs and their child resources
|
||||||
|
|
||||||
|
In order to exclude the URLs: `http://target/api/buy` and `http://target/api/sell`, and their child resources. To provide multiple URLs we use the `,` character as follows:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
variables:
|
||||||
|
FUZZAPI_EXCLUDE_URLS: http://target/api/buy,http://target/api/sell
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Excluding URL using regular expressions
|
||||||
|
|
||||||
|
In order to exclude exactly `https://target/api/v1/user/create` and `https://target/api/v2/user/create` or any other version (`v3`,`v4`, and more). We could use `https://target/api/v.*/user/create$`, in the previous regular expression `.` indicates any character and `*` indicates zero or more times, additionally `$` indicates that the URL should end there.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
variables:
|
||||||
|
FUZZAPI_EXCLUDE_URLS: https://target/api/v.*/user/create$
|
||||||
|
```
|
||||||
|
|
||||||
### Header Fuzzing
|
### Header Fuzzing
|
||||||
|
|
||||||
Header fuzzing is disabled by default due to the high number of false positives that occur with many
|
Header fuzzing is disabled by default due to the high number of false positives that occur with many
|
||||||
|
|
|
@ -544,6 +544,7 @@ can be added, removed, and modified by creating a custom configuration.
|
||||||
|[`DAST_API_CONFIG`](#configuration-files) | DAST API configuration file. Defaults to `.gitlab-dast-api.yml`. |
|
|[`DAST_API_CONFIG`](#configuration-files) | DAST API configuration file. Defaults to `.gitlab-dast-api.yml`. |
|
||||||
|[`DAST_API_PROFILE`](#configuration-files) | Configuration profile to use during testing. Defaults to `Quick`. |
|
|[`DAST_API_PROFILE`](#configuration-files) | Configuration profile to use during testing. Defaults to `Quick`. |
|
||||||
|[`DAST_API_EXCLUDE_PATHS`](#exclude-paths) | Exclude API URL paths from testing. |
|
|[`DAST_API_EXCLUDE_PATHS`](#exclude-paths) | Exclude API URL paths from testing. |
|
||||||
|
|[`DAST_API_EXCLUDE_URLS`](#exclude-urls) | Exclude API URL from testing. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/357195) in GitLab 14.10. |
|
||||||
|[`DAST_API_EXCLUDE_PARAMETER_ENV`](#exclude-parameters) | JSON string containing excluded parameters. |
|
|[`DAST_API_EXCLUDE_PARAMETER_ENV`](#exclude-parameters) | JSON string containing excluded parameters. |
|
||||||
|[`DAST_API_EXCLUDE_PARAMETER_FILE`](#exclude-parameters) | Path to a JSON file containing excluded parameters. |
|
|[`DAST_API_EXCLUDE_PARAMETER_FILE`](#exclude-parameters) | Path to a JSON file containing excluded parameters. |
|
||||||
|[`DAST_API_OPENAPI`](#openapi-specification) | OpenAPI specification file or URL. |
|
|[`DAST_API_OPENAPI`](#openapi-specification) | OpenAPI specification file or URL. |
|
||||||
|
@ -1249,6 +1250,65 @@ variables:
|
||||||
|
|
||||||
The `dast-api-exclude-parameters.json` is a JSON document that follows the structure of [exclude parameters document](#exclude-parameters-using-a-json-document).
|
The `dast-api-exclude-parameters.json` is a JSON document that follows the structure of [exclude parameters document](#exclude-parameters-using-a-json-document).
|
||||||
|
|
||||||
|
### Exclude URLS
|
||||||
|
|
||||||
|
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/357195) in GitLab 14.10.
|
||||||
|
|
||||||
|
As an alternative to excluding by paths, you can filter by any other component in the URL by using the `DAST_API_EXCLUDE_URLS` CI/CD variable. This variable can be set in your `.gitlab-ci.yml` file. The variable can store multiple values, separated by commas (`,`). Each value is a regular expression. Because each entry is a regular expression, an entry like `.*` will exclude all URLs because it is a regular expression that matches everything.
|
||||||
|
|
||||||
|
In your job output you can check if any URLs matched any provided regular expression from `DAST_API_EXCLUDE_URLS`. Matching operations are listed in the **Excluded Operations** section. Operations listed in the **Excluded Operations** should not be listed in the **Tested Operations** section. For example the following portion of a job output:
|
||||||
|
|
||||||
|
```plaintext
|
||||||
|
2021-05-27 21:51:08 [INF] API Security: --[ Tested Operations ]-------------------------
|
||||||
|
2021-05-27 21:51:08 [INF] API Security: 201 POST http://target:7777/api/users CREATED
|
||||||
|
2021-05-27 21:51:08 [INF] API Security: ------------------------------------------------
|
||||||
|
2021-05-27 21:51:08 [INF] API Security: --[ Excluded Operations ]-----------------------
|
||||||
|
2021-05-27 21:51:08 [INF] API Security: GET http://target:7777/api/messages
|
||||||
|
2021-05-27 21:51:08 [INF] API Security: POST http://target:7777/api/messages
|
||||||
|
2021-05-27 21:51:08 [INF] API Security: ------------------------------------------------
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
Each value in `DAST_API_EXCLUDE_URLS` is a regular expression. Characters such as `.` , `*` and `$` among many others have special meanings in [regular expressions](https://en.wikipedia.org/wiki/Regular_expression#Standards).
|
||||||
|
|
||||||
|
#### Examples
|
||||||
|
|
||||||
|
##### Excluding a URL and child resources
|
||||||
|
|
||||||
|
The following example excludes the URL `http://target/api/auth` and its child resources.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
variables:
|
||||||
|
DAST_API_EXCLUDE_URLS: http://target/api/auth
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Excluding two URLs and allow their child resources
|
||||||
|
|
||||||
|
To exclude the URLs `http://target/api/buy` and `http://target/api/sell` but allowing to scan their child resources, for instance: `http://target/api/buy/toy` or `http://target/api/sell/chair`. You could use the value `http://target/api/buy/$,http://target/api/sell/$`. This value is using two regular expressions, each of them separated by a `,` character. Hence, it contains `http://target/api/buy$` and `http://target/api/sell$`. In each regular expression, the trailing `$` character points out where the matching URL should end.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
variables:
|
||||||
|
DAST_API_EXCLUDE_URLS: http://target/api/buy/$,http://target/api/sell/$
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Excluding two URLs and their child resources
|
||||||
|
|
||||||
|
In order to exclude the URLs: `http://target/api/buy` and `http://target/api/sell`, and their child resources. To provide multiple URLs we use the `,` character as follows:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
variables:
|
||||||
|
DAST_API_EXCLUDE_URLS: http://target/api/buy,http://target/api/sell
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Excluding URL using regular expressions
|
||||||
|
|
||||||
|
In order to exclude exactly `https://target/api/v1/user/create` and `https://target/api/v2/user/create` or any other version (`v3`,`v4`, and more). We could use `https://target/api/v.*/user/create$`, in the previous regular expression `.` indicates any character and `*` indicates zero or more times, additionally `$` indicates that the URL should end there.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
variables:
|
||||||
|
DAST_API_EXCLUDE_URLS: https://target/api/v.*/user/create$
|
||||||
|
```
|
||||||
|
|
||||||
## Running your first scan
|
## Running your first scan
|
||||||
|
|
||||||
When configured correctly, a CI/CD pipeline contains a `dast` stage and an `dast_api` job. The job only fails when an invalid configuration is provided. During normal operation, the job always succeeds even if vulnerabilities are identified during testing.
|
When configured correctly, a CI/CD pipeline contains a `dast` stage and an `dast_api` job. The job only fails when an invalid configuration is provided. During normal operation, the job always succeeds even if vulnerabilities are identified during testing.
|
||||||
|
|
|
@ -9773,6 +9773,9 @@ msgstr ""
|
||||||
msgid "ContainerRegistry|Image repository not found"
|
msgid "ContainerRegistry|Image repository not found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ContainerRegistry|Image repository temporarily cannot be marked for deletion. Please try again in a few minutes. %{docLinkStart}More details%{docLinkEnd}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "ContainerRegistry|Image repository will be deleted"
|
msgid "ContainerRegistry|Image repository will be deleted"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { GlButton } from '@gitlab/ui';
|
import { GlButton, GlTooltip, GlSprintf } from '@gitlab/ui';
|
||||||
import { shallowMount } from '@vue/test-utils';
|
import { shallowMount } from '@vue/test-utils';
|
||||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
|
||||||
import component from '~/packages_and_registries/container_registry/explorer/components/delete_button.vue';
|
import component from '~/packages_and_registries/container_registry/explorer/components/delete_button.vue';
|
||||||
|
import { LIST_DELETE_BUTTON_DISABLED_FOR_MIGRATION } from '~/packages_and_registries/container_registry/explorer/constants/list';
|
||||||
|
|
||||||
describe('delete_button', () => {
|
describe('delete_button', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
|
@ -12,6 +12,7 @@ describe('delete_button', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const findButton = () => wrapper.find(GlButton);
|
const findButton = () => wrapper.find(GlButton);
|
||||||
|
const findTooltip = () => wrapper.find(GlTooltip);
|
||||||
|
|
||||||
const mountComponent = (props) => {
|
const mountComponent = (props) => {
|
||||||
wrapper = shallowMount(component, {
|
wrapper = shallowMount(component, {
|
||||||
|
@ -19,8 +20,9 @@ describe('delete_button', () => {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
directives: {
|
stubs: {
|
||||||
GlTooltip: createMockDirective(),
|
GlTooltip,
|
||||||
|
GlSprintf,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -33,15 +35,25 @@ describe('delete_button', () => {
|
||||||
describe('tooltip', () => {
|
describe('tooltip', () => {
|
||||||
it('the title is controlled by tooltipTitle prop', () => {
|
it('the title is controlled by tooltipTitle prop', () => {
|
||||||
mountComponent();
|
mountComponent();
|
||||||
const tooltip = getBinding(wrapper.element, 'gl-tooltip');
|
const tooltip = findTooltip();
|
||||||
expect(tooltip).toBeDefined();
|
expect(tooltip).toBeDefined();
|
||||||
expect(tooltip.value.title).toBe(defaultProps.tooltipTitle);
|
expect(tooltip.text()).toBe(defaultProps.tooltipTitle);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is disabled when tooltipTitle is disabled', () => {
|
it('is disabled when tooltipTitle is disabled', () => {
|
||||||
mountComponent({ tooltipDisabled: true });
|
mountComponent({ tooltipDisabled: true });
|
||||||
const tooltip = getBinding(wrapper.element, 'gl-tooltip');
|
expect(findTooltip().props('disabled')).toBe(true);
|
||||||
expect(tooltip.value.disabled).toBe(true);
|
});
|
||||||
|
|
||||||
|
it('works with a link', () => {
|
||||||
|
mountComponent({
|
||||||
|
tooltipTitle: LIST_DELETE_BUTTON_DISABLED_FOR_MIGRATION,
|
||||||
|
tooltipLink: 'foo',
|
||||||
|
});
|
||||||
|
expect(findTooltip().text()).toMatchInterpolatedText(
|
||||||
|
LIST_DELETE_BUTTON_DISABLED_FOR_MIGRATION,
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('button', () => {
|
describe('button', () => {
|
||||||
|
@ -70,4 +82,3 @@ describe('delete_button', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
LIST_DELETE_BUTTON_DISABLED,
|
LIST_DELETE_BUTTON_DISABLED,
|
||||||
REMOVE_REPOSITORY_LABEL,
|
REMOVE_REPOSITORY_LABEL,
|
||||||
IMAGE_DELETE_SCHEDULED_STATUS,
|
IMAGE_DELETE_SCHEDULED_STATUS,
|
||||||
|
IMAGE_MIGRATING_STATE,
|
||||||
SCHEDULED_STATUS,
|
SCHEDULED_STATUS,
|
||||||
ROOT_IMAGE_TEXT,
|
ROOT_IMAGE_TEXT,
|
||||||
} from '~/packages_and_registries/container_registry/explorer/constants';
|
} from '~/packages_and_registries/container_registry/explorer/constants';
|
||||||
|
@ -41,6 +42,9 @@ describe('Image List Row', () => {
|
||||||
item,
|
item,
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
|
provide: {
|
||||||
|
config: {},
|
||||||
|
},
|
||||||
directives: {
|
directives: {
|
||||||
GlTooltip: createMockDirective(),
|
GlTooltip: createMockDirective(),
|
||||||
},
|
},
|
||||||
|
@ -178,6 +182,12 @@ describe('Image List Row', () => {
|
||||||
expect(findDeleteBtn().props('disabled')).toBe(state);
|
expect(findDeleteBtn().props('disabled')).toBe(state);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
it('is disabled when migrationState is importing', () => {
|
||||||
|
mountComponent({ item: { ...item, migrationState: IMAGE_MIGRATING_STATE } });
|
||||||
|
|
||||||
|
expect(findDeleteBtn().props('disabled')).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('tags count', () => {
|
describe('tags count', () => {
|
||||||
|
|
|
@ -5,6 +5,7 @@ export const imagesListResponse = [
|
||||||
name: 'rails-12009',
|
name: 'rails-12009',
|
||||||
path: 'gitlab-org/gitlab-test/rails-12009',
|
path: 'gitlab-org/gitlab-test/rails-12009',
|
||||||
status: null,
|
status: null,
|
||||||
|
migrationState: 'default',
|
||||||
location: '0.0.0.0:5000/gitlab-org/gitlab-test/rails-12009',
|
location: '0.0.0.0:5000/gitlab-org/gitlab-test/rails-12009',
|
||||||
canDelete: true,
|
canDelete: true,
|
||||||
createdAt: '2020-11-03T13:29:21Z',
|
createdAt: '2020-11-03T13:29:21Z',
|
||||||
|
@ -17,6 +18,7 @@ export const imagesListResponse = [
|
||||||
name: 'rails-20572',
|
name: 'rails-20572',
|
||||||
path: 'gitlab-org/gitlab-test/rails-20572',
|
path: 'gitlab-org/gitlab-test/rails-20572',
|
||||||
status: null,
|
status: null,
|
||||||
|
migrationState: 'default',
|
||||||
location: '0.0.0.0:5000/gitlab-org/gitlab-test/rails-20572',
|
location: '0.0.0.0:5000/gitlab-org/gitlab-test/rails-20572',
|
||||||
canDelete: true,
|
canDelete: true,
|
||||||
createdAt: '2020-09-21T06:57:43Z',
|
createdAt: '2020-09-21T06:57:43Z',
|
||||||
|
|
|
@ -428,5 +428,25 @@ RSpec.describe Types::BaseObject do
|
||||||
expect(result.dig('data', 'users', 'nodes'))
|
expect(result.dig('data', 'users', 'nodes'))
|
||||||
.to contain_exactly({ 'name' => active_users.first.name })
|
.to contain_exactly({ 'name' => active_users.first.name })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.authorize' do
|
||||||
|
let_it_be(:read_only_type) do
|
||||||
|
Class.new(described_class) do
|
||||||
|
authorize :read_only
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let_it_be(:inherited_read_only_type) { Class.new(read_only_type) }
|
||||||
|
|
||||||
|
it 'keeps track of the specified value' do
|
||||||
|
expect(described_class.authorize).to be_nil
|
||||||
|
expect(read_only_type.authorize).to match_array [:read_only]
|
||||||
|
expect(inherited_read_only_type.authorize).to match_array [:read_only]
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'can not redefine the authorize value' do
|
||||||
|
expect { read_only_type.authorize(:write_only) }.to raise_error('Cannot redefine authorize')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe GitlabSchema.types['ContainerRepositoryDetails'] do
|
RSpec.describe GitlabSchema.types['ContainerRepositoryDetails'] do
|
||||||
fields = %i[id name path location created_at updated_at expiration_policy_started_at status tags_count can_delete expiration_policy_cleanup_status tags size project]
|
fields = %i[id name path location created_at updated_at expiration_policy_started_at
|
||||||
|
status tags_count can_delete expiration_policy_cleanup_status tags size
|
||||||
|
project migration_state]
|
||||||
|
|
||||||
it { expect(described_class.graphql_name).to eq('ContainerRepositoryDetails') }
|
it { expect(described_class.graphql_name).to eq('ContainerRepositoryDetails') }
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe GitlabSchema.types['ContainerRepository'] do
|
RSpec.describe GitlabSchema.types['ContainerRepository'] do
|
||||||
fields = %i[id name path location created_at updated_at expiration_policy_started_at status tags_count can_delete expiration_policy_cleanup_status project]
|
fields = %i[id name path location created_at updated_at expiration_policy_started_at
|
||||||
|
status tags_count can_delete expiration_policy_cleanup_status project
|
||||||
|
migration_state]
|
||||||
|
|
||||||
it { expect(described_class.graphql_name).to eq('ContainerRepository') }
|
it { expect(described_class.graphql_name).to eq('ContainerRepository') }
|
||||||
|
|
||||||
|
|
|
@ -268,4 +268,15 @@ RSpec.describe NamespacesHelper do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#pipeline_usage_quota_app_data' do
|
||||||
|
it 'returns a hash with necessary data for the frontend' do
|
||||||
|
expect(helper.pipeline_usage_quota_app_data(user_group)).to eql({
|
||||||
|
namespace_actual_plan_name: user_group.actual_plan_name,
|
||||||
|
namespace_path: user_group.full_path,
|
||||||
|
namespace_id: user_group.id,
|
||||||
|
page_size: Kaminari.config.default_per_page
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
require_migration!('finalize_traversal_ids_background_migrations')
|
||||||
|
|
||||||
|
RSpec.describe FinalizeTraversalIdsBackgroundMigrations, :migration do
|
||||||
|
shared_context 'incomplete background migration' do
|
||||||
|
before do
|
||||||
|
# Jobs enqueued in Sidekiq.
|
||||||
|
Sidekiq::Testing.disable! do
|
||||||
|
BackgroundMigrationWorker.perform_in(10, job_class_name, [1, 2, 100])
|
||||||
|
BackgroundMigrationWorker.perform_in(20, job_class_name, [3, 4, 100])
|
||||||
|
end
|
||||||
|
|
||||||
|
# Jobs tracked in the database.
|
||||||
|
# table(:background_migration_jobs).create!(
|
||||||
|
Gitlab::Database::BackgroundMigrationJob.create!(
|
||||||
|
class_name: job_class_name,
|
||||||
|
arguments: [5, 6, 100],
|
||||||
|
status: Gitlab::Database::BackgroundMigrationJob.statuses['pending']
|
||||||
|
)
|
||||||
|
# table(:background_migration_jobs).create!(
|
||||||
|
Gitlab::Database::BackgroundMigrationJob.create!(
|
||||||
|
class_name: job_class_name,
|
||||||
|
arguments: [7, 8, 100],
|
||||||
|
status: Gitlab::Database::BackgroundMigrationJob.statuses['succeeded']
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'BackfillNamespaceTraversalIdsRoots background migration' do
|
||||||
|
let(:job_class_name) { 'BackfillNamespaceTraversalIdsRoots' }
|
||||||
|
|
||||||
|
include_context 'incomplete background migration'
|
||||||
|
|
||||||
|
before do
|
||||||
|
migrate!
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like(
|
||||||
|
'finalized tracked background migration',
|
||||||
|
Gitlab::BackgroundMigration::BackfillNamespaceTraversalIdsRoots
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'BackfillNamespaceTraversalIdsChildren background migration' do
|
||||||
|
let(:job_class_name) { 'BackfillNamespaceTraversalIdsChildren' }
|
||||||
|
|
||||||
|
include_context 'incomplete background migration'
|
||||||
|
|
||||||
|
before do
|
||||||
|
migrate!
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like(
|
||||||
|
'finalized tracked background migration',
|
||||||
|
Gitlab::BackgroundMigration::BackfillNamespaceTraversalIdsChildren
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
|
@ -36,9 +36,11 @@ RSpec.describe BulkImports::EntityWorker do
|
||||||
expect(logger)
|
expect(logger)
|
||||||
.to receive(:info).twice
|
.to receive(:info).twice
|
||||||
.with(
|
.with(
|
||||||
worker: described_class.name,
|
hash_including(
|
||||||
entity_id: entity.id,
|
'entity_id' => entity.id,
|
||||||
current_stage: nil
|
'current_stage' => nil,
|
||||||
|
'message' => 'Stage starting'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -64,18 +66,20 @@ RSpec.describe BulkImports::EntityWorker do
|
||||||
expect(logger)
|
expect(logger)
|
||||||
.to receive(:info).twice
|
.to receive(:info).twice
|
||||||
.with(
|
.with(
|
||||||
worker: described_class.name,
|
hash_including(
|
||||||
entity_id: entity.id,
|
'entity_id' => entity.id,
|
||||||
current_stage: nil
|
'current_stage' => nil
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(logger)
|
expect(logger)
|
||||||
.to receive(:error)
|
.to receive(:error)
|
||||||
.with(
|
.with(
|
||||||
worker: described_class.name,
|
hash_including(
|
||||||
entity_id: entity.id,
|
'entity_id' => entity.id,
|
||||||
current_stage: nil,
|
'current_stage' => nil,
|
||||||
error_message: 'Error!'
|
'message' => 'Error!'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -90,6 +94,18 @@ RSpec.describe BulkImports::EntityWorker do
|
||||||
let(:job_args) { [entity.id, 0] }
|
let(:job_args) { [entity.id, 0] }
|
||||||
|
|
||||||
it 'do not enqueue a new pipeline job if the current stage still running' do
|
it 'do not enqueue a new pipeline job if the current stage still running' do
|
||||||
|
expect_next_instance_of(Gitlab::Import::Logger) do |logger|
|
||||||
|
expect(logger)
|
||||||
|
.to receive(:info).twice
|
||||||
|
.with(
|
||||||
|
hash_including(
|
||||||
|
'entity_id' => entity.id,
|
||||||
|
'current_stage' => 0,
|
||||||
|
'message' => 'Stage running'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
expect(BulkImports::PipelineWorker)
|
expect(BulkImports::PipelineWorker)
|
||||||
.not_to receive(:perform_async)
|
.not_to receive(:perform_async)
|
||||||
|
|
||||||
|
@ -110,9 +126,10 @@ RSpec.describe BulkImports::EntityWorker do
|
||||||
expect(logger)
|
expect(logger)
|
||||||
.to receive(:info).twice
|
.to receive(:info).twice
|
||||||
.with(
|
.with(
|
||||||
worker: described_class.name,
|
hash_including(
|
||||||
entity_id: entity.id,
|
'entity_id' => entity.id,
|
||||||
current_stage: 0
|
'current_stage' => 0
|
||||||
|
)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -35,14 +35,16 @@ RSpec.describe BulkImports::ExportRequestWorker do
|
||||||
expect(client).to receive(:post).and_raise(BulkImports::NetworkError, 'Export error').twice
|
expect(client).to receive(:post).and_raise(BulkImports::NetworkError, 'Export error').twice
|
||||||
end
|
end
|
||||||
|
|
||||||
expect(Gitlab::Import::Logger).to receive(:warn).with(
|
expect(Gitlab::Import::Logger).to receive(:error).with(
|
||||||
bulk_import_entity_id: entity.id,
|
hash_including(
|
||||||
pipeline_class: 'ExportRequestWorker',
|
'bulk_import_entity_id' => entity.id,
|
||||||
exception_class: 'BulkImports::NetworkError',
|
'pipeline_class' => 'ExportRequestWorker',
|
||||||
exception_message: 'Export error',
|
'exception_class' => 'BulkImports::NetworkError',
|
||||||
correlation_id_value: anything,
|
'exception_message' => 'Export error',
|
||||||
bulk_import_id: bulk_import.id,
|
'correlation_id_value' => anything,
|
||||||
bulk_import_entity_type: entity.source_type
|
'bulk_import_id' => bulk_import.id,
|
||||||
|
'bulk_import_entity_type' => entity.source_type
|
||||||
|
)
|
||||||
).twice
|
).twice
|
||||||
|
|
||||||
perform_multiple(job_args)
|
perform_multiple(job_args)
|
||||||
|
|
|
@ -34,9 +34,10 @@ RSpec.describe BulkImports::PipelineWorker do
|
||||||
expect(logger)
|
expect(logger)
|
||||||
.to receive(:info)
|
.to receive(:info)
|
||||||
.with(
|
.with(
|
||||||
worker: described_class.name,
|
hash_including(
|
||||||
pipeline_name: 'FakePipeline',
|
'pipeline_name' => 'FakePipeline',
|
||||||
entity_id: entity.id
|
'entity_id' => entity.id
|
||||||
|
)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ RSpec.describe BulkImports::PipelineWorker do
|
||||||
.to receive(:perform_async)
|
.to receive(:perform_async)
|
||||||
.with(entity.id, pipeline_tracker.stage)
|
.with(entity.id, pipeline_tracker.stage)
|
||||||
|
|
||||||
expect(subject).to receive(:jid).and_return('jid')
|
allow(subject).to receive(:jid).and_return('jid')
|
||||||
|
|
||||||
subject.perform(pipeline_tracker.id, pipeline_tracker.stage, entity.id)
|
subject.perform(pipeline_tracker.id, pipeline_tracker.stage, entity.id)
|
||||||
|
|
||||||
|
@ -79,10 +80,11 @@ RSpec.describe BulkImports::PipelineWorker do
|
||||||
expect(logger)
|
expect(logger)
|
||||||
.to receive(:error)
|
.to receive(:error)
|
||||||
.with(
|
.with(
|
||||||
worker: described_class.name,
|
hash_including(
|
||||||
pipeline_tracker_id: pipeline_tracker.id,
|
'pipeline_tracker_id' => pipeline_tracker.id,
|
||||||
entity_id: entity.id,
|
'entity_id' => entity.id,
|
||||||
message: 'Unstarted pipeline not found'
|
'message' => 'Unstarted pipeline not found'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -107,10 +109,11 @@ RSpec.describe BulkImports::PipelineWorker do
|
||||||
expect(logger)
|
expect(logger)
|
||||||
.to receive(:error)
|
.to receive(:error)
|
||||||
.with(
|
.with(
|
||||||
worker: described_class.name,
|
hash_including(
|
||||||
pipeline_name: 'InexistentPipeline',
|
'pipeline_name' => 'InexistentPipeline',
|
||||||
entity_id: entity.id,
|
'entity_id' => entity.id,
|
||||||
message: "'InexistentPipeline' is not a valid BulkImport Pipeline"
|
'message' => "'InexistentPipeline' is not a valid BulkImport Pipeline"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -126,7 +129,7 @@ RSpec.describe BulkImports::PipelineWorker do
|
||||||
.to receive(:perform_async)
|
.to receive(:perform_async)
|
||||||
.with(entity.id, pipeline_tracker.stage)
|
.with(entity.id, pipeline_tracker.stage)
|
||||||
|
|
||||||
expect(subject).to receive(:jid).and_return('jid')
|
allow(subject).to receive(:jid).and_return('jid')
|
||||||
|
|
||||||
subject.perform(pipeline_tracker.id, pipeline_tracker.stage, entity.id)
|
subject.perform(pipeline_tracker.id, pipeline_tracker.stage, entity.id)
|
||||||
|
|
||||||
|
@ -151,10 +154,11 @@ RSpec.describe BulkImports::PipelineWorker do
|
||||||
expect(logger)
|
expect(logger)
|
||||||
.to receive(:error)
|
.to receive(:error)
|
||||||
.with(
|
.with(
|
||||||
worker: described_class.name,
|
hash_including(
|
||||||
pipeline_name: 'Pipeline',
|
'pipeline_name' => 'Pipeline',
|
||||||
entity_id: entity.id,
|
'entity_id' => entity.id,
|
||||||
message: 'Failed entity status'
|
'message' => 'Failed entity status'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -183,7 +187,7 @@ RSpec.describe BulkImports::PipelineWorker do
|
||||||
.and_raise(exception)
|
.and_raise(exception)
|
||||||
end
|
end
|
||||||
|
|
||||||
expect(subject).to receive(:jid).and_return('jid').twice
|
allow(subject).to receive(:jid).and_return('jid')
|
||||||
|
|
||||||
expect_any_instance_of(BulkImports::Tracker) do |tracker|
|
expect_any_instance_of(BulkImports::Tracker) do |tracker|
|
||||||
expect(tracker).to receive(:retry).and_call_original
|
expect(tracker).to receive(:retry).and_call_original
|
||||||
|
@ -193,9 +197,10 @@ RSpec.describe BulkImports::PipelineWorker do
|
||||||
expect(logger)
|
expect(logger)
|
||||||
.to receive(:info)
|
.to receive(:info)
|
||||||
.with(
|
.with(
|
||||||
worker: described_class.name,
|
hash_including(
|
||||||
pipeline_name: 'FakePipeline',
|
'pipeline_name' => 'FakePipeline',
|
||||||
entity_id: entity.id
|
'entity_id' => entity.id
|
||||||
|
)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -292,10 +297,11 @@ RSpec.describe BulkImports::PipelineWorker do
|
||||||
expect(logger)
|
expect(logger)
|
||||||
.to receive(:error)
|
.to receive(:error)
|
||||||
.with(
|
.with(
|
||||||
worker: described_class.name,
|
hash_including(
|
||||||
pipeline_name: 'NdjsonPipeline',
|
'pipeline_name' => 'NdjsonPipeline',
|
||||||
entity_id: entity.id,
|
'entity_id' => entity.id,
|
||||||
message: 'Pipeline timeout'
|
'message' => 'Pipeline timeout'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -318,10 +324,11 @@ RSpec.describe BulkImports::PipelineWorker do
|
||||||
expect(logger)
|
expect(logger)
|
||||||
.to receive(:error)
|
.to receive(:error)
|
||||||
.with(
|
.with(
|
||||||
worker: described_class.name,
|
hash_including(
|
||||||
pipeline_name: 'NdjsonPipeline',
|
'pipeline_name' => 'NdjsonPipeline',
|
||||||
entity_id: entity.id,
|
'entity_id' => entity.id,
|
||||||
message: 'Error!'
|
'message' => 'Error!'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue