Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
		
							parent
							
								
									f52c68bbac
								
							
						
					
					
						commit
						bb6a3bf05e
					
				|  | @ -1653,7 +1653,6 @@ RSpec/MissingFeatureCategory: | |||
|     - 'ee/spec/services/arkose/blocked_users_report_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/audit_event_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/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/award_emojis/add_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/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/user_preferences/update_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/post_process_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/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/ldap_group_reset_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/cleanup_service_spec.rb' | ||||
|  | @ -1756,33 +1737,7 @@ RSpec/MissingFeatureCategory: | |||
|     - '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/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/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/gitlab/license_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/web_ide_terminal_entity_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/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/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/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_cluster/sidekiq_cluster_spec.rb' | ||||
|     - 'spec/spam/concerns/has_spam_action_response_fields_spec.rb' | ||||
|  |  | |||
|  | @ -1,25 +1,19 @@ | |||
| import Vue from 'vue'; | ||||
| import { darkModeEnabled } from '~/lib/utils/color_utils'; | ||||
| import { setUrlParams } from '~/lib/utils/url_utility'; | ||||
| 
 | ||||
| export function getFrameSrc(url) { | ||||
|   return `${setUrlParams({ theme: darkModeEnabled() ? 'dark' : 'light' }, url)}&kiosk=inline-embed`; | ||||
| } | ||||
| import ObservabilityApp from '~/observability/components/observability_app.vue'; | ||||
| import { SKELETON_VARIANT_EMBED, INLINE_EMBED_DIMENSIONS } from '~/observability/constants'; | ||||
| 
 | ||||
