Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-03-17 03:08:51 +00:00
parent f52c68bbac
commit bb6a3bf05e
142 changed files with 512 additions and 498 deletions

View File

@ -1653,7 +1653,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/services/arkose/blocked_users_report_service_spec.rb' - 'ee/spec/services/arkose/blocked_users_report_service_spec.rb'
- 'ee/spec/services/arkose/record_user_data_service_spec.rb' - 'ee/spec/services/arkose/record_user_data_service_spec.rb'
- 'ee/spec/services/arkose/token_verification_service_spec.rb' - 'ee/spec/services/arkose/token_verification_service_spec.rb'
- 'ee/spec/services/audit_event_service_spec.rb'
- 'ee/spec/services/audit_events/build_service_spec.rb' - 'ee/spec/services/audit_events/build_service_spec.rb'
- 'ee/spec/services/audit_events/custom_audit_event_service_spec.rb' - 'ee/spec/services/audit_events/custom_audit_event_service_spec.rb'
- 'ee/spec/services/audit_events/impersonation_audit_event_service_spec.rb' - 'ee/spec/services/audit_events/impersonation_audit_event_service_spec.rb'
@ -1676,7 +1675,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb' - 'ee/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb'
- 'ee/spec/services/award_emojis/add_service_spec.rb' - 'ee/spec/services/award_emojis/add_service_spec.rb'
- 'ee/spec/services/award_emojis/destroy_service_spec.rb' - 'ee/spec/services/award_emojis/destroy_service_spec.rb'
- 'ee/spec/services/base_count_service_spec.rb'
- 'ee/spec/services/billable_members/destroy_service_spec.rb' - 'ee/spec/services/billable_members/destroy_service_spec.rb'
- 'ee/spec/services/boards/create_service_spec.rb' - 'ee/spec/services/boards/create_service_spec.rb'
- 'ee/spec/services/boards/epic_boards/create_service_spec.rb' - 'ee/spec/services/boards/epic_boards/create_service_spec.rb'
@ -1695,28 +1693,11 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/services/boards/update_service_spec.rb' - 'ee/spec/services/boards/update_service_spec.rb'
- 'ee/spec/services/boards/user_preferences/update_service_spec.rb' - 'ee/spec/services/boards/user_preferences/update_service_spec.rb'
- 'ee/spec/services/branches/delete_service_spec.rb' - 'ee/spec/services/branches/delete_service_spec.rb'
- 'ee/spec/services/ee/auto_merge_service_spec.rb'
- 'ee/spec/services/ee/event_create_service_spec.rb'
- 'ee/spec/services/ee/merge_request_metrics_service_spec.rb'
- 'ee/spec/services/ee/notes/destroy_service_spec.rb' - 'ee/spec/services/ee/notes/destroy_service_spec.rb'
- 'ee/spec/services/ee/notes/post_process_service_spec.rb' - 'ee/spec/services/ee/notes/post_process_service_spec.rb'
- 'ee/spec/services/ee/notes/quick_actions_service_spec.rb' - 'ee/spec/services/ee/notes/quick_actions_service_spec.rb'
- 'ee/spec/services/ee/notes/update_service_spec.rb' - 'ee/spec/services/ee/notes/update_service_spec.rb'
- 'ee/spec/services/ee/null_notification_service_spec.rb'
- 'ee/spec/services/ee/post_receive_service_spec.rb'
- 'ee/spec/services/ee/preview_markdown_service_spec.rb'
- 'ee/spec/services/ee/users/approve_service_spec.rb'
- 'ee/spec/services/ee/users/authorized_build_service_spec.rb'
- 'ee/spec/services/ee/users/block_service_spec.rb'
- 'ee/spec/services/ee/users/build_service_spec.rb'
- 'ee/spec/services/ee/users/create_service_spec.rb'
- 'ee/spec/services/ee/users/destroy_service_spec.rb'
- 'ee/spec/services/ee/users/migrate_records_to_ghost_user_service_spec.rb'
- 'ee/spec/services/ee/users/reject_service_spec.rb'
- 'ee/spec/services/ee/users/update_service_spec.rb'
- 'ee/spec/services/ee/vulnerability_feedback_module/update_service_spec.rb'
- 'ee/spec/services/external_status_checks/create_service_spec.rb' - 'ee/spec/services/external_status_checks/create_service_spec.rb'
- 'ee/spec/services/ldap_group_reset_service_spec.rb'
- 'ee/spec/services/projects/after_rename_service_spec.rb' - 'ee/spec/services/projects/after_rename_service_spec.rb'
- 'ee/spec/services/projects/alerting/notify_service_spec.rb' - 'ee/spec/services/projects/alerting/notify_service_spec.rb'
- 'ee/spec/services/projects/cleanup_service_spec.rb' - 'ee/spec/services/projects/cleanup_service_spec.rb'
@ -1756,33 +1737,7 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/services/requirements_management/process_test_reports_service_spec.rb' - 'ee/spec/services/requirements_management/process_test_reports_service_spec.rb'
- 'ee/spec/services/resource_access_tokens/create_service_spec.rb' - 'ee/spec/services/resource_access_tokens/create_service_spec.rb'
- 'ee/spec/services/resource_access_tokens/revoke_service_spec.rb' - 'ee/spec/services/resource_access_tokens/revoke_service_spec.rb'
- 'ee/spec/services/start_pull_mirroring_service_spec.rb'
- 'ee/spec/services/system_note_service_spec.rb'
- 'ee/spec/services/timebox_report_service_spec.rb' - 'ee/spec/services/timebox_report_service_spec.rb'
- 'ee/spec/services/todo_service_spec.rb'
- 'ee/spec/services/users/abuse/namespace_bans/create_service_spec.rb'
- 'ee/spec/services/users/abuse/namespace_bans/destroy_service_spec.rb'
- 'ee/spec/services/users/abuse/projects_download_ban_check_service_spec.rb'
- 'ee/spec/services/users/captcha_challenge_service_spec.rb'
- 'ee/spec/services/users/update_highest_member_role_service_spec.rb'
- 'ee/spec/services/users_ops_dashboard_projects/destroy_service_spec.rb'
- 'ee/spec/services/vulnerability_exports/create_service_spec.rb'
- 'ee/spec/services/vulnerability_exports/export_service_spec.rb'
- 'ee/spec/services/vulnerability_external_issue_links/create_service_spec.rb'
- 'ee/spec/services/vulnerability_external_issue_links/destroy_service_spec.rb'
- 'ee/spec/services/vulnerability_feedback/destroy_service_spec.rb'
- 'ee/spec/services/vulnerability_issue_links/create_service_spec.rb'
- 'ee/spec/services/vulnerability_issue_links/delete_service_spec.rb'
- 'ee/spec/services/vulnerability_merge_request_links/create_service_spec.rb'
- 'ee/spec/services/vulnerability_scanners/list_service_spec.rb'
- 'ee/spec/services/web_hook_service_spec.rb'
- 'ee/spec/services/wiki_pages/create_service_spec.rb'
- 'ee/spec/services/wiki_pages/destroy_service_spec.rb'
- 'ee/spec/services/wiki_pages/update_service_spec.rb'
- 'ee/spec/services/wikis/create_attachment_service_spec.rb'
- 'ee/spec/services/work_items/update_service_spec.rb'
- 'ee/spec/services/work_items/widgets/status_service/update_service_spec.rb'
- 'ee/spec/services/work_items/widgets/weight_service/update_service_spec.rb'
- 'ee/spec/tasks/geo/git_rake_spec.rb' - 'ee/spec/tasks/geo/git_rake_spec.rb'
- 'ee/spec/tasks/gitlab/license_rake_spec.rb' - 'ee/spec/tasks/gitlab/license_rake_spec.rb'
- 'ee/spec/tasks/gitlab/spdx_rake_spec.rb' - 'ee/spec/tasks/gitlab/spdx_rake_spec.rb'
@ -6096,120 +6051,10 @@ RSpec/MissingFeatureCategory:
- 'spec/serializers/user_serializer_spec.rb' - 'spec/serializers/user_serializer_spec.rb'
- 'spec/serializers/web_ide_terminal_entity_spec.rb' - 'spec/serializers/web_ide_terminal_entity_spec.rb'
- 'spec/serializers/web_ide_terminal_serializer_spec.rb' - 'spec/serializers/web_ide_terminal_serializer_spec.rb'
- 'spec/services/access_token_validation_service_spec.rb'
- 'spec/services/application_settings/update_service_spec.rb' - 'spec/services/application_settings/update_service_spec.rb'
- 'spec/services/applications/create_service_spec.rb' - 'spec/services/applications/create_service_spec.rb'
- 'spec/services/audit_event_service_spec.rb'
- 'spec/services/auto_merge_service_spec.rb'
- 'spec/services/base_container_service_spec.rb'
- 'spec/services/base_count_service_spec.rb'
- 'spec/services/bulk_create_integration_service_spec.rb'
- 'spec/services/bulk_push_event_payload_service_spec.rb'
- 'spec/services/bulk_update_integration_service_spec.rb'
- 'spec/services/cohorts_service_spec.rb'
- 'spec/services/compare_service_spec.rb'
- 'spec/services/event_create_service_spec.rb'
- 'spec/services/gpg_keys/destroy_service_spec.rb' - 'spec/services/gpg_keys/destroy_service_spec.rb'
- 'spec/services/gravatar_service_spec.rb'
- 'spec/services/import_export_clean_up_service_spec.rb'
- 'spec/services/markdown_content_rewriter_service_spec.rb'
- 'spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb' - 'spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb'
- 'spec/services/note_summary_spec.rb'
- 'spec/services/post_receive_service_spec.rb'
- 'spec/services/preview_markdown_service_spec.rb'
- 'spec/services/push_event_payload_service_spec.rb'
- 'spec/services/repository_archive_clean_up_service_spec.rb'
- 'spec/services/reset_project_cache_service_spec.rb'
- 'spec/services/service_response_spec.rb'
- 'spec/services/system_hooks_service_spec.rb'
- 'spec/services/task_list_toggle_service_spec.rb'
- 'spec/services/tasks_to_be_done/base_service_spec.rb'
- 'spec/services/terraform/remote_state_handler_spec.rb'
- 'spec/services/terraform/states/destroy_service_spec.rb'
- 'spec/services/terraform/states/trigger_destroy_service_spec.rb'
- 'spec/services/test_hooks/project_service_spec.rb'
- 'spec/services/test_hooks/system_service_spec.rb'
- 'spec/services/timelogs/delete_service_spec.rb'
- 'spec/services/todo_service_spec.rb'
- 'spec/services/todos/allowed_target_filter_service_spec.rb'
- 'spec/services/todos/destroy/confidential_issue_service_spec.rb'
- 'spec/services/todos/destroy/design_service_spec.rb'
- 'spec/services/todos/destroy/destroyed_issuable_service_spec.rb'
- 'spec/services/todos/destroy/project_private_service_spec.rb'
- 'spec/services/todos/destroy/unauthorized_features_service_spec.rb'
- 'spec/services/topics/merge_service_spec.rb'
- 'spec/services/two_factor/destroy_service_spec.rb'
- 'spec/services/update_container_registry_info_service_spec.rb'
- 'spec/services/update_merge_request_metrics_service_spec.rb'
- 'spec/services/upload_service_spec.rb'
- 'spec/services/uploads/destroy_service_spec.rb'
- 'spec/services/user_preferences/update_service_spec.rb'
- 'spec/services/users/activity_service_spec.rb'
- 'spec/services/users/approve_service_spec.rb'
- 'spec/services/users/authorized_build_service_spec.rb'
- 'spec/services/users/ban_service_spec.rb'
- 'spec/services/users/banned_user_base_service_spec.rb'
- 'spec/services/users/batch_status_cleaner_service_spec.rb'
- 'spec/services/users/block_service_spec.rb'
- 'spec/services/users/build_service_spec.rb'
- 'spec/services/users/create_service_spec.rb'
- 'spec/services/users/destroy_service_spec.rb'
- 'spec/services/users/dismiss_callout_service_spec.rb'
- 'spec/services/users/dismiss_group_callout_service_spec.rb'
- 'spec/services/users/dismiss_project_callout_service_spec.rb'
- 'spec/services/users/email_verification/generate_token_service_spec.rb'
- 'spec/services/users/email_verification/validate_token_service_spec.rb'
- 'spec/services/users/in_product_marketing_email_records_spec.rb'
- 'spec/services/users/keys_count_service_spec.rb'
- 'spec/services/users/last_push_event_service_spec.rb'
- 'spec/services/users/migrate_records_to_ghost_user_in_batches_service_spec.rb'
- 'spec/services/users/migrate_records_to_ghost_user_service_spec.rb'
- 'spec/services/users/refresh_authorized_projects_service_spec.rb'
- 'spec/services/users/registrations_build_service_spec.rb'
- 'spec/services/users/reject_service_spec.rb'
- 'spec/services/users/repair_ldap_blocked_service_spec.rb'
- 'spec/services/users/respond_to_terms_service_spec.rb'
- 'spec/services/users/saved_replies/create_service_spec.rb'
- 'spec/services/users/saved_replies/destroy_service_spec.rb'
- 'spec/services/users/saved_replies/update_service_spec.rb'
- 'spec/services/users/set_status_service_spec.rb'
- 'spec/services/users/signup_service_spec.rb'
- 'spec/services/users/unban_service_spec.rb'
- 'spec/services/users/unblock_service_spec.rb'
- 'spec/services/users/update_canonical_email_service_spec.rb'
- 'spec/services/users/update_highest_member_role_service_spec.rb'
- 'spec/services/users/update_service_spec.rb'
- 'spec/services/users/update_todo_count_cache_service_spec.rb'
- 'spec/services/users/upsert_credit_card_validation_service_spec.rb'
- 'spec/services/users/validate_manual_otp_service_spec.rb'
- 'spec/services/users/validate_push_otp_service_spec.rb'
- 'spec/services/verify_pages_domain_service_spec.rb'
- 'spec/services/web_hooks/destroy_service_spec.rb'
- 'spec/services/web_hooks/log_destroy_service_spec.rb'
- 'spec/services/web_hooks/log_execution_service_spec.rb'
- 'spec/services/webauthn/authenticate_service_spec.rb'
- 'spec/services/webauthn/register_service_spec.rb'
- 'spec/services/wiki_pages/base_service_spec.rb'
- 'spec/services/wiki_pages/create_service_spec.rb'
- 'spec/services/wiki_pages/destroy_service_spec.rb'
- 'spec/services/wiki_pages/event_create_service_spec.rb'
- 'spec/services/wiki_pages/update_service_spec.rb'
- 'spec/services/wikis/create_attachment_service_spec.rb'
- 'spec/services/work_items/build_service_spec.rb'
- 'spec/services/work_items/create_from_task_service_spec.rb'
- 'spec/services/work_items/create_service_spec.rb'
- 'spec/services/work_items/delete_service_spec.rb'
- 'spec/services/work_items/delete_task_service_spec.rb'
- 'spec/services/work_items/parent_links/destroy_service_spec.rb'
- 'spec/services/work_items/task_list_reference_removal_service_spec.rb'
- 'spec/services/work_items/task_list_reference_replacement_service_spec.rb'
- 'spec/services/work_items/update_service_spec.rb'
- 'spec/services/work_items/widgets/assignees_service/update_service_spec.rb'
- 'spec/services/work_items/widgets/description_service/update_service_spec.rb'
- 'spec/services/work_items/widgets/milestone_service/create_service_spec.rb'
- 'spec/services/work_items/widgets/milestone_service/update_service_spec.rb'
- 'spec/services/work_items/widgets/start_and_due_date_service/update_service_spec.rb'
- 'spec/services/x509_certificate_revoke_service_spec.rb'
- 'spec/sidekiq/cron/job_gem_dependency_spec.rb' - 'spec/sidekiq/cron/job_gem_dependency_spec.rb'
- 'spec/sidekiq_cluster/sidekiq_cluster_spec.rb' - 'spec/sidekiq_cluster/sidekiq_cluster_spec.rb'
- 'spec/spam/concerns/has_spam_action_response_fields_spec.rb' - 'spec/spam/concerns/has_spam_action_response_fields_spec.rb'

View File

@ -1,25 +1,19 @@
import Vue from 'vue'; import Vue from 'vue';
import { darkModeEnabled } from '~/lib/utils/color_utils'; import ObservabilityApp from '~/observability/components/observability_app.vue';
import { setUrlParams } from '~/lib/utils/url_utility'; import { SKELETON_VARIANT_EMBED, INLINE_EMBED_DIMENSIONS } from '~/observability/constants';
export function getFrameSrc(url) {
return `${setUrlParams({ theme: darkModeEnabled() ? 'dark' : 'light' }, url)}&kiosk=inline-embed`;
}
const mountVueComponent = (element) => { const mountVueComponent = (element) => {
const url = [element.dataset.frameUrl]; const url = element.dataset.frameUrl;
return new Vue({ return new Vue({
el: element, el: element,
render(h) { render(h) {
return h('iframe', { return h(ObservabilityApp, {
style: { props: {
height: '366px', observabilityIframeSrc: url,
width: '768px', inlineEmbed: true,
}, skeletonVariant: SKELETON_VARIANT_EMBED,
attrs: { height: INLINE_EMBED_DIMENSIONS.HEIGHT,
src: getFrameSrc(url), width: INLINE_EMBED_DIMENSIONS.WIDTH,
frameBorder: '0',
}, },
}); });
}, },
@ -27,7 +21,5 @@ const mountVueComponent = (element) => {
}; };
export default function renderObservability(elements) { export default function renderObservability(elements) {
elements.forEach((element) => { return elements.map(mountVueComponent);
mountVueComponent(element);
});
} }

View File

@ -102,10 +102,10 @@ export default {
'issuable-info-container': !canReorder, 'issuable-info-container': !canReorder,
'card-body': canReorder, 'card-body': canReorder,
}" }"
class="item-body gl-display-flex gl-align-items-center gl-gap-3 gl-px-3 gl-py-2 py-xl-0 gl-mx-n2" class="item-body gl-display-flex gl-align-items-center gl-gap-3 gl-mx-n2"
> >
<div <div
class="item-contents gl-display-flex gl-align-items-center gl-flex-wrap gl-flex-grow-1 gl-gap-2 flex-xl-nowrap gl-min-h-7" class="item-contents gl-display-flex gl-align-items-center gl-flex-wrap gl-flex-grow-1 gl-gap-2 gl-px-3 gl-py-2 py-xl-0 flex-xl-nowrap gl-min-h-7"
> >
<!-- Title area: Status icon (XL) and title --> <!-- Title area: Status icon (XL) and title -->
<div class="item-title gl-display-flex gl-gap-3 gl-min-w-0"> <div class="item-title gl-display-flex gl-gap-3 gl-min-w-0">

View File

@ -96,8 +96,12 @@ export default {
label="Fetching related merge requests" label="Fetching related merge requests"
class="gl-py-4" class="gl-py-4"
/> />
<ul v-else class="content-list related-items-list"> <ul v-else class="content-list related-items-list gl-px-4! gl-py-3!">
<li v-for="mr in mergeRequests" :key="mr.id" class="list-item gl-m-0! gl-px-4! gl-py-3!"> <li
v-for="mr in mergeRequests"
:key="mr.id"
class="list-item gl-m-0! gl-p-0! gl-border-b-0!"
>
<related-issuable-item <related-issuable-item
:id-key="mr.id" :id-key="mr.id"
:display-reference="mr.reference" :display-reference="mr.reference"

View File

@ -2,7 +2,7 @@
import { darkModeEnabled } from '~/lib/utils/color_utils'; import { darkModeEnabled } from '~/lib/utils/color_utils';
import { setUrlParams } from '~/lib/utils/url_utility'; import { setUrlParams } from '~/lib/utils/url_utility';
import { MESSAGE_EVENT_TYPE, SKELETON_VARIANTS_BY_ROUTE } from '../constants'; import { MESSAGE_EVENT_TYPE, FULL_APP_DIMENSIONS } from '../constants';
import ObservabilitySkeleton from './skeleton/index.vue'; import ObservabilitySkeleton from './skeleton/index.vue';
export default { export default {
@ -14,25 +14,33 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
inlineEmbed: {
type: Boolean,
required: false,
default: false,
},
skeletonVariant: {
type: String,
required: false,
default: 'dashboards',
},
height: {
type: String,
required: false,
default: FULL_APP_DIMENSIONS.HEIGHT,
},
width: {
type: String,
required: false,
default: FULL_APP_DIMENSIONS.WIDTH,
},
}, },
computed: { computed: {
iframeSrcWithParams() { iframeSrcWithParams() {
return setUrlParams( return `${setUrlParams(
{ theme: darkModeEnabled() ? 'dark' : 'light', username: gon?.current_username }, { theme: darkModeEnabled() ? 'dark' : 'light', username: gon?.current_username },
this.observabilityIframeSrc, this.observabilityIframeSrc,
); )}${this.inlineEmbed ? '&kiosk=inline-embed' : ''}`;
},
getSkeletonVariant() {
const [, variant] =
Object.entries(SKELETON_VARIANTS_BY_ROUTE).find(([path]) =>
this.$route.path.endsWith(path),
) || [];
const DEFAULT_SKELETON = 'dashboards';
if (!variant) return DEFAULT_SKELETON;
return variant;
}, },
}, },
mounted() { mounted() {
@ -54,38 +62,24 @@ export default {
this.$refs.observabilitySkeleton.onContentLoaded(); this.$refs.observabilitySkeleton.onContentLoaded();
break; break;
case MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE: case MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE:
this.routeUpdateHandler(payload); this.$emit('route-update', payload);
break; break;
default: default:
break; break;
} }
}, },
routeUpdateHandler(payload) {
const isNewObservabilityPath = this.$route?.query?.observability_path !== payload?.url;
const shouldNotHandleMessage = !payload.url || !isNewObservabilityPath;
if (shouldNotHandleMessage) {
return;
}
// this will update the `observability_path` query param on each route change inside Observability UI
this.$router.replace({
name: this.$route.pathname,
query: { ...this.$route.query, observability_path: payload.url },
});
},
}, },
}; };
</script> </script>
<template> <template>
<observability-skeleton ref="observabilitySkeleton" :variant="getSkeletonVariant"> <observability-skeleton ref="observabilitySkeleton" :variant="skeletonVariant">
<iframe <iframe
id="observability-ui-iframe" id="observability-ui-iframe"
data-testid="observability-ui-iframe" data-testid="observability-ui-iframe"
frameborder="0" frameborder="0"
height="100%" :width="width"
:height="height"
:src="iframeSrcWithParams" :src="iframeSrcWithParams"
sandbox="allow-same-origin allow-forms allow-scripts" sandbox="allow-same-origin allow-forms allow-scripts"
></iframe> ></iframe>

View File

@ -0,0 +1,15 @@
<script>
import { GlSkeletonLoader } from '@gitlab/ui';
export default {
components: {
GlSkeletonLoader,
},
};
</script>
<template>
<gl-skeleton-loader>
<rect y="5" width="400" height="30" rx="2" ry="2" />
<rect y="50" width="400" height="80" rx="2" ry="2" />
</gl-skeleton-loader>
</template>

View File

@ -8,10 +8,12 @@ import {
OBSERVABILITY_ROUTES, OBSERVABILITY_ROUTES,
TIMEOUT_ERROR_LABEL, TIMEOUT_ERROR_LABEL,
TIMEOUT_ERROR_MESSAGE, TIMEOUT_ERROR_MESSAGE,
SKELETON_VARIANT_EMBED,
} from '../../constants'; } from '../../constants';
import DashboardsSkeleton from './dashboards.vue'; import DashboardsSkeleton from './dashboards.vue';
import ExploreSkeleton from './explore.vue'; import ExploreSkeleton from './explore.vue';
import ManageSkeleton from './manage.vue'; import ManageSkeleton from './manage.vue';
import EmbedSkeleton from './embed.vue';
export default { export default {
components: { components: {
@ -19,11 +21,13 @@ export default {
DashboardsSkeleton, DashboardsSkeleton,
ExploreSkeleton, ExploreSkeleton,
ManageSkeleton, ManageSkeleton,
EmbedSkeleton,
GlAlert, GlAlert,
}, },
SKELETON_VARIANTS_BY_ROUTE, SKELETON_VARIANTS_BY_ROUTE,
SKELETON_STATE, SKELETON_STATE,
OBSERVABILITY_ROUTES, OBSERVABILITY_ROUTES,
SKELETON_VARIANT_EMBED,
i18n: { i18n: {
TIMEOUT_ERROR_LABEL, TIMEOUT_ERROR_LABEL,
TIMEOUT_ERROR_MESSAGE, TIMEOUT_ERROR_MESSAGE,
@ -102,6 +106,7 @@ export default {
<dashboards-skeleton v-if="isSkeletonShown($options.OBSERVABILITY_ROUTES.DASHBOARDS)" /> <dashboards-skeleton v-if="isSkeletonShown($options.OBSERVABILITY_ROUTES.DASHBOARDS)" />
<explore-skeleton v-else-if="isSkeletonShown($options.OBSERVABILITY_ROUTES.EXPLORE)" /> <explore-skeleton v-else-if="isSkeletonShown($options.OBSERVABILITY_ROUTES.EXPLORE)" />
<manage-skeleton v-else-if="isSkeletonShown($options.OBSERVABILITY_ROUTES.MANAGE)" /> <manage-skeleton v-else-if="isSkeletonShown($options.OBSERVABILITY_ROUTES.MANAGE)" />
<embed-skeleton v-else-if="variant === $options.SKELETON_VARIANT_EMBED" />
<gl-skeleton-loader v-else> <gl-skeleton-loader v-else>
<rect y="2" width="10" height="8" /> <rect y="2" width="10" height="8" />
@ -122,12 +127,14 @@ export default {
{{ $options.i18n.TIMEOUT_ERROR_MESSAGE }} {{ $options.i18n.TIMEOUT_ERROR_MESSAGE }}
</gl-alert> </gl-alert>
<div <transition>
v-show="state === $options.SKELETON_STATE.HIDDEN" <div
data-testid="observability-wrapper" v-show="state === $options.SKELETON_STATE.HIDDEN"
class="gl-flex-grow-1 gl-display-flex gl-flex-direction-column gl-flex-align-items-stretch" data-testid="observability-wrapper"
> class="gl-flex-grow-1 gl-display-flex gl-flex-direction-column gl-flex-align-items-stretch"
<slot></slot> >
</div> <slot></slot>
</div>
</transition>
</div> </div>
</template> </template>

View File

@ -17,6 +17,8 @@ export const SKELETON_VARIANTS_BY_ROUTE = Object.freeze({
[OBSERVABILITY_ROUTES.MANAGE]: 'manage', [OBSERVABILITY_ROUTES.MANAGE]: 'manage',
}); });
export const SKELETON_VARIANT_EMBED = 'embed';
export const SKELETON_STATE = Object.freeze({ export const SKELETON_STATE = Object.freeze({
ERROR: 'error', ERROR: 'error',
VISIBLE: 'visible', VISIBLE: 'visible',
@ -30,3 +32,13 @@ export const DEFAULT_TIMERS = Object.freeze({
export const TIMEOUT_ERROR_LABEL = __('Unable to load the page'); export const TIMEOUT_ERROR_LABEL = __('Unable to load the page');
export const TIMEOUT_ERROR_MESSAGE = __('Reload the page to try again.'); export const TIMEOUT_ERROR_MESSAGE = __('Reload the page to try again.');
export const INLINE_EMBED_DIMENSIONS = Object.freeze({
HEIGHT: '366px',
WIDTH: '768px',
});
export const FULL_APP_DIMENSIONS = Object.freeze({
HEIGHT: '100%',
WIDTH: '100%',
});

View File

@ -2,6 +2,7 @@ import Vue from 'vue';
import VueRouter from 'vue-router'; import VueRouter from 'vue-router';
import ObservabilityApp from './components/observability_app.vue'; import ObservabilityApp from './components/observability_app.vue';
import { SKELETON_VARIANTS_BY_ROUTE } from './constants';
Vue.use(VueRouter); Vue.use(VueRouter);
@ -17,10 +18,41 @@ export default () => {
return new Vue({ return new Vue({
el, el,
router, router,
computed: {
skeletonVariant() {
const [, variant] =
Object.entries(SKELETON_VARIANTS_BY_ROUTE).find(([path]) =>
this.$route.path.endsWith(path),
) || [];
return variant;
},
},
methods: {
routeUpdateHandler(payload) {
const isNewObservabilityPath = this.$route?.query?.observability_path !== payload?.url;
const shouldNotHandleMessage = !payload.url || !isNewObservabilityPath;
if (shouldNotHandleMessage) {
return;
}
// this will update the `observability_path` query param on each route change inside Observability UI
this.$router.replace({
name: this.$route?.pathname,
query: { ...this.$route.query, observability_path: payload.url },
});
},
},
render(h) { render(h) {
return h(ObservabilityApp, { return h(ObservabilityApp, {
props: { props: {
observabilityIframeSrc: el.dataset.observabilityIframeSrc, observabilityIframeSrc: el.dataset.observabilityIframeSrc,
skeletonVariant: this.skeletonVariant,
},
on: {
'route-update': (payload) => this.routeUpdateHandler(payload),
}, },
}); });
}, },

View File

@ -159,6 +159,11 @@ $item-remove-button-space: 42px;
.mr-ci-status { .mr-ci-status {
line-height: 0; line-height: 0;
a:focus {
@include gl-rounded-full;
@include gl-focus;
}
} }
@include media-breakpoint-down(xs) { @include media-breakpoint-down(xs) {

View File

@ -7,8 +7,9 @@ module Types
description 'Values for sorting projects' description 'Values for sorting projects'
value 'SIMILARITY', 'Most similar to the search query.', value: :similarity value 'SIMILARITY', 'Most similar to the search query.', value: :similarity
value 'STORAGE', 'Sort by storage size.', value: :storage value 'ACTIVITY_DESC', 'Sort by latest activity, descending order.', value: :latest_activity_desc
value 'ACTIVITY_DESC', 'Sort by latest activity, in descending order.', value: :latest_activity_desc
end end
end end
end end
Types::Projects::NamespaceProjectSortEnum.prepend_mod

View File

@ -13,4 +13,5 @@
help_text: '%{help_text} %{learn_more_link}'.html_safe % { help_text: help_text, learn_more_link: learn_more_link }, help_text: '%{help_text} %{learn_more_link}'.html_safe % { help_text: help_text, learn_more_link: learn_more_link },
checkbox_options: { checked: group.auto_devops_enabled? } checkbox_options: { checked: group.auto_devops_enabled? }
= f.submit _('Save changes'), class: 'gl-mt-5', pajamas_button: true = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, button_options: { class: 'gl-mt-5' }) do
= _('Save changes')

View File

@ -1,6 +1,7 @@
--- ---
table_name: bulk_import_batch_trackers table_name: bulk_import_batch_trackers
classes: [] classes:
- BulkImports::BatchTracker
feature_categories: feature_categories:
- importers - importers
description: Used to store and track the import status of a batch of relations for the migration description: Used to store and track the import status of a batch of relations for the migration

View File

@ -1,6 +1,7 @@
--- ---
table_name: bulk_import_export_batches table_name: bulk_import_export_batches
classes: [] classes:
- BulkImports::ExportBatch
feature_categories: feature_categories:
- importers - importers
description: Used to track the generation status of export batch files for groups description: Used to track the generation status of export batch files for groups

View File

@ -47,6 +47,7 @@ classes:
- Integrations::Shimo - Integrations::Shimo
- Integrations::Slack - Integrations::Slack
- Integrations::SlackSlashCommands - Integrations::SlackSlashCommands
- Integrations::SquashTm
- Integrations::Teamcity - Integrations::Teamcity
- Integrations::UnifyCircuit - Integrations::UnifyCircuit
- Integrations::WebexTeams - Integrations::WebexTeams

View File

@ -23781,9 +23781,11 @@ Values for sorting projects.
| Value | Description | | Value | Description |
| ----- | ----------- | | ----- | ----------- |
| <a id="namespaceprojectsortactivity_desc"></a>`ACTIVITY_DESC` | Sort by latest activity, in descending order. | | <a id="namespaceprojectsortactivity_desc"></a>`ACTIVITY_DESC` | Sort by latest activity, descending order. |
| <a id="namespaceprojectsortsimilarity"></a>`SIMILARITY` | Most similar to the search query. | | <a id="namespaceprojectsortsimilarity"></a>`SIMILARITY` | Most similar to the search query. |
| <a id="namespaceprojectsortstorage"></a>`STORAGE` | Sort by storage size. | | <a id="namespaceprojectsortstorage"></a>`STORAGE` | Sort by excess repository storage size, descending order. |
| <a id="namespaceprojectsortstorage_size_asc"></a>`STORAGE_SIZE_ASC` | Sort by total storage size, ascending order. |
| <a id="namespaceprojectsortstorage_size_desc"></a>`STORAGE_SIZE_DESC` | Sort by total storage size, descending order. |
### `NegatedIterationWildcardId` ### `NegatedIterationWildcardId`

View File

@ -630,6 +630,7 @@ The following variables allow configuration of global dependency scanning settin
| `DS_EXCLUDED_ANALYZERS` | Specify the analyzers (by name) to exclude from Dependency Scanning. For more information, see [Dependency Scanning Analyzers](analyzers.md). | | `DS_EXCLUDED_ANALYZERS` | Specify the analyzers (by name) to exclude from Dependency Scanning. For more information, see [Dependency Scanning Analyzers](analyzers.md). |
| `DS_EXCLUDED_PATHS` | Exclude files and directories from the scan based on the paths. A comma-separated list of patterns. Patterns can be globs (see [`doublestar.Match`](https://pkg.go.dev/github.com/bmatcuk/doublestar/v4@v4.0.2#Match) for supported patterns), or file or folder paths (for example, `doc,spec`). Parent directories also match patterns. Default: `"spec, test, tests, tmp"`. | | `DS_EXCLUDED_PATHS` | Exclude files and directories from the scan based on the paths. A comma-separated list of patterns. Patterns can be globs (see [`doublestar.Match`](https://pkg.go.dev/github.com/bmatcuk/doublestar/v4@v4.0.2#Match) for supported patterns), or file or folder paths (for example, `doc,spec`). Parent directories also match patterns. Default: `"spec, test, tests, tmp"`. |
| `DS_IMAGE_SUFFIX` | Suffix added to the image name. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/354796) in GitLab 14.10.) Automatically set to `"-fips"` when FIPS mode is enabled. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/357922) in GitLab 15.0.) | | `DS_IMAGE_SUFFIX` | Suffix added to the image name. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/354796) in GitLab 14.10.) Automatically set to `"-fips"` when FIPS mode is enabled. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/357922) in GitLab 15.0.) |
| `DS_MAX_DEPTH` | Defines how many directory levels deep that the analyzer should search for supported files to scan. A value of `-1` scans all directories regardless of depth. Default: `2`. |
| `SECURE_ANALYZERS_PREFIX` | Override the name of the Docker registry providing the official default images (proxy). Read more about [customizing analyzers](analyzers.md). | | `SECURE_ANALYZERS_PREFIX` | Override the name of the Docker registry providing the official default images (proxy). Read more about [customizing analyzers](analyzers.md). |
| `SECURE_LOG_LEVEL` | Set the minimum logging level. Messages of this logging level or higher are output. From highest to lowest severity, the logging levels are: `fatal`, `error`, `warn`, `info`, `debug`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10880) in GitLab 13.1. Default: `info`. | | `SECURE_LOG_LEVEL` | Set the minimum logging level. Messages of this logging level or higher are output. From highest to lowest severity, the logging levels are: `fatal`, `error`, `warn`, `info`, `debug`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10880) in GitLab 13.1. Default: `info`. |

View File

@ -10,8 +10,12 @@ info: To determine the technical writer assigned to the Stage/Group associated w
You can use scan result policies to take action based on scan results. For example, one type of scan You can use scan result policies to take action based on scan results. For example, one type of scan
result policy is a security approval policy that allows approval to be required based on the result policy is a security approval policy that allows approval to be required based on the
findings of one or more security scan jobs. Scan result policies are evaluated after a CI scanning findings of one or more security scan jobs. Scan result policies are evaluated after a CI scanning job is fully executed.
job is fully executed. The following video gives you an overview of GitLab scan result policies:
NOTE:
Scan result policies are applicable only to [protected](../../project/protected_branches.md) target branches.
The following video gives you an overview of GitLab scan result policies:
<div class="video-fallback"> <div class="video-fallback">
See the video: <a href="https://youtu.be/w5I9gcUgr9U">Overview of GitLab Scan Result Policies</a>. See the video: <a href="https://youtu.be/w5I9gcUgr9U">Overview of GitLab Scan Result Policies</a>.

View File

@ -170,11 +170,7 @@ passing in an optional value to the `commit_sha` query parameter.
## Compliance frameworks report ## Compliance frameworks report
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/387910) in GitLab 15.10 with a flag named `compliance_frameworks_report`. Disabled by default. > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/387910) in GitLab 15.10.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `compliance_frameworks_report`.
On GitLab.com, this feature is available.
With compliance frameworks report, you can see the compliance frameworks that are applied to projects in a group. Each row of the report shows: With compliance frameworks report, you can see the compliance frameworks that are applied to projects in a group. Each row of the report shows:

View File

@ -9,7 +9,12 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8092) in GitLab 15.9 [with a flag](../../administration/feature_flags.md) named `license_scanning_policies`. Disabled by default. > [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8092) in GitLab 15.9 [with a flag](../../administration/feature_flags.md) named `license_scanning_policies`. Disabled by default.
License Approval Policies allow you to specify multiple types of criteria that define when approval is required before a merge request can be merged in. The following video provides an overview of these policies. License Approval Policies allow you to specify multiple types of criteria that define when approval is required before a merge request can be merged in.
NOTE:
License Approval Policies are applicable only to [protected](../project/protected_branches.md) target branches.
The following video provides an overview of these policies.
<div class="video-fallback"> <div class="video-fallback">
See the video: <a href="https://www.youtube.com/watch?v=34qBQ9t8qO8">Overview of GitLab License Approval Policies</a>. See the video: <a href="https://www.youtube.com/watch?v=34qBQ9t8qO8">Overview of GitLab License Approval Policies</a>.

View File

@ -56,15 +56,15 @@ dependency_scanning:
.gemnasium-shared-rule: .gemnasium-shared-rule:
exists: exists:
- '{Gemfile.lock,*/Gemfile.lock,*/*/Gemfile.lock}' - '**/Gemfile.lock'
- '{composer.lock,*/composer.lock,*/*/composer.lock}' - '**/composer.lock'
- '{gems.locked,*/gems.locked,*/*/gems.locked}' - '**/gems.locked'
- '{go.sum,*/go.sum,*/*/go.sum}' - '**/go.sum'
- '{npm-shrinkwrap.json,*/npm-shrinkwrap.json,*/*/npm-shrinkwrap.json}' - '**/npm-shrinkwrap.json'
- '{package-lock.json,*/package-lock.json,*/*/package-lock.json}' - '**/package-lock.json'
- '{yarn.lock,*/yarn.lock,*/*/yarn.lock}' - '**/yarn.lock'
- '{packages.lock.json,*/packages.lock.json,*/*/packages.lock.json}' - '**/packages.lock.json'
- '{conan.lock,*/conan.lock,*/*/conan.lock}' - '**/conan.lock'
gemnasium-dependency_scanning: gemnasium-dependency_scanning:
extends: extends:
@ -91,10 +91,10 @@ gemnasium-dependency_scanning:
.gemnasium-maven-shared-rule: .gemnasium-maven-shared-rule:
exists: exists:
- '{build.gradle,*/build.gradle,*/*/build.gradle}' - '**/build.gradle'
- '{build.gradle.kts,*/build.gradle.kts,*/*/build.gradle.kts}' - '**/build.gradle.kts'
- '{build.sbt,*/build.sbt,*/*/build.sbt}' - '**/build.sbt'
- '{pom.xml,*/pom.xml,*/*/pom.xml}' - '**/pom.xml'
gemnasium-maven-dependency_scanning: gemnasium-maven-dependency_scanning:
extends: extends:
@ -119,12 +119,12 @@ gemnasium-maven-dependency_scanning:
.gemnasium-python-shared-rule: .gemnasium-python-shared-rule:
exists: exists:
- '{requirements.txt,*/requirements.txt,*/*/requirements.txt}' - '**/requirements.txt'
- '{requirements.pip,*/requirements.pip,*/*/requirements.pip}' - '**/requirements.pip'
- '{Pipfile,*/Pipfile,*/*/Pipfile}' - '**/Pipfile'
- '{requires.txt,*/requires.txt,*/*/requires.txt}' - '**/requires.txt'
- '{setup.py,*/setup.py,*/*/setup.py}' - '**/setup.py'
- '{poetry.lock,*/poetry.lock,*/*/poetry.lock}' - '**/poetry.lock'
gemnasium-python-dependency_scanning: gemnasium-python-dependency_scanning:
extends: extends:

View File

@ -56,15 +56,15 @@ dependency_scanning:
.gemnasium-shared-rule: .gemnasium-shared-rule:
exists: exists:
- '{Gemfile.lock,*/Gemfile.lock,*/*/Gemfile.lock}' - '**/Gemfile.lock'
- '{composer.lock,*/composer.lock,*/*/composer.lock}' - '**/composer.lock'
- '{gems.locked,*/gems.locked,*/*/gems.locked}' - '**/gems.locked'
- '{go.sum,*/go.sum,*/*/go.sum}' - '**/go.sum'
- '{npm-shrinkwrap.json,*/npm-shrinkwrap.json,*/*/npm-shrinkwrap.json}' - '**/npm-shrinkwrap.json'
- '{package-lock.json,*/package-lock.json,*/*/package-lock.json}' - '**/package-lock.json'
- '{yarn.lock,*/yarn.lock,*/*/yarn.lock}' - '**/yarn.lock'
- '{packages.lock.json,*/packages.lock.json,*/*/packages.lock.json}' - '**/packages.lock.json'
- '{conan.lock,*/conan.lock,*/*/conan.lock}' - '**/conan.lock'
gemnasium-dependency_scanning: gemnasium-dependency_scanning:
extends: extends:
@ -109,10 +109,10 @@ gemnasium-dependency_scanning:
.gemnasium-maven-shared-rule: .gemnasium-maven-shared-rule:
exists: exists:
- '{build.gradle,*/build.gradle,*/*/build.gradle}' - '**/build.gradle'
- '{build.gradle.kts,*/build.gradle.kts,*/*/build.gradle.kts}' - '**/build.gradle.kts'
- '{build.sbt,*/build.sbt,*/*/build.sbt}' - '**/build.sbt'
- '{pom.xml,*/pom.xml,*/*/pom.xml}' - '**/pom.xml'
gemnasium-maven-dependency_scanning: gemnasium-maven-dependency_scanning:
extends: extends:
@ -155,12 +155,12 @@ gemnasium-maven-dependency_scanning:
.gemnasium-python-shared-rule: .gemnasium-python-shared-rule:
exists: exists:
- '{requirements.txt,*/requirements.txt,*/*/requirements.txt}' - '**/requirements.txt'
- '{requirements.pip,*/requirements.pip,*/*/requirements.pip}' - '**/requirements.pip'
- '{Pipfile,*/Pipfile,*/*/Pipfile}' - '**/Pipfile'
- '{requires.txt,*/requires.txt,*/*/requires.txt}' - '**/requires.txt'
- '{setup.py,*/setup.py,*/*/setup.py}' - '**/setup.py'
- '{poetry.lock,*/poetry.lock,*/*/poetry.lock}' - '**/poetry.lock'
gemnasium-python-dependency_scanning: gemnasium-python-dependency_scanning:
extends: extends:

View File

@ -1,7 +1,10 @@
# frozen_string_literal: true # frozen_string_literal: true
module QA module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_security do RSpec.describe 'Verify', :runner, product_group: :pipeline_security, quarantine: {
issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/396855',
type: :flaky
} do
describe "Unlocking job artifacts across parent-child pipelines" do describe "Unlocking job artifacts across parent-child pipelines" do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }

View File

@ -147,14 +147,14 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do
selected_group.add_owner(user) selected_group.add_owner(user)
end end
it 'can successfully transfer the group', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/384966' do it 'can successfully transfer the group' do
visit edit_group_path(selected_group) visit edit_group_path(selected_group)
page.within('[data-testid="transfer-locations-dropdown"]') do page.within('[data-testid="transfer-locations-dropdown"]') do
click_button _('Select parent group') click_button _('Select parent group')
fill_in _('Search'), with: target_group_name fill_in _('Search'), with: target_group_name
wait_for_requests wait_for_requests
click_button target_group_name click_button(target_group_name || 'No parent group')
end end
click_button s_('GroupSettings|Transfer group') click_button s_('GroupSettings|Transfer group')
@ -166,7 +166,10 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do
click_button 'Confirm' click_button 'Confirm'
end end
expect(page).to have_text "Group '#{selected_group.name}' was successfully transferred." within('[data-testid="breadcrumb-links"]') do
expect(page).to have_content(target_group_name) if target_group_name
expect(page).to have_content(selected_group.name)
end
expect(current_url).to include(selected_group.reload.full_path) expect(current_url).to include(selected_group.reload.full_path)
end end
end end
@ -175,7 +178,7 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do
let(:selected_group) { create(:group, path: 'foo-subgroup', parent: group) } let(:selected_group) { create(:group, path: 'foo-subgroup', parent: group) }
context 'when transfering to no parent group' do context 'when transfering to no parent group' do
let(:target_group_name) { 'No parent group' } let(:target_group_name) { nil }
it_behaves_like 'can transfer the group' it_behaves_like 'can transfer the group'
end end

View File

@ -8,9 +8,6 @@ RSpec.describe 'Observability rendering', :js, feature_category: :metrics do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:observable_url) { "https://www.gitlab.com/groups/#{group.path}/-/observability/explore?observability_path=/explore?foo=bar" } let_it_be(:observable_url) { "https://www.gitlab.com/groups/#{group.path}/-/observability/explore?observability_path=/explore?foo=bar" }
let_it_be(:expected_observable_url) { "https://observe.gitlab.com/-/#{group.id}/explore?foo=bar" } let_it_be(:expected_observable_url) { "https://observe.gitlab.com/-/#{group.id}/explore?foo=bar" }
let_it_be(:expected) do
%(<iframe src="#{expected_observable_url}&amp;theme=light&amp;kiosk=inline-embed" frameborder="0")
end
before do before do
stub_config_setting(url: "https://www.gitlab.com") stub_config_setting(url: "https://www.gitlab.com")

View File

@ -1,40 +1,43 @@
import Vue from 'vue';
import { createWrapper } from '@vue/test-utils';
import renderObservability from '~/behaviors/markdown/render_observability'; import renderObservability from '~/behaviors/markdown/render_observability';
import * as ColorUtils from '~/lib/utils/color_utils'; import { INLINE_EMBED_DIMENSIONS, SKELETON_VARIANT_EMBED } from '~/observability/constants';
import ObservabilityApp from '~/observability/components/observability_app.vue';
describe('Observability iframe renderer', () => { describe('renderObservability', () => {
const findObservabilityIframes = (theme = 'light') => let subject;
document.querySelectorAll(
`iframe[src="https://observe.gitlab.com/?theme=${theme}&kiosk=inline-embed"]`,
);
const renderEmbeddedObservability = () => {
renderObservability([...document.querySelectorAll('.js-render-observability')]);
jest.runAllTimers();
};
beforeEach(() => { beforeEach(() => {
document.body.dataset.page = ''; subject = document.createElement('div');
document.body.innerHTML = ''; subject.classList.add('js-render-observability');
subject.dataset.frameUrl = 'https://observe.gitlab.com/';
document.body.appendChild(subject);
}); });
it('renders an observability iframe', () => { afterEach(() => {
document.body.innerHTML = `<div class="js-render-observability" data-frame-url="https://observe.gitlab.com/"></div>`; subject.remove();
expect(findObservabilityIframes()).toHaveLength(0);
renderEmbeddedObservability();
expect(findObservabilityIframes()).toHaveLength(1);
}); });
it('renders iframe with dark param when GL has dark theme', () => { it('should return an array of Vue instances', () => {
document.body.innerHTML = `<div class="js-render-observability" data-frame-url="https://observe.gitlab.com/"></div>`; const vueInstances = renderObservability([
jest.spyOn(ColorUtils, 'darkModeEnabled').mockImplementation(() => true); ...document.querySelectorAll('.js-render-observability'),
]);
expect(vueInstances).toEqual([expect.any(Vue)]);
});
expect(findObservabilityIframes('dark')).toHaveLength(0); it('should correctly pass props to the ObservabilityApp component', () => {
const vueInstances = renderObservability([
...document.querySelectorAll('.js-render-observability'),
]);
renderEmbeddedObservability(); const wrapper = createWrapper(vueInstances[0]);
expect(findObservabilityIframes('dark')).toHaveLength(1); expect(wrapper.findComponent(ObservabilityApp).props()).toMatchObject({
observabilityIframeSrc: 'https://observe.gitlab.com/',
skeletonVariant: SKELETON_VARIANT_EMBED,
inlineEmbed: true,
height: INLINE_EMBED_DIMENSIONS.HEIGHT,
width: INLINE_EMBED_DIMENSIONS.WIDTH,
});
}); });
}); });

View File

@ -0,0 +1,64 @@
import { createWrapper } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import renderObservability from '~/observability/index';
import ObservabilityApp from '~/observability/components/observability_app.vue';
import { SKELETON_VARIANTS_BY_ROUTE } from '~/observability/constants';
describe('renderObservability', () => {
let element;
let vueInstance;
let component;
const OBSERVABILITY_ROUTES = Object.keys(SKELETON_VARIANTS_BY_ROUTE);
const SKELETON_VARIANTS = Object.values(SKELETON_VARIANTS_BY_ROUTE);
beforeEach(() => {
element = document.createElement('div');
element.setAttribute('id', 'js-observability-app');
element.dataset.observabilityIframeSrc = 'https://observe.gitlab.com/';
document.body.appendChild(element);
vueInstance = renderObservability();
component = createWrapper(vueInstance).findComponent(ObservabilityApp);
});
afterEach(() => {
element.remove();
});
it('should return a Vue instance', () => {
expect(vueInstance).toEqual(expect.any(Vue));
});
it('should render the ObservabilityApp component', () => {
expect(component.props('observabilityIframeSrc')).toBe('https://observe.gitlab.com/');
});
describe('skeleton variant', () => {
it.each`
pathDescription | path | variant
${'dashboards'} | ${OBSERVABILITY_ROUTES[0]} | ${SKELETON_VARIANTS[0]}
${'explore'} | ${OBSERVABILITY_ROUTES[1]} | ${SKELETON_VARIANTS[1]}
${'manage dashboards'} | ${OBSERVABILITY_ROUTES[2]} | ${SKELETON_VARIANTS[2]}
${'any other'} | ${'unknown/route'} | ${SKELETON_VARIANTS[0]}
`(
'renders the $variant skeleton variant for $pathDescription path',
async ({ path, variant }) => {
component.vm.$router.push(path);
await nextTick();
expect(component.props('skeletonVariant')).toBe(variant);
},
);
});
it('handle route-update events', async () => {
component.vm.$router.push('/something?foo=bar');
component.vm.$emit('route-update', { url: '/some_path' });
expect(component.vm.$router.currentRoute.path).toBe('/something');
expect(component.vm.$router.currentRoute.query).toEqual({
foo: 'bar',
observability_path: '/some_path',
});
});
});

View File

@ -1,19 +1,20 @@
import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import ObservabilityApp from '~/observability/components/observability_app.vue'; import ObservabilityApp from '~/observability/components/observability_app.vue';
import ObservabilitySkeleton from '~/observability/components/skeleton/index.vue'; import ObservabilitySkeleton from '~/observability/components/skeleton/index.vue';
import {
import { MESSAGE_EVENT_TYPE, SKELETON_VARIANTS_BY_ROUTE } from '~/observability/constants'; MESSAGE_EVENT_TYPE,
INLINE_EMBED_DIMENSIONS,
FULL_APP_DIMENSIONS,
SKELETON_VARIANT_EMBED,
} from '~/observability/constants';
import { darkModeEnabled } from '~/lib/utils/color_utils'; import { darkModeEnabled } from '~/lib/utils/color_utils';
jest.mock('~/lib/utils/color_utils'); jest.mock('~/lib/utils/color_utils');
describe('Observability root app', () => { describe('ObservabilityApp', () => {
let wrapper; let wrapper;
const replace = jest.fn();
const $router = {
replace,
};
const $route = { const $route = {
pathname: 'https://gitlab.com/gitlab-org/', pathname: 'https://gitlab.com/gitlab-org/',
path: 'https://gitlab.com/gitlab-org/-/observability/dashboards', path: 'https://gitlab.com/gitlab-org/-/observability/dashboards',
@ -26,21 +27,19 @@ describe('Observability root app', () => {
const TEST_IFRAME_SRC = 'https://observe.gitlab.com/9970/?groupId=14485840'; const TEST_IFRAME_SRC = 'https://observe.gitlab.com/9970/?groupId=14485840';
const OBSERVABILITY_ROUTES = Object.keys(SKELETON_VARIANTS_BY_ROUTE); const TEST_USERNAME = 'test-user';
const SKELETON_VARIANTS = Object.values(SKELETON_VARIANTS_BY_ROUTE); const mountComponent = (props) => {
const mountComponent = (route = $route) => {
wrapper = shallowMountExtended(ObservabilityApp, { wrapper = shallowMountExtended(ObservabilityApp, {
propsData: { propsData: {
observabilityIframeSrc: TEST_IFRAME_SRC, observabilityIframeSrc: TEST_IFRAME_SRC,
...props,
}, },
stubs: { stubs: {
'observability-skeleton': ObservabilitySkeleton, 'observability-skeleton': ObservabilitySkeleton,
}, },
mocks: { mocks: {
$router, $route,
$route: route,
}, },
}); });
}; };
@ -48,13 +47,11 @@ describe('Observability root app', () => {
const dispatchMessageEvent = (message) => const dispatchMessageEvent = (message) =>
window.dispatchEvent(new MessageEvent('message', message)); window.dispatchEvent(new MessageEvent('message', message));
beforeEach(() => {
gon.current_username = TEST_USERNAME;
});
describe('iframe src', () => { describe('iframe src', () => {
const TEST_USERNAME = 'test-user';
beforeEach(() => {
gon.current_username = TEST_USERNAME;
});
it('should render an iframe with observabilityIframeSrc, decorated with light theme and username', () => { it('should render an iframe with observabilityIframeSrc, decorated with light theme and username', () => {
darkModeEnabled.mockReturnValueOnce(false); darkModeEnabled.mockReturnValueOnce(false);
mountComponent(); mountComponent();
@ -88,48 +85,70 @@ describe('Observability root app', () => {
}); });
}); });
describe('on GOUI_ROUTE_UPDATE', () => { describe('iframe kiosk query param', () => {
it('should not call replace method from vue router if message event does not have url', () => { it('when inlineEmbed, it should set the proper kiosk query parameter', () => {
mountComponent(); mountComponent({
dispatchMessageEvent({ inlineEmbed: true,
type: MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE,
payload: { data: 'some other data' },
}); });
expect(replace).not.toHaveBeenCalled();
const iframe = findIframe();
expect(iframe.attributes('src')).toBe(
`${TEST_IFRAME_SRC}&theme=light&username=${TEST_USERNAME}&kiosk=inline-embed`,
);
});
});
describe('iframe size', () => {
it('should set the specified size', () => {
mountComponent({
height: INLINE_EMBED_DIMENSIONS.HEIGHT,
width: INLINE_EMBED_DIMENSIONS.WIDTH,
});
const iframe = findIframe();
expect(iframe.attributes('width')).toBe(INLINE_EMBED_DIMENSIONS.WIDTH);
expect(iframe.attributes('height')).toBe(INLINE_EMBED_DIMENSIONS.HEIGHT);
}); });
it.each` it('should fallback to default size', () => {
condition | origin | observability_path | url mountComponent({});
${'message origin is different from iframe source origin'} | ${'https://example.com'} | ${'/'} | ${'/explore'}
${'path is same as before (observability_path)'} | ${'https://observe.gitlab.com'} | ${'/foo?bar=test'} | ${'/foo?bar=test'}
`(
'should not call replace method from vue router if $condition',
async ({ origin, observability_path, url }) => {
mountComponent({ ...$route, query: { observability_path } });
dispatchMessageEvent({
data: { type: MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE, payload: { url } },
origin,
});
expect(replace).not.toHaveBeenCalled();
},
);
it('should call replace method from vue router on message event callback', () => { const iframe = findIframe();
expect(iframe.attributes('width')).toBe(FULL_APP_DIMENSIONS.WIDTH);
expect(iframe.attributes('height')).toBe(FULL_APP_DIMENSIONS.HEIGHT);
});
});
describe('skeleton variant', () => {
it('sets the specified skeleton variant', () => {
mountComponent({ skeletonVariant: SKELETON_VARIANT_EMBED });
const props = wrapper.findComponent(ObservabilitySkeleton).props();
expect(props.variant).toBe(SKELETON_VARIANT_EMBED);
});
it('should have a default skeleton variant', () => {
mountComponent();
const props = wrapper.findComponent(ObservabilitySkeleton).props();
expect(props.variant).toBe('dashboards');
});
});
describe('on GOUI_ROUTE_UPDATE', () => {
it('should emit a route-update event', () => {
mountComponent(); mountComponent();
const payload = { url: '/explore' };
dispatchMessageEvent({ dispatchMessageEvent({
data: { type: MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE, payload: { url: '/explore' } }, data: { type: MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE, payload },
origin: 'https://observe.gitlab.com', origin: 'https://observe.gitlab.com',
}); });
expect(replace).toHaveBeenCalled(); expect(wrapper.emitted('route-update')[0]).toEqual([payload]);
expect(replace).toHaveBeenCalledWith({
name: 'https://gitlab.com/gitlab-org/',
query: {
otherQuery: 100,
observability_path: '/explore',
},
});
}); });
}); });
@ -163,34 +182,17 @@ describe('Observability root app', () => {
}); });
}); });
describe('skeleton variant', () => { describe('on unmount', () => {
it.each` it('should not emit any even on route update', () => {
pathDescription | path | variant
${'dashboards'} | ${OBSERVABILITY_ROUTES[0]} | ${SKELETON_VARIANTS[0]}
${'explore'} | ${OBSERVABILITY_ROUTES[1]} | ${SKELETON_VARIANTS[1]}
${'manage dashboards'} | ${OBSERVABILITY_ROUTES[2]} | ${SKELETON_VARIANTS[2]}
${'any other'} | ${'unknown/route'} | ${SKELETON_VARIANTS[0]}
`('renders the $variant skeleton variant for $pathDescription path', ({ path, variant }) => {
mountComponent({ ...$route, path });
const props = wrapper.findComponent(ObservabilitySkeleton).props();
expect(props.variant).toBe(variant);
});
});
describe('on observability ui unmount', () => {
it('should remove message event and should not call replace method from vue router', () => {
mountComponent(); mountComponent();
wrapper.destroy(); wrapper.destroy();
// testing event cleanup logic, should not call on messege event after component is destroyed
dispatchMessageEvent({ dispatchMessageEvent({
data: { type: MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE, payload: { url: '/explore' } }, data: { type: MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE, payload: { url: '/explore' } },
origin: 'https://observe.gitlab.com', origin: 'https://observe.gitlab.com',
}); });
expect(replace).not.toHaveBeenCalled(); expect(wrapper.emitted('route-update')).toBeUndefined();
}); });
}); });
}); });

View File

@ -6,8 +6,13 @@ import Skeleton from '~/observability/components/skeleton/index.vue';
import DashboardsSkeleton from '~/observability/components/skeleton/dashboards.vue'; import DashboardsSkeleton from '~/observability/components/skeleton/dashboards.vue';
import ExploreSkeleton from '~/observability/components/skeleton/explore.vue'; import ExploreSkeleton from '~/observability/components/skeleton/explore.vue';
import ManageSkeleton from '~/observability/components/skeleton/manage.vue'; import ManageSkeleton from '~/observability/components/skeleton/manage.vue';
import EmbedSkeleton from '~/observability/components/skeleton/embed.vue';
import { SKELETON_VARIANTS_BY_ROUTE, DEFAULT_TIMERS } from '~/observability/constants'; import {
SKELETON_VARIANTS_BY_ROUTE,
DEFAULT_TIMERS,
SKELETON_VARIANT_EMBED,
} from '~/observability/constants';
describe('Skeleton component', () => { describe('Skeleton component', () => {
let wrapper; let wrapper;
@ -22,6 +27,8 @@ describe('Skeleton component', () => {
const findManageSkeleton = () => wrapper.findComponent(ManageSkeleton); const findManageSkeleton = () => wrapper.findComponent(ManageSkeleton);
const findEmbedSkeleton = () => wrapper.findComponent(EmbedSkeleton);
const findAlert = () => wrapper.findComponent(GlAlert); const findAlert = () => wrapper.findComponent(GlAlert);
const mountComponent = ({ ...props } = {}) => { const mountComponent = ({ ...props } = {}) => {
@ -97,16 +104,20 @@ describe('Skeleton component', () => {
${'dashboards'} | ${'variant is dashboards'} | ${SKELETON_VARIANTS[0]} ${'dashboards'} | ${'variant is dashboards'} | ${SKELETON_VARIANTS[0]}
${'explore'} | ${'variant is explore'} | ${SKELETON_VARIANTS[1]} ${'explore'} | ${'variant is explore'} | ${SKELETON_VARIANTS[1]}
${'manage'} | ${'variant is manage'} | ${SKELETON_VARIANTS[2]} ${'manage'} | ${'variant is manage'} | ${SKELETON_VARIANTS[2]}
${'embed'} | ${'variant is embed'} | ${SKELETON_VARIANT_EMBED}
${'default'} | ${'variant is not manage, dashboards or explore'} | ${'unknown'} ${'default'} | ${'variant is not manage, dashboards or explore'} | ${'unknown'}
`('should render $skeletonType skeleton if $condition', async ({ skeletonType, variant }) => { `('should render $skeletonType skeleton if $condition', async ({ skeletonType, variant }) => {
mountComponent({ variant }); mountComponent({ variant });
jest.advanceTimersByTime(DEFAULT_TIMERS.CONTENT_WAIT_MS); jest.advanceTimersByTime(DEFAULT_TIMERS.CONTENT_WAIT_MS);
await nextTick(); await nextTick();
const showsDefaultSkeleton = !SKELETON_VARIANTS.includes(variant); const showsDefaultSkeleton = ![...SKELETON_VARIANTS, SKELETON_VARIANT_EMBED].includes(
variant,
);
expect(findDashboardsSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANTS[0]); expect(findDashboardsSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANTS[0]);
expect(findExploreSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANTS[1]); expect(findExploreSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANTS[1]);
expect(findManageSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANTS[2]); expect(findManageSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANTS[2]);
expect(findEmbedSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANT_EMBED);
expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(showsDefaultSkeleton); expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(showsDefaultSkeleton);
}); });

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe AccessTokenValidationService do RSpec.describe AccessTokenValidationService, feature_category: :system_access do
describe ".include_any_scope?" do describe ".include_any_scope?" do
let(:request) { double("request") } let(:request) { double("request") }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe AuditEventService, :with_license do RSpec.describe AuditEventService, :with_license, feature_category: :audit_events do
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user, :with_sign_ins) } let_it_be(:user) { create(:user, :with_sign_ins) }
let_it_be(:project_member) { create(:project_member, user: user) } let_it_be(:project_member) { create(:project_member, user: user) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe AutoMergeService do RSpec.describe AutoMergeService, feature_category: :code_review_workflow do
let_it_be(:project) { create(:project, :repository) } let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe BaseContainerService do RSpec.describe BaseContainerService, feature_category: :container_registry do
let(:project) { Project.new } let(:project) { Project.new }
let(:user) { User.new } let(:user) { User.new }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe BaseCountService, :use_clean_rails_memory_store_caching do RSpec.describe BaseCountService, :use_clean_rails_memory_store_caching, feature_category: :shared do
let(:service) { described_class.new } let(:service) { described_class.new }
describe '#relation_for_count' do describe '#relation_for_count' do

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe BulkCreateIntegrationService do RSpec.describe BulkCreateIntegrationService, feature_category: :integrations do
include JiraIntegrationHelpers include JiraIntegrationHelpers
before_all do before_all do

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe BulkPushEventPayloadService do RSpec.describe BulkPushEventPayloadService, feature_category: :source_code_management do
let(:event) { create(:push_event) } let(:event) { create(:push_event) }
let(:push_data) do let(:push_data) do

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe BulkUpdateIntegrationService do RSpec.describe BulkUpdateIntegrationService, feature_category: :integrations do
include JiraIntegrationHelpers include JiraIntegrationHelpers
before_all do before_all do

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe CohortsService do RSpec.describe CohortsService, feature_category: :shared do
describe '#execute' do describe '#execute' do
def month_start(months_ago) def month_start(months_ago)
months_ago.months.ago.beginning_of_month.to_date months_ago.months.ago.beginning_of_month.to_date

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe CompareService do RSpec.describe CompareService, feature_category: :source_code_management do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:service) { described_class.new(project, 'feature') } let(:service) { described_class.new(project, 'feature') }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redis_shared_state do RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redis_shared_state, feature_category: :service_ping do
include SnowplowHelpers include SnowplowHelpers
let(:service) { described_class.new } let(:service) { described_class.new }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe GravatarService do RSpec.describe GravatarService, feature_category: :user_profile do
describe '#execute' do describe '#execute' do
let(:url) { 'http://example.com/avatar?hash=%{hash}&size=%{size}&email=%{email}&username=%{username}' } let(:url) { 'http://example.com/avatar?hash=%{hash}&size=%{size}&email=%{email}&username=%{username}' }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe ImportExportCleanUpService do RSpec.describe ImportExportCleanUpService, feature_category: :importers do
describe '#execute' do describe '#execute' do
let(:service) { described_class.new } let(:service) { described_class.new }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe MarkdownContentRewriterService do RSpec.describe MarkdownContentRewriterService, feature_category: :team_planning do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:source_parent) { create(:project, :public) } let_it_be(:source_parent) { create(:project, :public) }
let_it_be(:target_parent) { create(:project, :public) } let_it_be(:target_parent) { create(:project, :public) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe NoteSummary do RSpec.describe NoteSummary, feature_category: :code_review_workflow do
let(:project) { build(:project) } let(:project) { build(:project) }
let(:noteable) { build(:issue) } let(:noteable) { build(:issue) }
let(:user) { build(:user) } let(:user) { build(:user) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe PostReceiveService do RSpec.describe PostReceiveService, feature_category: :team_planning do
include GitlabShellHelpers include GitlabShellHelpers
include Gitlab::Routing include Gitlab::Routing

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe PreviewMarkdownService do RSpec.describe PreviewMarkdownService, feature_category: :team_planning do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe PushEventPayloadService do RSpec.describe PushEventPayloadService, feature_category: :source_code_management do
let(:event) { create(:push_event) } let(:event) { create(:push_event) }
describe '#execute' do describe '#execute' do

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe RepositoryArchiveCleanUpService do RSpec.describe RepositoryArchiveCleanUpService, feature_category: :source_code_management do
subject(:service) { described_class.new } subject(:service) { described_class.new }
describe '#execute (new archive locations)' do describe '#execute (new archive locations)' do

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe ResetProjectCacheService do RSpec.describe ResetProjectCacheService, feature_category: :projects do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:user) { create(:user) } let(:user) { create(:user) }

View File

@ -7,7 +7,7 @@ require 're2'
require_relative '../../app/services/service_response' require_relative '../../app/services/service_response'
require_relative '../../lib/gitlab/error_tracking' require_relative '../../lib/gitlab/error_tracking'
RSpec.describe ServiceResponse do RSpec.describe ServiceResponse, feature_category: :shared do
describe '.success' do describe '.success' do
it 'creates a successful response without a message' do it 'creates a successful response without a message' do
expect(described_class.success).to be_success expect(described_class.success).to be_success

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe SystemHooksService do RSpec.describe SystemHooksService, feature_category: :webhooks do
describe '#execute_hooks_for' do describe '#execute_hooks_for' do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) } let_it_be(:group) { create(:group) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe TaskListToggleService do RSpec.describe TaskListToggleService, feature_category: :team_planning do
let(:markdown) do let(:markdown) do
<<-EOT.strip_heredoc <<-EOT.strip_heredoc
* [ ] Task 1 * [ ] Task 1

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe TasksToBeDone::BaseService do RSpec.describe TasksToBeDone::BaseService, feature_category: :team_planning do
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }
let_it_be(:current_user) { create(:user) } let_it_be(:current_user) { create(:user) }
let_it_be(:assignee_one) { create(:user) } let_it_be(:assignee_one) { create(:user) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Terraform::RemoteStateHandler do RSpec.describe Terraform::RemoteStateHandler, feature_category: :infrastructure_as_code do
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }
let_it_be(:developer) { create(:user, developer_projects: [project]) } let_it_be(:developer) { create(:user, developer_projects: [project]) }
let_it_be(:maintainer) { create(:user, maintainer_projects: [project]) } let_it_be(:maintainer) { create(:user, maintainer_projects: [project]) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Terraform::States::DestroyService do RSpec.describe Terraform::States::DestroyService, feature_category: :infrastructure_as_code do
let_it_be(:state) { create(:terraform_state, :with_version, :deletion_in_progress) } let_it_be(:state) { create(:terraform_state, :with_version, :deletion_in_progress) }
let(:file) { instance_double(Terraform::StateUploader, relative_path: 'path') } let(:file) { instance_double(Terraform::StateUploader, relative_path: 'path') }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Terraform::States::TriggerDestroyService do RSpec.describe Terraform::States::TriggerDestroyService, feature_category: :infrastructure_as_code do
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user, maintainer_projects: [project]) } let_it_be(:user) { create(:user, maintainer_projects: [project]) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe TestHooks::ProjectService do RSpec.describe TestHooks::ProjectService, feature_category: :code_testing do
include AfterNextHelpers include AfterNextHelpers
let(:current_user) { create(:user) } let(:current_user) { create(:user) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe TestHooks::SystemService do RSpec.describe TestHooks::SystemService, feature_category: :code_testing do
include AfterNextHelpers include AfterNextHelpers
describe '#execute' do describe '#execute' do

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Timelogs::DeleteService do RSpec.describe Timelogs::DeleteService, feature_category: :team_planning do
let_it_be(:author) { create(:user) } let_it_be(:author) { create(:user) }
let_it_be(:project) { create(:project, :public) } let_it_be(:project) { create(:project, :public) }
let_it_be(:issue) { create(:issue, project: project) } let_it_be(:issue) { create(:issue, project: project) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe TodoService do RSpec.describe TodoService, feature_category: :team_planning do
include AfterNextHelpers include AfterNextHelpers
let_it_be(:project) { create(:project, :repository) } let_it_be(:project) { create(:project, :repository) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Todos::AllowedTargetFilterService do RSpec.describe Todos::AllowedTargetFilterService, feature_category: :team_planning do
include DesignManagementTestHelpers include DesignManagementTestHelpers
let_it_be(:authorized_group) { create(:group, :private) } let_it_be(:authorized_group) { create(:group, :private) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Todos::Destroy::ConfidentialIssueService do RSpec.describe Todos::Destroy::ConfidentialIssueService, feature_category: :team_planning do
let(:project) { create(:project, :public) } let(:project) { create(:project, :public) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:author) { create(:user) } let(:author) { create(:user) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Todos::Destroy::DesignService do RSpec.describe Todos::Destroy::DesignService, feature_category: :design_management do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:user_2) { create(:user) } let_it_be(:user_2) { create(:user) }
let_it_be(:design) { create(:design) } let_it_be(:design) { create(:design) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Todos::Destroy::DestroyedIssuableService do RSpec.describe Todos::Destroy::DestroyedIssuableService, feature_category: :team_planning do
describe '#execute' do describe '#execute' do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Todos::Destroy::ProjectPrivateService do RSpec.describe Todos::Destroy::ProjectPrivateService, feature_category: :team_planning do
let(:group) { create(:group, :public) } let(:group) { create(:group, :public) }
let(:project) { create(:project, :public, group: group) } let(:project) { create(:project, :public, group: group) }
let(:user) { create(:user) } let(:user) { create(:user) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Todos::Destroy::UnauthorizedFeaturesService do RSpec.describe Todos::Destroy::UnauthorizedFeaturesService, feature_category: :team_planning do
let_it_be(:project, reload: true) { create(:project, :public, :repository) } let_it_be(:project, reload: true) { create(:project, :public, :repository) }
let_it_be(:issue) { create(:issue, project: project) } let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:mr) { create(:merge_request, source_project: project) } let_it_be(:mr) { create(:merge_request, source_project: project) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Topics::MergeService do RSpec.describe Topics::MergeService, feature_category: :shared do
let_it_be(:source_topic) { create(:topic, name: 'source_topic') } let_it_be(:source_topic) { create(:topic, name: 'source_topic') }
let_it_be(:target_topic) { create(:topic, name: 'target_topic') } let_it_be(:target_topic) { create(:topic, name: 'target_topic') }
let_it_be(:project_1) { create(:project, :public, topic_list: source_topic.name) } let_it_be(:project_1) { create(:project, :public, topic_list: source_topic.name) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe TwoFactor::DestroyService do RSpec.describe TwoFactor::DestroyService, feature_category: :system_access do
let_it_be(:current_user) { create(:user) } let_it_be(:current_user) { create(:user) }
subject { described_class.new(current_user, user: user).execute } subject { described_class.new(current_user, user: user).execute }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe UpdateContainerRegistryInfoService do RSpec.describe UpdateContainerRegistryInfoService, feature_category: :container_registry do
let_it_be(:application_settings) { Gitlab::CurrentSettings } let_it_be(:application_settings) { Gitlab::CurrentSettings }
let_it_be(:api_url) { 'http://registry.gitlab' } let_it_be(:api_url) { 'http://registry.gitlab' }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe MergeRequestMetricsService do RSpec.describe MergeRequestMetricsService, feature_category: :code_review_workflow do
let(:metrics) { create(:merge_request).metrics } let(:metrics) { create(:merge_request).metrics }
describe '#merge' do describe '#merge' do

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe UploadService do RSpec.describe UploadService, feature_category: :shared do
describe 'File service' do describe 'File service' do
before do before do
@user = create(:user) @user = create(:user)

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Uploads::DestroyService do RSpec.describe Uploads::DestroyService, feature_category: :shared do
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be_with_reload(:upload) { create(:upload, :issuable_upload, model: project) } let_it_be_with_reload(:upload) { create(:upload, :issuable_upload, model: project) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe UserPreferences::UpdateService do RSpec.describe UserPreferences::UpdateService, feature_category: :user_profile do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:params) { { view_diffs_file_by_file: false } } let(:params) { { view_diffs_file_by_file: false } }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::ActivityService do RSpec.describe Users::ActivityService, feature_category: :user_profile do
include ExclusiveLeaseHelpers include ExclusiveLeaseHelpers
let(:user) { create(:user, last_activity_on: last_activity_on) } let(:user) { create(:user, last_activity_on: last_activity_on) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::ApproveService do RSpec.describe Users::ApproveService, feature_category: :user_management do
let_it_be(:current_user) { create(:admin) } let_it_be(:current_user) { create(:admin) }
let(:user) { create(:user, :blocked_pending_approval) } let(:user) { create(:user, :blocked_pending_approval) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::AuthorizedBuildService do RSpec.describe Users::AuthorizedBuildService, feature_category: :user_management do
describe '#execute' do describe '#execute' do
let_it_be(:current_user) { create(:user) } let_it_be(:current_user) { create(:user) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::BanService do RSpec.describe Users::BanService, feature_category: :user_management do
let(:user) { create(:user) } let(:user) { create(:user) }
let_it_be(:current_user) { create(:admin) } let_it_be(:current_user) { create(:admin) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::BannedUserBaseService do RSpec.describe Users::BannedUserBaseService, feature_category: :user_management do
let(:admin) { create(:admin) } let(:admin) { create(:admin) }
let(:base_service) { described_class.new(admin) } let(:base_service) { described_class.new(admin) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::BatchStatusCleanerService do RSpec.describe Users::BatchStatusCleanerService, feature_category: :user_management do
let_it_be(:user_status_1) { create(:user_status, emoji: 'coffee', message: 'msg1', clear_status_at: 1.year.ago) } let_it_be(:user_status_1) { create(:user_status, emoji: 'coffee', message: 'msg1', clear_status_at: 1.year.ago) }
let_it_be(:user_status_2) { create(:user_status, emoji: 'coffee', message: 'msg1', clear_status_at: 1.year.from_now) } let_it_be(:user_status_2) { create(:user_status, emoji: 'coffee', message: 'msg1', clear_status_at: 1.year.from_now) }
let_it_be(:user_status_3) { create(:user_status, emoji: 'coffee', message: 'msg1', clear_status_at: 2.years.ago) } let_it_be(:user_status_3) { create(:user_status, emoji: 'coffee', message: 'msg1', clear_status_at: 2.years.ago) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::BlockService do RSpec.describe Users::BlockService, feature_category: :user_management do
let_it_be(:current_user) { create(:admin) } let_it_be(:current_user) { create(:admin) }
subject(:service) { described_class.new(current_user) } subject(:service) { described_class.new(current_user) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::BuildService do RSpec.describe Users::BuildService, feature_category: :user_management do
using RSpec::Parameterized::TableSyntax using RSpec::Parameterized::TableSyntax
describe '#execute' do describe '#execute' do

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::CreateService do RSpec.describe Users::CreateService, feature_category: :user_management do
describe '#execute' do describe '#execute' do
let(:password) { User.random_password } let(:password) { User.random_password }
let(:admin_user) { create(:admin) } let(:admin_user) { create(:admin) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::DestroyService do RSpec.describe Users::DestroyService, feature_category: :user_management do
let!(:user) { create(:user) } let!(:user) { create(:user) }
let!(:admin) { create(:admin) } let!(:admin) { create(:admin) }
let!(:namespace) { user.namespace } let!(:namespace) { user.namespace }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::DismissCalloutService do RSpec.describe Users::DismissCalloutService, feature_category: :user_management do
describe '#execute' do describe '#execute' do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::DismissGroupCalloutService do RSpec.describe Users::DismissGroupCalloutService, feature_category: :user_management do
describe '#execute' do describe '#execute' do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) } let_it_be(:group) { create(:group) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::DismissProjectCalloutService do RSpec.describe Users::DismissProjectCalloutService, feature_category: :user_management do
describe '#execute' do describe '#execute' do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::EmailVerification::GenerateTokenService do RSpec.describe Users::EmailVerification::GenerateTokenService, feature_category: :system_access do
using RSpec::Parameterized::TableSyntax using RSpec::Parameterized::TableSyntax
let(:service) { described_class.new(attr: attr) } let(:service) { described_class.new(attr: attr) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::EmailVerification::ValidateTokenService, :clean_gitlab_redis_rate_limiting do RSpec.describe Users::EmailVerification::ValidateTokenService, :clean_gitlab_redis_rate_limiting, feature_category: :system_access do
using RSpec::Parameterized::TableSyntax using RSpec::Parameterized::TableSyntax
let(:service) { described_class.new(attr: attr, user: user, token: token) } let(:service) { described_class.new(attr: attr, user: user, token: token) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::InProductMarketingEmailRecords do RSpec.describe Users::InProductMarketingEmailRecords, feature_category: :onboarding do
let_it_be(:user) { create :user } let_it_be(:user) { create :user }
subject(:records) { described_class.new } subject(:records) { described_class.new }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::KeysCountService, :use_clean_rails_memory_store_caching do RSpec.describe Users::KeysCountService, :use_clean_rails_memory_store_caching, feature_category: :system_access do
let(:user) { create(:user) } let(:user) { create(:user) }
subject { described_class.new(user) } subject { described_class.new(user) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::LastPushEventService do RSpec.describe Users::LastPushEventService, feature_category: :source_code_management do
let(:user) { build(:user, id: 1) } let(:user) { build(:user, id: 1) }
let(:project) { build(:project, id: 2) } let(:project) { build(:project, id: 2) }
let(:event) { build(:push_event, id: 3, author: user, project: project) } let(:event) { build(:push_event, id: 3, author: user, project: project) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::MigrateRecordsToGhostUserInBatchesService do RSpec.describe Users::MigrateRecordsToGhostUserInBatchesService, feature_category: :user_management do
let(:service) { described_class.new } let(:service) { described_class.new }
let_it_be(:ghost_user_migration) { create(:ghost_user_migration) } let_it_be(:ghost_user_migration) { create(:ghost_user_migration) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::MigrateRecordsToGhostUserService do RSpec.describe Users::MigrateRecordsToGhostUserService, feature_category: :user_management do
include BatchDestroyDependentAssociationsHelper include BatchDestroyDependentAssociationsHelper
let!(:user) { create(:user) } let!(:user) { create(:user) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::RefreshAuthorizedProjectsService do RSpec.describe Users::RefreshAuthorizedProjectsService, feature_category: :user_management do
include ExclusiveLeaseHelpers include ExclusiveLeaseHelpers
# We're using let! here so that any expectations for the service class are not # We're using let! here so that any expectations for the service class are not

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::RegistrationsBuildService do RSpec.describe Users::RegistrationsBuildService, feature_category: :system_access do
describe '#execute' do describe '#execute' do
let(:base_params) { build_stubbed(:user).slice(:first_name, :last_name, :username, :email, :password) } let(:base_params) { build_stubbed(:user).slice(:first_name, :last_name, :username, :email, :password) }
let(:skip_param) { {} } let(:skip_param) { {} }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::RejectService do RSpec.describe Users::RejectService, feature_category: :user_management do
let_it_be(:current_user) { create(:admin) } let_it_be(:current_user) { create(:admin) }
let(:user) { create(:user, :blocked_pending_approval) } let(:user) { create(:user, :blocked_pending_approval) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::RepairLdapBlockedService do RSpec.describe Users::RepairLdapBlockedService, feature_category: :system_access do
let(:user) { create(:omniauth_user, provider: 'ldapmain', state: 'ldap_blocked') } let(:user) { create(:omniauth_user, provider: 'ldapmain', state: 'ldap_blocked') }
let(:identity) { user.ldap_identity } let(:identity) { user.ldap_identity }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::RespondToTermsService do RSpec.describe Users::RespondToTermsService, feature_category: :user_profile do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:term) { create(:term) } let(:term) { create(:term) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::SavedReplies::CreateService do RSpec.describe Users::SavedReplies::CreateService, feature_category: :team_planning do
describe '#execute' do describe '#execute' do
let_it_be(:current_user) { create(:user) } let_it_be(:current_user) { create(:user) }
let_it_be(:saved_reply) { create(:saved_reply, user: current_user) } let_it_be(:saved_reply) { create(:saved_reply, user: current_user) }

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Users::SavedReplies::DestroyService do RSpec.describe Users::SavedReplies::DestroyService, feature_category: :team_planning do
describe '#execute' do describe '#execute' do
let!(:saved_reply) { create(:saved_reply) } let!(:saved_reply) { create(:saved_reply) }

Some files were not shown because too many files have changed in this diff Show More