| const mountVueComponent = (element) => { | ||||
|   const url = [element.dataset.frameUrl]; | ||||
| 
 | ||||
|   const url = element.dataset.frameUrl; | ||||
|   return new Vue({ | ||||
|     el: element, | ||||
|     render(h) { | ||||
|       return h('iframe', { | ||||
|         style: { | ||||
|           height: '366px', | ||||
|           width: '768px', | ||||
|         }, | ||||
|         attrs: { | ||||
|           src: getFrameSrc(url), | ||||
|           frameBorder: '0', | ||||
|       return h(ObservabilityApp, { | ||||
|         props: { | ||||
|           observabilityIframeSrc: url, | ||||
|           inlineEmbed: true, | ||||
|           skeletonVariant: SKELETON_VARIANT_EMBED, | ||||
|           height: INLINE_EMBED_DIMENSIONS.HEIGHT, | ||||
|           width: INLINE_EMBED_DIMENSIONS.WIDTH, | ||||
|         }, | ||||
|       }); | ||||
|     }, | ||||
|  | @ -27,7 +21,5 @@ const mountVueComponent = (element) => { | |||
| }; | ||||
| 
 | ||||
| export default function renderObservability(elements) { | ||||
|   elements.forEach((element) => { | ||||
|     mountVueComponent(element); | ||||
|   }); | ||||
|   return elements.map(mountVueComponent); | ||||
| } | ||||
|  |  | |||
|  | @ -102,10 +102,10 @@ export default { | |||
|       'issuable-info-container': !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 | ||||
|       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 --> | ||||
|       <div class="item-title gl-display-flex gl-gap-3 gl-min-w-0"> | ||||
|  |  | |||
|  | @ -96,8 +96,12 @@ export default { | |||
|         label="Fetching related merge requests" | ||||
|         class="gl-py-4" | ||||
|       /> | ||||
|       <ul v-else class="content-list related-items-list"> | ||||
|         <li v-for="mr in mergeRequests" :key="mr.id" class="list-item gl-m-0! gl-px-4! gl-py-3!"> | ||||
|       <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-p-0! gl-border-b-0!" | ||||
|         > | ||||
|           <related-issuable-item | ||||
|             :id-key="mr.id" | ||||
|             :display-reference="mr.reference" | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| import { darkModeEnabled } from '~/lib/utils/color_utils'; | ||||
| 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'; | ||||
| 
 | ||||
| export default { | ||||
|  | @ -14,25 +14,33 @@ export default { | |||
|       type: String, | ||||
|       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: { | ||||
|     iframeSrcWithParams() { | ||||
|       return setUrlParams( | ||||
|       return `${setUrlParams( | ||||
|         { theme: darkModeEnabled() ? 'dark' : 'light', username: gon?.current_username }, | ||||
|         this.observabilityIframeSrc, | ||||
|       ); | ||||
|     }, | ||||
|     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; | ||||
|       )}${this.inlineEmbed ? '&kiosk=inline-embed' : ''}`; | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|  | @ -54,38 +62,24 @@ export default { | |||
|           this.$refs.observabilitySkeleton.onContentLoaded(); | ||||
|           break; | ||||
|         case MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE: | ||||
|           this.routeUpdateHandler(payload); | ||||
|           this.$emit('route-update', payload); | ||||
|           break; | ||||
|         default: | ||||
|           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> | ||||
| 
 | ||||
| <template> | ||||
|   <observability-skeleton ref="observabilitySkeleton" :variant="getSkeletonVariant"> | ||||
|   <observability-skeleton ref="observabilitySkeleton" :variant="skeletonVariant"> | ||||
|     <iframe | ||||
|       id="observability-ui-iframe" | ||||
|       data-testid="observability-ui-iframe" | ||||
|       frameborder="0" | ||||
|       height="100%" | ||||
|       :width="width" | ||||
|       :height="height" | ||||
|       :src="iframeSrcWithParams" | ||||
|       sandbox="allow-same-origin allow-forms allow-scripts" | ||||
|     ></iframe> | ||||
|  |  | |||
|  | @ -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> | ||||
|  | @ -8,10 +8,12 @@ import { | |||
|   OBSERVABILITY_ROUTES, | ||||
|   TIMEOUT_ERROR_LABEL, | ||||
|   TIMEOUT_ERROR_MESSAGE, | ||||
|   SKELETON_VARIANT_EMBED, | ||||
| } from '../../constants'; | ||||
| import DashboardsSkeleton from './dashboards.vue'; | ||||
| import ExploreSkeleton from './explore.vue'; | ||||
| import ManageSkeleton from './manage.vue'; | ||||
| import EmbedSkeleton from './embed.vue'; | ||||
| 
 | ||||
| export default { | ||||
|   components: { | ||||
|  | @ -19,11 +21,13 @@ export default { | |||
|     DashboardsSkeleton, | ||||
|     ExploreSkeleton, | ||||
|     ManageSkeleton, | ||||
|     EmbedSkeleton, | ||||
|     GlAlert, | ||||
|   }, | ||||
|   SKELETON_VARIANTS_BY_ROUTE, | ||||
|   SKELETON_STATE, | ||||
|   OBSERVABILITY_ROUTES, | ||||
|   SKELETON_VARIANT_EMBED, | ||||
|   i18n: { | ||||
|     TIMEOUT_ERROR_LABEL, | ||||
|     TIMEOUT_ERROR_MESSAGE, | ||||
|  | @ -102,6 +106,7 @@ export default { | |||
|         <dashboards-skeleton v-if="isSkeletonShown($options.OBSERVABILITY_ROUTES.DASHBOARDS)" /> | ||||
|         <explore-skeleton v-else-if="isSkeletonShown($options.OBSERVABILITY_ROUTES.EXPLORE)" /> | ||||
|         <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> | ||||
|           <rect y="2" width="10" height="8" /> | ||||
|  | @ -122,6 +127,7 @@ export default { | |||
|       {{ $options.i18n.TIMEOUT_ERROR_MESSAGE }} | ||||
|     </gl-alert> | ||||
| 
 | ||||
|     <transition> | ||||
|       <div | ||||
|         v-show="state === $options.SKELETON_STATE.HIDDEN" | ||||
|         data-testid="observability-wrapper" | ||||
|  | @ -129,5 +135,6 @@ export default { | |||
|       > | ||||
|         <slot></slot> | ||||
|       </div> | ||||
|     </transition> | ||||
|   </div> | ||||
| </template> | ||||
|  |  | |||
|  | @ -17,6 +17,8 @@ export const SKELETON_VARIANTS_BY_ROUTE = Object.freeze({ | |||
|   [OBSERVABILITY_ROUTES.MANAGE]: 'manage', | ||||
| }); | ||||
| 
 | ||||
| export const SKELETON_VARIANT_EMBED = 'embed'; | ||||
| 
 | ||||
| export const SKELETON_STATE = Object.freeze({ | ||||
|   ERROR: 'error', | ||||
|   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_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%', | ||||
| }); | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ import Vue from 'vue'; | |||
| import VueRouter from 'vue-router'; | ||||
| 
 | ||||
| import ObservabilityApp from './components/observability_app.vue'; | ||||
| import { SKELETON_VARIANTS_BY_ROUTE } from './constants'; | ||||
| 
 | ||||
| Vue.use(VueRouter); | ||||
| 
 | ||||
|  | @ -17,10 +18,41 @@ export default () => { | |||
|   return new Vue({ | ||||
|     el, | ||||
|     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) { | ||||
|       return h(ObservabilityApp, { | ||||
|         props: { | ||||
|           observabilityIframeSrc: el.dataset.observabilityIframeSrc, | ||||
|           skeletonVariant: this.skeletonVariant, | ||||
|         }, | ||||
|         on: { | ||||
|           'route-update': (payload) => this.routeUpdateHandler(payload), | ||||
|         }, | ||||
|       }); | ||||
|     }, | ||||
|  |  | |||
|  | @ -159,6 +159,11 @@ $item-remove-button-space: 42px; | |||
| 
 | ||||
| .mr-ci-status { | ||||
|   line-height: 0; | ||||
| 
 | ||||
|   a:focus { | ||||
|     @include gl-rounded-full; | ||||
|     @include gl-focus; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @include media-breakpoint-down(xs) { | ||||
|  |  | |||
|  | @ -7,8 +7,9 @@ module Types | |||
|       description 'Values for sorting projects' | ||||
| 
 | ||||
|       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, in descending order.', value: :latest_activity_desc | ||||
|       value 'ACTIVITY_DESC', 'Sort by latest activity, descending order.', value: :latest_activity_desc | ||||
|     end | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| Types::Projects::NamespaceProjectSortEnum.prepend_mod | ||||
|  |  | |||
|  | @ -13,4 +13,5 @@ | |||
|             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? } | ||||
| 
 | ||||
|       = 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') | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| --- | ||||
| table_name: bulk_import_batch_trackers | ||||
| classes: [] | ||||
| classes: | ||||
| - BulkImports::BatchTracker | ||||
| feature_categories: | ||||
| - importers | ||||
| description: Used to store and track the import status of a batch of relations for the migration | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| --- | ||||
| table_name: bulk_import_export_batches | ||||
| classes: [] | ||||
| classes: | ||||
| - BulkImports::ExportBatch | ||||
| feature_categories: | ||||
| - importers | ||||
| description: Used to track the generation status of export batch files for groups | ||||
|  |  | |||
|  | @ -47,6 +47,7 @@ classes: | |||
| - Integrations::Shimo | ||||
| - Integrations::Slack | ||||
| - Integrations::SlackSlashCommands | ||||
| - Integrations::SquashTm | ||||
| - Integrations::Teamcity | ||||
| - Integrations::UnifyCircuit | ||||
| - Integrations::WebexTeams | ||||
|  |  | |||
|  | @ -23781,9 +23781,11 @@ Values for sorting projects. | |||
| 
 | ||||
| | 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="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` | ||||
| 
 | ||||
|  |  | |||
|  | @ -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_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_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_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`. | | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 | ||||
| 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 | ||||
| job is fully executed. The following video gives you an overview of GitLab scan result policies: | ||||
| findings of one or more security scan jobs. Scan result policies are evaluated after a CI scanning job is fully executed. | ||||
| 
 | ||||
| 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"> | ||||
|   See the video: <a href="https://youtu.be/w5I9gcUgr9U">Overview of GitLab Scan Result Policies</a>. | ||||
|  |  | |||
|  | @ -170,11 +170,7 @@ passing in an optional value to the `commit_sha` query parameter. | |||
| 
 | ||||
| ## 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. | ||||
| 
 | ||||
| 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. | ||||
| > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/387910) in GitLab 15.10. | ||||
| 
 | ||||
| With compliance frameworks report, you can see the compliance frameworks that are applied to projects in a group. Each row of the report shows: | ||||
| 
 | ||||
|  |  | |||
|  | @ -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. | ||||
| 
 | ||||
| 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"> | ||||
|   See the video: <a href="https://www.youtube.com/watch?v=34qBQ9t8qO8">Overview of GitLab License Approval Policies</a>. | ||||
|  |  | |||
|  | @ -56,15 +56,15 @@ dependency_scanning: | |||
| 
 | ||||
| .gemnasium-shared-rule: | ||||
|   exists: | ||||
|     - '{Gemfile.lock,*/Gemfile.lock,*/*/Gemfile.lock}' | ||||
|     - '{composer.lock,*/composer.lock,*/*/composer.lock}' | ||||
|     - '{gems.locked,*/gems.locked,*/*/gems.locked}' | ||||
|     - '{go.sum,*/go.sum,*/*/go.sum}' | ||||
|     - '{npm-shrinkwrap.json,*/npm-shrinkwrap.json,*/*/npm-shrinkwrap.json}' | ||||
|     - '{package-lock.json,*/package-lock.json,*/*/package-lock.json}' | ||||
|     - '{yarn.lock,*/yarn.lock,*/*/yarn.lock}' | ||||
|     - '{packages.lock.json,*/packages.lock.json,*/*/packages.lock.json}' | ||||
|     - '{conan.lock,*/conan.lock,*/*/conan.lock}' | ||||
|     - '**/Gemfile.lock' | ||||
|     - '**/composer.lock' | ||||
|     - '**/gems.locked' | ||||
|     - '**/go.sum' | ||||
|     - '**/npm-shrinkwrap.json' | ||||
|     - '**/package-lock.json' | ||||
|     - '**/yarn.lock' | ||||
|     - '**/packages.lock.json' | ||||
|     - '**/conan.lock' | ||||
| 
 | ||||
| gemnasium-dependency_scanning: | ||||
|   extends: | ||||
|  | @ -91,10 +91,10 @@ gemnasium-dependency_scanning: | |||
| 
 | ||||
| .gemnasium-maven-shared-rule: | ||||
|   exists: | ||||
|     - '{build.gradle,*/build.gradle,*/*/build.gradle}' | ||||
|     - '{build.gradle.kts,*/build.gradle.kts,*/*/build.gradle.kts}' | ||||
|     - '{build.sbt,*/build.sbt,*/*/build.sbt}' | ||||
|     - '{pom.xml,*/pom.xml,*/*/pom.xml}' | ||||
|     - '**/build.gradle' | ||||
|     - '**/build.gradle.kts' | ||||
|     - '**/build.sbt' | ||||
|     - '**/pom.xml' | ||||
| 
 | ||||
| gemnasium-maven-dependency_scanning: | ||||
|   extends: | ||||
|  | @ -119,12 +119,12 @@ gemnasium-maven-dependency_scanning: | |||
| 
 | ||||
| .gemnasium-python-shared-rule: | ||||
|   exists: | ||||
|     - '{requirements.txt,*/requirements.txt,*/*/requirements.txt}' | ||||
|     - '{requirements.pip,*/requirements.pip,*/*/requirements.pip}' | ||||
|     - '{Pipfile,*/Pipfile,*/*/Pipfile}' | ||||
|     - '{requires.txt,*/requires.txt,*/*/requires.txt}' | ||||
|     - '{setup.py,*/setup.py,*/*/setup.py}' | ||||
|     - '{poetry.lock,*/poetry.lock,*/*/poetry.lock}' | ||||
|     - '**/requirements.txt' | ||||
|     - '**/requirements.pip' | ||||
|     - '**/Pipfile' | ||||
|     - '**/requires.txt' | ||||
|     - '**/setup.py' | ||||
|     - '**/poetry.lock' | ||||
| 
 | ||||
| gemnasium-python-dependency_scanning: | ||||
|   extends: | ||||
|  |  | |||
|  | @ -56,15 +56,15 @@ dependency_scanning: | |||
| 
 | ||||
| .gemnasium-shared-rule: | ||||
|   exists: | ||||
|     - '{Gemfile.lock,*/Gemfile.lock,*/*/Gemfile.lock}' | ||||
|     - '{composer.lock,*/composer.lock,*/*/composer.lock}' | ||||
|     - '{gems.locked,*/gems.locked,*/*/gems.locked}' | ||||
|     - '{go.sum,*/go.sum,*/*/go.sum}' | ||||
|     - '{npm-shrinkwrap.json,*/npm-shrinkwrap.json,*/*/npm-shrinkwrap.json}' | ||||
|     - '{package-lock.json,*/package-lock.json,*/*/package-lock.json}' | ||||
|     - '{yarn.lock,*/yarn.lock,*/*/yarn.lock}' | ||||
|     - '{packages.lock.json,*/packages.lock.json,*/*/packages.lock.json}' | ||||
|     - '{conan.lock,*/conan.lock,*/*/conan.lock}' | ||||
|     - '**/Gemfile.lock' | ||||
|     - '**/composer.lock' | ||||
|     - '**/gems.locked' | ||||
|     - '**/go.sum' | ||||
|     - '**/npm-shrinkwrap.json' | ||||
|     - '**/package-lock.json' | ||||
|     - '**/yarn.lock' | ||||
|     - '**/packages.lock.json' | ||||
|     - '**/conan.lock' | ||||
| 
 | ||||
| gemnasium-dependency_scanning: | ||||
|   extends: | ||||
|  | @ -109,10 +109,10 @@ gemnasium-dependency_scanning: | |||
| 
 | ||||
| .gemnasium-maven-shared-rule: | ||||
|   exists: | ||||
|     - '{build.gradle,*/build.gradle,*/*/build.gradle}' | ||||
|     - '{build.gradle.kts,*/build.gradle.kts,*/*/build.gradle.kts}' | ||||
|     - '{build.sbt,*/build.sbt,*/*/build.sbt}' | ||||
|     - '{pom.xml,*/pom.xml,*/*/pom.xml}' | ||||
|     - '**/build.gradle' | ||||
|     - '**/build.gradle.kts' | ||||
|     - '**/build.sbt' | ||||
|     - '**/pom.xml' | ||||
| 
 | ||||
| gemnasium-maven-dependency_scanning: | ||||
|   extends: | ||||
|  | @ -155,12 +155,12 @@ gemnasium-maven-dependency_scanning: | |||
| 
 | ||||
| .gemnasium-python-shared-rule: | ||||
|   exists: | ||||
|     - '{requirements.txt,*/requirements.txt,*/*/requirements.txt}' | ||||
|     - '{requirements.pip,*/requirements.pip,*/*/requirements.pip}' | ||||
|     - '{Pipfile,*/Pipfile,*/*/Pipfile}' | ||||
|     - '{requires.txt,*/requires.txt,*/*/requires.txt}' | ||||
|     - '{setup.py,*/setup.py,*/*/setup.py}' | ||||
|     - '{poetry.lock,*/poetry.lock,*/*/poetry.lock}' | ||||
|     - '**/requirements.txt' | ||||
|     - '**/requirements.pip' | ||||
|     - '**/Pipfile' | ||||
|     - '**/requires.txt' | ||||
|     - '**/setup.py' | ||||
|     - '**/poetry.lock' | ||||
| 
 | ||||
| gemnasium-python-dependency_scanning: | ||||
|   extends: | ||||
|  |  | |||
|  | @ -1,7 +1,10 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| 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 | ||||
|       let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } | ||||
| 
 | ||||
|  |  | |||
|  | @ -147,14 +147,14 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do | |||
|         selected_group.add_owner(user) | ||||
|       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) | ||||
| 
 | ||||
|         page.within('[data-testid="transfer-locations-dropdown"]') do | ||||
|           click_button _('Select parent group') | ||||
|           fill_in _('Search'), with: target_group_name | ||||
|           wait_for_requests | ||||
|           click_button target_group_name | ||||
|           click_button(target_group_name || 'No parent group') | ||||
|         end | ||||
| 
 | ||||
|         click_button s_('GroupSettings|Transfer group') | ||||
|  | @ -166,7 +166,10 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do | |||
|           click_button 'Confirm' | ||||
|         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) | ||||
|       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) } | ||||
| 
 | ||||
|       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' | ||||
|       end | ||||
|  |  | |||
|  | @ -8,9 +8,6 @@ RSpec.describe 'Observability rendering', :js, feature_category: :metrics do | |||
|   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(:expected_observable_url) { "https://observe.gitlab.com/-/#{group.id}/explore?foo=bar" } | ||||
|   let_it_be(:expected) do | ||||
|     %(<iframe src="#{expected_observable_url}&theme=light&kiosk=inline-embed" frameborder="0") | ||||
|   end | ||||
| 
 | ||||
|   before do | ||||
|     stub_config_setting(url: "https://www.gitlab.com") | ||||
|  |  | |||
|  | @ -1,40 +1,43 @@ | |||
| import Vue from 'vue'; | ||||
| import { createWrapper } from '@vue/test-utils'; | ||||
| 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', () => { | ||||
|   const findObservabilityIframes = (theme = 'light') => | ||||
|     document.querySelectorAll( | ||||
|       `iframe[src="https://observe.gitlab.com/?theme=${theme}&kiosk=inline-embed"]`, | ||||
|     ); | ||||
| 
 | ||||
|   const renderEmbeddedObservability = () => { | ||||
|     renderObservability([...document.querySelectorAll('.js-render-observability')]); | ||||
|     jest.runAllTimers(); | ||||
|   }; | ||||
| describe('renderObservability', () => { | ||||
|   let subject; | ||||
| 
 | ||||
|   beforeEach(() => { | ||||
|     document.body.dataset.page = ''; | ||||
|     document.body.innerHTML = ''; | ||||
|     subject = document.createElement('div'); | ||||
|     subject.classList.add('js-render-observability'); | ||||
|     subject.dataset.frameUrl = 'https://observe.gitlab.com/'; | ||||
|     document.body.appendChild(subject); | ||||
|   }); | ||||
| 
 | ||||
|   it('renders an observability iframe', () => { | ||||
|     document.body.innerHTML = `<div class="js-render-observability" data-frame-url="https://observe.gitlab.com/"></div>`; | ||||
| 
 | ||||
|     expect(findObservabilityIframes()).toHaveLength(0); | ||||
| 
 | ||||
|     renderEmbeddedObservability(); | ||||
| 
 | ||||
|     expect(findObservabilityIframes()).toHaveLength(1); | ||||
|   afterEach(() => { | ||||
|     subject.remove(); | ||||
|   }); | ||||
| 
 | ||||
|   it('renders iframe with dark param when GL has dark theme', () => { | ||||
|     document.body.innerHTML = `<div class="js-render-observability" data-frame-url="https://observe.gitlab.com/"></div>`; | ||||
|     jest.spyOn(ColorUtils, 'darkModeEnabled').mockImplementation(() => true); | ||||
|   it('should return an array of Vue instances', () => { | ||||
|     const vueInstances = renderObservability([ | ||||
|       ...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, | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|  |  | |||
|  | @ -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', | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|  | @ -1,19 +1,20 @@ | |||
| import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; | ||||
| import ObservabilityApp from '~/observability/components/observability_app.vue'; | ||||
| import ObservabilitySkeleton from '~/observability/components/skeleton/index.vue'; | ||||
| 
 | ||||
| import { MESSAGE_EVENT_TYPE, SKELETON_VARIANTS_BY_ROUTE } from '~/observability/constants'; | ||||
| import { | ||||
|   MESSAGE_EVENT_TYPE, | ||||
|   INLINE_EMBED_DIMENSIONS, | ||||
|   FULL_APP_DIMENSIONS, | ||||
|   SKELETON_VARIANT_EMBED, | ||||
| } from '~/observability/constants'; | ||||
| 
 | ||||
| import { darkModeEnabled } from '~/lib/utils/color_utils'; | ||||
| 
 | ||||
| jest.mock('~/lib/utils/color_utils'); | ||||
| 
 | ||||
| describe('Observability root app', () => { | ||||
| describe('ObservabilityApp', () => { | ||||
|   let wrapper; | ||||
|   const replace = jest.fn(); | ||||
|   const $router = { | ||||
|     replace, | ||||
|   }; | ||||
| 
 | ||||
|   const $route = { | ||||
|     pathname: 'https://gitlab.com/gitlab-org/', | ||||
|     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 OBSERVABILITY_ROUTES = Object.keys(SKELETON_VARIANTS_BY_ROUTE); | ||||
|   const TEST_USERNAME = 'test-user'; | ||||
| 
 | ||||
|   const SKELETON_VARIANTS = Object.values(SKELETON_VARIANTS_BY_ROUTE); | ||||
| 
 | ||||
|   const mountComponent = (route = $route) => { | ||||
|   const mountComponent = (props) => { | ||||
|     wrapper = shallowMountExtended(ObservabilityApp, { | ||||
|       propsData: { | ||||
|         observabilityIframeSrc: TEST_IFRAME_SRC, | ||||
|         ...props, | ||||
|       }, | ||||
|       stubs: { | ||||
|         'observability-skeleton': ObservabilitySkeleton, | ||||
|       }, | ||||
|       mocks: { | ||||
|         $router, | ||||
|         $route: route, | ||||
|         $route, | ||||
|       }, | ||||
|     }); | ||||
|   }; | ||||
|  | @ -48,13 +47,11 @@ describe('Observability root app', () => { | |||
|   const dispatchMessageEvent = (message) => | ||||
|     window.dispatchEvent(new MessageEvent('message', message)); | ||||
| 
 | ||||
|   describe('iframe src', () => { | ||||
|     const TEST_USERNAME = 'test-user'; | ||||
| 
 | ||||
|   beforeEach(() => { | ||||
|     gon.current_username = TEST_USERNAME; | ||||
|   }); | ||||
| 
 | ||||
|   describe('iframe src', () => { | ||||
|     it('should render an iframe with observabilityIframeSrc, decorated with light theme and username', () => { | ||||
|       darkModeEnabled.mockReturnValueOnce(false); | ||||
|       mountComponent(); | ||||
|  | @ -88,48 +85,70 @@ describe('Observability root app', () => { | |||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('on GOUI_ROUTE_UPDATE', () => { | ||||
|     it('should not call replace method from vue router if message event does not have url', () => { | ||||
|       mountComponent(); | ||||
|       dispatchMessageEvent({ | ||||
|         type: MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE, | ||||
|         payload: { data: 'some other data' }, | ||||
|       }); | ||||
|       expect(replace).not.toHaveBeenCalled(); | ||||
|   describe('iframe kiosk query param', () => { | ||||
|     it('when inlineEmbed, it should set the proper kiosk query parameter', () => { | ||||
|       mountComponent({ | ||||
|         inlineEmbed: true, | ||||
|       }); | ||||
| 
 | ||||
|     it.each` | ||||
|       condition                                                  | origin                          | observability_path | url | ||||
|       ${'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(); | ||||
|       }, | ||||
|       const iframe = findIframe(); | ||||
| 
 | ||||
|       expect(iframe.attributes('src')).toBe( | ||||
|         `${TEST_IFRAME_SRC}&theme=light&username=${TEST_USERNAME}&kiosk=inline-embed`, | ||||
|       ); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|     it('should call replace method from vue router on message event callback', () => { | ||||
|   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('should fallback to default size', () => { | ||||
|       mountComponent({}); | ||||
| 
 | ||||
|       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(); | ||||
| 
 | ||||
|       const payload = { url: '/explore' }; | ||||
|       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', | ||||
|       }); | ||||
| 
 | ||||
|       expect(replace).toHaveBeenCalled(); | ||||
|       expect(replace).toHaveBeenCalledWith({ | ||||
|         name: 'https://gitlab.com/gitlab-org/', | ||||
|         query: { | ||||
|           otherQuery: 100, | ||||
|           observability_path: '/explore', | ||||
|         }, | ||||
|       }); | ||||
|       expect(wrapper.emitted('route-update')[0]).toEqual([payload]); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|  | @ -163,34 +182,17 @@ describe('Observability root app', () => { | |||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   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', ({ 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', () => { | ||||
|   describe('on unmount', () => { | ||||
|     it('should not emit any even on route update', () => { | ||||
|       mountComponent(); | ||||
|       wrapper.destroy(); | ||||
| 
 | ||||
|       // testing event cleanup logic, should not call on messege event after component is destroyed
 | ||||
| 
 | ||||
|       dispatchMessageEvent({ | ||||
|         data: { type: MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE, payload: { url: '/explore' } }, | ||||
|         origin: 'https://observe.gitlab.com', | ||||
|       }); | ||||
| 
 | ||||
|       expect(replace).not.toHaveBeenCalled(); | ||||
|       expect(wrapper.emitted('route-update')).toBeUndefined(); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|  |  | |||
|  | @ -6,8 +6,13 @@ import Skeleton from '~/observability/components/skeleton/index.vue'; | |||
| import DashboardsSkeleton from '~/observability/components/skeleton/dashboards.vue'; | ||||
| import ExploreSkeleton from '~/observability/components/skeleton/explore.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', () => { | ||||
|   let wrapper; | ||||
|  | @ -22,6 +27,8 @@ describe('Skeleton component', () => { | |||
| 
 | ||||
|   const findManageSkeleton = () => wrapper.findComponent(ManageSkeleton); | ||||
| 
 | ||||
|   const findEmbedSkeleton = () => wrapper.findComponent(EmbedSkeleton); | ||||
| 
 | ||||
|   const findAlert = () => wrapper.findComponent(GlAlert); | ||||
| 
 | ||||
|   const mountComponent = ({ ...props } = {}) => { | ||||
|  | @ -97,16 +104,20 @@ describe('Skeleton component', () => { | |||
|       ${'dashboards'} | ${'variant is dashboards'}                        | ${SKELETON_VARIANTS[0]} | ||||
|       ${'explore'}    | ${'variant is explore'}                           | ${SKELETON_VARIANTS[1]} | ||||
|       ${'manage'}     | ${'variant is manage'}                            | ${SKELETON_VARIANTS[2]} | ||||
|       ${'embed'}      | ${'variant is embed'}                             | ${SKELETON_VARIANT_EMBED} | ||||
|       ${'default'}    | ${'variant is not manage, dashboards or explore'} | ${'unknown'} | ||||
|     `('should render $skeletonType skeleton if $condition', async ({ skeletonType, variant }) => {
 | ||||
|       mountComponent({ variant }); | ||||
|       jest.advanceTimersByTime(DEFAULT_TIMERS.CONTENT_WAIT_MS); | ||||
|       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(findExploreSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANTS[1]); | ||||
|       expect(findManageSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANTS[2]); | ||||
|       expect(findEmbedSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANT_EMBED); | ||||
| 
 | ||||
|       expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(showsDefaultSkeleton); | ||||
|     }); | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe AccessTokenValidationService do | ||||
| RSpec.describe AccessTokenValidationService, feature_category: :system_access do | ||||
|   describe ".include_any_scope?" do | ||||
|     let(:request) { double("request") } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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(:user) { create(:user, :with_sign_ins) } | ||||
|   let_it_be(:project_member) { create(:project_member, user: user) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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(:user) { create(:user) } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe BaseContainerService do | ||||
| RSpec.describe BaseContainerService, feature_category: :container_registry do | ||||
|   let(:project) { Project.new } | ||||
|   let(:user) { User.new } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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 } | ||||
| 
 | ||||
|   describe '#relation_for_count' do | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe BulkCreateIntegrationService do | ||||
| RSpec.describe BulkCreateIntegrationService, feature_category: :integrations do | ||||
|   include JiraIntegrationHelpers | ||||
| 
 | ||||
|   before_all do | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe BulkPushEventPayloadService do | ||||
| RSpec.describe BulkPushEventPayloadService, feature_category: :source_code_management do | ||||
|   let(:event) { create(:push_event) } | ||||
| 
 | ||||
|   let(:push_data) do | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe BulkUpdateIntegrationService do | ||||
| RSpec.describe BulkUpdateIntegrationService, feature_category: :integrations do | ||||
|   include JiraIntegrationHelpers | ||||
| 
 | ||||
|   before_all do | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe CohortsService do | ||||
| RSpec.describe CohortsService, feature_category: :shared do | ||||
|   describe '#execute' do | ||||
|     def month_start(months_ago) | ||||
|       months_ago.months.ago.beginning_of_month.to_date | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe CompareService do | ||||
| RSpec.describe CompareService, feature_category: :source_code_management do | ||||
|   let(:project) { create(:project, :repository) } | ||||
|   let(:user) { create(:user) } | ||||
|   let(:service) { described_class.new(project, 'feature') } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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 | ||||
| 
 | ||||
|   let(:service) { described_class.new } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe GravatarService do | ||||
| RSpec.describe GravatarService, feature_category: :user_profile do | ||||
|   describe '#execute' do | ||||
|     let(:url) { 'http://example.com/avatar?hash=%{hash}&size=%{size}&email=%{email}&username=%{username}' } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe ImportExportCleanUpService do | ||||
| RSpec.describe ImportExportCleanUpService, feature_category: :importers do | ||||
|   describe '#execute' do | ||||
|     let(:service) { described_class.new } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe MarkdownContentRewriterService do | ||||
| RSpec.describe MarkdownContentRewriterService, feature_category: :team_planning do | ||||
|   let_it_be(:user) { create(:user) } | ||||
|   let_it_be(:source_parent) { create(:project, :public) } | ||||
|   let_it_be(:target_parent) { create(:project, :public) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe NoteSummary do | ||||
| RSpec.describe NoteSummary, feature_category: :code_review_workflow do | ||||
|   let(:project)  { build(:project) } | ||||
|   let(:noteable) { build(:issue) } | ||||
|   let(:user)     { build(:user) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe PostReceiveService do | ||||
| RSpec.describe PostReceiveService, feature_category: :team_planning do | ||||
|   include GitlabShellHelpers | ||||
|   include Gitlab::Routing | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe PreviewMarkdownService do | ||||
| RSpec.describe PreviewMarkdownService, feature_category: :team_planning do | ||||
|   let(:user) { create(:user) } | ||||
|   let(:project) { create(:project, :repository) } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe PushEventPayloadService do | ||||
| RSpec.describe PushEventPayloadService, feature_category: :source_code_management do | ||||
|   let(:event) { create(:push_event) } | ||||
| 
 | ||||
|   describe '#execute' do | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe RepositoryArchiveCleanUpService do | ||||
| RSpec.describe RepositoryArchiveCleanUpService, feature_category: :source_code_management do | ||||
|   subject(:service) { described_class.new } | ||||
| 
 | ||||
|   describe '#execute (new archive locations)' do | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe ResetProjectCacheService do | ||||
| RSpec.describe ResetProjectCacheService, feature_category: :projects do | ||||
|   let(:project) { create(:project) } | ||||
|   let(:user) { create(:user) } | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ require 're2' | |||
| require_relative '../../app/services/service_response' | ||||
| require_relative '../../lib/gitlab/error_tracking' | ||||
| 
 | ||||
| RSpec.describe ServiceResponse do | ||||
| RSpec.describe ServiceResponse, feature_category: :shared do | ||||
|   describe '.success' do | ||||
|     it 'creates a successful response without a message' do | ||||
|       expect(described_class.success).to be_success | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe SystemHooksService do | ||||
| RSpec.describe SystemHooksService, feature_category: :webhooks do | ||||
|   describe '#execute_hooks_for' do | ||||
|     let_it_be(:user) { create(:user) } | ||||
|     let_it_be(:group) { create(:group) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe TaskListToggleService do | ||||
| RSpec.describe TaskListToggleService, feature_category: :team_planning do | ||||
|   let(:markdown) do | ||||
|     <<-EOT.strip_heredoc | ||||
|       * [ ] Task 1 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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(:current_user) { create(:user) } | ||||
|   let_it_be(:assignee_one) { create(:user) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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(:developer) { create(:user, developer_projects: [project]) } | ||||
|   let_it_be(:maintainer) { create(:user, maintainer_projects: [project]) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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(:file) { instance_double(Terraform::StateUploader, relative_path: 'path') } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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(:user) { create(:user, maintainer_projects: [project]) } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe TestHooks::ProjectService do | ||||
| RSpec.describe TestHooks::ProjectService, feature_category: :code_testing do | ||||
|   include AfterNextHelpers | ||||
| 
 | ||||
|   let(:current_user) { create(:user) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe TestHooks::SystemService do | ||||
| RSpec.describe TestHooks::SystemService, feature_category: :code_testing do | ||||
|   include AfterNextHelpers | ||||
| 
 | ||||
|   describe '#execute' do | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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(:project) { create(:project, :public) } | ||||
|   let_it_be(:issue) { create(:issue, project: project) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe TodoService do | ||||
| RSpec.describe TodoService, feature_category: :team_planning do | ||||
|   include AfterNextHelpers | ||||
| 
 | ||||
|   let_it_be(:project) { create(:project, :repository) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Todos::AllowedTargetFilterService do | ||||
| RSpec.describe Todos::AllowedTargetFilterService, feature_category: :team_planning do | ||||
|   include DesignManagementTestHelpers | ||||
| 
 | ||||
|   let_it_be(:authorized_group) { create(:group, :private) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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(:user)           { create(:user) } | ||||
|   let(:author)         { create(:user) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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_2)   { create(:user) } | ||||
|   let_it_be(:design)   { create(:design) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Todos::Destroy::DestroyedIssuableService do | ||||
| RSpec.describe Todos::Destroy::DestroyedIssuableService, feature_category: :team_planning do | ||||
|   describe '#execute' do | ||||
|     let_it_be(:user) { create(:user) } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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(:project)        { create(:project, :public, group: group) } | ||||
|   let(:user)           { create(:user) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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(:issue)          { create(:issue, project: project) } | ||||
|   let_it_be(:mr)             { create(:merge_request, source_project: project) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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(:target_topic) { create(:topic, name: 'target_topic') } | ||||
|   let_it_be(:project_1) { create(:project, :public, topic_list: source_topic.name) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe TwoFactor::DestroyService do | ||||
| RSpec.describe TwoFactor::DestroyService, feature_category: :system_access do | ||||
|   let_it_be(:current_user) { create(:user) } | ||||
| 
 | ||||
|   subject { described_class.new(current_user, user: user).execute } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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(:api_url) { 'http://registry.gitlab' } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe MergeRequestMetricsService do | ||||
| RSpec.describe MergeRequestMetricsService, feature_category: :code_review_workflow do | ||||
|   let(:metrics) { create(:merge_request).metrics } | ||||
| 
 | ||||
|   describe '#merge' do | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe UploadService do | ||||
| RSpec.describe UploadService, feature_category: :shared do | ||||
|   describe 'File service' do | ||||
|     before do | ||||
|       @user = create(:user) | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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(:user) { create(:user) } | ||||
|   let_it_be_with_reload(:upload) { create(:upload, :issuable_upload, model: project) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe UserPreferences::UpdateService do | ||||
| RSpec.describe UserPreferences::UpdateService, feature_category: :user_profile do | ||||
|   let(:user) { create(:user) } | ||||
|   let(:params) { { view_diffs_file_by_file: false } } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::ActivityService do | ||||
| RSpec.describe Users::ActivityService, feature_category: :user_profile do | ||||
|   include ExclusiveLeaseHelpers | ||||
| 
 | ||||
|   let(:user) { create(:user, last_activity_on: last_activity_on) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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(:user) { create(:user, :blocked_pending_approval) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::AuthorizedBuildService do | ||||
| RSpec.describe Users::AuthorizedBuildService, feature_category: :user_management do | ||||
|   describe '#execute' do | ||||
|     let_it_be(:current_user) { create(:user) } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::BanService do | ||||
| RSpec.describe Users::BanService, feature_category: :user_management do | ||||
|   let(:user) { create(:user) } | ||||
| 
 | ||||
|   let_it_be(:current_user) { create(:admin) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::BannedUserBaseService do | ||||
| RSpec.describe Users::BannedUserBaseService, feature_category: :user_management do | ||||
|   let(:admin) { create(:admin) } | ||||
|   let(:base_service) { described_class.new(admin) } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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_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) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::BlockService do | ||||
| RSpec.describe Users::BlockService, feature_category: :user_management do | ||||
|   let_it_be(:current_user) { create(:admin) } | ||||
| 
 | ||||
|   subject(:service) { described_class.new(current_user) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::BuildService do | ||||
| RSpec.describe Users::BuildService, feature_category: :user_management do | ||||
|   using RSpec::Parameterized::TableSyntax | ||||
| 
 | ||||
|   describe '#execute' do | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::CreateService do | ||||
| RSpec.describe Users::CreateService, feature_category: :user_management do | ||||
|   describe '#execute' do | ||||
|     let(:password) { User.random_password } | ||||
|     let(:admin_user) { create(:admin) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::DestroyService do | ||||
| RSpec.describe Users::DestroyService, feature_category: :user_management do | ||||
|   let!(:user)      { create(:user) } | ||||
|   let!(:admin)     { create(:admin) } | ||||
|   let!(:namespace) { user.namespace } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::DismissCalloutService do | ||||
| RSpec.describe Users::DismissCalloutService, feature_category: :user_management do | ||||
|   describe '#execute' do | ||||
|     let_it_be(:user) { create(:user) } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::DismissGroupCalloutService do | ||||
| RSpec.describe Users::DismissGroupCalloutService, feature_category: :user_management do | ||||
|   describe '#execute' do | ||||
|     let_it_be(:user) { create(:user) } | ||||
|     let_it_be(:group) { create(:group) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::DismissProjectCalloutService do | ||||
| RSpec.describe Users::DismissProjectCalloutService, feature_category: :user_management do | ||||
|   describe '#execute' do | ||||
|     let_it_be(:user) { create(:user) } | ||||
|     let_it_be(:project) { create(:project) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::EmailVerification::GenerateTokenService do | ||||
| RSpec.describe Users::EmailVerification::GenerateTokenService, feature_category: :system_access do | ||||
|   using RSpec::Parameterized::TableSyntax | ||||
| 
 | ||||
|   let(:service) { described_class.new(attr: attr) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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 | ||||
| 
 | ||||
|   let(:service) { described_class.new(attr: attr, user: user, token: token) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::InProductMarketingEmailRecords do | ||||
| RSpec.describe Users::InProductMarketingEmailRecords, feature_category: :onboarding do | ||||
|   let_it_be(:user) { create :user } | ||||
| 
 | ||||
|   subject(:records) { described_class.new } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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) } | ||||
| 
 | ||||
|   subject { described_class.new(user) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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(:project) { build(:project, id: 2) } | ||||
|   let(:event) { build(:push_event, id: 3, author: user, project: project) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::MigrateRecordsToGhostUserInBatchesService do | ||||
| RSpec.describe Users::MigrateRecordsToGhostUserInBatchesService, feature_category: :user_management do | ||||
|   let(:service) { described_class.new } | ||||
| 
 | ||||
|   let_it_be(:ghost_user_migration) { create(:ghost_user_migration) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::MigrateRecordsToGhostUserService do | ||||
| RSpec.describe Users::MigrateRecordsToGhostUserService, feature_category: :user_management do | ||||
|   include BatchDestroyDependentAssociationsHelper | ||||
| 
 | ||||
|   let!(:user) { create(:user) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::RefreshAuthorizedProjectsService do | ||||
| RSpec.describe Users::RefreshAuthorizedProjectsService, feature_category: :user_management do | ||||
|   include ExclusiveLeaseHelpers | ||||
| 
 | ||||
|   # We're using let! here so that any expectations for the service class are not | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::RegistrationsBuildService do | ||||
| RSpec.describe Users::RegistrationsBuildService, feature_category: :system_access do | ||||
|   describe '#execute' do | ||||
|     let(:base_params) { build_stubbed(:user).slice(:first_name, :last_name, :username, :email, :password) } | ||||
|     let(:skip_param) { {} } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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(:user) { create(:user, :blocked_pending_approval) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| 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(:identity) { user.ldap_identity } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::RespondToTermsService do | ||||
| RSpec.describe Users::RespondToTermsService, feature_category: :user_profile do | ||||
|   let(:user) { create(:user) } | ||||
|   let(:term) { create(:term) } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::SavedReplies::CreateService do | ||||
| RSpec.describe Users::SavedReplies::CreateService, feature_category: :team_planning do | ||||
|   describe '#execute' do | ||||
|     let_it_be(:current_user) { create(:user) } | ||||
|     let_it_be(:saved_reply) { create(:saved_reply, user: current_user) } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Users::SavedReplies::DestroyService do | ||||
| RSpec.describe Users::SavedReplies::DestroyService, feature_category: :team_planning do | ||||
|   describe '#execute' do | ||||
|     let!(:saved_reply) { create(:saved_reply) } | ||||
| 
 | ||||
|  |  | |||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue